                                                               
// This is the LL(1) grammar to generate a parser 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
 
"// parser generated from parse.txt LL(1) grammar 24 Sept 2002"
"#include compile.h"
"#include parse.h"
"extern int lv, CP;"
"extern int DS;"
"char name[NAMELEN];"

//pass [ a ] = 
//  "a = putSym(main,tyFUNCTION,0,0);"
//  "out2(icCall,a);"
//  "out(icStop);"
//  "lex();" 
//    ps1 %

pass = dcl pass | tkEOF %

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

dcl = tkIDENTIFIER "strcpy(name,tokstring);" dcl2 %
dcl2 [ n pv ] =
  tkLPAREN "pv = setFunc(name); n = CP-2;" tkRPAREN block 
    "patch(n,lv-pv); clean();" |
  var %

var [ n ] = 
  tkLBRACKET tkNUMBER "n = atoi(tokstring);" tkRBRACKET 
    "putSym(name,tyVECTOR,DS,n); DS+=n;" var2 | 
//    "putSym(name,tySCALAR,DS,1); DS+=1;" 
    var2 %
var2 =
  tkCOMMA tkIDENTIFIER "strcpy(name,tokstring);" var | tkSEMICOLON %

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

//  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 p0 prlist tkRPAREN tkSEMICOLON |
  tkSTAR tkIDENTIFIER "doRval(tokstring);" tkEQ expr tkSEMICOLON 
    "out(icSet);" |
  tkIDENTIFIER "strcpy(name,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 = tkCOMMA p1 prlist | nil %
p0 = p1 | nil %
p1 = tkSTRING "printstr();" | expr "out(icPrint);" %

stmt2 [ a ref ] =
  tkEQ "doLval(name);" expr tkSEMICOLON "out(icSet);" |
  tkLBRACKET "ref = getVec(name); out2(icLvalg,ref);"
    expr tkRBRACKET "out(icIndex);" tkEQ expr tkSEMICOLON "out(icSet);" |
  tkLPAREN "a = doFunc(name);" tkRPAREN tkSEMICOLON "out2(icCall,a);" %

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

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 "strcpy(name,tokstring);" mod2 |
  t1 %
t1 =
  tkIDENTIFIER "strcpy(name,tokstring);" mod |
  tkNUMBER "out2(icLit,atoi(tokstring));" |
  tkLPAREN expr tkRPAREN %

mod [ a ref ] =
  tkLBRACKET "ref = getVec(name); out2(icLvalg,ref);"
    expr tkRBRACKET "out(icIndex); out(icFetch);" |
  tkLPAREN "a=0; a=doFunc(name);" tkRPAREN "out2(icCall,a);" |
  "doRval(name);" nil %

mod2 [ ref ] =
  tkLBRACKET "ref = getVec(name); out2(icLvalg,ref);" 
    expr tkRBRACKET "out(icIndex);" |
  "doLval(name);" nil %

// end 