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

$ /* parser generated from parse.txt LL(1) grammar 1 May 2001 */
$ /* fix bug if in stmt1  unary minus in item and change symtab API  23 Dec 2001 */
$ #include "compile.h"
$ extern int lv, pvnum, CP;
// $ extern sym_entry symtab[];

ps2 [ a pv ] ->
  tkNUMBER $pv=setFunc(tokstring);a=CP-2; formal tkNUMBER $line=atoi(tokstring);
  block $patch(a,lv-pv);clean(); ps2 | tkEOF #

formal -> tkIDENTIFIER $insertLocal(tokstring); formal | nil #
block -> tkLBRACE stmts tkRBRACE #
stmt -> block | stmt1 #
stmts -> stmt1 stmts | nil #
stmt1 [ a b type ref arg ] ->
  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 p0 prlist tkRPAREN tkSEMICOLON |
  tkSTAR tkIDENTIFIER $a=getsym(tokstring,&type,&ref,&arg);doRval(type,ref); 
    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 #
p0 -> p1 | nil #
p1 -> tkSTRING $printstr(); | expr $out(icPrint); #

stmt2 [ a type ref arg ] ->
  $a=getsym(tokstring,&type,&ref,&arg);
  tkEQ $doLval(type,ref); expr tkSEMICOLON $out(icSet); |
  tkLBRACKET $chktype(type,tyVECTOR);out2(icLvalg,ref);
    expr tkRBRACKET $out(icIndex); tkEQ expr tkSEMICOLON $out(icSet); |
  tkLPAREN $chktype(type,tyFUNCTION); 
    $doparam(arg); tkRPAREN tkSEMICOLON $out2(icCall,a); #
// it is important to separate $chktype() and $doparam() to lex()

expr -> term exprs | nil #
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 #

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 type ref arg ] ->
  $a=getsym(tokstring,&type,&ref,&arg);
  tkLBRACKET $chktype(type,tyVECTOR);out2(icLvalg,ref);
    expr tkRBRACKET $out(icIndex);out(icFetch); |
  tkLPAREN $chktype(type,tyFUNCTION); 
    $doparam(arg); tkRPAREN $out2(icCall,a); |
  $doRval(type,ref); nil #
// it is important to separate here to lex()

mod2 [ a type ref arg ] ->
  $a=getsym(tokstring,&type,&ref,&arg);
  tkLBRACKET $chktype(type,tyVECTOR);out2(icLvalg,ref);
    expr tkRBRACKET $out(icIndex); |
  $doLval(type,ref); nil #

END
