(* ----------------------------------------------------------------------------
 * $Id: MASPARSE.mi,v 1.5 1995/11/05 08:57:07 kredel Exp $
 * ----------------------------------------------------------------------------
 * This file is part of MAS.
 * ----------------------------------------------------------------------------
 * Copyright (c) 1989 - 1992 Universitaet Passau
 * ----------------------------------------------------------------------------
 * $Log: MASPARSE.mi,v $
 * Revision 1.5  1995/11/05 08:57:07  kredel
 * List expressions and small letter key words.
 *
 * Revision 1.2  1994/10/06  12:00:01  kredel
 * Added support for parallel language constructs: CON, CONFOR, ATOMIC, semaphore
 *
 * Revision 1.1.1.1  1993/06/11  12:55:08  kredel
 * Initial Version 0.7 of MAS from University of Passau
 *
 * Revision 1.4  1992/10/15  16:27:50  kredel
 * Changed rcsid variable
 *
 * Revision 1.3  1992/02/16  17:54:29  pesch
 * CONST-deviniton moved again.
 *
 * Revision 1.2  1992/02/12  17:32:27  pesch
 * Moved CONST definition to the right place
 *
 * Revision 1.1  1992/01/22  15:11:22  kredel
 * Initial revision
 *
 * ----------------------------------------------------------------------------
 *)

IMPLEMENTATION MODULE MASPARSE;

(* MAS Parser Implementation Module. *)



(* Import lists and declarations. *)

FROM MASELEM IMPORT GAMMAINT;

FROM MASSTOR IMPORT BETA, SIL, LIST,
                    LENGTH, SRED, LISTVAR,
                    LIST1, ADV, FIRST, RED, COMP, INV;

FROM MASBIOS IMPORT DIBUFF, CREAD, CREADB, BKSP, LISTS, 
                    CWRITE, MASCHR, MASORD, BLINES, SWRITE;

FROM SACLIST IMPORT AWRITE, AREAD, LIST2, ADV2, FIRST2, ADV3,
                    CCONC, CINV, COMP2, LIST3, FIRST3, CLOUT;

FROM MASSYM2 IMPORT SYWRIT, SYMBOL, ENTER, SREAD, GET, PUT;

FROM MASSYM IMPORT ELEMP, MEMQ, UREAD, UWRITE, UWRIT1, NOSHOW;

FROM MASLISPU IMPORT EXTYP, Declare;
                    
FROM MASLISP IMPORT EQS, NEQS, GTS, LTS, GEQ, LEQ, NOTS, UND, ODER,   
                    ADD, SUB, MUL, QUOT, REM, POW,
                    QUOTE, SETQ, STRNG, LISTX, 
                    PROGN, VARS, IFS, WHL, RPT, DE, 
                    CONVVAL, CONVDES,
                    EXPOS, SPEC, SORT, SIG, IMPRT, IMPL, 
                    UNIT, MODEL, MAP, AXIOM, RULE, WHEN,
                    DEFAULT, ASSIGN, TINFO, ENV;

CONST rcsidi = "$Id: MASPARSE.mi,v 1.5 1995/11/05 08:57:07 kredel Exp $";
CONST copyrighti = "Copyright (c) 1989 - 1992 Universitaet Passau";


(*generic function names. *)

VAR SUM, DIF, PROD, Q, REMAIN, EXP: LIST;

(*parse names. *)
 
VAR sum, dif, prod, quot, remain, exp: LIST;


(* scanner/parser definitions. *)
TYPE Token    = ( null, not, and, or, times, div, mod, plus, minus, power, 
                  eql, neq, lss, leq, gtr, geq, 
                  when, equiv, arrow, tinfo, listex, 
                  comma, rparen, rbrace, rbrack, lparen, lbrace, lbrack,
                  until, else, then, do, to, 
                  becomes, string, number, colon, ident, semicolon,
                  end, if, repeat, while, begin, 
                  map, rule, sig, var, sort, import, procedure, 
                  expose, spec, model, impl, axiom, 
                  period, eof );
 
VAR tok: Token;      (*last token type read*)
    tokval: LIST;    (*last token read*)
    ch:   CHAR;      (*last character read*)
    ach:  LIST;      (*ALDES code of last character read*)
    KW:   LIST;      (*key word inicator*)
    noerr: BOOLEAN;  (*error during parsing*)
    blv: LIST;       (*block local variables. *)
    genpars: BOOLEAN; (*flag, if generic/non generic parsing. *)


(* Scanner and Parser. *) 

PROCEDURE SyntaxErr(n: GAMMAINT);
(*Report on syntax error with number n. *)
VAR   m: INTEGER; c: LIST;
BEGIN
(*1*) SWRITE("["); AWRITE(n); SWRITE("] ");
      m:=INTEGER(n); noerr:=FALSE;
(*2*) CASE m OF 
           1  : SWRITE("=") | 
           2  : SWRITE("identifier or , or ;") | 
           4  : SWRITE("identifier") | 
           5  : SWRITE("; or ,") | 
           6  : SWRITE("expression") | 
           7  : SWRITE(")") | 
           8  : SWRITE("factor") | 
           9  : SWRITE(".") | 
          10  : SWRITE("assignment") | 
          13  : SWRITE(":= or (") | 
          14  : SWRITE("statement") | 
          15  : SWRITE(":") | 
          16  : SWRITE("then") | 
          17  : SWRITE("; or end") | 
          18  : SWRITE("do") | 
          20  : SWRITE("relation") | 
          21  : SWRITE(", or )") |
          22  : SWRITE("->") |
          23  : SWRITE("( or ident") |
          24  : SWRITE("(") |
          25  : SWRITE("condition") |
          26  : SWRITE("number")  |
          27  : SWRITE(", or ) or ;") |
          28  : SWRITE(";") |
          29  : SWRITE("end or ;") |
          30  : SWRITE(", or ]") |
          31  : SWRITE("/") |
          32  : SWRITE("==") |
          33  : SWRITE("end or ; or begin") |
          34  : SWRITE(", or }") |
          35  : SWRITE("to") |
           ELSE SWRITE("don't know what is") 
                END;
      SWRITE(" expected ");
