                                                               
// 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 #

ps1 -> dcl ps1 | 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
