The bali2javacc Tool

The bali2javacc tool is a command-line application that converts a Bali grammar file into JavaCC parser source code. This document describes how bali2javacc can be invoked, but it doesn't describe the semantics of parser generation (some of that can be found in the HowTo guide). The reader should be familiar with the Bali language documentation and the HowTo guide.

Invoking bali2javacc

The bali2javacc tool accepts a single Bali grammar file as input and it produces a single JavaCC parser file. Suppose the Bali input grammar is in file grammar.b and that the output is to be placed into file grammar.jj. Then, the following command is appropriate:

bali2javacc grammar.b -output grammar.jj

That's it! If desired, an optional -package option can also be placed on the command line to specify a single-identifier package name to contain the generated parser. If the desired package name is parser, the following command can be used:

bali2javacc grammar.b -output grammar.jj -package parser

If no -package option is provided, the generated parser will be placed into the default (no-name) package.

Example (with Generated Output!)

We suppose that the Bali input grammar is as shown below:

grammar.b
TOKEN : {
    <COMPARISON : "==" | "!=">
    | <INTEGER : <DIGIT> (<DIGIT>)*>
}

Program : Statement (";" Statement)* ;

Statement : Assignment | Control ;

Assignment : IDENTIFIER "=" Expression :: AssignmentNode ;

Expression : Operand [Addition] :: ExpressionNode ;

Operand : IDENTIFIER :: IdentifierOperand
	| INTEGER :: IntegerOperand ;

Addition : "+" Expression :: AdditionNode ;

Control : If | While ;

If : "if" Test ThenClause [ElseClause] :: IfNode ;

Test : "(" Expression COMPARISON Expression ")" :: TestNode ;

ThenClause : "then" Assignment :: ThenNode ;

ElseClause : "else" Assignment :: ElseNode ;

While : "while" Test "do" Assignment :: WhileNode ;

If bali2javacc is invoked as follows:

bali2javacc grammar.b -output grammar.jj -package parser

then the generated JavaCC file will contain the following output:

grammar.jj
// Automatically generated code.  Edit at your own risk!
// Generated by bali2javacc v2002.09.04.

//-----------------------------------//
// Options block:
//-----------------------------------//

// No options blocks defined in Bali grammar.

//-----------------------------------//
// Parser code block:
//-----------------------------------//

PARSER_BEGIN(BaliParser)

package example ;

public class BaliParser {

    private static Program parseRoot = null ;

    public static Program getStartRoot () {
        return parseRoot ;
    }

    public static Program getStartRoot (BaliParser parser)
    throws ParseException {
        try {
            parseRoot = parser.Program () ;
            parser.requireEOF () ;
            return parseRoot ;
        } catch (TokenMgrError error) {
            ParseException e = new ParseException ("token error occurred") ;
            e.initCause (error) ;
            throw e ;
        }
    }

    // Wraps an optional node around an AstNode:
    //
    static AstOptNode opt (AstNode node) {
        return new AstOptNode () . setParms (node) ;
    }
    
    // Wraps an optional node around an AstToken:
    //
    static AstOptToken opt (AstToken token) {
        return new AstOptToken () . setParms (token) ;
    }
    
    // Forces an end-of-file check in the tokenStream:
    //
    public void requireEOF () throws ParseException {
        try {
            jj_consume_token (BaliParserConstants.EOF) ;
        } catch (TokenMgrError error) {
            ParseException e = new ParseException ("EOF error") ;
            e.initCause (error) ;
            throw e ;
        }
    }
    
    // Converts a JavaCC Token to a Bali AstToken:
    //
    static AstToken t2at (Token tok) {
    
        // Special case -- if token is optional:
        //
        if (tok == null)
            return (null) ;
    
        StringBuffer buffer = new StringBuffer () ;
        Token special = tok.specialToken;
        while (special != null) {
            buffer.insert (0, special.toString()) ;
            special = special.specialToken ;
        }
        String white = buffer.toString () ;
    
        return new AstToken().setParms (white, tok.image, tok.endLine) ;
    }
}

PARSER_END(BaliParser)

//-----------------------------------//
// Token manager declarations:
//-----------------------------------//

// No TOKEN_MGR_DECLS defined in Bali grammar.

//-----------------------------------//
// Standard token definitions:
//-----------------------------------//

SPECIAL_TOKEN : {" "|"\f"|"\n"|"\r"|"\t"}

// COMMENTS:

MORE : {
    "//" : IN_SINGLE_LINE_COMMENT
    | <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
    | "/*" : IN_MULTI_LINE_COMMENT
}

<IN_SINGLE_LINE_COMMENT>
SPECIAL_TOKEN : {
    <SINGLE_LINE_COMMENT: "\n" | "\n\r" | "\r" | "\r\n"> : DEFAULT
}

