// FILE. . . . . /home/hak/ilt/doc/ilog/jacc/Calculator.grm
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Latitude407.Ilog.Biz
// STARTED ON. . Tue Dec 14 18:19:32 2004

// Last modified on Tue Dec 28 17:02:04 2004 by hak

/**
 * This is a grammar for a simple arithmetic calculator.
 */

%import java.util.HashMap;

%access public

%start Session

%root  Expression
%root  Definition

%token NUMBER IDENTIFIER
%left '+' '-'
%left '*' '/'
%right UMINUS

%{
  HashMap defs = new HashMap();
%}

%nodeprefix "Calculator"
%nodesuffix ""

%nodeclass public Definition implements Cloneable
        {
          private String message;

          public String getMessage()
            {
              return message;
            }

          public void setMessage(String msg)
            {
              message = msg;
            }
        }
%%

Session
        : Actions Exit
        ;

Actions
  	: /* empty */
        | Actions Action
        ;

/**
 * An action is either an expression, a definition, or an error,
 * followed by a semicolon.
 */
Action
  	: Expression
        {
          currentNode().show(); // show the current parse tree
          if (!Double.isNaN($1.nvalue())) System.out.println($1.nvalue());
          CalculatorTokenizer.prompt();
        }
          ';'
        | Definition
        {
          currentNode().show(); // show the current parse tree
          System.out.println($1.getMessage());
          CalculatorTokenizer.prompt();
        }
          ';'
	| error
	{
	  errorManager().reportErrors(true);
          CalculatorTokenizer.prompt();
	} ';'
        ;

/**
 * An $Expression$ is one of the following forms:
 */
Expression
        : /**
	   * An $IDENTIFIER$ is an $Expression$.
	   */
          IDENTIFIER
        {
          Double value = (Double)defs.get($1.svalue());
          if (value == null)
            System.out.println("*** Undefined identifier: "+$1.svalue());
          else
            $$.setNvalue(value.doubleValue());
        }
        | /**
	   * A $NUMBER$ is an $Expression$.
	   */
          NUMBER
        | /**
	   * An addition is an expression.
	   */
          Expression '+' Expression
        {
          $$.setNvalue($1.nvalue() + $3.nvalue());
        }
        | /**
	   * A subtraction is an expression.
	   */
          Expression '-' Expression
        {
          $$.setNvalue($1.nvalue() - $3.nvalue());
        }
        | /**
	   * A multiplication is an expression.
	   */
          Expression '*' Expression
        {
          $$.setNvalue($1.nvalue() * $3.nvalue());
        }
        | /**
	   * A division is an expression.
	   */
          Expression '/' Expression
        {
          $$.setNvalue($1.nvalue() / $3.nvalue());
        }
        | /**
	   * A negative expression is an expression.
	   */
          '-' Expression        %prec UMINUS
        {
          $$.setNvalue(- $2.nvalue());
        }
        | /**
	   * A parenthesized expression is an expression.
	   */
          '(' Expression ')'
        {
          $$.setNvalue($2.nvalue());
        }
        ;

/**
 * A definition stores the value of an expression as an identifier.
 */
Definition
        : IDENTIFIER '=' Expression
        {
          defs.put($1.svalue(),new Double($3.nvalue()));
          $$.setNvalue($3.nvalue());
          $$.setSvalue($1.svalue());
          $$.setMessage("*** Defined "+$$.svalue()+" ("+$$.nvalue()+")");
        }
        ;
/**
 * Action for exiting the calculator.
 */
Exit
  	: 'exit'
        {
	  System.out.println("*** Bye bye!...");
	  System.exit(0);
	} ';'
	;

