home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d524 / kamin.lha / Kamin / P-Distr.lzh / apl.p next >
Text File  |  1989-06-27  |  42KB  |  1,432 lines

  1. (*****************************************************************
  2.  *                     DECLARATIONS                              *
  3.  *****************************************************************)
  4. program apl (input, output);
  5.  
  6. label 99;
  7.  
  8. const
  9.    NAMELENG = 20;      (* Maximum length of a name *)
  10.    MAXNAMES = 100;     (* Maximum number of different names *)
  11.    MAXINPUT = 500;     (* Maximum length of an input *)
  12.    PROMPT = '-> ';
  13.    PROMPT2 = '> ';
  14.    COMMENTCHAR = ';';
  15.    TABCODE = 9;        (* in ASCII *)
  16.  
  17. type
  18.    NAMESIZE = 0..NAMELENG;
  19.    NAMESTRING = packed array [1..NAMELENG] of char;
  20.  
  21.    NAME = 1 .. MAXNAMES; (* a NAME is an index in printNames *)
  22.  
  23.    BUILTINOP = (IFOP,WHILEOP,SETOP,BEGINOP,
  24.                 PLUSOP,MINUSOP,TIMESOP,DIVOP,MAXOP,
  25.                 OROP,ANDOP,EQOP,LTOP,GTOP,
  26.                 REDPLUSOP,REDMINUSOP,REDTIMESOP,
  27.                 REDDIVOP,REDMAXOP,REDOROP,REDANDOP,
  28.                 COMPRESSOP,SHAPEOP,RAVELOP,RESTRUCTOP,
  29.                 CATOP,INDXOP,TRANSOP,SUBOP,PRINTOP);
  30.    VALUEOP = PLUSOP .. PRINTOP;
  31.    CONTROLOP = IFOP .. BEGINOP;
  32.    REDOP = REDPLUSOP .. REDANDOP;
  33.  
  34.    APLVALUE = ^APLVALUEREC;
  35.    INTLIST = ^INTLISTREC;
  36.    EXP = ^EXPREC;
  37.    EXPLIST = ^EXPLISTREC;
  38.    ENV = ^ENVREC;
  39.    VALUELIST = ^VALUELISTREC;
  40.    NAMELIST = ^NAMELISTREC;
  41.    FUNDEF = ^FUNDEFREC;
  42.  
  43.    RANK = (SCALAR,VECTOR,MATRIX);
  44.    APLVALUEREC = record
  45.                intvals: INTLIST;
  46.                case rnk: RANK of
  47.                   SCALAR: ();
  48.                   VECTOR: (leng: integer);
  49.                   MATRIX: (rows, cols: integer)
  50.             end;
  51.  
  52.    INTLISTREC = record
  53.                int: integer;
  54.                nextint: INTLIST
  55.             end;
  56.  
  57.    EXPTYPE = (VALEXP,VAREXP,APEXP);
  58.    EXPREC = record
  59.                case etype: EXPTYPE of
  60.                   VALEXP: (aplval: APLVALUE);
  61.                   VAREXP: (varble: NAME);
  62.                   APEXP: (optr: NAME; args: EXPLIST)
  63.             end;
  64.  
  65.    EXPLISTREC = record
  66.                head: EXP;
  67.                tail: EXPLIST
  68.             end;
  69.  
  70.    VALUELISTREC = record
  71.                head: APLVALUE;
  72.                tail: VALUELIST
  73.             end;
  74.  
  75.    NAMELISTREC = record
  76.                head: NAME;
  77.                tail: NAMELIST
  78.             end;
  79.  
  80.    ENVREC = record
  81.                vars: NAMELIST;
  82.                values: VALUELIST
  83.             end;
  84.  
  85.    FUNDEFREC = record
  86.                funname: NAME;
  87.                formals: NAMELIST;
  88.                body: EXP;
  89.                nextfundef: FUNDEF
  90.             end;
  91.  
  92. var
  93.    fundefs: FUNDEF;
  94.    
  95.    globalEnv: ENV;
  96.    
  97.    currentExp: EXP;
  98.    
  99.    userinput: array [1..MAXINPUT] of char;
  100.    inputleng, pos: 0..MAXINPUT;
  101.    
  102.    printNames: array [NAME] of NAMESTRING;
  103.    numNames, numBuiltins: NAME;
  104.  
  105.    quittingtime: Boolean;
  106.  
  107. (*****************************************************************
  108.  *                     DATA STRUCTURE OP'S                       *
  109.  *****************************************************************)
  110.  
  111. (* mkVALEXP - return an EXP of type VALEXP with aplval a         *)
  112. function mkVALEXP (a: APLVALUE): EXP;
  113. var e: EXP;
  114. begin
  115.    new(e);
  116.    e^.etype := VALEXP;
  117.    e^.aplval := a;
  118.    mkVALEXP := e
  119. end; (* mkVALEXP *)
  120.  
  121. (* mkVAREXP - return an EXP of type VAREXP with varble nm        *)
  122. function mkVAREXP (nm: NAME): EXP;
  123. var e: EXP;
  124. begin
  125.    new(e);
  126.    e^.etype := VAREXP;
  127.    e^.varble := nm;
  128.    mkVAREXP := e
  129. end; (* mkVAREXP *)
  130.  
  131. (* mkAPEXP - return EXP of type APEXP w/ optr op and args el     *)
  132. function mkAPEXP (op: NAME; el: EXPLIST): EXP;
  133. var e: EXP;
  134. begin
  135.    new(e);
  136.    e^.etype := APEXP;
  137.    e^.optr := op;
  138.    e^.args := el;
  139.    mkAPEXP := e
  140. end; (* mkAPEXP *)
  141.  
  142. (* mkExplist - return an EXPLIST with head e and tail el         *)
  143. function mkExplist (e: EXP; el: EXPLIST): EXPLIST;
  144. var newel: EXPLIST;
  145. begin
  146.    new(newel);
  147.    newel^.head := e;
  148.    newel^.tail := el;
  149.    mkExplist := newel
  150. end; (* mkExplist *)
  151.  
  152. (* mkNamelist - return a NAMELIST with head n and tail nl        *)
  153. function mkNamelist (nm: NAME; nl: NAMELIST): NAMELIST;
  154. var newnl: NAMELIST;
  155. begin
  156.    new(newnl);
  157.    newnl^.head := nm;
  158.    newnl^.tail := nl;
  159.    mkNamelist := newnl
  160. end; (* mkNamelist *)
  161.  
  162. (* mkValuelist - return an VALUELIST with head a and tail vl     *)
  163. function mkValuelist (a: APLVALUE; vl: VALUELIST): VALUELIST;
  164. var newvl: VALUELIST;
  165. begin
  166.    new(newvl);
  167.    newvl^.head := a;
  168.    newvl^.tail := vl;
  169.    mkValuelist := newvl
  170. end; (* mkValuelist *)
  171.  
  172. (* mkEnv - return an ENV with vars nl and values vl              *)
  173. function mkEnv (nl: NAMELIST; vl: VALUELIST): ENV;
  174. var rho: ENV;
  175. begin
  176.    new(rho);
  177.    rho^.vars := nl;
  178.    rho^.values := vl;
  179.    mkEnv := rho
  180. end; (* mkEnv *)
  181.  
  182. (* lengthVL - return length of VALUELIST vl                      *)
  183. function lengthVL (vl: VALUELIST): integer;
  184. var i: integer;
  185. begin
  186.    i := 0;
  187.    while vl <> nil do begin
  188.       i := i+1;
  189.       vl := vl^.tail
  190.       end;
  191.    lengthVL := i
  192. end; (* lengthVL *)
  193.  
  194. (* lengthNL - return length of NAMELIST nl                       *)
  195. function lengthNL (nl: NAMELIST): integer;
  196. var i: integer;
  197. begin
  198.    i := 0;
  199.    while nl <> nil do begin
  200.       i := i+1;
  201.       nl := nl^.tail
  202.       end;
  203.    lengthNL := i
  204. end; (* lengthNL *)
  205.  
  206. (* lengthIL - return length of INTLIST il                        *)
  207. function lengthIL (il: INTLIST) : integer;
  208. var i: integer;
  209. begin
  210.    i := 0;
  211.    while il <> nil do begin
  212.       i := i+1;
  213.       il := il^.nextint
  214.       end;
  215.    lengthIL := i
  216. end; (* lengthIL *)
  217.  
  218. (*****************************************************************
  219.  *                     NAME MANAGEMENT                           *
  220.  *****************************************************************)
  221.  
  222. (* fetchFun - get function definition of fname from fundefs      *)
  223. function fetchFun (fname: NAME): FUNDEF;
  224. var
  225.    f: FUNDEF;
  226.    found: Boolean;
  227. begin
  228.    found := false;
  229.    f := fundefs;
  230.    while (f <> nil) and not found do
  231.       if f^.funname = fname
  232.       then found := true
  233.       else f := f^.nextfundef;
  234.    fetchFun := f
  235. end; (* fetchFun *)
  236.  
  237. (* newFunDef - add new function fname w/ parameters nl, body e   *)
  238. procedure newFunDef (fname: NAME; nl: NAMELIST; e: EXP);
  239. var f: FUNDEF;
  240. begin
  241.    f := fetchFun(fname);
  242.    if f = nil (* fname not yet defined as a function *)
  243.    then begin
  244.            new(f);
  245.            f^.nextfundef := fundefs; (* place new FUNDEFREC *)
  246.            fundefs := f              (* on fundefs list *)
  247.         end;
  248.    f^.funname := fname;
  249.    f^.formals := nl;
  250.    f^.body := e
  251. end; (* newFunDef *)
  252.  
  253. (* initNames - place all pre-defined names into printNames       *)
  254. procedure initNames;
  255. var i: integer;
  256. begin
  257.    fundefs := nil;
  258.    i := 1;
  259.    printNames[i] := 'if                  '; i := i+1;
  260.    printNames[i] := 'while               '; i := i+1;
  261.    printNames[i] := 'set                 '; i := i+1;
  262.    printNames[i] := 'begin               '; i := i+1;
  263.    printNames[i] := '+                   '; i := i+1;
  264.    printNames[i] := '-                   '; i := i+1;
  265.    printNames[i] := '*                   '; i := i+1;
  266.    printNames[i] := '/                   '; i := i+1;
  267.    printNames[i] := 'max                 '; i := i+1;
  268.    printNames[i] := 'or                  '; i := i+1;
  269.    printNames[i] := 'and                 '; i := i+1;
  270.    printNames[i] := '=                   '; i := i+1;
  271.    printNames[i] := '<                   '; i := i+1;
  272.    printNames[i] := '>                   '; i := i+1;
  273.    printNames[i] := '+/                  '; i := i+1;
  274.    printNames[i] := '-/                  '; i := i+1;
  275.    printNames[i] := '*/                  '; i := i+1;
  276.    printNames[i] := '//                  '; i := i+1;
  277.    printNames[i] := 'max/                '; i := i+1;
  278.    printNames[i] := 'or/                 '; i := i+1;
  279.    printNames[i] := 'and/                '; i := i+1;
  280.    printNames[i] := 'compress            '; i := i+1;
  281.    printNames[i] := 'shape               '; i := i+1;
  282.    printNames[i] := 'ravel               '; i := i+1;
  283.    printNames[i] := 'restruct            '; i := i+1;
  284.    printNames[i] := 'cat                 '; i := i+1;
  285.    printNames[i] := 'indx                '; i := i+1;
  286.    printNames[i] := 'trans               '; i := i+1;
  287.    printNames[i] := '[]                  '; i := i+1;
  288.    printNames[i] := 'print               ';
  289.    numNames := i;
  290.    numBuiltins := i
  291. end; (* initNames *)
  292.  
  293. (* install - insert new name into printNames                     *)
  294. function install (nm: NAMESTRING): NAME;
  295. var
  296.    i: integer;
  297.    found: Boolean;
  298. begin
  299.    i := 1; found := false;
  300.    while (i <= numNames) and not found
  301.    do if nm = printNames[i]
  302.       then found := true
  303.       else i := i+1;
  304.    if not found
  305.    then begin
  306.            if i > MAXNAMES
  307.            then begin
  308.                    writeln('No more room for names');
  309.                    goto 99
  310.                 end;
  311.            numNames := i;
  312.            printNames[i] := nm
  313.         end;
  314.    install := i
  315. end; (* install *)
  316.  
  317. (* prName - print name nm                                        *)
  318. procedure prName (nm: NAME);
  319. var i: integer;
  320. begin
  321.    i := 1;
  322.    while i <= NAMELENG
  323.    do if printNames[nm][i] <> ' '
  324.       then begin
  325.               write(printNames[nm][i]);
  326.               i := i+1
  327.            end
  328.       else i := NAMELENG+1
  329. end; (* prName *)
  330.  
  331. (* primOp - translate NAME optr to corresponding BUILTINOP       *)
  332. function primOp (optr: NAME): BUILTINOP;
  333. var
  334.    op: BUILTINOP;
  335.    i: integer;
  336. begin
  337.    op := IFOP; (* N.B. IFOP is first value in BUILTINOPS *)
  338.    for i := 1 to optr-1 do op := succ(op);
  339.    primOp := op
  340. end; (* primOp *)
  341.  
  342. (*****************************************************************
  343.  *                        INPUT                                  *
  344.  *****************************************************************)
  345.  
  346. (* isDelim - check if c is a delimiter                           *)
  347. function isDelim (c: char): Boolean;
  348. begin
  349.    isDelim := c in ['(', ')', ' ', COMMENTCHAR]
  350. end; (* isDelim *)
  351.  
  352. (* skipblanks - return next non-blank position in userinput      *)
  353. function skipblanks (p: integer): integer;
  354. begin
  355.    while userinput[p] = ' ' do p := p+1;
  356.    skipblanks := p
  357. end; (* skipblanks *)
  358. (* matches - check if string nm matches userinput[s .. s+leng]   *)
  359. function matches (s: integer; leng: NAMESIZE;
  360.                    nm: NAMESTRING): Boolean;
  361. var
  362.    match: Boolean;
  363.    i: integer;
  364. begin
  365.    match := true; i := 1;
  366.    while match and (i <= leng) do begin
  367.       if userinput[s] <> nm[i] then match := false;
  368.       i := i+1;
  369.       s := s+1
  370.       end;
  371.    if not isDelim(userinput[s]) then match := false;
  372.    matches := match
  373. end; (* matches *)
  374.  
  375. (* reader - read char's into userinput; be sure input not blank  *)
  376. procedure reader;
  377.  
  378. (* readInput - read char's into userinput                        *)
  379.    procedure readInput;
  380.  
  381.    var c: char;
  382.  
  383. (* nextchar - read next char - filter tabs and comments          *)
  384.       procedure nextchar (var c: char);
  385.       begin
  386.          read(c);
  387.          if c = chr(TABCODE)
  388.          then c := ' '
  389.          else if c = COMMENTCHAR
  390.               then begin while not eoln do read(c); c := ' ' end
  391.       end; (* nextchar *)
  392.  
  393. (* readParens - read char's, ignoring newlines, to matching ')'  *)
  394.       procedure readParens;
  395.       var
  396.          parencnt: integer; (* current depth of parentheses *)
  397.          c: char;
  398.       begin
  399.          parencnt := 1; (* '(' just read *)
  400.          repeat
  401.             if eoln then write(PROMPT2);
  402.             nextchar(c);
  403.             pos := pos+1;
  404.             if pos = MAXINPUT
  405.             then begin
  406.                     writeln('User input too long');
  407.                     goto 99
  408.                  end;
  409.             userinput[pos] := c;
  410.             if c = '(' then parencnt := parencnt+1;
  411.             if c = ')' then parencnt := parencnt-1
  412.          until parencnt = 0
  413.       end; (* readParens *)
  414.  
  415.    begin (* readInput *)
  416.       write(PROMPT);
  417.       pos := 0;
  418.       repeat
  419.          pos := pos+1;
  420.          if pos = MAXINPUT
  421.          then begin
  422.                  writeln('User input too long');
  423.                  goto 99
  424.               end;
  425.          nextchar(c);
  426.          userinput[pos] := c;
  427.          if userinput[pos] = '(' then readParens
  428.       until eoln;
  429.       inputleng := pos;
  430.       userinput[pos+1] := COMMENTCHAR (* sentinel *)
  431.    end; (* readInput *)
  432.  
  433. begin (* reader *)
  434.     repeat
  435.        readInput;
  436.        pos := skipblanks(1);
  437.     until pos <= inputleng (* ignore blank lines *)
  438. end; (* reader *)
  439. (* parseName - return (installed) NAME starting at userinput[pos]*)
  440. function parseName: NAME;
  441. var
  442.    nm: NAMESTRING; (* array to accumulate characters *)
  443.    leng: NAMESIZE; (* length of name *)
  444. begin
  445.    leng := 0;
  446.    while (pos <= inputleng) and not isDelim(userinput[pos])
  447.    do begin
  448.          if leng = NAMELENG
  449.          then begin
  450.                  writeln('Name too long, begins: ', nm);
  451.                  goto 99
  452.               end;
  453.          leng := leng+1;
  454.          nm[leng] := userinput[pos];
  455.          pos := pos+1
  456.       end;
  457.    if leng = 0
  458.    then begin
  459.            writeln('Error: expected name, instead read: ',
  460.                    userinput[pos]);
  461.            goto 99
  462.         end;
  463.    for leng := leng+1 to NAMELENG do nm[leng] := ' ';
  464.    pos := skipblanks(pos); (* skip blanks after name *)
  465.    parseName := install(nm)
  466. end; (* parseName *)
  467.  
  468. (* isNumber - check if a number begins at pos                    *)
  469. function isNumber (pos: integer): Boolean;
  470.  
  471. (* isDigits - check if sequence of digits begins at pos          *)
  472.    function isDigits (pos: integer): Boolean;
  473.    begin
  474.       if not (userinput[pos] in ['0'..'9'])
  475.       then isDigits := false
  476.       else begin
  477.               isDigits := true;
  478.               while userinput[pos] in ['0'..'9'] do pos := pos+1;
  479.               if not isDelim(userinput[pos])
  480.               then isDigits := false
  481.            end
  482.    end; (* isDigits *)
  483.  
  484. begin
  485.    isNumber := isDigits(pos) or
  486.               ((userinput[pos] = '-') and isDigits(pos+1))
  487. end; (* isNumber *)
  488.  
  489. (* isValue - check if a number or vector const begins at pos     *)
  490. function isValue (pos: integer): Boolean;
  491. begin
  492.    isValue:= (userinput[pos] = '''') or isNumber(pos)
  493. end; (* isValue *)
  494.  
  495. (* parseVal - return APL value starting at userinput[pos]         *)
  496. function parseVal: APLVALUE;
  497.  
  498. var result: APLVALUE;
  499.  
  500. (* parseInt - return number starting at userinput[pos]            *)
  501.    function parseInt: integer;
  502.    var n, sign: integer;
  503.    begin
  504.       n := 0;
  505.       sign := 1;
  506.       if userinput[pos] = '-'
  507.       then begin
  508.               sign := -1;
  509.               pos := pos+1
  510.            end;
  511.       while userinput[pos] in ['0'..'9'] do
  512.          begin
  513.             n := 10*n + (ord(userinput[pos]) - ord('0'));
  514.             pos := pos+1
  515.          end;
  516.       pos := skipblanks(pos); (* skip blanks after number *)
  517.       parseInt := n*sign
  518.    end; (* parseInt *)
  519.  
  520. (* parseVec - return INTLIST starting at userinput[pos]           *)
  521.    function parseVec: INTLIST;
  522.    var il: INTLIST;
  523.    begin
  524.       if userinput[pos] = ')'
  525.       then begin
  526.               pos := skipblanks(pos+1); (* skip ') ...' *)
  527.               il := nil
  528.            end
  529.       else begin
  530.               new(il);
  531.               il^.int := parseInt;
  532.               il^.nextint := parseVec
  533.            end;
  534.       parseVec := il
  535.    end; (* parseVec *)
  536.  
  537. begin (* parseVal *)
  538.    new(result);
  539.    with result^ do
  540.       if userinput[pos] = ''''
  541.       then begin
  542.               rnk := VECTOR;
  543.               pos := skipblanks(pos+2); (* skip "'(..." *)
  544.               intvals := parseVec;
  545.               leng := lengthIL(intvals)
  546.            end
  547.       else begin
  548.               rnk := SCALAR;
  549.               new(intvals);
  550.               intvals^.int := parseInt;
  551.               intvals^.nextint := nil
  552.            end;
  553.    parseVal := result
  554. end; (* parseVal *)
  555.  
  556. function parseEL: EXPLIST; forward;
  557.  
  558. (* parseExp - return EXP starting at userinput[pos]              *)
  559. function parseExp: EXP;
  560. var
  561.    nm: NAME;
  562.    el: EXPLIST;
  563. begin
  564.    if userinput[pos] = '('
  565.    then begin   (* APEXP *)
  566.            pos := skipblanks(pos+1); (* skip '( ..' *)
  567.            nm := parseName;
  568.            el := parseEL;
  569.            parseExp := mkAPEXP(nm, el)
  570.         end
  571.    else if isValue(pos)
  572.         then parseExp := mkVALEXP(parseVal)   (* VALEXP *)
  573.         else parseExp := mkVAREXP(parseName)  (* VAREXP *)
  574. end; (* parseExp *)
  575.  
  576. (* parseEL - return EXPLIST starting at userinput[pos]           *)
  577. function parseEL;
  578. var
  579.    e: EXP;
  580.    el: EXPLIST;
  581. begin
  582.    if userinput[pos] = ')'
  583.    then begin
  584.            pos := skipblanks(pos+1); (* skip ') ..' *)
  585.            parseEL := nil
  586.         end
  587.    else begin
  588.            e := parseExp;
  589.            el := parseEL;
  590.            parseEL := mkExplist(e, el)
  591.         end
  592. end; (* parseEL *)
  593.  
  594. (* parseNL - return NAMELIST starting at userinput[pos]          *)
  595. function parseNL: NAMELIST;
  596. var
  597.    nm: NAME;
  598.    nl: NAMELIST;
  599. begin
  600.    if userinput[pos] = ')'
  601.    then begin
  602.            pos := skipblanks(pos+1); (* skip ') ..' *)
  603.            parseNL := nil
  604.         end
  605.    else begin
  606.            nm := parseName;
  607.            nl := parseNL;
  608.            parseNL := mkNamelist(nm, nl)
  609.         end
  610. end; (* parseNL *)
  611.  
  612. (* parseDef - parse function definition at userinput[pos]        *)
  613. function parseDef: NAME;
  614. var
  615.    fname: NAME;        (* function name *)
  616.    nl: NAMELIST;       (* formal parameters *)
  617.    e: EXP;             (* body *)
  618. begin
  619.    pos := skipblanks(pos+1); (* skip '( ..' *)
  620.    pos := skipblanks(pos+6); (* skip 'define ..' *)
  621.    fname := parseName;
  622.    pos := skipblanks(pos+1); (* skip '( ..' *)
  623.    nl := parseNL;
  624.    e := parseExp;
  625.    pos := skipblanks(pos+1); (* skip ') ..' *)
  626.    newFunDef(fname, nl, e);
  627.    parseDef := fname
  628. end; (* parseDef *)
  629.  
  630. (*****************************************************************
  631.  *                     ENVIRONMENTS                              *
  632.  *****************************************************************)
  633.  
  634. (* emptyEnv - return an environment with no bindings             *)
  635. function emptyEnv: ENV;
  636. begin
  637.    emptyEnv := mkEnv(nil, nil)
  638. end; (* emptyEnv *)
  639.  
  640. (* bindVar - bind variable nm to value a in environment rho      *)
  641. procedure bindVar (nm: NAME; a: APLVALUE; rho: ENV);
  642. begin
  643.    rho^.vars := mkNamelist(nm, rho^.vars);
  644.    rho^.values := mkValuelist(a, rho^.values)
  645. end; (* bindVar *)
  646.  
  647. (* findVar - look up nm in rho                                   *)
  648. function findVar (nm: NAME; rho: ENV): VALUELIST;
  649. var
  650.    nl: NAMELIST;
  651.    vl: VALUELIST;
  652.    found: Boolean;
  653. begin
  654.    found := false;
  655.    nl := rho^.vars;
  656.    vl := rho^.values;
  657.    while (nl <> nil) and not found do
  658.       if nl^.head = nm
  659.       then found := true
  660.       else begin
  661.               nl := nl^.tail;
  662.               vl := vl^.tail
  663.            end;
  664.    findVar := vl
  665. end; (* findVar *)
  666.  
  667. (* assign - assign value a to variable nm in rho                 *)
  668. procedure assign (nm: NAME; a: APLVALUE; rho: ENV);
  669. var varloc: VALUELIST;
  670. begin
  671.    varloc := findVar(nm, rho);
  672.    varloc^.head := a
  673. end; (* assign *)
  674.  
  675. (* fetch - return number bound to nm in rho                      *)
  676. function fetch (nm: NAME; rho: ENV): APLVALUE;
  677. var vl: VALUELIST;
  678. begin
  679.    vl := findVar(nm, rho);
  680.    fetch := vl^.head
  681. end; (* fetch *)
  682.  
  683. (* isBound - check if nm is bound in rho                         *)
  684. function isBound (nm: NAME; rho: ENV): Boolean;
  685. begin
  686.    isBound := findVar(nm, rho) <> nil
  687. end; (* isBound *)
  688.  
  689. (*****************************************************************
  690.  *                     APL VALUES                                *
  691.  *****************************************************************)
  692.  
  693. (* prValue - print APL value a                                   *)
  694. procedure prValue (a: APLVALUE);
  695.  
  696. (* prIntlist - print INTLIST il as dim1 x dim2 matrix            *)
  697.    procedure prIntlist (il: INTLIST; dim1, dim2: integer);
  698.    var i, j: integer;
  699.    begin
  700.       for i:= 1 to dim1 do begin
  701.          for j:= 1 to dim2 do begin
  702.             write(il^.int:6, ' ');
  703.             il := il^.nextint
  704.             end;
  705.          writeln
  706.          end
  707.    end; (* prIntlist *)
  708.  
  709. begin (* prValue *)
  710.    with a^ do
  711.       case rnk of
  712.          SCALAR: prIntlist(intvals, 1, 1);
  713.          VECTOR: prIntlist(intvals, 1, leng);
  714.          MATRIX: prIntlist(intvals, rows, cols);
  715.       end
  716. end; (* prValue *)
  717.  
  718. (* isTrueVal - return true if first value in a is one            *)
  719. function isTrueVal (a: APLVALUE): Boolean;
  720. begin
  721.     with a^ do
  722.        if intvals = nil
  723.        then isTrueVal := false
  724.        else isTrueVal := intvals^.int = 1
  725. end; (* isTrueVal *)
  726.  
  727. (* applyValueOp - apply VALUEOP op to arguments in VALUELIST vl  *)
  728. function applyValueOp (op: VALUEOP; vl: VALUELIST): APLVALUE;
  729.  
  730. var a1, a2, result: APLVALUE;
  731.  
  732. (* size - return number of elements in a                         *)
  733.    function size (a: APLVALUE): integer;
  734.    begin
  735.       with a^ do
  736.          case rnk of
  737.             SCALAR: size := 1;
  738.             VECTOR: size := leng;
  739.             MATRIX: size := rows * cols
  740.          end
  741.    end; (* size *)
  742.  
  743. (* skipover - return pointer to nth record in il                 *)
  744.    function skipover (n: integer; il: INTLIST): INTLIST;
  745.    begin  
  746.        while n > 0 do begin
  747.           il := il^.nextint;
  748.           n := n-1
  749.           end;
  750.        skipover := il
  751.    end; (* skipover *)
  752.  
  753. (* applyArithOp - apply binary operator to a1 and a2              *)
  754.    procedure applyArithOp (op: BUILTINOP; a1, a2: APLVALUE);
  755.  
  756. (* copyrank - copy rank and shape of a to r                      *)
  757.       procedure copyrank (a, r: APLVALUE);
  758.       begin
  759.          with r^ do
  760.             begin
  761.                rnk := a^.rnk;
  762.                case rnk of
  763.                   SCALAR: ;
  764.                   VECTOR: leng := a^.leng;
  765.                   MATRIX:
  766.                      begin
  767.                         rows := a^.rows;
  768.                         cols := a^.cols;
  769.                      end
  770.                end (* case *)
  771.             end (* with *)
  772.       end; (* copyrank *)
  773.  
  774. (* applyOp - apply VALUEOP op to integer arguments               *)
  775.       function applyOp (op: BUILTINOP; i, j: integer): integer;
  776.       begin
  777.          case op of
  778.             PLUSOP: applyOp := i+j;
  779.             MINUSOP: applyOp := i-j;
  780.             TIMESOP: applyOp := i*j;
  781.             DIVOP: applyOp := i div j;
  782.             MAXOP:
  783.                if i > j then applyOp := i else applyOp := j;
  784.             OROP:
  785.                if (i = 1) or (j = 1) then applyOp := 1
  786.                                      else applyOp := 0;
  787.             ANDOP:
  788.                if (i = 1) and (j = 1) then applyOp := 1
  789.                                       else applyOp := 0;
  790.             EQOP:
  791.                if i = j then applyOp := 1 else applyOp := 0;
  792.             LTOP:
  793.                if i < j then applyOp := 1 else applyOp := 0;
  794.             GTOP:
  795.                if i > j then applyOp := 1 else applyOp := 0
  796.          end (* case *)
  797.       end; (* applyOp *)
  798.  
  799. (* applyIntlis - apply op to two lists, extending appropriately  *)
  800.       function applyIntlis (op: BUILTINOP; il1, il2: INTLIST;
  801.                           il1leng, il2leng: integer): INTLIST;
  802.       var il:INTLIST;
  803.       begin
  804.          if (il1 = nil) or (il2 = nil)
  805.          then applyIntlis := nil
  806.          else begin
  807.                  new(il);
  808.                  with il^ do begin
  809.                     int := applyOp(op, il1^.int, il2^.int);
  810.                     if il1leng = 1
  811.                     then nextint := applyIntlis(op, il1,
  812.                               il2^.nextint, il1leng, il2leng)
  813.                     else if il2leng = 1
  814.                          then nextint :=
  815.                                applyIntlis(op, il1^.nextint,
  816.                                             il2, il1leng, il2leng)
  817.                         else nextint :=
  818.                                applyIntlis(op, il1^.nextint,
  819.                                  il2^.nextint, il1leng, il2leng);
  820.                     applyIntlis := il
  821.                     end (* with *)
  822.               end
  823.       end; (* applyIntlis *)
  824.  
  825.    begin  (* applyArithOp *)
  826.       new(result);
  827.       if (a1^.rnk = SCALAR)
  828.       then copyrank(a2, result)
  829.       else if (a2^.rnk = SCALAR)
  830.            then copyrank(a1, result)
  831.            else if size(a1) = 1
  832.                 then copyrank(a2, result)
  833.                 else copyrank(a1, result);
  834.       result^.intvals := applyIntlis(op, a1^.intvals,
  835.                               a2^.intvals, size(a1), size(a2))
  836.    end; (* applyArithOp *)
  837.  
  838. (* applyRedOp - apply reduction operator                         *)
  839.    procedure applyRedOp (op: REDOP; a: APLVALUE);
  840.  
  841. (* applyOp - apply base operator of reduction operator           *)
  842.       function applyOp (op: BUILTINOP; i, j: integer): integer;
  843.       begin
  844.          case op of
  845.             REDPLUSOP: applyOp := i+j;
  846.             REDMINUSOP: applyOp := i-j;
  847.             REDTIMESOP: applyOp := i*j;
  848.             REDDIVOP: applyOp := i div j;
  849.             REDMAXOP:
  850.                if i > j then applyOp := i else applyOp := j;
  851.             REDOROP:
  852.                if (i = 1) or (j = 1) then applyOp := 1
  853.                                      else applyOp := 0;
  854.             REDANDOP:
  855.                if (i = 1) and (j = 1) then applyOp := 1
  856.                                       else applyOp := 0
  857.          end (* case *)
  858.       end; (* applyOp *)
  859.  
  860. (* redVec - reduce op (argument to applyRedOp) over list         *)
  861.       function redVec (il: INTLIST; leng: integer): integer;
  862.       begin
  863.          if leng = 0
  864.          then redVec := 0
  865.          else if leng = 1
  866.               then redVec := il^.int
  867.               else redVec := applyOp(op, il^.int,
  868.                                 redVec(il^.nextint, leng-1))
  869.       end; (* redVec *)
  870.  
  871. (* redMat - reduce op (argument to applyRedOp) over matrix       *)
  872.       function redMat (il: INTLIST; cols, rows: integer): INTLIST;
  873.       var ilnew: INTLIST;
  874.       begin
  875.          if rows = 0 then redMat := nil
  876.          else begin
  877.                  new(ilnew);
  878.                  ilnew^.int := redVec(il, cols);
  879.                  ilnew^.nextint :=
  880.                           redMat(skipover(cols, il), cols, rows-1);
  881.                  redMat := ilnew
  882.               end
  883.       end; (* redmat *)
  884.  
  885.    begin (* applyRedOp *)
  886.       new(result);
  887.       case a^.rnk of
  888.          SCALAR: result := a;
  889.          VECTOR:
  890.             with result^ do begin
  891.                rnk := SCALAR;
  892.                new(intvals);
  893.                intvals^.int := redVec(a^.intvals, a^.leng);
  894.                intvals^.nextint := nil
  895.                end;
  896.          MATRIX:
  897.             with result^ do begin
  898.                rnk := VECTOR;
  899.                leng := a^.rows;
  900.                intvals := redMat(a^.intvals, a^.cols, leng)
  901.                end
  902.       end (* case *)
  903.    end; (* applyRedOp *)
  904.  
  905. (* append - append il2 to il1; il1 is altered                    *)
  906.    function append (il1, il2: INTLIST): INTLIST;
  907.    begin
  908.       if il1 = nil
  909.       then append := il2
  910.       else begin
  911.               append := il1;
  912.               while il1^.nextint <> nil do il1 := il1^.nextint;
  913.               il1^.nextint := il2
  914.            end
  915.    end; (* append *)
  916.  
  917. (* ncopy - copy elements of src until list has reps elements     *)
  918.    function ncopy (src: INTLIST; reps: integer): INTLIST;
  919.    var
  920.       il, suffix: INTLIST;
  921.       i: integer;
  922.    begin
  923.       if reps = 0
  924.       then ncopy := nil
  925.       else begin
  926.               new(il);
  927.               ncopy := il;
  928.               il^.int := src^.int;
  929.               suffix := src^.nextint;
  930.               for i := 2 to reps do begin
  931.                  if suffix = nil (* exhausted src *)
  932.                  then suffix := src; (* start over *)
  933.                  new(il^.nextint);
  934.                  il := il^.nextint;
  935.                  il^.int := suffix^.int;
  936.                  suffix := suffix^.nextint
  937.                  end
  938.            end
  939.    end; (* ncopy *)
  940.  
  941. (* compress - compress a1 over a2                                *)
  942.    procedure compress (a1, a2: APLVALUE);
  943.  
  944.    var width: integer;
  945.  
  946. (* ilcompress - il1 over il2, taking il2 in chunks of size width *)
  947.       function ilcompress (il1, il2: INTLIST;
  948.                               width: integer): INTLIST;
  949.       var il: INTLIST;
  950.       begin
  951.          if il1 = nil
  952.          then ilcompress := nil
  953.          else if il1^.int = 1
  954.               then begin
  955.                       il := ncopy(il2, width);
  956.                       il := append(il, ilcompress(il1^.nextint,
  957.                                     skipover(width, il2), width));
  958.                       ilcompress := il
  959.                    end
  960.               else ilcompress := ilcompress(il1^.nextint,
  961.                                       skipover(width, il2), width)
  962.       end; (* ilcompress *)
  963.  
  964. (* countones - count ones in il                                  *)
  965.       function countones (il: INTLIST): integer;
  966.       var i: integer;
  967.       begin
  968.          i := 0;
  969.          while il <> nil do begin
  970.             if il^.int = 1 then i := i+1;
  971.             il := il^.nextint
  972.             end;
  973.          countones := i
  974.       end; (* countones *)
  975.  
  976.    begin (* compress *)
  977.       with a2^ do
  978.          if rnk = VECTOR then width := 1 else width := cols;
  979.       new(result);
  980.       with result^ do begin
  981.          rnk := a2^.rnk;
  982.          intvals := ilcompress(a1^.intvals,
  983.                                a2^.intvals, width);
  984.          if rnk = VECTOR
  985.          then leng := countones(a1^.intvals)
  986.          else begin
  987.                  cols := a2^.cols;
  988.                  rows := countones(a1^.intvals)
  989.               end
  990.          end (* with *)
  991.    end; (* compress *)
  992.  
  993. (* shape - return vector giving dimensions of a                  *)
  994.    procedure shape (a: APLVALUE);
  995.    var il: INTLIST;
  996.    begin
  997.       new(result);
  998.       result^.rnk := VECTOR;
  999.       with a^ do
  1000.          case rnk of
  1001.             SCALAR:
  1002.                begin
  1003.                   result^.leng := 0;
  1004.                   result^.intvals := nil
  1005.                end;
  1006.             VECTOR:
  1007.                begin
  1008.                   result^.leng := 1;
  1009.                   new(il);
  1010.                   result^.intvals := il;
  1011.                   il^.int := leng;
  1012.                   il^.nextint := nil
  1013.                end;
  1014.             MATRIX:
  1015.                begin
  1016.                   result^.leng := 2;
  1017.                   new(il);
  1018.                   result^.intvals := il;
  1019.                   il^.int := rows;
  1020.                   new(il^.nextint);
  1021.                   il := il^.nextint;
  1022.                   il^.int := cols;
  1023.                   il^.nextint := nil
  1024.                end
  1025.          end (* case *)
  1026.    end; (* shape *)
  1027.  
  1028. (* ravel - transform a to a vector without changing elements     *)
  1029.    procedure ravel (a: APLVALUE);
  1030.    var size: integer;
  1031.    begin
  1032.       new(result);
  1033.       with a^ do
  1034.          case rnk of
  1035.             SCALAR: size := 1;
  1036.             VECTOR: size := leng;
  1037.             MATRIX: size := rows*cols
  1038.          end;
  1039.       with result^ do begin
  1040.          rnk := VECTOR;
  1041.          leng := size;
  1042.          intvals := a^.intvals
  1043.          end
  1044.    end; (* ravel *)
  1045.  
  1046. (* restruct - restructure valuevec according to shapevec         *)
  1047.    procedure restruct (shapevec, valuevec: APLVALUE);
  1048.    var
  1049.       newrank: RANK;
  1050.       dim1, dim2: integer;
  1051.    begin
  1052.       if (valuevec^.intvals = nil)
  1053.       then begin
  1054.               writeln('Cannot restructure null vector');
  1055.               goto 99
  1056.            end;
  1057.       with shapevec^ do
  1058.          if rnk = SCALAR
  1059.          then begin
  1060.                  newrank := VECTOR;
  1061.                  dim1 := intvals^.int;
  1062.                  dim2 := 1
  1063.               end
  1064.          else if leng = 0
  1065.               then begin
  1066.                       newrank := SCALAR;
  1067.                       dim1 := 1;
  1068.                       dim2 := 1
  1069.                    end
  1070.               else if leng = 1
  1071.                    then begin
  1072.                            newrank := VECTOR;
  1073.                            dim1 := intvals^.int;
  1074.                            dim2 := 1
  1075.                         end
  1076.                    else begin
  1077.                            newrank := MATRIX;
  1078.                            dim1 := intvals^.int;
  1079.                            dim2 := intvals^.nextint^.int
  1080.                         end; (* with *)
  1081.       new(result);
  1082.       with result^ do begin
  1083.          rnk := newrank;
  1084.          if rnk = VECTOR
  1085.          then leng := dim1
  1086.          else if rnk = MATRIX
  1087.               then begin
  1088.                       rows := dim1;
  1089.                       cols := dim2
  1090.                    end;
  1091.          intvals := ncopy(valuevec^.intvals, dim1*dim2)
  1092.          end (* with *)
  1093.    end; (* restruct *)
  1094.  
  1095. (* copyIntlis - make a fresh copy of il                          *)
  1096.    function copyIntlis (il: INTLIST): INTLIST;
  1097.    begin
  1098.       copyIntlis := ncopy(il, lengthIL(il))
  1099.    end; (* copyIntlis *)
  1100.  
  1101. (* cat - create a vector by joining ravels of a1 and a2          *)
  1102.    procedure cat (a1, a2: APLVALUE);
  1103.    begin
  1104.       new(result);
  1105.       with result^ do begin
  1106.          rnk := VECTOR;
  1107.          leng := size(a1) + size(a2);
  1108.          intvals := copyIntlis(a1^.intvals);
  1109.          intvals := append(intvals, a2^.intvals)
  1110.          end
  1111.    end; (* cat *)
  1112.  
  1113. (* indx - perform index generation, using first value in a       *)
  1114.    procedure indx (a: APLVALUE);
  1115.    var
  1116.       i: integer;
  1117.       il: INTLIST;
  1118.    begin
  1119.       i := a^.intvals^.int;
  1120.       new(result);
  1121.       with result^ do begin
  1122.          rnk := VECTOR;
  1123.          intvals := nil;
  1124.          leng := i;
  1125.          while i > 0 do begin
  1126.             new(il);
  1127.             il^.int := i;
  1128.             il^.nextint := intvals;
  1129.             intvals := il;
  1130.             i := i-1
  1131.             end (* while *)
  1132.          end (* with *)
  1133.    end; (* indx *)
  1134.  
  1135. (* trans - perform "trans"                                       *)
  1136.    procedure trans (a: APLVALUE);
  1137.    var
  1138.       il, ilnew: INTLIST;
  1139.       i: integer;
  1140.  
  1141. (* skiplist - subscript il by cols and rows                      *)
  1142.       function skiplist (il: INTLIST;
  1143.                  cols, rows: integer): INTLIST;
  1144.       var ilnew: INTLIST;
  1145.       begin
  1146.          new(ilnew);
  1147.          if rows = 1
  1148.          then begin
  1149.                  ilnew^.int := il^.int;
  1150.                  ilnew^.nextint := nil
  1151.               end
  1152.          else begin
  1153.                  ilnew^.int := il^.int;
  1154.                  ilnew^.nextint :=
  1155.                      skiplist(skipover(cols, il), cols, rows-1);
  1156.               end;
  1157.          skiplist := ilnew
  1158.       end; (* skiplist *)
  1159.  
  1160.    begin (* trans *)
  1161.       if (a^.rnk <> MATRIX) or (a^.intvals = nil)
  1162.       then result := a
  1163.       else begin
  1164.               new(result);
  1165.               with result^ do begin
  1166.                  rnk := MATRIX;
  1167.                  cols := a^.rows;
  1168.                  rows := a^.cols;
  1169.                  il := a^.intvals;
  1170.                  ilnew := nil;
  1171.                  for i:= 1 to rows do begin
  1172.                     ilnew := append(ilnew,
  1173.                                     skiplist(il, rows, cols));
  1174.                     il := il^.nextint
  1175.                     end;
  1176.                  intvals := ilnew
  1177.                  end (* with *)
  1178.            end
  1179.    end; (* trans *)
  1180.  
  1181. (* subscript - "[]" operation; a1 a vector or matrix, a2 vector  *)
  1182.    procedure subscript (a1, a2: APLVALUE);
  1183.  
  1184.    var width: integer;
  1185.  
  1186. (* sub - find nth chunk in il, each chunk having width elements  *)
  1187.       function sub (il: INTLIST; n, width: integer): INTLIST;
  1188.       var i, j: integer;
  1189.       begin
  1190.          for i:=1 to n-1 do
  1191.             for j:=1 to width do
  1192.                il := il^.nextint;
  1193.          sub := il
  1194.       end; (* sub *)
  1195.  
  1196. (* ilsub - subscript src by subs in chunks of size width         *)
  1197.       function ilsub (src, subs: INTLIST; width: integer): INTLIST;
  1198.       var il: INTLIST;
  1199.       begin
  1200.          if subs = nil
  1201.          then il := nil
  1202.          else begin
  1203.                  il := sub(src, subs^.int, width);
  1204.                  il := ncopy(il, width);
  1205.                  il := append(il, ilsub(src, subs^.nextint,
  1206.                                              width))
  1207.               end;
  1208.          ilsub := il
  1209.       end; (* ilsub *)
  1210.  
  1211.    begin (* subscript *)
  1212.       new(result);
  1213.       with result^ do begin
  1214.          rnk := a1^.rnk;
  1215.          if rnk = VECTOR
  1216.          then begin
  1217.                  if a2^.rnk = SCALAR
  1218.                  then leng := 1
  1219.                  else leng := a2^.leng;
  1220.                  width := 1
  1221.               end
  1222.          else begin
  1223.                  if a2^.rnk = SCALAR
  1224.                  then rows := 1
  1225.                  else rows := a2^.leng;
  1226.                  cols := a1^.cols;
  1227.                  width := cols
  1228.               end;
  1229.          intvals := ilsub(a1^.intvals, a2^.intvals, width)
  1230.          end (* with *)
  1231.    end; (* subscript *)
  1232.  
  1233. (* arity - return number of arguments expected by op             *)
  1234.    function arity (op: VALUEOP): integer;
  1235.    begin
  1236.       if op in [PLUSOP .. GTOP,COMPRESSOP,RESTRUCTOP,CATOP,SUBOP]
  1237.       then arity := 2 else arity := 1
  1238.    end; (* arity *)
  1239.  
  1240. begin (* applyValueOp *)
  1241.    if arity(op) <> lengthVL(vl)
  1242.    then begin
  1243.            write('Wrong number of arguments to ');
  1244.            prName(ord(op)+1);
  1245.            writeln;
  1246.            goto 99
  1247.         end;
  1248.    a1 := vl^.head; (* 1st actual *)
  1249.    if arity(op) = 2 then a2 := vl^.tail^.head; (* 2nd actual *)
  1250.    case op of
  1251.       PLUSOP,MINUSOP,TIMESOP,DIVOP,MAXOP,OROP,ANDOP,
  1252.       EQOP,LTOP,GTOP:
  1253.          applyArithOp(op, a1, a2);
  1254.       REDPLUSOP,REDMINUSOP,REDTIMESOP,REDDIVOP,REDMAXOP,
  1255.       REDOROP,REDANDOP:
  1256.          applyRedOp(op, a1);
  1257.       COMPRESSOP:
  1258.          compress(a1, a2);
  1259.       SHAPEOP:
  1260.          shape(a1);
  1261.       RAVELOP:
  1262.          ravel(a1);
  1263.       RESTRUCTOP:
  1264.          restruct(a1, a2);
  1265.       CATOP:
  1266.          cat(a1, a2);
  1267.       INDXOP:
  1268.          indx(a1);
  1269.       TRANSOP:
  1270.          trans(a1);
  1271.       SUBOP:
  1272.          subscript(a1, a2);
  1273.       PRINTOP:
  1274.          begin prValue(a1); result := a1 end
  1275.    end; (* case *)
  1276.    applyValueOp := result
  1277. end; (* applyValueOp *)
  1278.  
  1279. (*****************************************************************
  1280.  *                     EVALUATION                                *
  1281.  *****************************************************************)
  1282.  
  1283. (* eval - return value of expression e in local environment rho  *)
  1284. function eval (e: EXP; rho: ENV): APLVALUE;
  1285.  
  1286. var op: BUILTINOP;
  1287.  
  1288. (* evalList - evaluate each expression in el                     *)
  1289.    function evalList (el: EXPLIST): VALUELIST;
  1290.    var
  1291.       h: APLVALUE;
  1292.       t: VALUELIST;
  1293.    begin
  1294.       if el = nil then evalList := nil
  1295.       else begin
  1296.               h := eval(el^.head, rho);
  1297.               t := evalList(el^.tail);
  1298.               evalList := mkValuelist(h, t)
  1299.            end
  1300.    end; (* evalList *)
  1301.  
  1302. (* applyUserFun - look up definition of nm and apply to actuals  *)
  1303.    function applyUserFun (nm: NAME; actuals: VALUELIST): APLVALUE;
  1304.    var
  1305.       f: FUNDEF;
  1306.       rho: ENV;
  1307.    begin
  1308.       f := fetchFun(nm);
  1309.       if f = nil
  1310.       then begin
  1311.               write('Undefined function: ');
  1312.               prName(nm);
  1313.               writeln;
  1314.               goto 99
  1315.            end;
  1316.       with f^ do begin
  1317.          if lengthNL(formals) <> lengthVL(actuals)
  1318.          then begin
  1319.                  write('Wrong number of arguments to: ');
  1320.                  prName(nm);
  1321.                  writeln;
  1322.                  goto 99
  1323.               end;
  1324.          rho := mkEnv(formals, actuals);
  1325.          applyUserFun := eval(body, rho)
  1326.          end
  1327.    end; (* applyUserFun *)
  1328.  
  1329. (* applyCtrlOp - apply CONTROLOP op to args in rho               *)
  1330.    function applyCtrlOp (op: CONTROLOP;
  1331.                        args: EXPLIST): APLVALUE;
  1332.    var a: APLVALUE;
  1333.    begin
  1334.       with args^ do
  1335.          case op of
  1336.            IFOP:
  1337.               if isTrueVal(eval(head, rho))
  1338.               then applyCtrlOp := eval(tail^.head, rho)
  1339.               else applyCtrlOp := eval(tail^.tail^.head, rho);
  1340.            WHILEOP:
  1341.               begin
  1342.                  a := eval(head, rho);
  1343.                  while isTrueVal(a)
  1344.                  do begin
  1345.                        a := eval(tail^.head, rho);
  1346.                        a := eval(head, rho)
  1347.                     end;
  1348.                  applyCtrlOp := a
  1349.               end;
  1350.            SETOP:
  1351.               begin
  1352.                  a := eval(tail^.head, rho);
  1353.                  if isBound(head^.varble, rho)
  1354.                  then assign (head^.varble, a, rho)
  1355.                  else if isBound(head^.varble, globalEnv)
  1356.                       then assign(head^.varble, a, globalEnv)
  1357.                       else bindVar(head^.varble, a, globalEnv);
  1358.                  applyCtrlOp := a
  1359.               end;
  1360.            BEGINOP: 
  1361.               begin
  1362.                  while args^.tail <> nil do
  1363.                     begin
  1364.                        a := eval(args^.head, rho);
  1365.                        args := args^.tail
  1366.                     end;
  1367.                  applyCtrlOp := eval(args^.head, rho)
  1368.               end
  1369.          end (* case and with *)
  1370.    end; (* applyCtrlOp *)
  1371.  
  1372. begin (* eval *)
  1373.    with e^ do
  1374.       case etype of
  1375.          VALEXP:
  1376.             eval := aplval;
  1377.          VAREXP:
  1378.             if isBound(varble, rho)
  1379.             then eval := fetch(varble, rho)
  1380.             else if isBound(varble, globalEnv)
  1381.                  then eval := fetch(varble, globalEnv)
  1382.                  else begin
  1383.                          write('Undefined variable: ');
  1384.                          prName(varble);
  1385.                          writeln;
  1386.                          goto 99
  1387.                       end;
  1388.          APEXP: 
  1389.             if optr > numBuiltins
  1390.             then eval := applyUserFun(optr, evalList(args))
  1391.             else begin
  1392.                     op := primOp(optr);
  1393.                     if op in [IFOP .. BEGINOP]
  1394.                     then eval := applyCtrlOp(op, args)
  1395.                     else eval := applyValueOp(op,
  1396.                                      evalList(args))
  1397.                  end
  1398.       end (* case and with *)
  1399. end; (* eval *)
  1400.  
  1401. (*****************************************************************
  1402.  *                     READ-EVAL-PRINT LOOP                      *
  1403.  *****************************************************************)
  1404.  
  1405. begin (* apl main *)
  1406.    initNames;
  1407.    globalEnv := emptyEnv;
  1408.  
  1409.    quittingtime := false;
  1410. 99:
  1411.    while not quittingtime do begin
  1412.       reader;
  1413.       if matches(pos, 4, 'quit                ')
  1414.       then quittingtime := true
  1415.       else if (userinput[pos] = '(') and
  1416.               matches(skipblanks(pos+1), 6, 'define              ')
  1417.            then begin
  1418.                    prName(parseDef);
  1419.                    writeln
  1420.                 end
  1421.            else begin
  1422.                    currentExp := parseExp;
  1423.                    prValue(eval(currentExp, emptyEnv));
  1424.                    writeln;
  1425.                    writeln
  1426.                 end
  1427.       end (* while *)
  1428. end. (* apl *)
  1429.    
  1430.  
  1431.  
  1432.