Partial solutions to the programming assignments
------------------------------------------------

Grammar with the 'let' construct and power (^) operator:

<expr>        -> 'let' ID '=' <expr>
               | <term> <term_tail>
<term>        -> <factor> <factor_tail>
<term_tail>   -> <add_op> <term> <term_tail>
               | empty
<factor>      -> '-' <factor>
               | <power>
<factor_tail> -> <mult_op> <factor> <factor_tail>
               | empty
<power>       -> '(' <expr> ')'
               | '(' <expr> ')' '^' <power>
               | ID
               | ID ^ <power>
               | NUM
               | NUM ^ <power>

Alternative grammar:

<expr>        -> 'let' ID '=' <expr>
               | <term> <term_tail>
<term>        -> <factor> <factor_tail>
<term_tail>   -> <add_op> <term> <term_tail>
               | empty
<factor>      -> '-' <factor>
               | <power>
<factor_tail> -> <mult_op> <factor> <factor_tail>
               | empty
<power>       -> <simple> '^' <power>
               | <simple>
<simple>      -> '(' <expr> ')'
               | ID
               | NUM

The <expr> productions and semantic rules implemented as a recursive descent
parser in Java:

  // expr - parse <expr> -> 'let' ID '=' <expr> | <term> <term_tail>
  private static int expr(Hashtable exprin, Hashtable exprout) throws IOException
  {
    if (token == tokens.TT_WORD && tokens.sval.equals("let"))
    {
      getToken();
      String id = tokens.sval;
      getToken(); // advance to '='
      if (token != (int)'=')
        System.out.println("'=' expected");
      getToken(); // advance to <expr>
      int val = expr(exprin, exprout);
      exprout.put(id, new Integer(val));
      return val;
    }
    else
    {
      Hashtable termout = new Hashtable();
      int subtotal = term(exprin, termout);
      return term_tail(subtotal, termout, exprout);
    }
  }

The <power> productions (of the first grammar above) and semantic rules
implemented as a recursive descent parser in Java:

  // power - parse <power> -> '(' <expr> ')' | '(' < expr> ')' '^' <power> | ID | ID '^' <power> | NUM | NUM '^' <power>
  private static int power(Hashtable powerin, Hashtable powerout) throws IOException
  {
    Hashtable power1 = powerin;
    int val = 0;
    if (token == (int)'(')
    {
      getToken();
      val = expr(powerin, power1);
      if (token == (int)')')
        getToken();
      else
        System.out.println("closing ')' expected");
    }
    else if (token == tokens.TT_WORD)
    {
      String id = tokens.sval;
      getToken();
      if (powerin.containsKey(id))
        val = ((Integer)powerin.get(id)).intValue();
      else
        System.out.println("identifier '" + id + "' unassigned");
    }
    else if (token == tokens.TT_NUMBER)
    {
      val = (int)tokens.nval;
      getToken();
    }
    else
      System.out.println("power expected");
    if (token == (int)'^')
    {
      getToken();
      return (int)Math.pow(val, power(power1, powerout));
    }
    else
    {
      powerout.putAll(power1);
      return val;
    }
  }
}

The main method should set up the Hashtable variables and invoke expr:

    // set up hashtables
    Hashtable exprin = new Hashtable();
    Hashtable exprout = new Hashtable();

    // parse expression and get calculated value:
    int value = expr(exprin, exprout);

Don't forget to copy the Hashtable contents when necessary with the putAll
method of Hashtable, as in term_tail for example:

  // term_tail - parse <term_tail> -> <add_op> <term> <term_tail> | empty
  private static int term_tail(int subtotal, Hashtable tailin, Hashtable tailout) throws IOException
  {
    if (token == (int)'+')
    {
      getToken();
      Hashtable termout = new Hashtable();
      int termvalue = term(tailin, termout);
      return term_tail(subtotal + termvalue, termout, tailout);
    }
    else if (token == (int)'-')
    {
      getToken();
      Hashtable termout = new Hashtable();
      int termvalue = term(tailin, termout);
      return term_tail(subtotal - termvalue, termout, tailout);
    }
    else
    {
      tailout.putAll(tailin);
      return subtotal;
    }
  }