(*3*) BKSP; DIBUFF; c:=CREAD();  
(*9*) END SyntaxErr;


PROCEDURE SyntaxWrn(n: GAMMAINT);
(*Report warning on syntax error with number n. *)
VAR m: INTEGER;
BEGIN
(*1*) SWRITE("["); AWRITE(n); SWRITE("] ");
      m:=INTEGER(n); 
(*2*) CASE m OF 
           1  : SWRITE("identifier") | 
           2  : SWRITE("algorithm name")  
           ELSE SWRITE("don't know what is") 
                END;
      SWRITE(" expected ");   
(*9*) END SyntaxWrn;


PROCEDURE SyntaxTest(s: Token; n: GAMMAINT);
(*Test if curent token is expected. *)
VAR m: INTEGER;
BEGIN
(*1*) IF tok < s THEN SyntaxErr(n);
         REPEAT GetToken UNTIL tok >= s;
         END;
(*9*) END SyntaxTest;


PROCEDURE KeyWord(s: Token; VAR S: ARRAY OF CHAR);
(*Declare key word. *)
VAR X: LIST;
    P: GAMMAINT;
BEGIN
(*1*) (*intern. *) X:=ENTER(LISTS(S));
(*2*) (*key word property. *) P:=GAMMAINT(ORD(s));
      PUT(X,KW,P);
(*3*) END KeyWord;


PROCEDURE GetCh;
(*Get next character. *)
BEGIN
(*1*) ach:=CREAD();
      ch:=MASCHR(ach);
(*3*) (*3*) END GetCh;


PROCEDURE Comment;
(*Skip comment. Recursively nested comments are accepted. *)
VAR   lev: LIST;
BEGIN
(*1*) lev:=1; 
(*2*) REPEAT GetCh; 
             IF ch = '*' THEN GetCh;  
                IF ch = ')' THEN GetCh; lev:=lev-1 END;
                END;
             IF ch = '(' THEN GetCh;  
                IF ch = '*' THEN GetCh; lev:=lev+1 END;
                END;
             UNTIL lev = 0;
(*3*) END Comment;


PROCEDURE GetString(c: CHAR): LIST;
(*Get String. *)
VAR s: LIST;
BEGIN
(*1*) s:=SIL;
(*2*) LOOP GetCh;
           IF ch = c THEN GetCh;
              IF ch <> c THEN EXIT END;
              END;
           s:=COMP(ach,s);
           END;
      s:=INV(s);
      RETURN(s);
(*3*) END GetString;


PROCEDURE GetIdent(): LIST;
(*Get Identifier. *)
VAR s, p: LIST;
BEGIN
(*1*) BKSP; s:=SREAD();
(*2*) p:=GET(s,KW);
      IF p <> SIL 
         THEN tok:=VAL(Token,CARDINAL(p)) 
         ELSE p:=GET(s,EXTYP); 
              IF p = SIL THEN 
                 IF NOT MEMQ(s,blv) THEN blv:=COMP(s,blv) END;
                 END; 
              END;
      RETURN(s);
(*3*) END GetIdent;


PROCEDURE GetToken;
(*Get next token. *)
BEGIN
(*1*) WHILE ch = " " DO GetCh END;
      tokval:=SIL;
(*2*) CASE ch OF 
          '"'  : tok:=string;  
                 tokval:=GetString('"') |
          "'"  : tok:=string;  
                 tokval:=GetString("'") |
          "#"  : tok:=neq; GetCh |
          "("  : GetCh;
                 IF ch = "*" THEN Comment; GetToken;
                             ELSE tok:=lparen END |
          ")"  : tok:=rparen; GetCh |
          "["  : tok:=lbrack; GetCh |
          "]"  : tok:=rbrack; GetCh |
          "{"  : tok:=lbrace; GetCh |
          "}"  : tok:=rbrace; GetCh |
          "^"  : tok:=power; GetCh |
          "*"  : GetCh;
                 IF ch = "*" THEN GetCh; tok:=power;
                             ELSE tok:=times END |
          "+"  : tok:=plus; GetCh |
          ","  : tok:=comma; GetCh |
          "-"  : GetCh; 
                 IF ch = ">" THEN GetCh; tok:=arrow;
                             ELSE tok:=minus END |
          "."  : tok:=period; ch:='.' |
          "/"  : tok:=div; GetCh |
          "%"  : tok:=mod; GetCh |
     "0".."9"  : tok:=number; BKSP; 
                 tokval:=AREAD(); GetCh |
          ":"  : GetCh;
                 IF ch = "=" THEN GetCh; tok:=becomes;
                             ELSE tok:=colon END |
          ";"  : tok:=semicolon; GetCh |
          "<"  : GetCh;
                    IF ch = "=" THEN GetCh; tok:=leq;
                 ELSIF ch = ">" THEN GetCh; tok:=neq;
                                ELSE tok:=lss END |
          "="  : GetCh;
                    IF ch = "=" THEN GetCh; tok:=equiv;
                 ELSIF ch = ">" THEN GetCh; tok:=rule;
                                ELSE tok:=eql END |
          ">"  : GetCh;
                 IF ch = "=" THEN GetCh; tok:=geq;
                             ELSE tok:=gtr END |
     "A".."Z"  : tok:=ident;  
                 tokval:=GetIdent(); GetCh |
     "a".."z"  : tok:=ident;  
                 tokval:=GetIdent(); GetCh 
            ELSE tok:=null; GetCh
                 END;
