Save the Result!

Instead of matching non-terminals as true/false questions, we can have them build nodes for the AST and return them to us. We can also store the values of identifiers and numbers into local variables for use in a new AST node. So, we might do something like this:

public Statement statement()
{
  switch (scanner.peek())
  {
    Token.repeat :
      match(Token.repeat);
      Statement s = statement();
      match(Token.until);
      Expression e = expression();
      return new RepeatStatement( s, e );
    Token.print :
      match(Token.print);
      Token t = match(Token.identifier);
      return new PrintStatement( new Identifier(t) );
    Token.identifier :
      Token t = match(Token.identifier);
      match(Token.assign);
      Expression e = expression();
      return new AssignmentStatement( new Identifier(t), e );
    default:
      return null;
  }
}

public Expression expression()
{
  switch (scanner.peek())
  {
    Token.identifier :
      Token t = match(Token.identifier);
      match(Token.equals);
      Expression e = expression();
      return new EqualsTest( new Identifier(t), e );
    Token.zeroPredicate :
      match(Token.zeroPredicate);
      Expression e = expression();
      return new ZeroTest( e );
    Token.number :
      Token t = match(Token.number);
      return new Number( t );
    default:
      return null;
  }
}

That's not too bad...