<IN_FORMAL_COMMENT>
SPECIAL_TOKEN : {
    <FORMAL_COMMENT: "*/" > : DEFAULT
}

<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN : {
    <MULTI_LINE_COMMENT: "*/" > : DEFAULT
}

<IN_SINGLE_LINE_COMMENT,IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
MORE : { < ~[] > }

TOKEN : {
    <#LETTER: ["a"-"z", "A"-"Z", "_", "$"]>
    | <#DIGIT: ["0"-"9"]>
}

//-----------------------------------//
// Bali tokens from grammar:
//-----------------------------------//

// No Bali tokens defined in Bali grammar.

//-----------------------------------//
// Regular-expression tokens from grammar:
//-----------------------------------//

TOKEN: {
    <COMPARISON : "==" | "!=">
    | <INTEGER : <DIGIT> (<DIGIT>)*>
}

//-----------------------------------//
// JAVACODE blocks from grammar:
//-----------------------------------//

// No JAVACODE blocks in Bali grammar.

//-----------------------------------//
// Productions from Bali grammar:
//-----------------------------------//

Program Program () : {
    Program list = new Program () ;
    Statement st0=null ;
    Token to0=null ;
} {
    st0=Statement()
    {list.add (new ProgramElem().setParms (st0)) ;}
    (
        to0=";"
        st0=Statement()
        {list.add (new ProgramElem().setParms (t2at(to0), st0)) ;}
    )*
    {return list ;}
}

Addition Addition () : {
    Expression ex0=null ;
    Token to0=null ;
} {
    to0="+"
    ex0=Expression()
    {return new AdditionNode().setParms (t2at(to0), ex0) ;}
}

Assignment Assignment () : {
    Expression ex0=null ;
    Token to1=null, to0=null ;
} {
    to0=<IDENTIFIER>
    to1="="
    ex0=Expression()
    {return new AssignmentNode().setParms (t2at(to0), t2at(to1), ex0) ;}
}

Control Control () : {
    If if0=null ;
    While wh0=null ;
} {
    if0=If()
    {return (Control) if0 ;}
    |
    wh0=While()
    {return (Control) wh0 ;}
}

ElseClause ElseClause () : {
    Assignment as0=null ;
    Token to0=null ;
} {
    to0="else"
    as0=Assignment()
    {return new ElseNode().setParms (t2at(to0), as0) ;}
}

Expression Expression () : {
    Addition ad0=null ;
    Operand op0=null ;
} {
    op0=Operand()
    [ ad0=Addition() ]
    {return new ExpressionNode().setParms (op0, opt(ad0)) ;}
}

If If () : {
    ElseClause el0=null ;
    Test te0=null ;
    ThenClause th0=null ;
    Token to0=null ;
} {
    to0="if"
    te0=Test()
    th0=ThenClause()
    [ el0=ElseClause() ]
    {return new IfNode().setParms (t2at(to0), te0, th0, opt(el0)) ;}
}

Operand Operand () : {
    Token to0=null ;
} {
    to0=<IDENTIFIER>
    {return new IdentifierOperand().setParms (t2at(to0)) ;}
    |
    to0=<INTEGER>
    {return new IntegerOperand().setParms (t2at(to0)) ;}
}

Statement Statement () : {
    Assignment as0=null ;
    Control co0=null ;
} {
    as0=Assignment()
    {return (Statement) as0 ;}
    |
    co0=Control()
    {return (Statement) co0 ;}
}

Test Test () : {
    Expression ex1=null, ex0=null ;
    Token to2=null, to1=null, to0=null ;
} {
    to0="("
    ex0=Expression()
    to1=<COMPARISON>
    ex1=Expression()
    to2=")"
    {return new TestNode().setParms
    (t2at(to0), ex0, t2at(to1), ex1, t2at(to2)) ;}
}

ThenClause ThenClause () : {
    Assignment as0=null ;
    Token to0=null ;
} {
    to0="then"
    as0=Assignment()
    {return new ThenNode().setParms (t2at(to0), as0) ;}
}

While While () : {
    Assignment as0=null ;
    Test te0=null ;
    Token to1=null, to0=null ;
} {
    to0="while"
    te0=Test()
    to1="do"
    as0=Assignment()
    {return new WhileNode().setParms (t2at(to0), te0, t2at(to1), as0) ;}
}

//-----------------------------------//
// Other standard tokens::
//-----------------------------------//

TOKEN : {
    <IDENTIFIER: <LETTER> (<LETTER> | <DIGIT>)*>
    | <OTHER: ~[]>
}

ATS Home Page

Copyright Software Systems Generator Research Group. All rights reserved.
Last modified: Thu May 1 13:53:06 CDT 2003

Jacob Sarvela