For simplicity, the following algorithm (and the other algorithms in this article) uses parallel assignments. In a programming language which does not have this feature, the parallel assignments need to be simulated with an auxiliary variable. For example… (old_r, r) := (r, old_r - quotient *r)is equivalent toprov := r; r := old_r - quotient * prov; old_r := prov;and similarly for the other parallel assignments.
What the author could have said was that by the syntax
( var1, var2, … varN ) := ( expr1, expr2, … exprN )he means that all expr are to be evaluated using values of the vars as they were prior to the statement and the vars are updated after all the exprs are evaluated. Technically, his example doesn't really say that, we must infer the generalization from the two-variable example.
The Rexx equivalent seems more natural to me.
PARSE VALUE expr1 expr2 … exprN WITH var1 var2 … varNmakes it clear that all the expressions are evaluated before the template is applied.
The "pseudocode" in the article can be converted line for line to correct Rexx.
function extended_gcd(a, b) s := 0; old_s := 1 t := 1; old_t := 0 r := b; old_r := a while r ≠ 0 quotient := old_r div r (old_r, r) := (r, old_r - quotient * r) (old_s, s) := (s, old_s - quotient * s) (old_t, t) := (t, old_t - quotient * t) output "Bézout coefficients:", (old_s, old_t) output "greatest common divisor:", old_r extended_gcd: procedure; a=arg(1); b=arg(2) s = 0; old_s = 1 t = 1; old_t = 0 r = b; old_r = a DO WHILE r \= 0 quotient = old_r % r PARSE VALUE r old_r − quotient * r WITH old_r r PARSE VALUE s old_s − quotient * s WITH old_s s PARSE VALUE t old_t − quotient * t WITH old_t t END RETURN old_s old_t old_r
PARSE VALUE … WITH templatesince template can include "directives" that allow one template to define more variables than there are expressions between VALUE and WITH. For example just the "position" directive with position=1 allows a construction such as:
which makes two copies of the first two expressions and single copies copies of the next three with "simplified" names. The first two expressions define new variables and the other three are there just to make copies of (stem).sch.g that can be referenced just as (stem)
PARSE VALUE tmid(visitor.sch.g) tmid(home.sch.g) vscr.sch.g hscr.sch.g typ.sch.g , WITH vid hid vscr hscr typ , 1 vid.g hid.g .Ex 1
Such a construction could be called "multiple parallel assignment." I use continuation and whitespace to make the assignment part of "parallel assignment" easier to read.
Pseudocode shorthand and even some formal languages include constructions like
x = y = z = t = valueas a form of multiple assignment of value to each of variables x, y, z and t. In Rexx that is an expression that evaluates to x = 0 for every value other than 0 for which it evaluates to x = 1. The variables y, z and t are unchanged by the statement.†
The intended result is
which is correctly expressed in Rexx byx = value; y = value; z = value; t = value
PARSE VALUE value WITH x 1 y 1 z 1 t 1 .
File 'Comp.txt' contains the following fields separated by the ASCII horizontal tab character:
IX BUCK MCNT TIEBRK BORDA BRANK PWRNK TNAME AVGRANK GEOMEAN HARMEANand the first line consists of those "column names" similarly separated by tabs. (Think of a spreadsheet.)
The following makes a list of the ranked teams (key.i), sets a flag for each team that is in the list (ranked?.tid) and saves the values of BUCKRANK, BRANK, AVGRANK, GEOMEAN and HARMEAN for each ranked team.
The first PARSE just allows the relevant fields from the record to be referenced as variables. The second uses one of them to calculate the index that allows other parts of the program to access them by team, sets a flag (by team) that indicaates the values exist, and then saves the values using that index. The second is equivalent to:
tab = '09'x key. = '' ranked?. = 0 discard = LINEIN('Comp.txt') /* file has a header line */ DO i=1 WHILE LINES('Comp.txt') > 0 PARSE VALUE LINEIN('Comp.txt') , WITH . (tab) buckrank (tab) . (tab) . (tab) . (tab) brank (tab) tname (tab) avgrank (tab) geomean (tab) harmean (tab) . PARSE VALUE tmid(tname) 1 buckrank brank avgrank geomean harmean , WITH tid ranked?.tid buckrank.tid brank.tid avgrank.tid geomean.tid harmean.tid , 1 key.i . END key.0 = i-1 /* account for the increment before the WHILE test that terminates the loop */ z = STREAM('Comp.txt','C','CLOSE')Ex 2
Performance comparisons of PARSE to the equivalent number of assignment statements are ambiguous. Separate assignment of the same literal to multiple variables is slightly faster than the equivalent PARSE VALUE constant WITH 1 var1 1 var2 1 … but the more "work" performed by the template the more likely PARSE VALUE … WITH is faster.
tid = tmid(tname) ranked?.tid = 1 buckrank.tid = buckrank brank.tid = brank avgrank.tid = avgrank geomean.tid = geomean harmean.tid = harmean key.i = tid
† Note that the first "=" in x = y = z = t = value is an assignment and the remainder are comparison operators. Assuming x, y, z and t are uninitialized before the statement, it is evaluated as follows:x = ( y = z ) = t = value x = ( 0 = t ) = value x = ( 0 = value )which is "x = 0" unless value is 0 in which case it is "x = 1".