Stem variables and subst
17 messages in this thread
Now that I have been playing with Arexx, I have run into a simple problem
that I have gotten stumped over. I have written a fairly complicated
script called UUTRAF which reads my traffic logs from UUCP and generates
weekly/daily/monthly/yearly reports. The hassle is that I want to use
stem variables based on the name of the node like:
host = 'mine';
time.host = time.host+thistime; /* we want to update time.mine */
What I have been forced to use is:
select
when host = 'mine' time.mine = time.mine + thistime;
when host = 'them' time.them = time.them + thistime;
otherwise time.other = time.other + thistime;
end
I have played with even using interpret to get that extra level of
substitution. Does anyone have any suggestions/clues?
What, you didn't find the ARexx manual to be as lucid and explanatory as, say,
K&R? 🙂 "Stem" is in the index under "symbol tokens: stem, 21".
This worked for me:
data.john = 'J'
count.john = 10
data.rick = 'R'
count.rick = 20
say data.john count.john ',' data.rick count.rick
pull user
say data.user count.user
Now, that's not to say that it didn't take me a while to get this to work the
way I thought it should. I think there's something that's not apparent to us
linear, non-associative programmers – maybe it has to do with the difference
.. hmm, no, that's not it. 🙂 From the examples in the ARexx book, and in
the 'Rexx Handbook', it looks like you should be able to set the 'user'
variable and retrieve the 'count'. That works in my example, but in yours
where you're setting 'host' to 'mine' or 'them' it's not working.
John,
You might want to direct your question to Bill Hawes; he shows up in the
AmigaTech forum almost immediately when his PPN is used, from what I've
seen. I don't have any ideas, but I'm no expert with Arexx, just "ok" with
it.
–Ben
…via AutoPilot
John,
Your example of having 'mine' substituted for time.host should work fine;
that's what stem variables are designed for. One thing to watch out for though
is that the substitution is case sensitive, and in fact the substituted string
can contain any characters at all. When you got to retrive the values, be sure
that the variable matches the alphabetic case you used to set the value.
A valuable aid for debugging stem variables is the TRACE C option; it will show
you the expanded (substituted) values of all compound variables.
Hope this helps …
Bill Hawes
For some reason, I couldn't get John's example code to work. It gave some kind
of "arithmetic conversion error."
You need to initialize any variables that you want to add something to.
-larry
Is the error you're getting something like "Arithmetic Mismatch Error"?
If so, I believe that the problem is that the stem variables are not
initialized to be numeric, e.g., time. = 0. Therefore when you attempt to
perform:
time.host = time.host + thistime
The interpreter tries to add thistime (which is numeric, I assume) to
time.host (which, if you've failed to initialize it, contains the string
"TIME.COUNT" <I think>). Boom, arithmetic mismatch.
I wrote a simple ARexx program to calculate total bytes and bytes per
second from my node (wlgami.cmhnet.org) a while back and ran into the same
problem. If you'd like, I could send this program to you (it's not very
long, ~60 lines).
Hope this helps,
Bill
Actually, I finally figured out my problem. This doesn't work:
t.DeepThot = 0
Host = 'DeepThot'
t.host = t.host + 1;
But this does work:
t.DeepThot = 0
t.DeepThot = t.DeepThot + 1;
Thinking a little, I found that this does work:
t.DeepThot = 0
Host = 'DEEPTHOT'
t.host = t.host + 1;
So, my ultimate solution has been to do:
t.DeepThot = 0
Host = 'DeepThot'
Host = Upper(Host)
t.host = t.host + 1
It looks like the problem is related to upper/lower case in the second
level substitution. I couldn't see this documented anywhere.
John,
>It looks like the problem is related to upper/lower case in the second
>level substitution. I couldn't see this documented anywhere.
From Page 3-3 of the C= ARexx manual (First paragraph after symbol
definitions):
"Simple, stem, and compound symbols are called variable s and may
be assigned a value during the course of the program execution. If a
variable has not been assigned a value, it is uninitialized. The value
for an uninitialized variable is the variable name itself (translated to
uppercase, if applicable)"
So you might say:
DeepThot = 'DeepThot' /* accounts for case of symbol*/
Host = 'DeepThot'
t.host = t.host + 1
Eg:
/* Test stem var DeeptThot example */
DeepThot = 'DeepThot'
Widget.DeepThot = 0
Host = 'DeepThot'
SAY "Before: " Widget.Host
Widget.Host = Widget.Host + 1
SAY "After (host):" Widget.Host
SAY "After (DeepThot):" Widget.DeepThot
EXIT
This rexx program yields the following output:
Before: 0
After (host): 1
After (DeepThot): 1
Hope this gives you an alternative solution to your problem
Clark -|-
Williams –O-o-O– Via George
Actually, the problem is that for the second level subtitution, it is not
automatically translated to upper case. Hence:
t.deepthot = 1
host = 'DeepThot'
say "Try1:" t.host
host = 'DEEPTHOT'
say "Try2:" t.host
results in
Try1: t.DeepThot
Try2: 0
I'm sorry John, I thought the confusion was because of the translation to
upper case caused by the un-initialized variable and the fact that host
names are case sensitive.
Actually I get a slightly different output (typo?) Try1: T.DeepThot (note
the capital 'T')
Try: 1 (not 0)
I think that the capital T is infact important.
Clark -|-
Williams –O-o-O– Via George
This sort of thing was recently driving me nuts. I finally wrote a pair of
library routines for setting/getting compound variables. Inside the library,
expressions are received already evaluated by ARexx so you just convert to
uppercase and use the RVI. This technique works when the seemingly obvious
fails. You can pass a literal 'stem.1' or a build up the stemname for use in
iterative loops:
astem = someotherstem.1.name
do i = 1 to n
astr = getvar(astem'.'i)
say astr
end
If astem evaluates to 'sam', the loop prints the values of sam.1..sam.n
Glad you got it going John. Just for kicks, here's a nifty program that goes
the Unix 'uniq' one better, in that the duplicate lines need not be in
immediate succession:
/* uniq – input from stdin, output to stdout
– outputs only unique lines.
example commands: uniq <infile
print only unique lines from infile
: sort infile | uniq >outfile
create outfile, which will contain a sorted list
of unique lines from infile
*/
do forever
x = readln(stdin)
if EOF(stdin) then exit
if temp.x ~= x then do
temp.x = x
say temp.x
end end
Use trace if you don't grok it at first. The corollary progam to only output
duplicate lines, is:
/* dup.rexx – output duplicate lines */
do forever
x = readln(stdin)
if EOF(stdin) then exit
if temp.x ~= x then do
temp.x = x
end
else
say temp.x end
-larry
Another fine example of why I'd love to pick over your REXX: directory. 🙂
John,
Well, that one was pretty straightforward and generic. Unfortunately, many of
the REXX: stuff requires other particular environments, programs, etc. I use
WShell, which allows pipes. I use execio, and so on. Makes it difficult for
others to get them going.
-larry
Now that's a unique implementation of the uniq function. I have used a
technique similar to that when I was sorting in a language that had no
arrays. I like that you don't have to sort it in order to get uniqueness.
Of course it does have a little of a memory hit…
Yes, it does use some memory, but I never worry much about that when it's small
and fast and does exactly what I wanted it to do.
I use it quite a bit. Recently, I was merging a couple of sets of airport ID
files, consisting of one ID followed by the airport location on each line. I
generated the combined files by using 'join' and 'sort', but could not directly
use 'uniq', since the rest of the line, after the ID was not necessarily the
same in both entries. This caused me to write a 'cut' program, which I used
along with 'dup.rexx' to isolate the ID, printing out a lit of duplicates. Love
them little utilities, pipes, and 'backtick'. 🙂
-larry