(*3*) END GetToken;


PROCEDURE PutToken;
(*Put current token. *)
BEGIN
(*1*) BLINES(0); SWRITE("Token: ");
(*2*) CASE tok OF 
          times  : SWRITE("times") |
          power  : SWRITE("power") |
          plus   : SWRITE("plus") |
          minus  : SWRITE("minus") |
          div    : SWRITE("div") |
          mod    : SWRITE("mod") |
      semicolon  : SWRITE("semicolon") |
          colon  : SWRITE("colon") |
          eof    : SWRITE("eof") |
          neq    : SWRITE("neq") |
          eql    : SWRITE("eql") |
          lss    : SWRITE("lss") |
          leq    : SWRITE("leq") |
          gtr    : SWRITE("gtr") |
          geq    : SWRITE("geq") |
          and    : SWRITE("and") |
          or     : SWRITE("or") |
          equiv  : SWRITE("equiv") |
          rule   : SWRITE("rule") |
          arrow  : SWRITE("arrow") |
          comma  : SWRITE("comma") |
        becomes  : SWRITE("becomes") |
          lparen : SWRITE("lparen") |
          rparen : SWRITE("rparen") |
          rbrack : SWRITE("rbrack") |
          lbrack : SWRITE("lbrack") |
          rbrace : SWRITE("rbrace") |
          lbrace : SWRITE("lbrace") |
          period : SWRITE("period") |
          do     : SWRITE("do") |
          if     : SWRITE("if") |
          end    : SWRITE("end") |
          not    : SWRITE("not") |
          var    : SWRITE("var") |
          expose : SWRITE("expose") |
          spec   : SWRITE("spec") |
          impl   : SWRITE("impl") |
          model  : SWRITE("model") |
          axiom  : SWRITE("axiom") |
          sig    : SWRITE("sig") |
          map    : SWRITE("map") |
          then   : SWRITE("then") |
          else   : SWRITE("else") |
          begin  : SWRITE("begin") |
          while  : SWRITE("while") |
          repeat : SWRITE("repeat") |
          until  : SWRITE("until") |
       procedure : SWRITE("procedure") |
          number : SWRITE("number "); AWRITE(tokval) |
          ident  : SWRITE("ident "); SYWRIT(tokval) | 
          string : SWRITE("string "); CLOUT(tokval) 
            ELSE SWRITE("null")
                 END;
      BLINES(0);
(*3*) END PutToken;


PROCEDURE Generate(s: Token; t: LIST): LIST;
(*Generate code for token s. *)
VAR code: LIST;
BEGIN
(*1*) CASE s OF 
       times  : code:=COMP(prod,t) |
       power  : code:=COMP(exp,t) |
       plus   : code:=COMP(sum,t) |
       minus  : code:=COMP(dif,t) |
       div    : code:=COMP(quot,t) |
       mod    : code:=COMP(remain,t) |
       neq    : code:=COMP(NEQS,t) |
       eql    : code:=COMP(EQS,t) |
       lss    : code:=COMP(LTS,t) |
       leq    : code:=COMP(LEQ,t) |
       gtr    : code:=COMP(GTS,t) |
       geq    : code:=COMP(GEQ,t) |
       and    : code:=COMP(UND,t) |
       or     : code:=COMP(ODER,t) |
       not    : code:=COMP(NOTS,t) |
       listex : code:=COMP(LISTX,t) |
     becomes  : code:=COMP(ASSIGN,t) |
       if     : code:=COMP(IFS,t) |
       var    : code:=COMP(VARS,t) |
       sort   : code:=COMP(SORT,t) |
       expose : code:=COMP(EXPOS,t) |
       tinfo  : code:=COMP2(LISTX,TINFO,t) |
       import : code:=COMP(IMPRT,t) |
       sig    : code:=COMP(SIG,t) |
       map    : code:=COMP(MAP,t) |
       rule   : code:=COMP(RULE,t) |
       begin  : IF t = SIL THEN code:=t
                   ELSIF RED(t) = SIL THEN code:=FIRST(t)
                   ELSE code:=COMP(PROGN,t) END |
       while  : code:=COMP(WHL,t) |
       repeat : code:=COMP(RPT,t) |
    procedure : code:=COMP(DE,t) |
       spec   : code:=COMP(SPEC,t) |
       model  : code:=COMP(MODEL,t) |
       impl   : code:=COMP(IMPL,t) |
       axiom  : code:=COMP(AXIOM,t) |
       string : code:=COMP(STRNG,t) 
         ELSE   code:=LIST2(QUOTE,t); 
                END;
      RETURN(code);
(*3*) END Generate;


