home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d524 / kamin.lha / Kamin / P-Distr.lzh / clu.p < prev    next >
Text File  |  1990-03-13  |  31KB  |  1,061 lines

  1. (*****************************************************************
  2.  *                     DECLARATIONS                              *
  3.  *****************************************************************)
  4. program clu (input, output);
  5.  
  6. label 99;
  7.  
  8. const
  9.    NAMELENG = 20;      (* Maximum length of a name *)
  10.    MAXNAMES = 150;     (* Maximum number of different names *)
  11.    MAXINPUT = 5000;    (* 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.    FNAMETYPE = (ONEPART,TWOPART);
  24.    FUNNAME = record
  25.                funpart: NAME;
  26.                case nametype: FNAMETYPE of
  27.                   ONEPART: ();
  28.                   TWOPART: (clpart: NAME)
  29.             end;
  30.       
  31.    BUILTINOP = (IFOP,WHILEOP,SETOP,BEGINOP,PLUSOP,MINUSOP,
  32.              TIMESOP,DIVOP,EQOP,LTOP,GTOP,PRINTOP);
  33.    VALUEOP = PLUSOP .. PRINTOP;
  34.    CONTROLOP = IFOP .. BEGINOP;
  35.  
  36.    CLUVALUE = ^CLUVALUEREC;
  37.    EXP = ^EXPREC;
  38.    EXPLIST = ^EXPLISTREC;
  39.    ENV = ^ENVREC;
  40.    VALUELIST = ^VALUELISTREC;
  41.    NAMELIST = ^NAMELISTREC;
  42.    FUNDEF = ^FUNDEFREC;
  43.    CLUSTER = ^CLUSTERREC;
  44.  
  45.    CLUVALUETYPE = (PRIM,USER);
  46.    CLUVALUEREC = record
  47.                case vtype: CLUVALUETYPE of
  48.                   PRIM: (intval: integer);
  49.                   USER: (userval: ENV)
  50.             end;
  51.  
  52.    EXPTYPE = (VALEXP,VAREXP,APEXP);
  53.    EXPREC = record
  54.                case etype: EXPTYPE of
  55.                   VALEXP: (valu: CLUVALUE);
  56.                   VAREXP: (varble: NAME);
  57.                   APEXP: (optr: FUNNAME; args: EXPLIST)
  58.             end;
  59.  
  60.    EXPLISTREC = record
  61.                head: EXP;
  62.                tail: EXPLIST
  63.             end;
  64.  
  65.    VALUELISTREC = record
  66.                head: CLUVALUE;
  67.                tail: VALUELIST
  68.             end;
  69.  
  70.    NAMELISTREC = record
  71.                head: NAME;
  72.                tail: NAMELIST
  73.             end;
  74.  
  75.    ENVREC = record
  76.                vars: NAMELIST;
  77.                values: VALUELIST
  78.             end;
  79.  
  80.    FUNTYPE = (NORMAL,CONSTRUCTOR,SELECTOR,SETTOR);
  81.    FUNDEFREC = record
  82.                funname: NAME;
  83.                nextfundef: FUNDEF;
  84.                case ftype : FUNTYPE of
  85.                   NORMAL: (formals: NAMELIST; body: EXP);
  86.                   CONSTRUCTOR, SELECTOR: ();
  87.                   SETTOR: (selname: NAME)
  88.             end;
  89.  
  90.    CLUSTERREC = record
  91.                clname: NAME;
  92.                clrep: NAMELIST;
  93.                exported: FUNDEF;
  94.                nonexported: FUNDEF;
  95.                nextcluster: CLUSTER
  96.             end;
  97.  
  98. var
  99.    fundefs: FUNDEF;
  100.    clusters: CLUSTER;
  101.    
  102.    globalEnv: ENV;
  103.    
  104.    currentExp: EXP;
  105.    
  106.    userinput: array [1..MAXINPUT] of char;
  107.    inputleng, pos: 0..MAXINPUT;
  108.    
  109.    printNames: array [NAME] of NAMESTRING;
  110.    numNames, numBuiltins: NAME;
  111.    
  112.    quittingtime: Boolean;
  113.  
  114. (*****************************************************************
  115.  *                     DATA STRUCTURE OP'S                       *
  116.  *****************************************************************)
  117.  
  118. (* mkVALEXP - return an EXP of type VALEXP with valu v           *)
  119. function mkVALEXP (v: CLUVALUE): EXP;
  120. var e: EXP;
  121. begin
  122.    new(e);
  123.    e^.etype := VALEXP;
  124.    e^.valu := v;
  125.    mkVALEXP := e
  126. end; (* mkVALEXP *)
  127.  
  128. (* mkVAREXP - return an EXP of type VAREXP with varble nm        *)
  129. function mkVAREXP (nm: NAME): EXP;
  130. var e: EXP;
  131. begin
  132.    new(e);
  133.    e^.etype := VAREXP;
  134.    e^.varble := nm;
  135.    mkVAREXP := e
  136. end; (* mkVAREXP *)
  137.  
  138. (* mkAPEXP - return EXP of type APEXP w/ optr op or cl$op        *)
  139. function mkAPEXP (ot: FNAMETYPE; op, cl: NAME; el: EXPLIST): EXP;
  140. var e: EXP;
  141. begin
  142.    new(e);
  143.    e^.etype := APEXP;
  144.    e^.optr.funpart := op;
  145.    e^.optr.nametype := ot;
  146.    if ot = TWOPART then e^.optr.clpart := cl;
  147.    e^.args := el;
  148.    mkAPEXP := e
  149. end; (* mkAPEXP *)
  150.  
  151. (* mkPRIM - return a CLUVALUE with integer value n               *)
  152. function mkPRIM (n: integer): CLUVALUE;
  153. var newval: CLUVALUE;
  154. begin
  155.    new(newval);
  156.    newval^.vtype := PRIM;
  157.    newval^.intval := n;
  158.    mkPRIM := newval
  159. end; (* mkPRIM *)
  160.  
  161. (* mkUSER - return a user-type CLUVALUE                          *)
  162. function mkUSER (rho: ENV): CLUVALUE;
  163. var newval: CLUVALUE;
  164. begin
  165.    new(newval);
  166.    newval^.vtype := USER;
  167.    newval^.userval := rho;
  168.    mkUSER := newval
  169. end; (* mkUSER *)
  170.  
  171. (* mkExplist - return an EXPLIST with head e and tail el         *)
  172. function mkExplist (e: EXP; el: EXPLIST): EXPLIST;
  173. var newel: EXPLIST;
  174. begin
  175.    new(newel);
  176.    newel^.head := e;
  177.    newel^.tail := el;
  178.    mkExplist := newel
  179. end; (* mkExplist *)
  180.  
  181. (* mkNamelist - return a NAMELIST with head n and tail nl        *)
  182. function mkNamelist (nm: NAME; nl: NAMELIST): NAMELIST;
  183. var newnl: NAMELIST;
  184. begin
  185.    new(newnl);
  186.    newnl^.head := nm;
  187.    newnl^.tail := nl;
  188.    mkNamelist := newnl
  189. end; (* mkNamelist *)
  190.  
  191. (* mkValuelist - return an VALUELIST with head v and tail vl     *)
  192. function mkValuelist (v: CLUVALUE; vl: VALUELIST): VALUELIST;
  193. var newvl: VALUELIST;
  194. begin
  195.    new(newvl);
  196.    newvl^.head := v;
  197.    newvl^.tail := vl;
  198.    mkValuelist := newvl
  199. end; (* mkValuelist *)
  200.  
  201. (* mkEnv - return an ENV with vars nl and values vl              *)
  202. function mkEnv (nl: NAMELIST; vl: VALUELIST): ENV;
  203. var rho: ENV;
  204. begin
  205.    new(rho);
  206.    rho^.vars := nl;
  207.    rho^.values := vl;
  208.    mkEnv := rho
  209. end; (* mkEnv *)
  210.  
  211. (* lengthVL - return length of VALUELIST vl                      *)
  212. function lengthVL (vl: VALUELIST): integer;
  213. var i: integer;
  214. begin
  215.    i := 0;
  216.    while vl <> nil do begin
  217.       i := i+1;
  218.       vl := vl^.tail
  219.       end;
  220.    lengthVL := i
  221. end; (* lengthVL *)
  222.  
  223. (* lengthNL - return length of NAMELIST nl                       *)
  224. function lengthNL (nl: NAMELIST): integer;
  225. var i: integer;
  226. begin
  227.    i := 0;
  228.    while nl <> nil do begin
  229.       i := i+1;
  230.       nl := nl^.tail
  231.       end;
  232.    lengthNL := i
  233. end; (* lengthNL *)
  234.  
  235. (*****************************************************************
  236.  *                     NAME MANAGEMENT                           *
  237.  *****************************************************************)
  238.  
  239. (* fetchCluster - get cluster definition of cname from clusters  *)
  240. function fetchCluster (cname: NAME): CLUSTER;
  241. var
  242.    cl: CLUSTER;
  243.    found: boolean;
  244. begin
  245.    found := false;
  246.    cl := clusters;
  247.    while (cl <> nil) and not found do
  248.       if cl^.clname = cname
  249.       then found := true
  250.       else cl := cl^.nextcluster;
  251.    fetchCluster := cl
  252. end; (* fetchCluster *)
  253.  
  254. (* newCluster - add new cluster cname to clusters                *)
  255. function newCluster (cname: NAME): CLUSTER;
  256. var cl: CLUSTER;
  257. begin
  258.    cl := fetchCluster(cname);
  259.    if cl = nil (* cname not yet defined as cluster *)
  260.    then begin
  261.            new(cl);
  262.            cl^.clname := cname;
  263.            cl^.nextcluster := clusters; (* place new CLUSTERREC *)
  264.            clusters := cl               (* on clusters list *)
  265.         end;
  266.    newCluster := cl
  267. end; (* newCluster *)
  268.  
  269. (* fetchFun - get function definition of NAME fname from fenv    *)
  270. function fetchFun (fname: NAME; fenv: FUNDEF): FUNDEF;
  271. var found: Boolean;
  272. begin
  273.    found := false;
  274.    while (fenv <> nil) and not found do
  275.       if fenv^.funname = fname
  276.       then found := true
  277.       else fenv := fenv^.nextfundef;
  278.    fetchFun := fenv
  279. end; (* fetchFun *)
  280.  
  281. (* newFunDef - add new function fname to fenv                    *)
  282. function newFunDef (fname: NAME; var fenv: FUNDEF): FUNDEF;
  283. var f: FUNDEF;
  284. begin
  285.    f := fetchFun(fname, fenv);
  286.    if f = nil (* fname not yet defined as a function *)
  287.    then begin
  288.            new(f);
  289.            f^.funname := fname;
  290.            f^.nextfundef := fenv; (* place new FUNDEFREC *)
  291.            fenv := f              (* on fenv list *)
  292.         end;
  293.    newFunDef := f
  294. end; (* newFunDef *)
  295.  
  296. (* initNames - place all pre-defined names into printNames       *)
  297. procedure initNames;
  298. var i: integer;
  299. begin
  300.    fundefs := nil;
  301.    clusters := nil;
  302.    i := 1;
  303.    printNames[i] := 'if                  '; i := i+1;
  304.    printNames[i] := 'while               '; i := i+1;
  305.    printNames[i] := 'set                 '; i := i+1;
  306.    printNames[i] := 'begin               '; i := i+1;
  307.    printNames[i] := '+                   '; i := i+1;
  308.    printNames[i] := '-                   '; i := i+1;
  309.    printNames[i] := '*                   '; i := i+1;
  310.    printNames[i] := '/                   '; i := i+1;
  311.    printNames[i] := '=                   '; i := i+1;
  312.    printNames[i] := '<                   '; i := i+1;
  313.    printNames[i] := '>                   '; i := i+1;
  314.    printNames[i] := 'print               ';
  315.    numNames := i;
  316.    numBuiltins := i
  317. end; (* initNames *)
  318.  
  319. (* install - insert new name into printNames                     *)
  320. function install (nm: NAMESTRING): NAME;
  321. var
  322.    i: integer;
  323.    found: Boolean;
  324. begin
  325.    i := 1; found := false;
  326.    while (i <= numNames) and not found
  327.    do if nm = printNames[i]
  328.       then found := true
  329.       else i := i+1;
  330.    if not found
  331.    then begin
  332.            if i > MAXNAMES
  333.            then begin
  334.                    writeln('No more room for names');
  335.                    goto 99
  336.                 end;
  337.            numNames := i;
  338.            printNames[i] := nm
  339.         end;
  340.    install := i
  341. end; (* install *)
  342.  
  343. (* prName - print name nm                                        *)
  344. procedure prName (nm: NAME);
  345. var i: integer;
  346. begin
  347.    i := 1;
  348.    while i <= NAMELENG
  349.    do if printNames[nm][i] <> ' '
  350.       then begin
  351.               write(printNames[nm][i]);
  352.               i := i+1
  353.            end
  354.       else i := NAMELENG+1
  355. end; (* prName *)
  356.  
  357. (* primOp - translate NAME optr to corresponding BUILTINOP       *)
  358. function primOp (optr: NAME): BUILTINOP;
  359. var
  360.    op: BUILTINOP;
  361.    i: integer;
  362. begin
  363.    op := IFOP; (* N.B. IFOP is first value in BUILTINOPS *)
  364.    for i := 1 to optr-1 do op := succ(op);
  365.    primOp := op
  366. end; (* primOp *)
  367.  
  368. (*****************************************************************
  369.  *                        INPUT                                  *
  370.  *****************************************************************)
  371.  
  372. (* isDelim - check if c is a delimiter                           *)
  373. function isDelim (c: char): Boolean;
  374. begin
  375.    isDelim := c in ['(', ')', ' ', '$', COMMENTCHAR]
  376. end; (* isDelim *)
  377.  
  378. (* skipblanks - return next non-blank position in userinput      *)
  379. function skipblanks (p: integer): integer;
  380. begin
  381.    while userinput[p] = ' ' do p := p+1;
  382.    skipblanks := p
  383. end; (* skipblanks *)
  384.  
  385. (* matches - check if string nm matches userinput[s .. s+leng]   *)
  386. function matches (s: integer; leng: NAMESIZE;
  387.                    nm: NAMESTRING): Boolean;
  388. var
  389.    match: Boolean;
  390.    i: integer;
  391. begin
  392.    match := true; i := 1;
  393.    while match and (i <= leng) do begin
  394.       if userinput[s] <> nm[i] then match := false;
  395.       i := i+1;
  396.       s := s+1
  397.       end;
  398.    if not isDelim(userinput[s]) then match := false;
  399.    matches := match
  400. end; (* matches *)
  401.  
  402. (* reader - read char's into userinput; be sure input not blank  *)
  403. procedure reader;
  404.  
  405. (* readInput - read char's into userinput                        *)
  406.    procedure readInput;
  407.  
  408.    var c: char;
  409.  
  410. (* nextchar - read next char - filter tabs and comments          *)
  411.       procedure nextchar (var c: char);
  412.       begin
  413.          read(c);
  414.          if c = chr(TABCODE)
  415.          then c := ' '
  416.          else if c = COMMENTCHAR
  417.               then begin while not eoln do read(c); c := ' ' end
  418.       end; (* nextchar *)
  419.  
  420. (* readParens - read char's, ignoring newlines, to matching ')'  *)
  421.       procedure readParens;
  422.       var
  423.          parencnt: integer; (* current depth of parentheses *)
  424.          c: char;
  425.       begin
  426.          parencnt := 1; (* '(' just read *)
  427.          repeat
  428.             if eoln then write(PROMPT2);
  429.             nextchar(c);
  430.             pos := pos+1;
  431.             if pos = MAXINPUT
  432.             then begin
  433.                     writeln('User input too long');
  434.                     goto 99
  435.                  end;
  436.             userinput[pos] := c;
  437.             if c = '(' then parencnt := parencnt+1;
  438.             if c = ')' then parencnt := parencnt-1
  439.          until parencnt = 0
  440.       end; (* readParens *)
  441.  
  442.    begin (* readInput *)
  443.       write(PROMPT);
  444.       pos := 0;
  445.       repeat
  446.          pos := pos+1;
  447.          if pos = MAXINPUT
  448.          then begin
  449.                  writeln('User input too long');
  450.                  goto 99
  451.               end;
  452.          nextchar(c);
  453.          userinput[pos] := c;
  454.          if userinput[pos] = '(' then readParens
  455.       until eoln;
  456.       inputleng := pos;
  457.       userinput[pos+1] := COMMENTCHAR (* sentinel *)
  458.    end; (* readInput *)
  459.  
  460. begin (* reader *)
  461.     repeat
  462.        readInput;
  463.        pos := skipblanks(1);
  464.     until pos <= inputleng (* ignore blank lines *)
  465. end; (* reader *)
  466.  
  467. (* parseName - return (installed) NAME starting at userinput[pos]*)
  468. function parseName: NAME;
  469. var
  470.    nm: NAMESTRING; (* array to accumulate characters *)
  471.    leng: NAMESIZE; (* length of name *)
  472. begin
  473.    leng := 0;
  474.    while (pos <= inputleng) and not isDelim(userinput[pos])
  475.    do begin
  476.          if leng = NAMELENG
  477.          then begin
  478.                  writeln('Name too long, begins: ', nm);
  479.                  goto 99
  480.               end;
  481.          leng := leng+1;
  482.          nm[leng] := userinput[pos];
  483.          pos := pos+1
  484.       end;
  485.    if leng = 0
  486.    then begin
  487.            writeln('Error: expected name, instead read: ',
  488.                    userinput[pos]);
  489.            goto 99
  490.         end;
  491.    for leng := leng+1 to NAMELENG do nm[leng] := ' ';
  492.    pos := skipblanks(pos); (* skip blanks after name *)
  493.    parseName := install(nm)
  494. end; (* parseName *)
  495.  
  496. (* isNumber - check if a number begins at pos                    *)
  497. function isNumber (pos: integer): Boolean;
  498.  
  499. (* isDigits - check if sequence of digits begins at pos          *)
  500.    function isDigits (pos: integer): Boolean;
  501.    begin
  502.       if not (userinput[pos] in ['0'..'9'])
  503.       then isDigits := false
  504.       else begin
  505.               isDigits := true;
  506.               while userinput[pos] in ['0'..'9'] do pos := pos+1;
  507.               if not isDelim(userinput[pos])
  508.               then isDigits := false
  509.            end
  510.    end; (* isDigits *)
  511.  
  512. begin (* isNumber *)
  513.    isNumber := isDigits(pos) or
  514.               ((userinput[pos] = '-') and isDigits(pos+1))
  515. end; (* isNumber *)
  516.  
  517. (* parseVal - return number starting at userinput[pos]           *)
  518. function parseVal: CLUVALUE;
  519. var n, sign: integer;
  520. begin
  521.    n := 0; sign := 1;
  522.    if userinput[pos] = '-'
  523.    then begin
  524.            sign := -1;
  525.            pos := pos+1
  526.         end;
  527.    while userinput[pos] in ['0'..'9'] do
  528.       begin
  529.          n := 10*n + (ord(userinput[pos]) - ord('0'));
  530.          pos := pos+1
  531.       end;
  532.    pos := skipblanks(pos); (* skip blanks after number *)
  533.    parseVal := mkPRIM(n*sign)
  534. end; (* parseVal *)
  535.  
  536. function parseEL: EXPLIST; forward;
  537.  
  538. (* parseExp - return EXP starting at userinput[pos]              *)
  539. function parseExp: EXP;
  540. var
  541.    fnm, cnm: NAME;
  542.    el: EXPLIST;
  543.    optrtype: FNAMETYPE;
  544. begin
  545.    if userinput[pos] = '('
  546.    then begin   (* APEXP *)
  547.            pos := skipblanks(pos+1); (* skip '( ..' *)
  548.            optrtype := ONEPART;
  549.            cnm := 1; (* arbitrary name *)
  550.            fnm := parseName;
  551.            if userinput[pos] = '$'
  552.            then begin (* two-part name *)
  553.                    pos := pos+1;
  554.                    cnm := fnm;
  555.                    optrtype := TWOPART;
  556.                    fnm := parseName
  557.                 end;
  558.            el := parseEL;
  559.            parseExp := mkAPEXP(optrtype, fnm, cnm, el)
  560.         end
  561.    else if isNumber(pos)
  562.         then parseExp := mkVALEXP(parseVal)   (* VALEXP *)
  563.         else parseExp := mkVAREXP(parseName)  (* VAREXP *)
  564. end; (* parseExp *)
  565.  
  566. (* parseEL - return EXPLIST starting at userinput[pos]           *)
  567. function parseEL;
  568. var
  569.    e: EXP;
  570.    el: EXPLIST;
  571. begin
  572.    if userinput[pos] = ')'
  573.    then begin
  574.            pos := skipblanks(pos+1); (* skip ') ..' *)
  575.            parseEL := nil
  576.         end
  577.    else begin
  578.            e := parseExp;
  579.            el := parseEL;
  580.            parseEL := mkExplist(e, el)
  581.         end
  582. end; (* parseEL *)
  583.  
  584. (* parseNL - return NAMELIST starting at userinput[pos]          *)
  585. function parseNL: NAMELIST;
  586. var
  587.    nm: NAME;
  588.    nl: NAMELIST;
  589. begin
  590.    if userinput[pos] = ')'
  591.    then begin
  592.            pos := skipblanks(pos+1); (* skip ') ..' *)
  593.            parseNL := nil
  594.         end
  595.    else begin
  596.            nm := parseName;
  597.            nl := parseNL;
  598.            parseNL := mkNamelist(nm, nl)
  599.         end
  600. end; (* parseNL *)
  601.  
  602. (* parseDef - parse function definition at userinput[pos]        *)
  603. function parseDef (var fenv: FUNDEF): NAME;
  604. var
  605.    fname: NAME;        (* function name *)
  606.    newfun: FUNDEF;     (* new FUNDEFREC *)
  607. begin
  608.    pos := skipblanks(pos+1); (* skip '( ..' *)
  609.    pos := skipblanks(pos+6); (* skip 'define ..' *)
  610.    fname := parseName;
  611.    newfun := newFunDef(fname, fenv);
  612.    newfun^.ftype := NORMAL;
  613.    pos := skipblanks(pos+1); (* skip '( ..' *)
  614.    newfun^.formals := parseNL;
  615.    newfun^.body := parseExp;
  616.    pos := skipblanks(pos+1); (* skip ') ..' *)
  617.    parseDef := fname
  618. end; (* parseDef *)
  619.  
  620. (* parseCluster - parse cluster definition at userinput[pos]     *)
  621. function parseCluster: NAME;
  622.  
  623. var
  624.    cname, sel, fname: NAME;
  625.    newclust: CLUSTER;
  626.    rep: NAMELIST;
  627.    cenv: FUNDEF;
  628.    confun, selfun, setfun: FUNDEF;
  629.  
  630. (* mkSetName - make name of settor corresponding to selector nm  *)
  631.   function mkSetName (nm: NAME): NAME;
  632.   var
  633.      setname: NAMESTRING;
  634.      i: integer;
  635.   begin
  636.      setname := 'set-                ';
  637.      if printNames[nm][NAMELENG-3] <> ' '
  638.      then begin
  639.              write('Selector name too long: ');
  640.              prName(nm);
  641.              writeln;
  642.              goto 99
  643.           end;
  644.      for i:=1 to NAMELENG-4
  645.         do setname[i+4] := printNames[nm][i];
  646.      mkSetName := install(setname)
  647.   end; (* mkSetName *)
  648.  
  649. begin (* parseCluster *)
  650.    pos := skipblanks(pos+1); (* skip '( ..' *)
  651.    pos := skipblanks(pos+7); (* skip 'cluster ...' *)
  652.    cname := parseName;
  653.    newclust := newCluster(cname);
  654.    pos := skipblanks(pos+1); (* skip '( ...' *)
  655.    pos := skipblanks(pos+3); (* skip 'rep ...' *)
  656.    rep := parseNL; (* selector names *)
  657.    newclust^.clrep := rep;
  658.    cenv := nil;
  659.    while userinput[pos]='(' do
  660.       begin
  661.          fname := parseDef(cenv);
  662.          prName(fname);
  663.          writeln
  664.       end;
  665.    newclust^.exported := cenv;
  666.    cenv := nil;
  667.    confun := newFunDef(cname, cenv);
  668.    confun^.ftype := CONSTRUCTOR;
  669.    while rep <> nil do
  670.       begin
  671.          sel := rep^.head;
  672.          selfun := newFunDef(sel, cenv);
  673.          selfun^.ftype := SELECTOR;
  674.          setfun := newFunDef(mkSetName(sel), cenv);
  675.          setfun^.ftype := SETTOR;
  676.          setfun^.selname := sel;
  677.          rep := rep^.tail
  678.       end;
  679.    newclust^.nonexported := cenv;
  680.    pos := skipblanks(pos+1); (* skip ') ..' *)
  681.    parseCluster := cname
  682. end; (* parseCluster *)
  683.  
  684. (*****************************************************************
  685.  *                     ENVIRONMENTS                              *
  686.  *****************************************************************)
  687.  
  688. (* emptyEnv - return an environment with no bindings             *)
  689. function emptyEnv: ENV;
  690. begin
  691.    emptyEnv := mkEnv(nil, nil)
  692. end; (* emptyEnv *)
  693.  
  694. (* bindVar - bind variable nm to value n in environment rho      *)
  695. procedure bindVar (nm: NAME; v: CLUVALUE; rho: ENV);
  696. begin
  697.    rho^.vars := mkNamelist(nm, rho^.vars);
  698.    rho^.values := mkValuelist(v, rho^.values)
  699. end; (* bindVar *)
  700.  
  701. (* findVar - look up nm in rho                                   *)
  702. function findVar (nm: NAME; rho: ENV): VALUELIST;
  703. var
  704.    nl: NAMELIST;
  705.    vl: VALUELIST;
  706.    found: Boolean;
  707. begin
  708.    found := false;
  709.    nl := rho^.vars;
  710.    vl := rho^.values;
  711.    while (nl <> nil) and not found do
  712.       if nl^.head = nm
  713.       then found := true
  714.       else begin
  715.               nl := nl^.tail;
  716.               vl := vl^.tail
  717.            end;
  718.    findVar := vl
  719. end; (* findVar *)
  720.  
  721. (* assign - assign value n to variable nm in rho                 *)
  722. procedure assign (nm: NAME; v: CLUVALUE; rho: ENV);
  723. var varloc: VALUELIST;
  724. begin
  725.    varloc := findVar(nm, rho);
  726.    varloc^.head := v
  727. end; (* assign *)
  728.  
  729. (* fetch - return number bound to nm in rho                      *)
  730. function fetch (nm: NAME; rho: ENV): CLUVALUE;
  731. var vl: VALUELIST;
  732. begin
  733.    vl := findVar(nm, rho);
  734.    fetch := vl^.head
  735. end; (* fetch *)
  736.  
  737. (* isBound - check if nm is bound in rho                         *)
  738. function isBound (nm: NAME; rho: ENV): Boolean;
  739. begin
  740.    isBound := findVar(nm, rho) <> nil
  741. end; (* isBound *)
  742.  
  743. (*****************************************************************
  744.  *                           VALUES                              *
  745.  *****************************************************************)
  746.  
  747. (* prValue - print value v                                       *)
  748. procedure prValue (v: CLUVALUE);
  749. begin
  750.    if v^.vtype = PRIM
  751.    then write(v^.intval:1)
  752.    else write('<userval>')
  753. end; (* prValue *)
  754.  
  755. (* isTrueVal - return true if v is true (non-zero) value         *)
  756. function isTrueVal (v: CLUVALUE): Boolean;
  757. begin
  758.   if v^.vtype = USER
  759.   then isTrueVal := true
  760.   else isTrueVal := v^.intval <> 0
  761. end; (* isTrueVal *)
  762.  
  763. (* applyValueOp - apply VALUEOP op to arguments in VALUELIST vl  *)
  764. function applyValueOp (op: VALUEOP; vl: VALUELIST): CLUVALUE;
  765.  
  766. var n, n1, n2: integer;
  767.  
  768. (* arity - return number of arguments expected by op             *)
  769.    function arity (op: VALUEOP): integer;
  770.    begin
  771.       if op in [PLUSOP .. GTOP] then arity := 2 else arity := 1
  772.    end; (* arity *)
  773.  
  774. begin (* applyValueOp *)
  775.    if arity(op) <> lengthVL(vl)
  776.    then begin
  777.            write('Wrong number of arguments to ');
  778.            prName(ord(op)+1);
  779.            writeln;
  780.            goto 99
  781.         end;
  782.    if op = PRINTOP
  783.    then begin
  784.            prValue(vl^.head);
  785.            writeln;
  786.            applyValueOp := vl^.head
  787.         end
  788.    else begin
  789.            if (vl^.head^.vtype <> PRIM)
  790.               or (vl^.tail^.head^.vtype <> PRIM)
  791.            then begin
  792.                    write('Arguments to primitive op not primitive: ');
  793.                    prName(ord(op)+1);
  794.                    writeln;
  795.                    goto 99
  796.                 end;
  797.            n1 := vl^.head^.intval; (* 1st actual *)
  798.            n2 := vl^.tail^.head^.intval; (* 2nd actual *)
  799.            case op of
  800.               PLUSOP: n := n1+n2;
  801.               MINUSOP: n := n1-n2;
  802.               TIMESOP: n := n1*n2;
  803.               DIVOP: n := n1 div n2;
  804.               EQOP: if n1 = n2 then n := 1 else n := 0;
  805.               LTOP: if n1 < n2 then n := 1 else n := 0;
  806.               GTOP: if n1 > n2 then n := 1 else n := 0
  807.            end; (* case *)
  808.            applyValueOp := mkPRIM(n)
  809.         end
  810. end; (* applyValueOp *)
  811.  
  812. (*****************************************************************
  813.  *                     EVALUATION                                *
  814.  *****************************************************************)
  815. (* eval - return value of e in environment rho, cluster c        *)
  816. function eval (e: EXP; rho: ENV; c: CLUSTER): CLUVALUE;
  817.  
  818. var op: BUILTINOP;
  819.  
  820. (* evalList - evaluate each expression in el                     *)
  821.    function evalList (el: EXPLIST): VALUELIST;
  822.    var
  823.       h: CLUVALUE;
  824.       t: VALUELIST;
  825.    begin
  826.       if el = nil then evalList := nil
  827.       else begin
  828.               h := eval(el^.head, rho, c);
  829.               t := evalList(el^.tail);
  830.               evalList := mkValuelist(h, t)
  831.            end
  832.    end; (* evalList *)
  833.  
  834. (* applyUserFun - look up definition of nm and apply to actuals  *)
  835.    function applyUserFun (nm: FUNNAME;
  836.                      actuals: VALUELIST): CLUVALUE;
  837.    var
  838.       f: FUNDEF;
  839.       rho, valrho: ENV;
  840.       v: CLUVALUE;
  841.       cl: CLUSTER;
  842.  
  843. (* checkArgs - check number/type (as far as possible) of args    *)
  844.       procedure checkArgs (nm: FUNNAME; f: FUNDEF; cl: CLUSTER);
  845.  
  846. (* arity - number of arguments expected by f                     *)
  847.          function arity: integer;
  848.          begin
  849.             with f^ do
  850.                case ftype of
  851.                   NORMAL: arity := lengthNL(formals);
  852.                   CONSTRUCTOR: arity := lengthNL(cl^.clrep);
  853.                   SELECTOR: arity := 1;
  854.                   SETTOR: arity := 2
  855.                end (* case and with *)
  856.          end; (* arity *)
  857.  
  858. (* typeError - print type error message                          *)
  859.          procedure typeError;
  860.          begin
  861.             write('Wrong type argument to: ');
  862.             prName(nm.funpart);
  863.             writeln;
  864.             goto 99
  865.          end; (* typeError *)
  866.  
  867.       begin (* checkArgs *)
  868.          if arity <> lengthVL(actuals)
  869.          then begin
  870.                  write('Wrong number of arguments to: ');
  871.                  prName(nm.funpart);
  872.                  writeln;
  873.                  goto 99
  874.               end;
  875.          with f^ do
  876.             begin
  877.                if ftype in [SELECTOR, SETTOR]
  878.                then if actuals^.head^.vtype = PRIM
  879.                     then typeError;
  880.                if ftype = SELECTOR
  881.                then if not isBound(nm.funpart,
  882.                                    actuals^.head^.userval)
  883.                     then typeError;
  884.                if ftype = SETTOR
  885.                then if not isBound(selname,
  886.                                    actuals^.head^.userval)
  887.                     then typeError
  888.             end
  889.       end; (* checkArgs *)
  890.  
  891.    begin (* applyUserFun *)
  892.       if nm.nametype = TWOPART
  893.       then begin
  894.               cl := fetchCluster(nm.clpart);
  895.               if cl = nil
  896.               then begin
  897.                       write('Non-existent cluster: ');
  898.                       prName(nm.clpart);
  899.                       writeln;
  900.                       goto 99
  901.                    end;
  902.               f := fetchFun(nm.funpart, cl^.exported)
  903.            end
  904.       else begin (* one-part name *)
  905.               cl := c;
  906.               if cl = nil (* called from top level *)
  907.               then f := fetchFun(nm.funpart, fundefs)
  908.               else begin (* try exported function first *)
  909.                       f := fetchFun(nm.funpart, cl^.exported);
  910.                       if f = nil
  911.                       then begin (* else non-exported *)
  912.                               f := fetchFun(nm.funpart,
  913.                                             cl^.nonexported);
  914.                               if f = nil
  915.                               then begin (* else top-level *)
  916.                                       cl := nil;
  917.                                       f := fetchFun(nm.funpart,
  918.                                                     fundefs);
  919.                                    end
  920.                            end
  921.                    end
  922.            end;
  923.       if f = nil
  924.       then begin
  925.               write('Undefined function: ');
  926.               prName(nm.funpart);
  927.               writeln;
  928.               goto 99
  929.            end;
  930.       checkArgs(nm, f, cl);
  931.       with f^ do
  932.          case ftype of
  933.             NORMAL:
  934.                begin
  935.                   rho := mkEnv(formals, actuals);
  936.                   applyUserFun := eval(body, rho, cl)
  937.                end;
  938.             CONSTRUCTOR:
  939.                applyUserFun := mkUSER(mkEnv(cl^.clrep, actuals));
  940.             SELECTOR:
  941.                begin
  942.                   valrho := actuals^.head^.userval;
  943.                   applyUserFun := fetch(nm.funpart, valrho)
  944.                end;
  945.             SETTOR:
  946.                begin
  947.                   valrho := actuals^.head^.userval;
  948.                   v := actuals^.tail^.head;
  949.                   assign(selname, v, valrho);
  950.                   applyUserFun := v
  951.                end
  952.          end (* case and with *)
  953.    end; (* applyUserFun *)
  954.  
  955. (* applyCtrlOp - apply CONTROLOP op to args in rho               *)
  956.    function applyCtrlOp (op: CONTROLOP;
  957.                        args: EXPLIST): CLUVALUE;
  958.    var v: CLUVALUE;
  959.    begin
  960.       with args^ do
  961.          case op of
  962.            IFOP:
  963.               if isTrueVal(eval(head, rho, c))
  964.               then applyCtrlOp := eval(tail^.head, rho, c)
  965.               else applyCtrlOp := eval(tail^.tail^.head, rho, c);
  966.            WHILEOP:
  967.               begin
  968.                  v := eval(head, rho, c);
  969.                  while isTrueVal(v)
  970.                  do begin
  971.                        v := eval(tail^.head, rho, c);
  972.                        v := eval(head, rho, c)
  973.                     end;
  974.                  applyCtrlOp := v
  975.               end;
  976.            SETOP:
  977.               begin
  978.                  v := eval(tail^.head, rho, c);
  979.                  if isBound(head^.varble, rho)
  980.                  then assign(head^.varble, v, rho)
  981.                  else if isBound(head^.varble, globalEnv)
  982.                       then assign(head^.varble, v, globalEnv)
  983.                       else bindVar(head^.varble, v, globalEnv);
  984.                  applyCtrlOp := v
  985.               end;
  986.            BEGINOP: 
  987.               begin
  988.                  while args^.tail <> nil do
  989.                     begin
  990.                        v := eval(args^.head, rho, c);
  991.                        args := args^.tail
  992.                     end;
  993.                  applyCtrlOp := eval(args^.head, rho, c)
  994.               end
  995.          end (* case and with *)
  996.    end; (* applyCtrlOp *)
  997.  
  998. begin (* eval *)
  999.    with e^ do
  1000.       case etype of
  1001.          VALEXP:
  1002.             eval := valu;
  1003.          VAREXP:
  1004.             if isBound(varble, rho)
  1005.             then eval := fetch(varble, rho)
  1006.             else if isBound(varble, globalEnv)
  1007.                  then eval := fetch(varble, globalEnv)
  1008.                  else begin
  1009.                          write('Undefined variable: ');
  1010.                          prName(varble);
  1011.                          writeln;
  1012.                          goto 99
  1013.                       end;
  1014.          APEXP: 
  1015.             if optr.funpart > numBuiltins
  1016.             then eval := applyUserFun(optr, evalList(args))
  1017.             else begin
  1018.                     op := primOp(optr.funpart);
  1019.                     if op in [IFOP .. BEGINOP]
  1020.                     then eval := applyCtrlOp(op, args)
  1021.                     else eval := applyValueOp(op,
  1022.                                      evalList(args))
  1023.                  end
  1024.       end (* case and with *)
  1025. end; (* eval *)
  1026.  
  1027. (*****************************************************************
  1028.  *                     READ-EVAL-PRINT LOOP                      *
  1029.  *****************************************************************)
  1030.  
  1031. begin (* clu main *)
  1032.    initNames;
  1033.    globalEnv := emptyEnv;
  1034.  
  1035.    quittingtime := false;
  1036. 99:
  1037.    while not quittingtime do begin
  1038.       reader;
  1039.       if matches(pos, 4, 'quit                ')
  1040.       then quittingtime := true
  1041.       else if (userinput[pos] = '(') and
  1042.               matches(skipblanks(pos+1), 6, 'define              ')
  1043.            then begin
  1044.                    prName(parseDef(fundefs));
  1045.                    writeln
  1046.                 end
  1047.            else if (userinput[pos]='(') and
  1048.                 matches(skipblanks(pos+1),7,'cluster             ')
  1049.                 then begin
  1050.                         prName(parseCluster);
  1051.                         writeln
  1052.                      end
  1053.                 else begin
  1054.                         currentExp := parseExp;
  1055.                         prValue(eval(currentExp, emptyEnv, nil));
  1056.                         writeln;
  1057.                         writeln
  1058.                      end
  1059.       end (* while *)
  1060. end. (* clu *)
  1061.