/*

File:    SimpCompRecDescent.jpp
Author:  zerksis d. umrigar (zdu@acm.org)
Copyright (C) 1997 Zerksis D. Umrigar
Last Update Time-stamp: "97/06/27 20:42:09 umrigar"

This code is distributed under the terms of the GNU General Public License.
See the file COPYING with this distribution, or

                http://www.fsf.org/copyleft/gpl.html

THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM.

*/

package zdu.parsdemo;

/*
Straight-forward recursive-descent parser whose derivation from a
translation scheme is sketched below:

Parser for following translation scheme (terminals enclosed within single
quotes or all upper-cased; semantic actions within braces; If a symbol
S has a synthesized attribute s, then the symbol is shown as S(s).

program
  : stmts
  ;
stmts
  : assgnStmt
  | assgnStmt ';' stmts
  ;  
assgnStmt
  : ID ':='  expr
  ;
expr
  : expr '+' term
  | expr '-' term
  | term
  ;
term
  : term '*' factor
  | term '/' factor
  | term 'div' factor
  | term 'mod' factor
  | factor
  ;
factor
  : '(' expr ')'
  | ID
  | NUM
  ;
*/



/*
After removing left-recursion, to allow recursive-descent parsing:

program
  : stmts
  ;
stmts
  : assgnStmt stmtsRest
  ;
stmtsRest
  : ';' stmts
  | EMPTY
  ;
assgnStmt
  : ID ':=' expr
  ;
expr
  : term exprRest
  ;
exprRest
  : '+' term exprRest
  | '-' term exprRest
  | EMPTY
  ;
term
  : factor termRest
  ;
termRest
  : '*' factor termRest 
  | '/' factor termRest 
  | 'div' factor termRest 
  | 'mod' factor termRest 
  | EMPTY
  ;
factor
  : '(' expr ')'
  | ID
  | NUM
  ;
*/


