package tiny;

import parser.*;
import lexer.*;
import node.*;
import analysis.*;
import java.util.*;

public class Evaluator extends DepthFirstAdapter
{
  /* (static) eval function */
  public static int eval(Node ast)
  {
    Evaluator e = new Evaluator();
    ast.apply(e);
    return e.getValue(ast);
  }
    
  /* Hashtable, holding intermediate values for AST nodes */
  private Hashtable values = new Hashtable();

  /* Utility methods to set/get values for AST nodes */
  private void setValue(Node node, int value)
  { values.put(node, new Integer(value));
  }

  private int getValue(Node node)
  { /* gets and removes the associated value.
       This reduces memory pressure, but you should 
       replace "remove" with "get" if you intend to
       lookup the same value more than once (e.g.: in
       an interpreter). */

    Integer value = (Integer) values.remove(node);
    return value.intValue();
  }

  /* We deal with each grammar alternative, one by one */

  /* AST root (hidden [start = exp;] production) */
  public void outStart(Start node)
  { setValue(node, getValue(node.getPExp())); }

  /* plus */
  public void outAPlusExp(APlusExp node)
  { setValue(node, getValue(node.getExp()) + getValue(node.getFactor())); }
  
  /* minus */
  public void outAMinusExp(AMinusExp node)
  { setValue(node, getValue(node.getExp()) - getValue(node.getFactor())); }

  /* factor */
  public void outAFactorExp(AFactorExp node)
  { setValue(node, getValue(node.getFactor())); }

  /* mult */
  public void outAMultFactor(AMultFactor node)
  { setValue(node, getValue(node.getFactor()) * getValue(node.getTerm())); }

  /* div */
  public void outADivdFactor(ADivdFactor node)
  { setValue(node, getValue(node.getFactor()) / getValue(node.getTerm())); }

  /* term */
  public void outATermFactor(ATermFactor node)
  { setValue(node, getValue(node.getTerm())); }

  /* parentheses */
  public void outAParenTerm(AParenTerm node)
  { setValue(node, getValue(node.getExp())); }

  /* identifier (!!!) */
  public void outAIdTerm(AIdTerm node)
  { throw new RuntimeException("I can't evaluate the value of an identifier!"); }
  
  /* number */
  public void outANumberTerm(ANumberTerm node)
  { setValue(node, Integer.parseInt(node.getNumber().getText())); }
}
