
// This is the LL(1) grammar to generate a parser for RZ language

$ /* parser generated from parse.txt LL(1) grammar 1 May 2001 */
$ #include "compile.h"
$ extern int lv;
$ extern FILE *FO;
$ extern int DS;

// 21 December 2001
// pass1 is not finished yet, checking redefine symbol not done, and main()
pass1 -> $lex(); ps1 #

ps1 -> dcl ps1 | tkEOF #
dcl -> tkIDENTIFIER dcl2 #
dcl2 [ a n ] ->
  $a=makesym();
  tkSEMICOLON $putsym(a,tySCALAR,DS,1);DS+=1; |
  tkLBRACKET tkNUMBER $n=atoi(tokstring); tkRBRACKET tkSEMICOLON
    $putsym(a,tyVECTOR,DS,n);DS+=n; |
  tkLPAREN $fprintf(FO,"%d%c",a,32); $n=formalParam(); tkRPAREN
    $putsym(a,tyFUNCTION,0,n); $copyBody();lex(); #

pass2 [ a ] ->
  $pass=2;
  $strcpy(tokstring,"main");a=getsym();
  $out2(icCall,a);out(icStop);lex(); ps2 #

ps2 [ a ] ->
  tkNUMBER $setsym();a=CP-2; locals tkNUMBER $line=atoi(tokstring);
  block $patch(a,lv-symtab[a].arg);clean(); ps2 | tkEOF #

locals -> tkIDENTIFIER $insertLocal(tokstring); locals | nil #
block -> tkLBRACE stmts tkRBRACE #
stmt -> block | stmt1 #
stmts -> stmt1 stmts | nil #

// fix IF by patchif 21 Dec 2001
stmt1 [ a b ] ->
  tkSEMICOLON |
  tkIF tkLPAREN expr tkRPAREN $out2(icJz,0);a=CP-2;
    stmt $b=CP; elsest $patchif(a,b,CP); |
  tkWHILE $a=CP; tkLPAREN expr tkRPAREN $out2(icJz,0);b=CP-2;
    stmt $out2(icJmp,a);patch(b,CP); |
  tkRETURN returnst |
  tkPRINT tkLPAREN p1 prlist tkRPAREN tkSEMICOLON |
  tkSTAR tkIDENTIFIER $a=getsym();doRval(a); tkEQ
    expr tkSEMICOLON $out(icSet); |
  tkIDENTIFIER stmt2 #

elsest [ a ] ->
  tkELSE $out2(icJmp,0);a=CP-2; stmt $patch(a,CP); | nil #
returnst ->
  tkSEMICOLON $out(icRet0); |
  expr $out(icRet1); tkSEMICOLON #
prlist -> tkCOMMA p1 prlist | nil #
p1 -> tkSTRING $printstr(); | expr $out(icPrint); #

stmt2 [ a c ] ->
  $a=getsym();
  tkEQ $doLval(a); expr tkSEMICOLON $out(icSet); |
  tkLBRACKET $chktype(a,tyVECTOR);out2(icLvalg,symtab[a].ref);
    expr tkRBRACKET $out(icIndex); tkEQ expr tkSEMICOLON $out(icSet); |
  tkLPAREN $chktype(a,tyFUNCTION); $c=param(); tkRPAREN tkSEMICOLON
    $chkarg(a,c);out2(icCall,a); #

expr -> term exprs #
exprs -> tkOROR term $out(icOr); exprs | nil #

// flatten f1 -> f2 f1s, f2 -> f3 f2s, f3 -> item f3s
// to  f1 -> item f3s f2s f1s

// term -> f1 terms #
// terms -> tkANDAND f1 $out(icAnd); terms | nil #

term -> item f3s f2s f1s terms #
terms -> tkANDAND item f3s f2s f1s $out(icAnd); terms | nil #

// f1 -> f2 f1s #
f1s -> tkLT item f3s f2s $out(icLt); f1s |
  tkLE item f3s f2s $out(icLe); f1s |
  tkEQEQ item f3s f2s $out(icEq); f1s |
  tkNE item f3s f2s $out(icNe); f1s |
  tkGE item f3s f2s $out(icGe); f1s |
  tkGT item f3s f2s $out(icGt); f1s |
  nil #

// f2 -> f3 f2s #
f2s -> tkPLUS item f3s $out(icAdd); f2s |
  tkMINUS item f3s $out(icSub); f2s |
  nil #

// f3 -> item f3s #
f3s -> tkSTAR item $out(icMul); f3s |
  tkSLASH item $out(icDiv); f3s |
  nil #

// fix unary minus 21 Dec 2001
item ->
  tkMINUS $out2(icLit,0); t1 $out(icSub); |
  tkNOT t1 $out(icNot); |
  tkSTAR t1 $out(icFetch); |
  tkAND tkIDENTIFIER mod2 |
  t1 #
t1 ->
  tkIDENTIFIER mod |
  tkNUMBER $out2(icLit,atoi(tokstring)); |
  tkLPAREN expr tkRPAREN #
mod [ a c ] ->
  $a=getsym();
  tkLBRACKET $chktype(a,tyVECTOR);out2(icLvalg,symtab[a].ref);
    expr tkRBRACKET $out(icIndex);out(icFetch); |
  tkLPAREN $chktype(a,tyFUNCTION); $c=param(); tkRPAREN
    $chkarg(a,c);out2(icCall,a); |
  $doRval(a); nil #
mod2 [ a ] ->
  $a=getsym();
  tkLBRACKET $chktype(a,tyVECTOR);out2(icLvalg,symtab[a].ref);
    expr tkRBRACKET $out(icIndex); |
  $doLval(a); nil #

END
