                                                               
// This is LL(1) grammar for RZ language    1 May 2001
// fix bug if in stmt, unary minus in item, change symtab  23 Dec 2001
// change to one pass  3 Jan 2002
// change syntax for variable declare name, name ... ;  24 Sept 2002
// lot of modifications to untangle parsing parameters
//   in function call        6 Oct 2010
  
"// parser generated from rz-grammar 17 Oct 2010"
"#include <compile.h>"
"#include <parse.h>"
"extern int lv, CP;"
"extern int DS;"
"int pv;"

pass = dcl pass | tkEOF %

// declaration is
//   - function definition    f(arg){ body }
//   - variable declaration   a, b, c[12] ... ;

dcl = tkIDENTIFIER "pusht(tokstring);" dcl2 %
dcl2 [ n ] =
  tkLPAREN "pv=0;" formal tkRPAREN "setFunc(popt(),pv); n=CP-2;" 
    block "patch(n,lv-pv); clean();" |
  tkLBRACKET tkNUMBER "n=atoi(tokstring);" tkRBRACKET 
    "putSym(popt(),tyVECTOR,DS,n); DS+=n;" dcl3 | 
  tkCOMMA "putSym(popt(),tySCALAR,DS,1); DS++;" |
  tkSEMICOLON "putSym(popt(),tySCALAR,DS,1); DS++;" %

dcl3 = tkCOMMA | tkSEMICOLON % 

formal = tkIDENTIFIER "doLocal(); pv++;" formals | nil %
formals = tkCOMMA formal | nil %

stmt = block | stmt1 %
stmts = stmt1 stmts | nil %
block = tkLBRACE stmts tkRBRACE %

//  statement is 
//    - ;
//    - if( expr ) stmt <else stmt>  optional
//    - while( expr ) stmt
//    - return <expr> ;
//    - print( ... ) ;
//    - *name = expr ;
//    - name = expr ;
//    - name[ expr ] = expr ; 
//    - name( ... ) ;    function call

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 prlist tkRPAREN tkSEMICOLON |
  tkSTAR tkIDENTIFIER "doRval(tokstring);" tkEQ expr tkSEMICOLON "out(icSet);" |
  tkIDENTIFIER "pusht(tokstring);" stmt2 %

elsest [ a ] =
  tkELSE "out2(icJmp,0);a=CP-2;" stmt "patch(a,CP);" | nil %
returnst =
  tkSEMICOLON "out(icRet0);" |
  expr tkSEMICOLON "out(icRet1);" %

prlist = pr1 prlists %
prlists = tkCOMMA prlist | nil %
pr1 = tkSTRING "printstr();" | expr "out(icPrint);" %

stmt2 =
  tkEQ "doLval(popt());" expr tkSEMICOLON "out(icSet);" |
  tkLBRACKET "out2(icLvalg,getVec(popt()));"
    expr tkRBRACKET "out(icIndex);" tkEQ expr tkSEMICOLON "out(icSet);" |
  tkLPAREN param tkRPAREN tkSEMICOLON "out2(icCall,getFunc(popt()));" %

param = expr params %
params = tkCOMMA param | nil %

//  an expression is
//   - term op term op . . . term
//   - precedence of op: (highest) unary * / + - compare && ||
//   - compare: lt le eq neq ge gt
//   - unary: - ! * &
//   - term: number, name, name[expr], name(...)
//   - ( expr )    parenthesis has highest precedence

expr = f4 exprs %
exprs = 
  tkOROR f4 "out(icOr);" exprs |
  tkANDAND f4 "out(icAnd);" exprs |
  nil %

f4 = f3 logic %
logic =  
  tkLT f3 "out(icLt);" logic |
  tkLE f3 "out(icLe);" logic |
  tkEQEQ f3 "out(icEq);" logic |
  tkNE f3 "out(icNe);" logic |
  tkGE f3 "out(icGe);" logic |
  tkGT f3 "out(icGt);" logic |
  nil %

f3 = f2 addsub %
addsub =
  tkPLUS f2 "out(icAdd);" addsub |
  tkMINUS f2 "out(icSub);" addsub |
  nil %

f2 = f1 muldiv %
muldiv = 
  tkSTAR f1 "out(icMul);" muldiv |
  tkSLASH f1 "out(icDiv);" muldiv |
  nil %

f1 =
  tkMINUS "out2(icLit,0);" term "out(icSub);" |
  tkNOT term "out(icNot);" |
  tkSTAR term "out(icFetch);" |
  tkAND tkIDENTIFIER "pusht(tokstring);" mod2 |  
  term %

term =
  tkIDENTIFIER "pusht(tokstring);" mod |
  tkNUMBER "out2(icLit,atoi(tokstring));" |
  tkLPAREN expr tkRPAREN %

mod =
  tkLBRACKET "out2(icLvalg,getVec(popt()));"
    expr tkRBRACKET "out(icIndex); out(icFetch);" |
  tkLPAREN param tkRPAREN "out2(icCall,getFunc(popt()));" |
  nil "doRval(popt());" %

mod2 =
  tkLBRACKET "out2(icLvalg,getVec(popt()));" 
    expr tkRBRACKET "out(icIndex);" |
  nil "doLval(popt());" %

// end 