Parsing Expressions in Java
by Cliff Berg

Figure 1:
     
Expression        : Term TermOp ;

TermOp            : Plus Term TermOp
                  | Hyphen Term TermOp
                  | ;

Term              : Factor FactorOp ;

FactorOp          : Asterisk Factor FactorOp
                  | Slash Factor FactorOp
                  | ;

Factor            : Primary PrimaryOp ;

PrimaryOp         : OpenParen EList CloseParen PrimaryOp
                  | ;

Primary           : Ident
                  | NumericLiteral
                  | OpenParen Expression CloseParen
                  | SignedExpression ;

IntExpression     : Expression ;

Selector          : Ident ;

SignedExpression  : Hyphen Primary
                  | Plus Primary ;

EList             : Expression MoreEList 
                  | ;

MoreEList         : Comma Expression MoreEList
                  | ;

NumericLiteral    : IntLiteral 
                  | FloatLiteral ;


Figure 2:

Primary         : Ident
                | Literal
                | OpenParen Expression CloseParen
                | SignedExpression ;


Figure 3:

TermOp          : Plus Term TermOp
                | Hyphen Term TermOp
                | ;    // null


Listing One
public interface Lexer
{
    public Token getNextToken() throws LexicalException;
    public String getTokenValue();
}


Listing Two
public interface Token
{
    public String getValue();
    public int getTokenKind();
}

Listing Three
public interface SymbolInstance
{
}
public abstract class Expression
implements SymbolInstance
{
    public abstract String toString();
    public void setType(Type t) { type = t; }
    public Type getType() { return type; }
    public Object evaluate(EvaluationContext evaluation_context) 
    { return null; }
    public void setSyntacticallyGrouped(boolean b) { sg = b; }
    public boolean syntacticallyGrouped() { return sg; }
    private boolean sg = false;
    private Type type;
}

Listing Four
Expression 
    IdentExpression
    LiteralExpression 
        NumericLiteralExpression 
            IntegerLiteralExpression
            FloatLiteralExpression
    FunctionCallExpression
    ArithmeticExpression 
        TermExpression
        FactorExpression
    SignedExpression

Listing Five
protected void push(Expression ex)
{
    stack.insertElementAt(ex, 0);
}
protected Expression pop()
{
    Expression e = (Expression)(stack.elementAt(0));
    stack.removeElementAt(0);
    return e;
}


Listing Six
public interface Type
{
    public boolean isInstanceOf(Type t);
}
public interface Symbol
{
    public String getName();
    public void setType(Type t);
    public Type getType();
}
public interface Region
{
    public Symbol lookup(String identifier);
    public Region getContainingRegion();
    public abstract Symbol createNewSymbol(String s);
}


Listing Seven
private static final int[][] first = 
{
    { k_NONE },
    { k_IntLiteral },
    { k_FloatLiteral },
    { k_Ident },
    { k_Asterisk },
    { k_Slash },
    { k_Plus },
    { k_Hyphen },
    { k_OpenParen },
    { k_CloseParen },
    { k_Comma },

    // k_Expression:
    { k_IntLiteral, k_FloatLiteral, k_Plus, k_Hyphen, 
        k_Ident, k_OpenParen },
    // k_Term:
    { k_FloatLiteral, k_IntLiteral, k_Hyphen, k_Plus, 
        k_OpenParen, k_Ident },
    // k_TermOp:
    { k_NONE, k_Hyphen, k_Plus },
    // k_Factor:
    { k_IntLiteral, k_FloatLiteral, k_Plus, k_Hyphen, 
        k_Ident, k_OpenParen },
    // k_FactorOp:
    { k_NONE, k_Slash, k_Asterisk },
    // k_Primary:
    { k_FloatLiteral, k_IntLiteral, k_Hyphen, k_Plus, 
        k_OpenParen, k_Ident },
    // k_PrimaryOp:
    { k_NONE, k_OpenParen },
    // k_EList:
    { k_FloatLiteral, k_IntLiteral, k_Hyphen, k_Plus, 
        k_OpenParen, k_Ident, k_NONE },
    // k_NumericLiteral:
    { k_FloatLiteral, k_IntLiteral },
    // k_SignedExpression:
    { k_Plus, k_Hyphen },
    // k_IntExpression:
    { k_FloatLiteral, k_IntLiteral, k_Hyphen, k_Plus, 
        k_OpenParen, k_Ident },
    // k_MoreEList:
    { k_NONE, k_Comma }
};


Listing Eight
protected static boolean tokenIsInFirstOf(int termkind, int symkind)
{
    int[] firstSet = first[symkind];
    for (int i = 0; i < firstSet.length; i++)
    {
        if (termkind == firstSet[i]) return true;
    }
    return false;
}

Listing Nine
protected void parse_Expression()
throws ParseException, LexicalException
{
    if (tokenIsInFirstOf(getTokenKind(), k_Term))
    {
        parse_Term();
        parse_TermOp();
        return;
    }
    throw createSyntacticException(k_Expression);
}

Listing Ten
protected void parse_TermOp()
throws ParseException, LexicalException
{
    if (tokenIsInFirstOf(getTokenKind(), k_Plus))
    {
        parse_Plus();
        parse_Term();
            
        TermExpression e = new TermExpression();
        Expression rhs = pop();
        Expression lhs = pop();
        e.setLHS(lhs);
        e.setRHS(rhs);
        e.setAdditive(true);
        e.setType(resolveType(lhs.getType(), PLUS, rhs.getType()));
        push(e);

        parse_TermOp();
        return;
    }
    if (tokenIsInFirstOf(getTokenKind(), k_Hyphen))
    {
        parse_Hyphen();
        // ...same as for k_Plus...
        e.setAdditive(false);
        // ...same as for k_Plus...
    }
    // Handle the null production case
    {
        if (getTokenKind() == k_NONE) wasReducing(k_TermOp);
        return;
    }
}

Listing Eleven
protected void parse_Ident()
throws ParseException, LexicalException
{
    if (getTokenKind() != k_Ident) throw createSyntacticException(k_Ident);
    IdentExpression e = new IdentExpression();

    Symbol s = null;
    try
    {
        s = resolve(getCurrentRegion(), getTokenValue(), false);
        e.setSymbol(s);
        e.setType(s.getType());
    }
    catch (UnresolvedSymbolException ex1)
    {
        // Symbol not found - that's ok at this level
    }
    catch (SymbolConflictException ex2)
    {
        throw new RuntimeException("Should not happen");
    }
    getNextToken();
    push(e);
    return;
}



6