PROCEDURE Parse(): LIST;
(*Parse program and generate code. *)
VAR s: LIST;
BEGIN
(*1*) noerr:=TRUE; ch:=" ";
(*2*) GetToken; s:=TopBlock(); 
      IF tok <> period THEN SyntaxErr(9) END;
      IF NOT noerr THEN s:=Generate(null,s) END; (*don't execute*)
      RETURN(s);
(*3*) END Parse;


PROCEDURE TopBlock(): LIST;
(*Parse top level block and generate code. *)
VAR   t, u, d: LIST;
BEGIN
(*1*) t:=SIL; 
(*2*) LOOP    IF tok = spec      THEN GetToken;
                                 u:=SpecDec(); t:=COMP(u,t) 
           ELSIF tok = impl      THEN GetToken;
                                 u:=ImplDec(); t:=COMP(u,t) 
           ELSIF tok = model     THEN GetToken;
                                 u:=ModDec(); t:=COMP(u,t) 
           ELSIF tok = axiom     THEN GetToken;
                                 u:=AxiomDec(); t:=COMP(u,t) 
           ELSIF tok = sort      THEN GetToken; u:=SortDec(); 
                                 t:=COMP(u,t); 
           ELSIF tok = var       THEN GetToken;
                                 u:=VarDec(); t:=COMP(u,t) 
           ELSIF tok = procedure THEN GetToken;
                                 u:=ProcDec(); t:=COMP(u,t) 
           ELSIF tok = expose    THEN GetToken;
                                 u:=ImportDec(expose); t:=COMP(u,t) 
            ELSE EXIT END; 
           IF tok = semicolon THEN GetToken 
                              ELSE EXIT END;
           END;
(*3*) u:=Statement(); IF u <> SIL THEN t:=COMP(u,t) END;
      t:=INV(t);
      t:=Generate(begin,t);
      RETURN(t);
(*5*) END TopBlock;


PROCEDURE Block(): LIST;
(*Parse inner block and generate code. *)
VAR   t, u, B, B1, B2, d: LIST;
BEGIN
(*1*) t:=SIL; B:=blv;
(*2*) LOOP    IF tok = var       THEN GetToken;
                                 u:=VarDec(); t:=COMP(u,t) 
           ELSIF tok = procedure THEN GetToken;
                                 u:=ProcDec(); t:=COMP(u,t) 
            ELSE EXIT END; 
           IF tok = semicolon THEN GetToken 
                              ELSE EXIT END;
           END;
(*3*) B1:=blv;
      u:=Statement(); IF u <> SIL THEN t:=COMP(u,t) END;
      t:=INV(t);
(*4*) (*analyse declarations. *) 
      B2:=blv;
      IF B2 <> B1 THEN 
         WHILE RED(B2) <> B1 DO B2:=RED(B2) END;
         SRED(B2,SIL); 
         SWRITE("Variable(s) declared: "); UWRITE(blv);
         d:=LIST2(blv,LISTX);
         d:=Generate(var,d); t:=COMP(d,t);
         END;
      blv:=B;     
      t:=Generate(begin,t);
      RETURN(t);
(*5*) END Block;


PROCEDURE SpecDec(): LIST;
(*Parse specification declaration and generate code. *)
VAR   s, u, n, B: LIST;
BEGIN
(*1*) B:=blv; s:=SIL; u:=SIL; n:=SIL;
(*2*) IF tok = ident THEN n:=tokval; s:=HeadDec(); 
                          u:=CINV(s); 
         ELSE SyntaxErr(4) END;
      IF tok = semicolon THEN GetToken; 
                         ELSE SyntaxErr(28) END;
(*3*) LOOP IF tok = sort THEN GetToken; s:=SortDec(); 
                              u:=COMP(s,u); 
        ELSIF tok = sig THEN GetToken; s:=SigDec(); 
                             u:=COMP(s,u);
        ELSIF tok = import THEN GetToken; s:=ImportDec(import); 
                                u:=COMP(s,u);
        ELSIF tok = end THEN GetToken; EXIT 
        ELSIF tok = semicolon THEN GetToken;
         ELSE SyntaxErr(29); EXIT END;
           END;
(*5*) IF tok = ident THEN 
         IF tokval <> n THEN SyntaxWrn(2); END;
         GetToken;
         ELSE SyntaxWrn(1); END;
(*6*) (*blv:=B; need this to parse mod, impl and axiom *)
      u:=INV(u); u:=Generate(spec,u); 
      RETURN(u);
(*9*) END SpecDec;


PROCEDURE ImplDec(): LIST;
(*Parse implementation declaration and generate code. *)
VAR   s, u, n, B: LIST;
BEGIN
(*1*) B:=blv; s:=SIL; u:=SIL; n:=SIL;
(*2*) IF tok = ident THEN n:=tokval; s:=HeadDec(); 
                          u:=CINV(s); 
         ELSE SyntaxErr(4) END;
      IF tok = semicolon THEN GetToken; 
                         ELSE SyntaxErr(28) END;
(*3*) LOOP IF tok = var THEN GetToken; s:=VarDec(); 
                              u:=COMP(s,u); 
        ELSIF tok = sort THEN GetToken; s:=SortDec(); 
                              u:=COMP(s,u); 
        ELSIF tok = procedure THEN GetToken; s:=ProcDec(); 
                             u:=COMP(s,u);
        ELSIF tok = import THEN GetToken; s:=ImportDec(import); 
                                u:=COMP(s,u);
        ELSIF tok = begin THEN EXIT 
        ELSIF tok = end THEN EXIT 
        ELSIF tok = semicolon THEN GetToken;
         ELSE SyntaxErr(33); EXIT END;
           END;
      IF tok = end THEN GetToken 
         ELSIF tok = begin THEN s:=Statement(); u:=COMP(s,u); 
         ELSE SyntaxErr(33) END; 
(*4*) IF tok = ident THEN 
         IF tokval <> n THEN SyntaxWrn(2); END;
         GetToken;
         ELSE SyntaxWrn(1); END;
(*5*) blv:=B;
      u:=INV(u); u:=Generate(impl,u); 
      RETURN(u);
(*9*) END ImplDec;


PROCEDURE ModDec(): LIST;
(*Parse model declaration and generate code. *)
VAR   s, u, n, B: LIST;
BEGIN
(*1*) B:=blv; s:=SIL; u:=SIL; 
(*2*) IF tok = ident THEN n:=tokval; s:=HeadDec(); 
                          u:=CINV(s); 
         ELSE SyntaxErr(4) END;
      IF tok = semicolon THEN GetToken; 
                         ELSE SyntaxErr(28) END;
(*3*) LOOP IF tok = map THEN GetToken; s:=MapDec(); 
                             u:=COMP(s,u);
        ELSIF tok = sort THEN GetToken; s:=SortDec(); 
                              u:=COMP(s,u); 
        ELSIF tok = import THEN GetToken; s:=ImportDec(import); 
                                u:=COMP(s,u);
        ELSIF tok = semicolon THEN GetToken   
        ELSIF tok = end THEN GetToken; EXIT   
         ELSE SyntaxErr(29); EXIT END;
           END;
(*4*) IF tok = ident THEN 
         IF tokval <> n THEN SyntaxWrn(2); END;
         GetToken;
         ELSE SyntaxWrn(1); END;
(*5*) blv:=B; 
      u:=INV(u); u:=Generate(model,u); 
      RETURN(u);
(*6*) END ModDec;


PROCEDURE AxiomDec(): LIST;
(*Parse axioms declaration and generate code. *)
VAR   s, u, n, B: LIST;
BEGIN
(*1*) B:=blv; s:=SIL; u:=SIL; n:=SIL;
(*2*) IF tok = ident THEN n:=tokval; s:=HeadDec(); 
                          u:=CINV(s); 
         ELSE SyntaxErr(4) END;
      IF tok = semicolon THEN GetToken; 
                         ELSE SyntaxErr(28) END;
(*3*) LOOP IF tok = rule   THEN GetToken; s:=RuleDec(); 
                              u:=COMP(s,u); 
        ELSIF tok = sort THEN GetToken; s:=SortDec(); 
                              u:=COMP(s,u); 
        ELSIF tok = import THEN GetToken; s:=ImportDec(import); 
                                u:=COMP(s,u);
        ELSIF tok = end THEN GetToken; EXIT 
        ELSIF tok = semicolon THEN GetToken;
         ELSE SyntaxErr(29); EXIT END;
           END;
(*4*) IF tok = ident THEN 
         IF tokval <> n THEN SyntaxWrn(2); END;
         GetToken;
         ELSE SyntaxWrn(1); END;
(*5*) blv:=B; 
      u:=INV(u); u:=Generate(axiom,u); 
      RETURN(u);
(*9*) END AxiomDec;


PROCEDURE ImportDec(t: Token): LIST;
(*Parse import declaration and generate code. *)
VAR   s, u, e: LIST;
BEGIN
(*1*) s:=SIL; u:=SIL; e:=SIL;  
      IF tok = ident THEN s:=HeadDec(); u:=COMP(s,u);  
         ELSE SyntaxErr(4) END;
(*3*) IF tok = lbrack THEN GetToken; s:=SIL;
         LOOP IF tok = ident THEN e:=tokval; GetToken;
                 IF tok = div THEN GetToken
                              ELSE SyntaxErr(31) END;
                 IF tok = ident THEN s:=COMP(tokval,s); s:=COMP(e,s);
                                     GetToken
                                ELSE SyntaxErr(4) END;
                 END; 
              IF tok = comma THEN GetToken
           ELSIF tok = rbrack THEN GetToken; EXIT
            ELSE SyntaxErr(30); EXIT END;
              END;
         s:=INV(s); u:=COMP(s,u); 
         END;
      u:=INV(u); u:=Generate(t,u); (*import or expose *) 
      RETURN(u);
(*3*) END ImportDec;


PROCEDURE MapDec(): LIST;
(*Parse generic map declaration and generate code. *)
VAR   s, u, t: LIST;
BEGIN
(*1*) s:=SIL; u:=SIL; t:=SIL; 
(*2*) IF tok = ident THEN u:=HeadDec(); t:=COMP(u,t); 
                     ELSE SyntaxErr(4) END;
      IF tok = arrow THEN GetToken; 
                     ELSE SyntaxErr(22) END;
(*3*) IF tok = ident THEN s:=HeadDec(); t:=COMP(s,t);
                     ELSE SyntaxErr(4) END;
(*4*) IF tok = when THEN GetToken; 
         IF tok = ident THEN s:=HeadDec(); t:=COMP(s,t);
                        ELSE SyntaxErr(4) END;
         END;
(*5*) t:=INV(t); 
      t:=Generate(map,t); 
      RETURN(t);
(*6*) END MapDec;


PROCEDURE RuleDec(): LIST;
(*Parse rule declaration and generate code. *)
VAR   s, u, t: LIST;
BEGIN
(*1*) s:=SIL; u:=SIL; 
(*2*) u:=Expression(); t:=LIST1(u);
      IF tok = rule THEN GetToken; 
                    ELSE SyntaxErr(32) END;
      s:=Expression(); t:=COMP(s,t);
(*3*) IF tok = when THEN GetToken; 
         s:=Condition(); t:=COMP(s,t) END;
(*4*) t:=INV(t);
      t:=Generate(rule,t); 
      RETURN(t);
(*5*) END RuleDec;


PROCEDURE VarDec(): LIST;
(*Parse variable declaration and generate code. *)
VAR s, u: LIST;
BEGIN
(*1*) s:=SIL; u:=SIL;  
(*2*) (*list of identifiers. *)
      LOOP IF tok = ident THEN s:=COMP(tokval,s); GetToken
                           ELSE SyntaxErr(4) END;
           IF tok = comma THEN GetToken
              ELSIF tok = colon THEN EXIT  
              ELSIF tok = ident THEN SyntaxErr(5)
              ELSE SyntaxErr(15); EXIT END;
           END;
       s:=INV(s); u:=COMP(s,u); 
(*3*) (*type info. *)
      IF tok = colon THEN GetToken; 
         s:=TypeExpression(); u:=COMP(s,u);  
         END;
      u:=INV(u); u:=Generate(var,u); 
      RETURN(u);
(*4*) END VarDec;


PROCEDURE SortDec(): LIST;
(*Parse sort declaration and generate code. *)
VAR   s: LIST;
BEGIN
(*1*) s:=SIL;   
      LOOP IF tok = ident THEN s:=COMP(tokval,s); GetToken
                          ELSE SyntaxErr(4) END;
           IF tok = comma THEN GetToken
              ELSIF tok = semicolon THEN EXIT  
              ELSE SyntaxErr(2); EXIT END;
           END;
(*2*) s:=INV(s); s:=Generate(sort,s); 
      RETURN(s);
(*3*) END SortDec;


PROCEDURE SigDec(): LIST;
(*Parse signature declaration and generate code. *)
VAR s, u: LIST;
BEGIN
(*1*) s:=SIL; u:=SIL;
(*2*) IF tok = ident THEN s:=COMP(tokval,s); GetToken
                     ELSE SyntaxErr(4) END;
(*4*) IF tok = lparen THEN GetToken; u:=IdentList(); 
                           IF tok = rparen THEN GetToken 
                              ELSE SyntaxErr(5) END;
                      ELSE SyntaxErr(23) END;
      s:=COMP(u,s); u:=SIL;
      IF tok = colon THEN GetToken;
         IF tok = ident THEN u:=LIST1(tokval); GetToken; 
                        ELSE SyntaxErr(23) END;
         END;
      s:=COMP(u,s); 
(*5*) s:=INV(s);
      s:=Generate(sig,s);
      RETURN(s);
(*6*) END SigDec;


PROCEDURE ProcDec(): LIST;
(*Parse procedure declaration and generate code. *)
VAR   t, s, u, a, up: LIST;
      ip: BOOLEAN;
BEGIN
(*1*) s:=SIL; u:=SIL; up:=SIL; a:=SIL; 
(*2*) IF tok = ident THEN a:=tokval; s:=COMP(a,s); GetToken
                     ELSE SyntaxErr(4) END;
(*3*) IF tok = lparen THEN GetToken;
         u:=IdentList(); 
         IF tok = semicolon THEN GetToken;
            IF tok = var THEN GetToken END;
            up:=IdentList(); END;
         IF tok = rparen THEN GetToken 
                         ELSE SyntaxErr(5) END;
         END;
      u:=LIST2(u,up);
      s:=COMP(u,s);
      IF tok = colon THEN GetToken;  
         IF tok = ident THEN t:=tokval; GetToken 
                             (* t is not used further *)
                        ELSE SyntaxErr(4) END
         END; 
      IF tok = semicolon THEN GetToken 
                         ELSE SyntaxErr(5) END; 
(*4*) u:=Block(); 
      s:=COMP(u,s); s:=INV(s); 
      s:=Generate(procedure,s);
      IF tok = ident THEN IF a <> tokval THEN SyntaxWrn(2) END; 
                          GetToken
                     ELSE SyntaxWrn(1) END;
      RETURN(s);
(*9*) END ProcDec;


PROCEDURE HeadDec(): LIST;
(*Parse header declaration and generate code. *)
VAR   s, u, a: LIST;
BEGIN
(*1*) s:=SIL; u:=SIL; a:=SIL; 
(*2*) IF tok = ident THEN a:=tokval; s:=COMP(a,s); GetToken
                     ELSE SyntaxErr(4) END;
(*3*) IF tok = lparen THEN GetToken;
         u:=IdentList(); 
         IF tok = rparen THEN GetToken 
                         ELSE SyntaxErr(24) END;
         END;
(*4*) s:=COMP(u,s); s:=INV(s); RETURN(s);
(*9*) END HeadDec;


PROCEDURE StatSeq(): LIST;
(*Parse statement sequence and generate code. *)
VAR s, t: LIST;
BEGIN
(*1*) t:=SIL;
      LOOP IF tok = semicolon THEN GetToken END;
           IF tok = end THEN GetToken; EXIT  
              ELSIF tok = else THEN EXIT 
              ELSIF tok = period THEN EXIT 
              ELSIF tok = until THEN GetToken; EXIT
                    END; 
           s:=Statement(); t:=COMP(s,t); 
           END; 
      IF t <> SIL THEN t:=INV(t); t:=Generate(begin,t) END;
      RETURN(t);
(*3*) END StatSeq;


PROCEDURE Statement(): LIST;
(*Parse statement and generate code. *)
VAR s, t, u: LIST;
BEGIN
(*1*) t:=SIL;
      SyntaxTest(ident,14);
(*2*) IF tok = ident THEN s:=tokval; GetToken; 
         IF tok = becomes THEN GetToken;
            u:=ListExpr(); 
            t:=LIST2(s,u); t:=Generate(becomes,t); 
            RETURN(t) 
         ELSIF tok = lparen THEN GetToken;  
            u:=ActParms(); 
            t:=COMP(s,u); (*=generate procedure call*)
            RETURN(t); 
            END;
         t:=LIST1(s); (*=generate procedure call*)
         RETURN(t); 
         END;
(*3*) IF tok = begin THEN GetToken; t:=StatSeq(); 
         RETURN(t);
         END;
(*4*) IF tok = if THEN GetToken; 
         s:=Condition(); t:=COMP(s,t);
         IF tok = then THEN GetToken;
                       ELSE SyntaxErr(16) END;
         s:=StatSeq(); t:=COMP(s,t);
         IF tok = else THEN GetToken;
            s:=StatSeq(); t:=COMP(s,t);
            END;
         t:=INV(t); t:=Generate(if,t);
         RETURN(t);
         END;
(*5*) IF tok = while THEN GetToken; 
         s:=Condition(); t:=COMP(s,t);
         IF tok = do THEN GetToken;
                     ELSE SyntaxErr(18) END;
         s:=StatSeq(); t:=COMP(s,t);
         t:=INV(t); t:=Generate(while,t);
         RETURN(t);
         END;
(*6*) IF tok = repeat THEN GetToken; 
         s:=StatSeq(); t:=COMP(s,t);
         s:=Condition(); t:=COMP(s,t);
         t:=INV(t); t:=Generate(repeat,t);
         RETURN(t);
         END;
(*7*) IF tok <> period THEN PutToken;  
         SyntaxTest(period,9) END;
      RETURN(t);
(*8*) END Statement;
 

PROCEDURE IdentList(): LIST;
(*Parse identifier list and generate code. *)
VAR s, u: LIST;
BEGIN 
(*1*) u:=SIL;
      IF (tok = rparen) OR (tok = semicolon) THEN RETURN(u) END;
(*2*) LOOP IF tok = ident THEN u:=COMP(tokval,u); GetToken
              ELSE SyntaxErr(4) END; 
           IF tok = comma THEN GetToken
              ELSIF (tok = rparen) OR (tok = semicolon) THEN EXIT
              ELSE SyntaxErr(27); EXIT END;
           END;
      u:=INV(u);
      RETURN(u);
(*3*) END IdentList;
 

PROCEDURE ActParms(): LIST;
(*Parse actual parameters and generate code. *)
VAR s, u: LIST;
BEGIN 
(*1*) u:=SIL;
(*2*) LOOP IF tok = rparen THEN GetToken; EXIT END;
           s:=ListExpr(); u:=COMP(s,u); 
           IF tok = comma THEN GetToken
              ELSIF tok = rparen THEN GetToken; EXIT
              ELSE SyntaxErr(21); EXIT END;
           END;
      u:=INV(u);
      RETURN(u);
(*3*) END ActParms;
 

PROCEDURE ListExpr(): LIST;
(*Parse list expression and generate code. *)
VAR s, u: LIST;
BEGIN 
(*1*) IF tok = lbrace THEN GetToken; 
         ELSE u:=Expression(); RETURN(u); END; 
      u:=SIL;
(*2*) LOOP IF tok = rbrace THEN GetToken; EXIT END;
           s:=Expression(); u:=COMP(s,u); 
           IF tok = comma THEN GetToken
              ELSIF tok = rbrace THEN GetToken; EXIT
              ELSE SyntaxErr(34); EXIT END;
           END;
      u:=INV(u); u:=Generate(listex,u); 
      RETURN(u);
(*3*) END ListExpr;


PROCEDURE Expression(): LIST;
(*Parse expression and generate code. *)
VAR s, t, u: LIST;
    oper: Token;
BEGIN 
(*1*) IF (plus <= tok) AND (tok <= minus) THEN
         oper:=tok; GetToken; s:=Term(); 
         IF oper = minus THEN s:=Generate(oper,LIST1(s)) END; 
         ELSE s:=Term(); 
         END;
(*2*) WHILE (plus <= tok) AND (tok <= minus) DO
            oper:=tok; GetToken; u:=Term(); 
            t:=LIST2(s,u); s:=Generate(oper,t); 
            END;
      RETURN(s);
(*3*) END Expression;


PROCEDURE Condition(): LIST;
(*Parse condition and generate code. *)
VAR s, t, u: LIST;
    oper: Token;
BEGIN 
(*1*) t:=SIL;
      IF tok = not THEN GetToken;
         t:=Condition(); t:=Generate(not,LIST1(t)) 
   ELSIF tok = lparen THEN GetToken;
         u:=Condition(); 
         IF tok = rparen THEN GetToken
                         ELSE SyntaxErr(7) END;
         IF (and <= tok) AND (tok <= or) THEN
            oper:=tok; GetToken; 
            IF tok = lparen THEN GetToken
                            ELSE SyntaxErr(24) END;
            s:=Condition();
            IF tok = rparen THEN GetToken
                            ELSE SyntaxErr(7) END;
            t:=LIST2(u,s); t:=Generate(oper,t)
            ELSE SyntaxErr(25) END
    ELSE u:=Expression(); 
         IF (eql <= tok) AND (tok <= geq) THEN
            oper:=tok; GetToken; s:=Expression();
            t:=LIST2(u,s); t:=Generate(oper,t)
            ELSE SyntaxErr(20) END; 
         END;
      RETURN(t);
(*3*) END Condition;


PROCEDURE Term(): LIST;
(*Parse term and generate code. *)
VAR s, t, u: LIST;
    oper: Token;
BEGIN 
(*1*) s:=Power();
      WHILE (times <= tok) AND (tok <= mod) DO
            oper:=tok; GetToken; u:=Power(); 
            t:=LIST2(s,u); s:=Generate(oper,t); 
            END;
      RETURN(s);
(*3*) END Term;


PROCEDURE Power(): LIST;
(*Parse power and generate code. *)
VAR   t, u, s: LIST;
BEGIN 
(*1*) t:=SIL; s:=1; t:=Factor();
      IF tok = power THEN GetToken;
         IF tok = minus THEN s:=-s; GetToken; END;
         IF tok = number THEN u:=tokval; GetToken;
            IF s < 0 THEN u:=-u END; 
            t:=LIST2(t,u); t:=Generate(power,t);
            ELSE SyntaxErr(26) END;
         END;
      RETURN(t);
(*3*) END Power;


PROCEDURE Factor(): LIST;
(*Parse factor and generate code. *)
VAR   s, t, u: LIST;
BEGIN 
(*1*) t:=SIL; 
      SyntaxTest(lparen,6);
      IF tok = ident THEN t:=tokval; GetToken; (*stands for itself*)
         IF tok = lparen THEN GetToken;
            u:=ActParms(); 
            t:=COMP(t,u); (*generate function call*)
            END;
         ELSIF tok = number THEN
               t:=tokval; GetToken; (*numbers stand for themselfs*)
         ELSIF tok = string THEN
               t:=tokval; t:=Generate(string,t); GetToken;
               IF tok = colon THEN GetToken; s:=TypeExpression();
                  t:=LIST3(CONVVAL,s,t); 
                  (*t:=LIST2(t,s); t:=Generate(tinfo,t);*)
                  END; 
         ELSIF tok = lparen THEN 
               GetToken; t:=Expression(); (*already code*)
               IF tok = rparen THEN GetToken ELSE SyntaxErr(7) END;
         ELSE SyntaxErr(8) END;
      RETURN(t);
(*3*) END Factor;


PROCEDURE TypeExpression(): LIST;
(*Parse type expression and generate code. *)
VAR   s, t, u: LIST;
BEGIN 
(*1*) t:=SIL; u:=SIL; s:=SIL;
      IF tok = ident THEN t:=tokval; GetToken; (*stands for itself*)
         IF tok = lparen THEN GetToken;
            u:=ActParms(); 
            t:=COMP(t,u); (*generate type term*)
            END;
         ELSE SyntaxErr(4) END;
      IF tok = string THEN s:=tokval; GetToken;
         s:=Generate(string,s); 
         s:=LIST3(CONVDES,t,s);
         END;
      t:=LIST3(LISTX,t,s);
      RETURN(t);
(*3*) END TypeExpression;


PROCEDURE InitScanner;
(*Initialize scanner procedures. *)
BEGIN
(*1*) Declare(KW,"KeyWord");
(*2*) (*Enter key words. *)
      KeyWord(do,"DO");
      KeyWord(to,"TO");
      KeyWord(if,"IF");
      KeyWord(end,"END");
      KeyWord(not,"NOT");
      KeyWord(and,"AND");
      KeyWord(or,"OR"); 
      KeyWord(var,"VAR");
      KeyWord(then,"THEN");
      KeyWord(else,"ELSE");
      KeyWord(begin,"BEGIN");
      KeyWord(sig,"SIGNATURE");
      KeyWord(while,"WHILE");
      KeyWord(until,"UNTIL");
      KeyWord(repeat,"REPEAT");
      KeyWord(procedure,"PROCEDURE");
      KeyWord(spec,"SPECIFICATION");
      KeyWord(model,"MODEL");
      KeyWord(import,"IMPORT");
      KeyWord(impl,"IMPLEMENTATION");
      KeyWord(axiom,"AXIOMS");
      KeyWord(map,"MAP");
      KeyWord(sort,"SORT");
      KeyWord(rule,"RULE");
      KeyWord(when,"WHEN");
      KeyWord(expose,"EXPOSE");
(*2*) (*Enter key words in lower case. *)
      KeyWord(do,"do");
      KeyWord(to,"to");
      KeyWord(if,"if");
      KeyWord(end,"end");
      KeyWord(not,"not");
      KeyWord(and,"and");
      KeyWord(or,"or"); 
      KeyWord(var,"var");
      KeyWord(then,"then");
      KeyWord(else,"else");
      KeyWord(begin,"begin");
      KeyWord(sig,"signature");
      KeyWord(while,"while");
      KeyWord(until,"until");
      KeyWord(repeat,"repeat");
      KeyWord(procedure,"procedure");
      KeyWord(spec,"specification");
      KeyWord(model,"model");
      KeyWord(import,"import");
      KeyWord(impl,"implementation");
      KeyWord(axiom,"axioms");
      KeyWord(map,"map");
      KeyWord(sort,"sort");
      KeyWord(rule,"rule");
      KeyWord(when,"when");
      KeyWord(expose,"expose");
(*9*) END InitScanner;


PROCEDURE InitParser;
(*Initialize parser and scanner procedures. *)
VAR   X, s, v: LIST;
BEGIN
(*1*) InitScanner; 
(*    Declare(CONVPARS,"CONVPARS"); (* access LISP convert. *)
      Declare(CONVDESC,"CONVDESC"); (* access LISP convert. *)
      Declare(REP,"REP");           (* representation tag. *)
*)
(*2*) Declare(SUM,"SUM");
      Declare(DIF,"DIF");
      Declare(PROD,"PROD");
      Declare(Q,"Q");
      Declare(REMAIN,"REMAIN");
      Declare(EXP,"EXP");
      SwitchParse(FALSE); 
(*3*) blv:=SIL; LISTVAR(blv); 
      X:=ENV; 
      WHILE X <> SIL DO ADV2(X,s,v,X);
            IF NOT MEMQ(s,blv) THEN blv:=COMP(s,blv) END;
            END;
(*9*) END InitParser;


PROCEDURE SwitchParse(g: BOOLEAN);
(*Switch parsing between generic / non-generic parse. 
If g = TRUE then the parser generates code for generic names, 
if g = FALSE then the parser generates code for the builtin LISP 
arithmetic functions. *)
BEGIN 
(*1*) (*to non-generic parsing. *)
      IF NOT g THEN genpars:=FALSE;
         sum:=ADD; dif:=SUB; prod:=MUL; quot:=QUOT; 
         remain:=REM; exp:=POW; 
         RETURN END; 
(*2*) (*to generic parsing. *)
      IF g THEN genpars:=TRUE;
         sum:=SUM; dif:=DIF; prod:=PROD; quot:=Q; 
         remain:=REMAIN; exp:=EXP; 
         RETURN END; 
(*9*) END SwitchParse;


(* Execution part. *)
BEGIN
 
InitParser;

END MASPARSE.



(* -EOF- *)