#define CALL(nonTerm)                                           \
  do {                                                          \
    call((NonTerm) prgSyms.get(#nonTerm), ruleN, __LINE__);     \
    nonTerm();                                                  \
  } while (false)

#define MATCH(tok)                                              \
  do {                                                          \
    match((Terminal) prgSyms.get(#tok), ruleN, __LINE__);       \
  } while (false)

#define RET()                                                   \
  do {                                                          \
    ret(ruleN, __LINE__); return;                               \
  } while (false)

#define ACCEPT()                                                \
  do {                                                          \
    accept(ruleN, __LINE__); return;                            \
  } while (false)

#define RULE(n)         int ruleN= n



import zdu.parsdemo.NonTerm;
import zdu.parsdemo.ParseException;
import zdu.parsdemo.ParseResetException;
import zdu.parsdemo.RecParser;
import zdu.parsdemo.Scanner;
import zdu.parsdemo.SimpCompLL1Gram;
import zdu.parsdemo.Terminal;

import java.util.Hashtable;

class SimpCompRecDescent extends RecParser 
{
  
  SimpCompRecDescent(SimpCompLL1Gram grammar, Scanner scanner,
                     ParseDisplay parseDisplay) {
    super(grammar, scanner, parseDisplay);

    prgSyms.put("assgnStmt", grammar.assgnStmt);
    prgSyms.put("expr", grammar.expr);
    prgSyms.put("exprRest", grammar.exprRest);
    prgSyms.put("factor", grammar.factor);
    prgSyms.put("program", grammar.program);
    prgSyms.put("stmts", grammar.stmts);
    prgSyms.put("stmtsRest", grammar.stmtsRest);
    prgSyms.put("term", grammar.term);
    prgSyms.put("termRest", grammar.termRest);

    prgSyms.put("'+'", grammar.ADD);
    prgSyms.put("ASSGN", grammar.ASSGN);
    prgSyms.put("DIV", grammar.DIV);
    prgSyms.put("'/'", grammar.DIVIDE);
    prgSyms.put("ID", grammar.ID);
    prgSyms.put("'('", grammar.LPAREN);
    prgSyms.put("MOD", grammar.MOD);
    prgSyms.put("'*'", grammar.MULT);
    prgSyms.put("NUM", grammar.NUM);
    prgSyms.put("')'", grammar.RPAREN);
    prgSyms.put("';'", grammar.SEMI);
    prgSyms.put("'-'", grammar.SUB);


  }

  SimpCompRecDescent(SimpCompLL1Gram grammar, Scanner scanner) {
    this(grammar, scanner, null);
  }

  protected final void parse() throws ParseException, ParseResetException
  {
    RULE(0);
    CALL(program);
    ACCEPT();
  }

  private void program() throws ParseException, ParseResetException
  {
    RULE(1);
    CALL(stmts);
  }

  private void stmts() throws ParseException, ParseResetException
  {
    RULE(2);
    CALL(assgnStmt);
    CALL(stmtsRest);
    RET(); /* stmts() */
  }

  private void stmtsRest() throws ParseException, ParseResetException
  {
    if (tok.getTokNum() == ';') {
      RULE(3);
      MATCH(';');
      CALL(stmts);
      RET(); /* stmtsRest() */
    }
    else {
      RULE(4);
      RET(); /* stmtsRest() */
    }
  }

  private void assgnStmt() throws ParseException, ParseResetException
  {
    RULE(5);
    MATCH(ID);
    MATCH(ASSGN);
    CALL(expr);
    RET(); /* assgnStmt() */
  }

  private void expr() throws ParseException, ParseResetException
  {
    RULE(6);
    CALL(term);
    CALL(exprRest);
    RET(); /* expr() */
  }

  private void exprRest() throws ParseException, ParseResetException
  {
    if (tok.getTokNum() == '+') {
      RULE(7);
      MATCH('+');
      CALL(term);
      CALL(exprRest);
      RET(); /* exprRest() */
    }
    else if (tok.getTokNum() == '-') {
      RULE(8);
      MATCH('-');
      CALL(term);
      CALL(exprRest);
      RET(); /* exprRest() */
    }
    else {
      RULE(9); 
      RET(); /* exprRest() */
    }
  }

  private void term() throws ParseException, ParseResetException
  {
    RULE(10);
    CALL(factor);
    CALL(termRest);
    RET(); /* term() */
  }

  private void termRest() throws ParseException, ParseResetException
  {
    if (tok.getTokNum() == '*') {
      RULE(11);
      MATCH('*');
      CALL(factor);
      CALL(termRest);
      RET(); /* termRest() */
    }
    else if (tok.getTokNum() == '/') {
      RULE(12);
      MATCH('/');
      CALL(factor);
      CALL(termRest);
      RET(); /* termRest() */
    }
    else if (tok.getTokNum() == SimpCompScanner.DIV_TOK) {
      RULE(13);
      MATCH(DIV);
      CALL(factor);
      CALL(termRest);
      RET(); /* termRest() */
    }
    else if (tok.getTokNum() == SimpCompScanner.MOD_TOK) {
      RULE(14);
      MATCH(MOD);
      CALL(factor);
      CALL(termRest);
      RET(); /* termRest() */
    }
    else {
      RULE(15);
      RET(); /* termRest() */
    }
  }

  private void factor() throws ParseException, ParseResetException
  {
    if (tok.getTokNum() == '(') {
      RULE(16);
      MATCH('(');
      CALL(expr);
      MATCH(')');
      RET(); /* factor() */
    }
    else if (tok.getTokNum() == SimpCompScanner.ID_TOK) {
      RULE(17);
      MATCH(ID);
      RET(); /* factor() */
    }
    else {
      RULE(18);
      String v= new String(scanner.lexemeText());
      MATCH(NUM);
      RET(); /* factor() */
    }
  }

  private Hashtable prgSyms= new Hashtable();

}


