[e-cvs] cvs commit: e/src/jsrc/antlr/preprocessor Grammar.java GrammarFile.java Hierarchy.java Option.java Preprocessor.java PreprocessorLexer.java PreprocessorTokenTypes.java PreprocessorTokenTypes.txt Rule.java Tool.java preproc.g
markm@eros.cs.jhu.edu
markm@eros.cs.jhu.edu
Wed, 3 Oct 2001 17:04:22 -0400
markm 01/10/03 17:04:21
Added: src/jsrc/antlr ANTLRError.java ANTLRException.java
ANTLRGrammarParseBehavior.java ANTLRHashString.java
ANTLRLexer.java ANTLRParser.java
ANTLRStringBuffer.java ANTLRTokdefLexer.java
ANTLRTokdefParser.java
ANTLRTokdefParserTokenTypes.java
ANTLRTokdefParserTokenTypes.txt
ANTLRTokenTypes.java ANTLRTokenTypes.txt
ASTFactory.java ASTIterator.java ASTNULLType.java
ASTPair.java ASTVisitor.java ActionElement.java
ActionTransInfo.java Alternative.java
AlternativeBlock.java AlternativeElement.java
BaseAST.java BlockContext.java BlockEndElement.java
BlockWithImpliedExitPath.java ByteBuffer.java
CharBuffer.java CharFormatter.java
CharLiteralElement.java CharQueue.java
CharRangeElement.java CharScanner.java
CharStreamException.java CharStreamIOException.java
CodeGenerator.java CommonAST.java
CommonASTWithHiddenTokens.java
CommonHiddenStreamToken.java CommonToken.java
CppBlockFinishingInfo.java CppCharFormatter.java
CppCodeGenerator.java DefaultFileLineFormatter.java
DefaultToolErrorHandler.java
DefineGrammarSymbols.java
DiagnosticCodeGenerator.java DumpASTVisitor.java
ExceptionHandler.java ExceptionSpec.java
FileCopyException.java FileLineFormatter.java
Grammar.java GrammarAnalyzer.java GrammarAtom.java
GrammarElement.java GrammarSymbol.java
HTMLCodeGenerator.java ImportVocabTokenManager.java
InputBuffer.java JavaBlockFinishingInfo.java
JavaCharFormatter.java JavaCodeGenerator.java
LLkAnalyzer.java LLkGrammarAnalyzer.java
LLkParser.java LexerGrammar.java
LexerSharedInputState.java Lookahead.java
MakeGrammar.java MismatchedCharException.java
MismatchedTokenException.java NameSpace.java
NoViableAltException.java
NoViableAltForCharException.java
OneOrMoreBlock.java Parser.java ParserGrammar.java
ParserSharedInputState.java
RecognitionException.java RuleBlock.java
RuleEndElement.java RuleRefElement.java
RuleSymbol.java SatherBlockFinishingInfo.java
SatherCharFormatter.java SatherCodeGenerator.java
SemanticException.java SimpleTokenManager.java
StringLiteralElement.java StringLiteralSymbol.java
SynPredBlock.java Token.java TokenBuffer.java
TokenManager.java TokenQueue.java
TokenRangeElement.java TokenRefElement.java
TokenStream.java TokenStreamBasicFilter.java
TokenStreamException.java
TokenStreamHiddenTokenFilter.java
TokenStreamIOException.java
TokenStreamRecognitionException.java
TokenStreamRetryException.java
TokenStreamSelector.java TokenSymbol.java Tool.java
ToolErrorHandler.java TreeBlockContext.java
TreeElement.java TreeParser.java
TreeParserSharedInputState.java
TreeSpecifierNode.java TreeWalkerGrammar.java
WildcardElement.java ZeroOrMoreBlock.java antlr.g
tokdef.g
src/jsrc/antlr/actions/cpp ActionLexer.java
ActionLexerTokenTypes.java
ActionLexerTokenTypes.txt action.g
src/jsrc/antlr/actions/java ActionLexer.java
ActionLexerTokenTypes.java
ActionLexerTokenTypes.txt action.g
src/jsrc/antlr/actions/sather ActionLexer.java
ActionLexerTokenTypes.java
ActionLexerTokenTypes.txt action.g
src/jsrc/antlr/collections AST.java ASTEnumeration.java
Enumerator.java List.java Stack.java
src/jsrc/antlr/collections/impl ASTArray.java
ASTEnumerator.java BitSet.java IndexedVector.java
IntRange.java LLCell.java LLEnumeration.java
LList.java Vector.java VectorEnumeration.java
VectorEnumerator.java
src/jsrc/antlr/debug DebuggingCharScanner.java
DebuggingInputBuffer.java DebuggingParser.java
Event.java GuessingEvent.java
InputBufferAdapter.java InputBufferEvent.java
InputBufferEventSupport.java
InputBufferListener.java InputBufferReporter.java
LLkDebuggingParser.java ListenerBase.java
MessageAdapter.java MessageEvent.java
MessageListener.java NewLineEvent.java
NewLineListener.java ParserAdapter.java
ParserController.java ParserEventSupport.java
ParserListener.java ParserMatchAdapter.java
ParserMatchEvent.java ParserMatchListener.java
ParserReporter.java ParserTokenAdapter.java
ParserTokenEvent.java ParserTokenListener.java
SemanticPredicateAdapter.java
SemanticPredicateEvent.java
SemanticPredicateListener.java
SyntacticPredicateAdapter.java
SyntacticPredicateEvent.java
SyntacticPredicateListener.java TraceAdapter.java
TraceEvent.java TraceListener.java Tracer.java
src/jsrc/antlr/debug/misc ASTFrame.java JTreeASTModel.java
JTreeASTPanel.java
src/jsrc/antlr/preprocessor Grammar.java GrammarFile.java
Hierarchy.java Option.java Preprocessor.java
PreprocessorLexer.java PreprocessorTokenTypes.java
PreprocessorTokenTypes.txt Rule.java Tool.java
preproc.g
Log:
Antlr 2.7.1, our point of departure for building support for quasis
Revision Changes Path
1.1 e/src/jsrc/antlr/ANTLRError.java
Index: ANTLRError.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ANTLRError.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class ANTLRError extends Error {
/**
* ANTLRError constructor comment.
*/
public ANTLRError() {
super();
}
/**
* ANTLRError constructor comment.
* @param s java.lang.String
*/
public ANTLRError(String s) {
super(s);
}
}
1.1 e/src/jsrc/antlr/ANTLRException.java
Index: ANTLRException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ANTLRException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class ANTLRException extends Exception {
public ANTLRException() {
super();
}
public ANTLRException(String s) {
super(s);
}
}
1.1 e/src/jsrc/antlr/ANTLRGrammarParseBehavior.java
Index: ANTLRGrammarParseBehavior.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ANTLRGrammarParseBehavior.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
public interface ANTLRGrammarParseBehavior {
public void abortGrammar();
public void beginAlt(boolean doAST_);
public void beginChildList();
// Exception handling
public void beginExceptionGroup();
public void beginExceptionSpec(Token label);
public void beginSubRule(Token label, int line, boolean not);
// Trees
public void beginTree(int line) throws SemanticException ;
public void defineRuleName(Token r, String access, boolean ruleAST, String docComment) throws SemanticException;
public void defineToken(Token tokname, Token tokliteral);
public void endAlt();
public void endChildList();
public void endExceptionGroup();
public void endExceptionSpec();
public void endGrammar();
public void endOptions();
public void endRule(String r);
public void endSubRule();
public void endTree();
public void hasError();
public void noASTSubRule();
public void oneOrMoreSubRule();
public void optionalSubRule();
public void refAction(Token action);
public void refArgAction(Token action);
public void setUserExceptions(String thr);
public void refCharLiteral(Token lit, Token label, boolean inverted, int autoGenType, boolean lastInRule);
public void refCharRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule);
public void refElementOption(Token option, Token value);
public void refTokensSpecElementOption(Token tok, Token option, Token value);
public void refExceptionHandler(Token exTypeAndName, Token action);
public void refHeaderAction(Token name,Token act);
public void refInitAction(Token action);
public void refMemberAction(Token act);
public void refPreambleAction(Token act);
public void refReturnAction(Token returnAction);
public void refRule(Token idAssign, Token r, Token label, Token arg, int autoGenType);
public void refSemPred(Token pred);
public void refStringLiteral(Token lit, Token label, int autoGenType, boolean lastInRule);
public void refToken(Token assignId, Token t, Token label, Token args,
boolean inverted, int autoGenType, boolean lastInRule);
public void refTokenRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule);
// Tree specifiers
public void refTreeSpecifier(Token treeSpec);
public void refWildcard(Token t, Token label, int autoGenType);
public void setArgOfRuleRef(Token argaction);
public void setCharVocabulary(BitSet b);
// Options
public void setFileOption(Token key, Token value, String filename);
public void setGrammarOption(Token key, Token value);
public void setRuleOption(Token key, Token value);
public void setSubruleOption(Token key, Token value);
public void startLexer(String file, Token name, String superClass, String doc);
// Flow control for grammars
public void startParser(String file, Token name, String superClass, String doc);
public void startTreeWalker(String file, Token name, String superClass, String doc);
public void synPred();
public void zeroOrMoreSubRule();
}
1.1 e/src/jsrc/antlr/ANTLRHashString.java
Index: ANTLRHashString.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ANTLRHashString.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
// class implements a String-like object whose sole purpose is to be
// entered into a lexer HashTable. It uses a lexer object to get
// information about case sensitivity.
public class ANTLRHashString {
// only one of s or buf is non-null
private String s;
private char[] buf;
private int len;
private CharScanner lexer;
private static final int prime = 151;
public ANTLRHashString(char[] buf, int length, CharScanner lexer) {
this.lexer = lexer;
setBuffer(buf, length);
}
// Hash strings constructed this way are unusable until setBuffer or setString are called.
public ANTLRHashString(CharScanner lexer) {
this.lexer = lexer;
}
public ANTLRHashString(String s, CharScanner lexer) {
this.lexer = lexer;
setString(s);
}
private final char charAt(int index) {
return (s!=null) ? s.charAt(index) : buf[index];
}
// Return true if o is an ANTLRHashString equal to this.
public boolean equals(Object o) {
if (!(o instanceof ANTLRHashString) && !(o instanceof String)) {
return false;
}
ANTLRHashString s;
if ( o instanceof String ) {
s = new ANTLRHashString((String)o,lexer);
}
else {
s = (ANTLRHashString)o;
}
int l = length();
if (s.length() != l) {
return false;
}
if (lexer.getCaseSensitiveLiterals()) {
for (int i = 0; i < l; i++) {
if (charAt(i) != s.charAt(i)) {
return false;
}
}
} else {
for (int i = 0; i < l; i++) {
if (lexer.toLower(charAt(i)) != lexer.toLower(s.charAt(i))) {
return false;
}
}
}
return true;
}
public int hashCode() {
int hashval = 0;
int l = length();
if (lexer.getCaseSensitiveLiterals()) {
for (int i = 0; i < l; i++) {
hashval = hashval * prime + charAt(i);
}
} else {
for (int i = 0; i < l; i++) {
hashval = hashval * prime + lexer.toLower(charAt(i));
}
}
return hashval;
}
private final int length() {
return (s!=null) ? s.length() : len;
}
public void setBuffer(char[] buf, int length) {
this.buf = buf;
this.len = length;
s = null;
}
public void setString(String s) {
this.s = s;
buf = null;
}
}
1.1 e/src/jsrc/antlr/ANTLRLexer.java
Index: ANTLRLexer.java
===================================================================
// $ANTLR 2.7.1: "antlr.g" -> "ANTLRLexer.java"$
package antlr;
import java.io.InputStream;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.TokenStreamRecognitionException;
import antlr.CharStreamException;
import antlr.CharStreamIOException;
import antlr.ANTLRException;
import java.io.Reader;
import java.util.Hashtable;
import antlr.CharScanner;
import antlr.InputBuffer;
import antlr.ByteBuffer;
import antlr.CharBuffer;
import antlr.Token;
import antlr.CommonToken;
import antlr.RecognitionException;
import antlr.NoViableAltForCharException;
import antlr.MismatchedCharException;
import antlr.TokenStream;
import antlr.ANTLRHashString;
import antlr.LexerSharedInputState;
import antlr.collections.impl.BitSet;
import antlr.SemanticException;
public class ANTLRLexer extends antlr.CharScanner implements ANTLRTokenTypes, TokenStream
{
/**Convert 'c' to an integer char value. */
public static int escapeCharValue(String cs) {
//System.out.println("escapeCharValue("+cs+")");
if ( cs.charAt(1)!='\\' ) return 0;
switch ( cs.charAt(2) ) {
case 'b' : return '\b';
case 'r' : return '\r';
case 't' : return '\t';
case 'n' : return '\n';
case 'f' : return '\f';
case '"' : return '\"';
case '\'' :return '\'';
case '\\' :return '\\';
case 'u' :
// Unicode char
if (cs.length() != 8) {
return 0;
}
else {
return
Character.digit(cs.charAt(3), 16) * 16 * 16 * 16 +
Character.digit(cs.charAt(4), 16) * 16 * 16 +
Character.digit(cs.charAt(5), 16) * 16 +
Character.digit(cs.charAt(6), 16);
}
case '0' :
case '1' :
case '2' :
case '3' :
if ( cs.length()>5 && Character.isDigit(cs.charAt(4)) ) {
return (cs.charAt(2)-'0')*8*8 + (cs.charAt(3)-'0')*8 + (cs.charAt(4)-'0');
}
if ( cs.length()>4 && Character.isDigit(cs.charAt(3)) ) {
return (cs.charAt(2)-'0')*8 + (cs.charAt(3)-'0');
}
return cs.charAt(2)-'0';
case '4' :
case '5' :
case '6' :
case '7' :
if ( cs.length()>4 && Character.isDigit(cs.charAt(3)) ) {
return (cs.charAt(2)-'0')*8 + (cs.charAt(3)-'0');
}
return cs.charAt(2)-'0';
default :
return 0;
}
}
public static int tokenTypeForCharLiteral(String lit) {
if ( lit.length()>3 ) { // does char contain escape?
return escapeCharValue(lit);
}
else {
return lit.charAt(1);
}
}
public ANTLRLexer(InputStream in) {
this(new ByteBuffer(in));
}
public ANTLRLexer(Reader in) {
this(new CharBuffer(in));
}
public ANTLRLexer(InputBuffer ib) {
this(new LexerSharedInputState(ib));
}
public ANTLRLexer(LexerSharedInputState state) {
super(state);
literals = new Hashtable();
literals.put(new ANTLRHashString("Parser", this), new Integer(30));
literals.put(new ANTLRHashString("catch", this), new Integer(41));
literals.put(new ANTLRHashString("Lexer", this), new Integer(12));
literals.put(new ANTLRHashString("exception", this), new Integer(40));
literals.put(new ANTLRHashString("class", this), new Integer(10));
literals.put(new ANTLRHashString("lexclass", this), new Integer(9));
literals.put(new ANTLRHashString("public", this), new Integer(32));
literals.put(new ANTLRHashString("header", this), new Integer(5));
literals.put(new ANTLRHashString("options", this), new Integer(51));
literals.put(new ANTLRHashString("charVocabulary", this), new Integer(18));
literals.put(new ANTLRHashString("tokens", this), new Integer(4));
literals.put(new ANTLRHashString("returns", this), new Integer(36));
literals.put(new ANTLRHashString("TreeParser", this), new Integer(13));
literals.put(new ANTLRHashString("private", this), new Integer(33));
literals.put(new ANTLRHashString("protected", this), new Integer(31));
literals.put(new ANTLRHashString("throws", this), new Integer(38));
literals.put(new ANTLRHashString("extends", this), new Integer(11));
caseSensitiveLiterals = true;
setCaseSensitive(true);
}
public Token nextToken() throws TokenStreamException {
Token theRetToken=null;
tryAgain:
for (;;) {
Token _token = null;
int _ttype = Token.INVALID_TYPE;
resetText();
try { // for char stream error handling
try { // for lexical error handling
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(true);
theRetToken=_returnToken;
break;
}
case '/':
{
mCOMMENT(true);
theRetToken=_returnToken;
break;
}
case '<':
{
mOPEN_ELEMENT_OPTION(true);
theRetToken=_returnToken;
break;
}
case '>':
{
mCLOSE_ELEMENT_OPTION(true);
theRetToken=_returnToken;
break;
}
case ',':
{
mCOMMA(true);
theRetToken=_returnToken;
break;
}
case '?':
{
mQUESTION(true);
theRetToken=_returnToken;
break;
}
case '#':
{
mTREE_BEGIN(true);
theRetToken=_returnToken;
break;
}
case '(':
{
mLPAREN(true);
theRetToken=_returnToken;
break;
}
case ')':
{
mRPAREN(true);
theRetToken=_returnToken;
break;
}
case ':':
{
mCOLON(true);
theRetToken=_returnToken;
break;
}
case '*':
{
mSTAR(true);
theRetToken=_returnToken;
break;
}
case '+':
{
mPLUS(true);
theRetToken=_returnToken;
break;
}
case ';':
{
mSEMI(true);
theRetToken=_returnToken;
break;
}
case '^':
{
mCARET(true);
theRetToken=_returnToken;
break;
}
case '!':
{
mBANG(true);
theRetToken=_returnToken;
break;
}
case '|':
{
mOR(true);
theRetToken=_returnToken;
break;
}
case '~':
{
mNOT_OP(true);
theRetToken=_returnToken;
break;
}
case '}':
{
mRCURLY(true);
theRetToken=_returnToken;
break;
}
case '\'':
{
mCHAR_LITERAL(true);
theRetToken=_returnToken;
break;
}
case '"':
{
mSTRING_LITERAL(true);
theRetToken=_returnToken;
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
mINT(true);
theRetToken=_returnToken;
break;
}
case '[':
{
mARG_ACTION(true);
theRetToken=_returnToken;
break;
}
case '{':
{
mACTION(true);
theRetToken=_returnToken;
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
mTOKEN_REF(true);
theRetToken=_returnToken;
break;
}
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
mRULE_REF(true);
theRetToken=_returnToken;
break;
}
default:
if ((LA(1)=='=') && (LA(2)=='>')) {
mIMPLIES(true);
theRetToken=_returnToken;
}
else if ((LA(1)=='.') && (LA(2)=='.')) {
mRANGE(true);
theRetToken=_returnToken;
}
else if ((LA(1)=='=') && (true)) {
mASSIGN(true);
theRetToken=_returnToken;
}
else if ((LA(1)=='.') && (true)) {
mWILDCARD(true);
theRetToken=_returnToken;
}
else {
if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}
else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
}
if ( _returnToken==null ) continue tryAgain; // found SKIP token
_ttype = _returnToken.getType();
_returnToken.setType(_ttype);
return _returnToken;
}
catch (RecognitionException e) {
throw new TokenStreamRecognitionException(e);
}
}
catch (CharStreamException cse) {
if ( cse instanceof CharStreamIOException ) {
throw new TokenStreamIOException(((CharStreamIOException)cse).io);
}
else {
throw new TokenStreamException(cse.getMessage());
}
}
}
}
public final void mWS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WS;
int _saveIndex;
{
switch ( LA(1)) {
case ' ':
{
match(' ');
break;
}
case '\t':
{
match('\t');
break;
}
case '\n':
{
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
break;
}
default:
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
if ( inputState.guessing==0 ) {
newline();
}
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
if ( inputState.guessing==0 ) {
_ttype = Token.SKIP;
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mCOMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = COMMENT;
int _saveIndex;
Token t=null;
{
if ((LA(1)=='/') && (LA(2)=='/')) {
mSL_COMMENT(false);
}
else if ((LA(1)=='/') && (LA(2)=='*')) {
mML_COMMENT(true);
t=_returnToken;
if ( inputState.guessing==0 ) {
_ttype = t.getType();
}
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( inputState.guessing==0 ) {
if ( _ttype != DOC_COMMENT ) _ttype = Token.SKIP;
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mSL_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = SL_COMMENT;
int _saveIndex;
match("//");
{
_loop153:
do {
if ((_tokenSet_0.member(LA(1)))) {
{
match(_tokenSet_0);
}
}
else {
break _loop153;
}
} while (true);
}
{
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
}
else if ((LA(1)=='\n')) {
match('\n');
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( inputState.guessing==0 ) {
newline();
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mML_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ML_COMMENT;
int _saveIndex;
match("/*");
{
if (((LA(1)=='*') && ((LA(2) >= '\u0003' && LA(2) <= '~')))&&( LA(2)!='/' )) {
match('*');
if ( inputState.guessing==0 ) {
_ttype = DOC_COMMENT;
}
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
{
_loop159:
do {
// nongreedy exit test
if ((LA(1)=='*') && (LA(2)=='/')) break _loop159;
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
}
else if ((LA(1)=='\r') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
match('\r');
if ( inputState.guessing==0 ) {
newline();
}
}
else if ((_tokenSet_0.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
{
match(_tokenSet_0);
}
}
else if ((LA(1)=='\n')) {
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
}
else {
break _loop159;
}
} while (true);
}
match("*/");
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mOPEN_ELEMENT_OPTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = OPEN_ELEMENT_OPTION;
int _saveIndex;
match('<');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mCLOSE_ELEMENT_OPTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = CLOSE_ELEMENT_OPTION;
int _saveIndex;
match('>');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mCOMMA(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = COMMA;
int _saveIndex;
match(',');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mQUESTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = QUESTION;
int _saveIndex;
match('?');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mTREE_BEGIN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TREE_BEGIN;
int _saveIndex;
match("#(");
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mLPAREN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = LPAREN;
int _saveIndex;
match('(');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mRPAREN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = RPAREN;
int _saveIndex;
match(')');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mCOLON(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = COLON;
int _saveIndex;
match(':');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mSTAR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STAR;
int _saveIndex;
match('*');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mPLUS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = PLUS;
int _saveIndex;
match('+');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ASSIGN;
int _saveIndex;
match('=');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mIMPLIES(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = IMPLIES;
int _saveIndex;
match("=>");
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mSEMI(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = SEMI;
int _saveIndex;
match(';');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mCARET(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = CARET;
int _saveIndex;
match('^');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mBANG(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = BANG;
int _saveIndex;
match('!');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = OR;
int _saveIndex;
match('|');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mWILDCARD(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WILDCARD;
int _saveIndex;
match('.');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mRANGE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = RANGE;
int _saveIndex;
match("..");
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mNOT_OP(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = NOT_OP;
int _saveIndex;
match('~');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mRCURLY(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = RCURLY;
int _saveIndex;
match('}');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mCHAR_LITERAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = CHAR_LITERAL;
int _saveIndex;
match('\'');
{
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '"':
case '#': case '$': case '%': case '&':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('\'');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match('\'');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mESC(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ESC;
int _saveIndex;
match('\\');
{
switch ( LA(1)) {
case 'n':
{
match('n');
break;
}
case 'r':
{
match('r');
break;
}
case 't':
{
match('t');
break;
}
case 'b':
{
match('b');
break;
}
case 'f':
{
match('f');
break;
}
case 'w':
{
match('w');
break;
}
case 'a':
{
match('a');
break;
}
case '"':
{
match('"');
break;
}
case '\'':
{
match('\'');
break;
}
case '\\':
{
match('\\');
break;
}
case '0': case '1': case '2': case '3':
{
{
matchRange('0','3');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
{
matchRange('0','9');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
matchRange('0','9');
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
break;
}
case '4': case '5': case '6': case '7':
{
{
matchRange('4','7');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
{
matchRange('0','9');
}
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
break;
}
case 'u':
{
match('u');
mXDIGIT(false);
mXDIGIT(false);
mXDIGIT(false);
mXDIGIT(false);
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mSTRING_LITERAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STRING_LITERAL;
int _saveIndex;
match('"');
{
_loop184:
do {
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '#':
case '$': case '%': case '&': case '\'':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('"');
break;
}
default:
{
break _loop184;
}
}
} while (true);
}
match('"');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mXDIGIT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = XDIGIT;
int _saveIndex;
switch ( LA(1)) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f':
{
matchRange('a','f');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F':
{
matchRange('A','F');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mDIGIT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = DIGIT;
int _saveIndex;
matchRange('0','9');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mVOCAB(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = VOCAB;
int _saveIndex;
matchRange('\3','\176');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mINT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = INT;
int _saveIndex;
{
int _cnt199=0;
_loop199:
do {
if (((LA(1) >= '0' && LA(1) <= '9'))) {
matchRange('0','9');
}
else {
if ( _cnt199>=1 ) { break _loop199; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt199++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mARG_ACTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ARG_ACTION;
int _saveIndex;
mNESTED_ARG_ACTION(false);
if ( inputState.guessing==0 ) {
setText(Tool.stripFrontBack(getText(), "[", "]"));
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mNESTED_ARG_ACTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = NESTED_ARG_ACTION;
int _saveIndex;
match('[');
{
_loop203:
do {
switch ( LA(1)) {
case '[':
{
mNESTED_ARG_ACTION(false);
break;
}
case '\n':
{
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
break;
}
case '\'':
{
mCHAR_LITERAL(false);
break;
}
case '"':
{
mSTRING_LITERAL(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\u000b':
case '\u000c': case '\u000e': case '\u000f': case '\u0010':
case '\u0011': case '\u0012': case '\u0013': case '\u0014':
case '\u0015': case '\u0016': case '\u0017': case '\u0018':
case '\u0019': case '\u001a': case '\u001b': case '\u001c':
case '\u001d': case '\u001e': case '\u001f': case ' ':
case '!': case '#': case '$': case '%':
case '&': case '(': case ')': case '*':
case '+': case ',': case '-': case '.':
case '/': case '0': case '1': case '2':
case '3': case '4': case '5': case '6':
case '7': case '8': case '9': case ':':
case ';': case '<': case '=': case '>':
case '?': case '@': case 'A': case 'B':
case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V':
case 'W': case 'X': case 'Y': case 'Z':
case '\\': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot(']');
break;
}
default:
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
}
else if ((LA(1)=='\r') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
match('\r');
if ( inputState.guessing==0 ) {
newline();
}
}
else {
break _loop203;
}
}
} while (true);
}
match(']');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mACTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ACTION;
int _saveIndex;
int actionLine=getLine();
mNESTED_ACTION(false);
{
if ((LA(1)=='?')) {
match('?');
if ( inputState.guessing==0 ) {
_ttype = SEMPRED;
}
}
else {
}
}
if ( inputState.guessing==0 ) {
if ( _ttype==ACTION ) {
setText(Tool.stripFrontBack(getText(), "{", "}"));
}
else {
setText(Tool.stripFrontBack(getText(), "{", "}?"));
}
CommonToken t = new CommonToken(_ttype,new String(text.getBuffer(),_begin,text.length()-_begin));
t.setLine(actionLine); // set action line to start
_token = t;
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mNESTED_ACTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = NESTED_ACTION;
int _saveIndex;
match('{');
{
_loop209:
do {
// nongreedy exit test
if ((LA(1)=='}') && (true)) break _loop209;
if ((LA(1)=='\n'||LA(1)=='\r') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
{
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
}
else if ((LA(1)=='\r') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
match('\r');
if ( inputState.guessing==0 ) {
newline();
}
}
else if ((LA(1)=='\n')) {
match('\n');
if ( inputState.guessing==0 ) {
newline();
}
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else if ((LA(1)=='{') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mNESTED_ACTION(false);
}
else if ((LA(1)=='\'') && (_tokenSet_1.member(LA(2)))) {
mCHAR_LITERAL(false);
}
else if ((LA(1)=='/') && (LA(2)=='*'||LA(2)=='/')) {
mCOMMENT(false);
}
else if ((LA(1)=='"') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mSTRING_LITERAL(false);
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
matchNot(EOF_CHAR);
}
else {
break _loop209;
}
} while (true);
}
match('}');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mTOKEN_REF(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TOKEN_REF;
int _saveIndex;
matchRange('A','Z');
{
_loop212:
do {
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '_':
{
match('_');
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
default:
{
break _loop212;
}
}
} while (true);
}
_ttype = testLiteralsTable(_ttype);
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mRULE_REF(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = RULE_REF;
int _saveIndex;
int t=0;
t=mINTERNAL_RULE_REF(false);
if ( inputState.guessing==0 ) {
_ttype=t;
}
{
if (true&&(t==LITERAL_options)) {
mWS_LOOP(false);
{
if ((LA(1)=='{')) {
match('{');
if ( inputState.guessing==0 ) {
_ttype = OPTIONS;
}
}
else {
}
}
}
else if (true&&(t==LITERAL_tokens)) {
mWS_LOOP(false);
{
if ((LA(1)=='{')) {
match('{');
if ( inputState.guessing==0 ) {
_ttype = TOKENS;
}
}
else {
}
}
}
else {
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final int mINTERNAL_RULE_REF(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int t;
int _ttype; Token _token=null; int _begin=text.length();
_ttype = INTERNAL_RULE_REF;
int _saveIndex;
t = RULE_REF;
matchRange('a','z');
{
_loop222:
do {
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '_':
{
match('_');
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
default:
{
break _loop222;
}
}
} while (true);
}
if ( inputState.guessing==0 ) {
t = testLiteralsTable(t);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
return t;
}
protected final void mWS_LOOP(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WS_LOOP;
int _saveIndex;
{
_loop219:
do {
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(false);
break;
}
case '/':
{
mCOMMENT(false);
break;
}
default:
{
break _loop219;
}
}
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mWS_OPT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WS_OPT;
int _saveIndex;
{
if ((_tokenSet_2.member(LA(1)))) {
mWS(false);
}
else {
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mNOT_USEFUL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = NOT_USEFUL;
int _saveIndex;
boolean synPredMatched227 = false;
if (((LA(1)=='a') && (true))) {
int _m227 = mark();
synPredMatched227 = true;
inputState.guessing++;
try {
{
match('a');
}
}
catch (RecognitionException pe) {
synPredMatched227 = false;
}
rewind(_m227);
inputState.guessing--;
}
if ( synPredMatched227 ) {
match('a');
}
else if ((LA(1)=='a') && (true)) {
match('a');
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
private static final long _tokenSet_0_data_[] = { -9224L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_0 = new BitSet(_tokenSet_0_data_);
private static final long _tokenSet_1_data_[] = { -549755813896L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_1 = new BitSet(_tokenSet_1_data_);
private static final long _tokenSet_2_data_[] = { 4294977024L, 0L, 0L };
public static final BitSet _tokenSet_2 = new BitSet(_tokenSet_2_data_);
}
1.1 e/src/jsrc/antlr/ANTLRParser.java
Index: ANTLRParser.java
===================================================================
// $ANTLR 2.7.1: "antlr.g" -> "ANTLRParser.java"$
package antlr;
import antlr.TokenBuffer;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.ANTLRException;
import antlr.LLkParser;
import antlr.Token;
import antlr.TokenStream;
import antlr.RecognitionException;
import antlr.NoViableAltException;
import antlr.MismatchedTokenException;
import antlr.SemanticException;
import antlr.ParserSharedInputState;
import antlr.collections.impl.BitSet;
import antlr.collections.AST;
import antlr.ASTPair;
import antlr.collections.impl.ASTArray;
import java.util.Enumeration;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class ANTLRParser extends antlr.LLkParser
implements ANTLRTokenTypes
{
private static final boolean DEBUG_PARSER = false;
ANTLRGrammarParseBehavior behavior;
Tool tool;
protected int blockNesting= -1;
public ANTLRParser(
TokenBuffer tokenBuf,
ANTLRGrammarParseBehavior behavior_,
Tool tool_
) {
super(tokenBuf, 1);
tokenNames = _tokenNames;
behavior = behavior_;
tool = tool_;
}
private boolean lastInRule() throws TokenStreamException {
if ( blockNesting==0 && (LA(1)==SEMI || LA(1)==LITERAL_exception || LA(1)==OR) ) {
return true;
}
return false;
}
private void checkForMissingEndRule(Token label) {
if ( label.getColumn()==1 ) {
Tool.warning("did you forget to terminate previous rule?", getFilename(), label.getLine());
}
}
protected ANTLRParser(TokenBuffer tokenBuf, int k) {
super(tokenBuf,k);
tokenNames = _tokenNames;
}
public ANTLRParser(TokenBuffer tokenBuf) {
this(tokenBuf,2);
}
protected ANTLRParser(TokenStream lexer, int k) {
super(lexer,k);
tokenNames = _tokenNames;
}
public ANTLRParser(TokenStream lexer) {
this(lexer,2);
}
public ANTLRParser(ParserSharedInputState state) {
super(state,2);
tokenNames = _tokenNames;
}
public final void grammar() throws RecognitionException, TokenStreamException {
Token n = null;
Token h = null;
try { // for error handling
{
_loop4:
do {
if ((LA(1)==LITERAL_header)) {
match(LITERAL_header);
{
switch ( LA(1)) {
case STRING_LITERAL:
{
n = LT(1);
match(STRING_LITERAL);
break;
}
case ACTION:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
h = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refHeaderAction(n,h);
}
}
else {
break _loop4;
}
} while (true);
}
{
switch ( LA(1)) {
case OPTIONS:
{
fileOptionsSpec();
break;
}
case EOF:
case ACTION:
case DOC_COMMENT:
case LITERAL_lexclass:
case LITERAL_class:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
_loop7:
do {
if (((LA(1) >= ACTION && LA(1) <= LITERAL_class))) {
classDef();
}
else {
break _loop7;
}
} while (true);
}
match(Token.EOF_TYPE);
}
catch (RecognitionException ex) {
if (inputState.guessing==0) {
reportError("rule grammar trapped: "+ex.toString());
consumeUntil(EOF);
} else {
throw ex;
}
}
}
public final void fileOptionsSpec() throws RecognitionException, TokenStreamException {
Token idTok; Token value;
match(OPTIONS);
{
_loop18:
do {
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF)) {
idTok=id();
match(ASSIGN);
value=optionValue();
if ( inputState.guessing==0 ) {
behavior.setFileOption(idTok, value,getInputState().filename);
}
match(SEMI);
}
else {
break _loop18;
}
} while (true);
}
match(RCURLY);
}
public final void classDef() throws RecognitionException, TokenStreamException {
Token a = null;
Token d = null;
String doc=null;
try { // for error handling
{
switch ( LA(1)) {
case ACTION:
{
a = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refPreambleAction(a);
}
break;
}
case DOC_COMMENT:
case LITERAL_lexclass:
case LITERAL_class:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case DOC_COMMENT:
{
d = LT(1);
match(DOC_COMMENT);
if ( inputState.guessing==0 ) {
doc=d.getText();
}
break;
}
case LITERAL_lexclass:
case LITERAL_class:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
boolean synPredMatched13 = false;
if (((LA(1)==LITERAL_lexclass||LA(1)==LITERAL_class) && (LA(2)==TOKEN_REF||LA(2)==RULE_REF))) {
int _m13 = mark();
synPredMatched13 = true;
inputState.guessing++;
try {
{
switch ( LA(1)) {
case LITERAL_lexclass:
{
match(LITERAL_lexclass);
break;
}
case LITERAL_class:
{
match(LITERAL_class);
id();
match(LITERAL_extends);
match(LITERAL_Lexer);
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
catch (RecognitionException pe) {
synPredMatched13 = false;
}
rewind(_m13);
inputState.guessing--;
}
if ( synPredMatched13 ) {
lexerSpec(doc);
}
else {
boolean synPredMatched15 = false;
if (((LA(1)==LITERAL_class) && (LA(2)==TOKEN_REF||LA(2)==RULE_REF))) {
int _m15 = mark();
synPredMatched15 = true;
inputState.guessing++;
try {
{
match(LITERAL_class);
id();
match(LITERAL_extends);
match(LITERAL_TreeParser);
}
}
catch (RecognitionException pe) {
synPredMatched15 = false;
}
rewind(_m15);
inputState.guessing--;
}
if ( synPredMatched15 ) {
treeParserSpec(doc);
}
else if ((LA(1)==LITERAL_class) && (LA(2)==TOKEN_REF||LA(2)==RULE_REF)) {
parserSpec(doc);
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
}
rules();
if ( inputState.guessing==0 ) {
behavior.endGrammar();
}
}
catch (RecognitionException ex) {
if (inputState.guessing==0) {
if ( ex instanceof NoViableAltException ) {
NoViableAltException e = (NoViableAltException)ex;
if ( e.token.getType()==DOC_COMMENT ) {
reportError("line "+ex.line+": JAVADOC comments may only prefix rules and grammars");
}
else {
reportError("rule classDef trapped: "+ex.toString());
}
}
else {
reportError("rule classDef trapped: "+ex.toString());
}
behavior.abortGrammar();
boolean consuming = true;
// consume everything until the next class definition or EOF
while (consuming) {
consume();
switch(LA(1)) {
case LITERAL_class:
case LITERAL_lexclass:
case EOF:
consuming = false;
break;
}
}
} else {
throw ex;
}
}
}
public final Token id() throws RecognitionException, TokenStreamException {
Token idTok ;
Token a = null;
Token b = null;
idTok = null;
switch ( LA(1)) {
case TOKEN_REF:
{
a = LT(1);
match(TOKEN_REF);
if ( inputState.guessing==0 ) {
idTok = a;
}
break;
}
case RULE_REF:
{
b = LT(1);
match(RULE_REF);
if ( inputState.guessing==0 ) {
idTok = b;
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
return idTok ;
}
public final void lexerSpec(
String doc
) throws RecognitionException, TokenStreamException {
Token lc = null;
Token a = null;
Token idTok;
String sup=null;
{
switch ( LA(1)) {
case LITERAL_lexclass:
{
lc = LT(1);
match(LITERAL_lexclass);
idTok=id();
if ( inputState.guessing==0 ) {
System.out.println("warning: line " + lc.getLine() + ": 'lexclass' is deprecated; use 'class X extends Lexer'");
}
break;
}
case LITERAL_class:
{
match(LITERAL_class);
idTok=id();
match(LITERAL_extends);
match(LITERAL_Lexer);
{
switch ( LA(1)) {
case LPAREN:
{
sup=superClass();
break;
}
case SEMI:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.startLexer(getFilename(), idTok,sup,doc);
}
match(SEMI);
{
switch ( LA(1)) {
case OPTIONS:
{
lexerOptionsSpec();
break;
}
case ACTION:
case DOC_COMMENT:
case TOKENS:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.endOptions();
}
{
switch ( LA(1)) {
case TOKENS:
{
tokensSpec();
break;
}
case ACTION:
case DOC_COMMENT:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case ACTION:
{
a = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refMemberAction(a);
}
break;
}
case DOC_COMMENT:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
public final void treeParserSpec(
String doc
) throws RecognitionException, TokenStreamException {
Token a = null;
Token idTok;
String sup=null;
match(LITERAL_class);
idTok=id();
match(LITERAL_extends);
match(LITERAL_TreeParser);
{
switch ( LA(1)) {
case LPAREN:
{
sup=superClass();
break;
}
case SEMI:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.startTreeWalker(getFilename(), idTok,sup,doc);
}
match(SEMI);
{
switch ( LA(1)) {
case OPTIONS:
{
treeParserOptionsSpec();
break;
}
case ACTION:
case DOC_COMMENT:
case TOKENS:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.endOptions();
}
{
switch ( LA(1)) {
case TOKENS:
{
tokensSpec();
break;
}
case ACTION:
case DOC_COMMENT:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case ACTION:
{
a = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refMemberAction(a);
}
break;
}
case DOC_COMMENT:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
public final void parserSpec(
String doc
) throws RecognitionException, TokenStreamException {
Token a = null;
Token idTok;
String sup=null;
match(LITERAL_class);
idTok=id();
{
switch ( LA(1)) {
case LITERAL_extends:
{
match(LITERAL_extends);
match(LITERAL_Parser);
{
switch ( LA(1)) {
case LPAREN:
{
sup=superClass();
break;
}
case SEMI:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
break;
}
case SEMI:
{
if ( inputState.guessing==0 ) {
System.out.println("warning: line " +
idTok.getLine() + ": use 'class X extends Parser'");
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.startParser(getFilename(), idTok, sup, doc);
}
match(SEMI);
{
switch ( LA(1)) {
case OPTIONS:
{
parserOptionsSpec();
break;
}
case ACTION:
case DOC_COMMENT:
case TOKENS:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.endOptions();
}
{
switch ( LA(1)) {
case TOKENS:
{
tokensSpec();
break;
}
case ACTION:
case DOC_COMMENT:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case ACTION:
{
a = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refMemberAction(a);
}
break;
}
case DOC_COMMENT:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
public final void rules() throws RecognitionException, TokenStreamException {
{
int _cnt68=0;
_loop68:
do {
if ((_tokenSet_0.member(LA(1))) && (_tokenSet_1.member(LA(2)))) {
rule();
}
else {
if ( _cnt68>=1 ) { break _loop68; } else {throw new NoViableAltException(LT(1), getFilename());}
}
_cnt68++;
} while (true);
}
}
public final Token optionValue() throws RecognitionException, TokenStreamException {
Token retval ;
Token sl = null;
Token cl = null;
Token il = null;
retval = null;
switch ( LA(1)) {
case TOKEN_REF:
case RULE_REF:
{
retval=qualifiedID();
break;
}
case STRING_LITERAL:
{
sl = LT(1);
match(STRING_LITERAL);
if ( inputState.guessing==0 ) {
retval = sl;
}
break;
}
case CHAR_LITERAL:
{
cl = LT(1);
match(CHAR_LITERAL);
if ( inputState.guessing==0 ) {
retval = cl;
}
break;
}
case INT:
{
il = LT(1);
match(INT);
if ( inputState.guessing==0 ) {
retval = il;
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
return retval ;
}
public final void parserOptionsSpec() throws RecognitionException, TokenStreamException {
Token idTok; Token value;
match(OPTIONS);
{
_loop21:
do {
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF)) {
idTok=id();
match(ASSIGN);
value=optionValue();
if ( inputState.guessing==0 ) {
behavior.setGrammarOption(idTok, value);
}
match(SEMI);
}
else {
break _loop21;
}
} while (true);
}
match(RCURLY);
}
public final void treeParserOptionsSpec() throws RecognitionException, TokenStreamException {
Token idTok; Token value;
match(OPTIONS);
{
_loop24:
do {
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF)) {
idTok=id();
match(ASSIGN);
value=optionValue();
if ( inputState.guessing==0 ) {
behavior.setGrammarOption(idTok, value);
}
match(SEMI);
}
else {
break _loop24;
}
} while (true);
}
match(RCURLY);
}
public final void lexerOptionsSpec() throws RecognitionException, TokenStreamException {
Token idTok; Token value; BitSet b;
match(OPTIONS);
{
_loop27:
do {
switch ( LA(1)) {
case LITERAL_charVocabulary:
{
match(LITERAL_charVocabulary);
match(ASSIGN);
b=charSet();
match(SEMI);
if ( inputState.guessing==0 ) {
behavior.setCharVocabulary(b);
}
break;
}
case TOKEN_REF:
case RULE_REF:
{
idTok=id();
match(ASSIGN);
value=optionValue();
if ( inputState.guessing==0 ) {
behavior.setGrammarOption(idTok, value);
}
match(SEMI);
break;
}
default:
{
break _loop27;
}
}
} while (true);
}
match(RCURLY);
}
public final BitSet charSet() throws RecognitionException, TokenStreamException {
BitSet b ;
b = null;
BitSet tmpSet = null;
b=setBlockElement();
{
_loop34:
do {
if ((LA(1)==OR)) {
match(OR);
tmpSet=setBlockElement();
if ( inputState.guessing==0 ) {
b.orInPlace(tmpSet);
}
}
else {
break _loop34;
}
} while (true);
}
return b ;
}
public final void subruleOptionsSpec() throws RecognitionException, TokenStreamException {
Token idTok; Token value;
match(OPTIONS);
{
_loop30:
do {
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF)) {
idTok=id();
match(ASSIGN);
value=optionValue();
if ( inputState.guessing==0 ) {
behavior.setSubruleOption(idTok, value);
}
match(SEMI);
}
else {
break _loop30;
}
} while (true);
}
match(RCURLY);
}
/** Match a.b.c.d qualified ids; WILDCARD here is overloaded as
* id separator; that is, I need a reference to the '.' token.
*/
public final Token qualifiedID() throws RecognitionException, TokenStreamException {
Token qidTok=null;
StringBuffer buf = new StringBuffer(30);
Token a;
a=id();
if ( inputState.guessing==0 ) {
buf.append(a.getText());
}
{
_loop144:
do {
if ((LA(1)==WILDCARD)) {
match(WILDCARD);
a=id();
if ( inputState.guessing==0 ) {
buf.append('.'); buf.append(a.getText());
}
}
else {
break _loop144;
}
} while (true);
}
if ( inputState.guessing==0 ) {
// can use either TOKEN_REF or RULE_REF; should
// really create a QID or something instead.
qidTok = new CommonToken(TOKEN_REF, buf.toString());
qidTok.setLine(a.getLine());
}
return qidTok;
}
public final BitSet setBlockElement() throws RecognitionException, TokenStreamException {
BitSet b ;
Token c1 = null;
Token c2 = null;
b = null;
int rangeMin = 0;
c1 = LT(1);
match(CHAR_LITERAL);
if ( inputState.guessing==0 ) {
rangeMin = ANTLRLexer.tokenTypeForCharLiteral(c1.getText());
b = BitSet.of(rangeMin);
}
{
switch ( LA(1)) {
case RANGE:
{
match(RANGE);
c2 = LT(1);
match(CHAR_LITERAL);
if ( inputState.guessing==0 ) {
int rangeMax = ANTLRLexer.tokenTypeForCharLiteral(c2.getText());
if (rangeMax < rangeMin) {
tool.error("Malformed range line "+c1.getLine());
}
for (int i = rangeMin+1; i <= rangeMax; i++) {
b.add(i);
}
}
break;
}
case SEMI:
case OR:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
return b ;
}
public final void tokensSpec() throws RecognitionException, TokenStreamException {
Token t1 = null;
Token s1 = null;
Token s3 = null;
match(TOKENS);
{
int _cnt43=0;
_loop43:
do {
if ((LA(1)==STRING_LITERAL||LA(1)==TOKEN_REF)) {
{
switch ( LA(1)) {
case TOKEN_REF:
{
if ( inputState.guessing==0 ) {
s1=null;
}
t1 = LT(1);
match(TOKEN_REF);
{
switch ( LA(1)) {
case ASSIGN:
{
match(ASSIGN);
s1 = LT(1);
match(STRING_LITERAL);
break;
}
case SEMI:
case OPEN_ELEMENT_OPTION:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.defineToken(t1, s1);
}
{
switch ( LA(1)) {
case OPEN_ELEMENT_OPTION:
{
tokensSpecOptions(t1);
break;
}
case SEMI:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
break;
}
case STRING_LITERAL:
{
s3 = LT(1);
match(STRING_LITERAL);
if ( inputState.guessing==0 ) {
behavior.defineToken(null, s3);
}
{
switch ( LA(1)) {
case OPEN_ELEMENT_OPTION:
{
tokensSpecOptions(s3);
break;
}
case SEMI:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
match(SEMI);
}
else {
if ( _cnt43>=1 ) { break _loop43; } else {throw new NoViableAltException(LT(1), getFilename());}
}
_cnt43++;
} while (true);
}
match(RCURLY);
}
public final void tokensSpecOptions(
Token t
) throws RecognitionException, TokenStreamException {
Token o=null, v=null;
match(OPEN_ELEMENT_OPTION);
o=id();
match(ASSIGN);
v=optionValue();
if ( inputState.guessing==0 ) {
behavior.refTokensSpecElementOption(t,o,v);
}
{
_loop46:
do {
if ((LA(1)==SEMI)) {
match(SEMI);
o=id();
match(ASSIGN);
v=optionValue();
if ( inputState.guessing==0 ) {
behavior.refTokensSpecElementOption(t,o,v);
}
}
else {
break _loop46;
}
} while (true);
}
match(CLOSE_ELEMENT_OPTION);
}
public final String superClass() throws RecognitionException, TokenStreamException {
String sup;
sup=null;
match(LPAREN);
if ( inputState.guessing==0 ) {
sup = LT(1).getText();
}
{
switch ( LA(1)) {
case TOKEN_REF:
{
match(TOKEN_REF);
break;
}
case RULE_REF:
{
match(RULE_REF);
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
match(RPAREN);
return sup;
}
public final void rule() throws RecognitionException, TokenStreamException {
Token d = null;
Token p1 = null;
Token p2 = null;
Token p3 = null;
Token aa = null;
Token rt = null;
Token a = null;
String access="public";
Token idTok;
String doc=null;
boolean ruleAutoGen = true;
blockNesting = -1; // block increments, so -1 to make rule at level 0
{
switch ( LA(1)) {
case DOC_COMMENT:
{
d = LT(1);
match(DOC_COMMENT);
if ( inputState.guessing==0 ) {
doc=d.getText();
}
break;
}
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case LITERAL_protected:
{
p1 = LT(1);
match(LITERAL_protected);
if ( inputState.guessing==0 ) {
access=p1.getText();
}
break;
}
case LITERAL_public:
{
p2 = LT(1);
match(LITERAL_public);
if ( inputState.guessing==0 ) {
access=p2.getText();
}
break;
}
case LITERAL_private:
{
p3 = LT(1);
match(LITERAL_private);
if ( inputState.guessing==0 ) {
access=p3.getText();
}
break;
}
case TOKEN_REF:
case RULE_REF:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
idTok=id();
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
ruleAutoGen = false;
}
break;
}
case ACTION:
case OPTIONS:
case ARG_ACTION:
case LITERAL_returns:
case COLON:
case LITERAL_throws:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.defineRuleName(idTok, access, ruleAutoGen, doc);
}
{
switch ( LA(1)) {
case ARG_ACTION:
{
aa = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
behavior.refArgAction(aa);
}
break;
}
case ACTION:
case OPTIONS:
case LITERAL_returns:
case COLON:
case LITERAL_throws:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case LITERAL_returns:
{
match(LITERAL_returns);
rt = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
behavior.refReturnAction(rt);
}
break;
}
case ACTION:
case OPTIONS:
case COLON:
case LITERAL_throws:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case LITERAL_throws:
{
throwsSpec();
break;
}
case ACTION:
case OPTIONS:
case COLON:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case OPTIONS:
{
ruleOptionsSpec();
break;
}
case ACTION:
case COLON:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case ACTION:
{
a = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refInitAction(a);
}
break;
}
case COLON:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
match(COLON);
block();
match(SEMI);
{
switch ( LA(1)) {
case LITERAL_exception:
{
exceptionGroup();
break;
}
case EOF:
case ACTION:
case DOC_COMMENT:
case LITERAL_lexclass:
case LITERAL_class:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.endRule(idTok.getText());
}
}
public final void throwsSpec() throws RecognitionException, TokenStreamException {
String t=null;
Token a,b;
match(LITERAL_throws);
a=id();
if ( inputState.guessing==0 ) {
t=a.getText();
}
{
_loop84:
do {
if ((LA(1)==COMMA)) {
match(COMMA);
b=id();
if ( inputState.guessing==0 ) {
t+=","+b.getText();
}
}
else {
break _loop84;
}
} while (true);
}
if ( inputState.guessing==0 ) {
behavior.setUserExceptions(t);
}
}
public final void ruleOptionsSpec() throws RecognitionException, TokenStreamException {
Token idTok; Token value;
match(OPTIONS);
{
_loop81:
do {
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF)) {
idTok=id();
match(ASSIGN);
value=optionValue();
if ( inputState.guessing==0 ) {
behavior.setRuleOption(idTok, value);
}
match(SEMI);
}
else {
break _loop81;
}
} while (true);
}
match(RCURLY);
}
public final void block() throws RecognitionException, TokenStreamException {
if ( inputState.guessing==0 ) {
blockNesting++;
}
alternative();
{
_loop87:
do {
if ((LA(1)==OR)) {
match(OR);
alternative();
}
else {
break _loop87;
}
} while (true);
}
if ( inputState.guessing==0 ) {
blockNesting--;
}
}
public final void exceptionGroup() throws RecognitionException, TokenStreamException {
if ( inputState.guessing==0 ) {
behavior.beginExceptionGroup();
}
{
int _cnt95=0;
_loop95:
do {
if ((LA(1)==LITERAL_exception)) {
exceptionSpec();
}
else {
if ( _cnt95>=1 ) { break _loop95; } else {throw new NoViableAltException(LT(1), getFilename());}
}
_cnt95++;
} while (true);
}
if ( inputState.guessing==0 ) {
behavior.endExceptionGroup();
}
}
public final void alternative() throws RecognitionException, TokenStreamException {
boolean altAutoGen = true;
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
altAutoGen=false;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.beginAlt(altAutoGen);
}
{
_loop91:
do {
if ((_tokenSet_2.member(LA(1)))) {
element();
}
else {
break _loop91;
}
} while (true);
}
{
switch ( LA(1)) {
case LITERAL_exception:
{
exceptionSpecNoLabel();
break;
}
case SEMI:
case OR:
case RPAREN:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.endAlt();
}
}
public final void element() throws RecognitionException, TokenStreamException {
elementNoOptionSpec();
{
switch ( LA(1)) {
case OPEN_ELEMENT_OPTION:
{
elementOptionSpec();
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
public final void exceptionSpecNoLabel() throws RecognitionException, TokenStreamException {
match(LITERAL_exception);
if ( inputState.guessing==0 ) {
behavior.beginExceptionSpec(null);
}
{
_loop102:
do {
if ((LA(1)==LITERAL_catch)) {
exceptionHandler();
}
else {
break _loop102;
}
} while (true);
}
if ( inputState.guessing==0 ) {
behavior.endExceptionSpec();
}
}
public final void exceptionSpec() throws RecognitionException, TokenStreamException {
Token aa = null;
Token labelAction = null;
match(LITERAL_exception);
{
switch ( LA(1)) {
case ARG_ACTION:
{
aa = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
labelAction = aa;
}
break;
}
case EOF:
case ACTION:
case DOC_COMMENT:
case LITERAL_lexclass:
case LITERAL_class:
case TOKEN_REF:
case RULE_REF:
case LITERAL_protected:
case LITERAL_public:
case LITERAL_private:
case LITERAL_exception:
case LITERAL_catch:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.beginExceptionSpec(labelAction);
}
{
_loop99:
do {
if ((LA(1)==LITERAL_catch)) {
exceptionHandler();
}
else {
break _loop99;
}
} while (true);
}
if ( inputState.guessing==0 ) {
behavior.endExceptionSpec();
}
}
public final void exceptionHandler() throws RecognitionException, TokenStreamException {
Token a1 = null;
Token a2 = null;
Token exType; Token exName;
match(LITERAL_catch);
a1 = LT(1);
match(ARG_ACTION);
a2 = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refExceptionHandler(a1, a2);
}
}
public final void elementNoOptionSpec() throws RecognitionException, TokenStreamException {
Token rr = null;
Token aa = null;
Token tr = null;
Token aa2 = null;
Token r2 = null;
Token aa3 = null;
Token a = null;
Token p = null;
Token label = null;
Token assignId = null;
Token args = null;
int autoGen = GrammarElement.AUTO_GEN_NONE;
switch ( LA(1)) {
case ACTION:
{
a = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refAction(a);
}
break;
}
case SEMPRED:
{
p = LT(1);
match(SEMPRED);
if ( inputState.guessing==0 ) {
behavior.refSemPred(p);
}
break;
}
case TREE_BEGIN:
{
tree();
break;
}
default:
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF) && (LA(2)==ASSIGN)) {
assignId=id();
match(ASSIGN);
{
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF) && (LA(2)==COLON)) {
label=id();
match(COLON);
if ( inputState.guessing==0 ) {
checkForMissingEndRule(label);
}
}
else if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF) && (_tokenSet_3.member(LA(2)))) {
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
{
switch ( LA(1)) {
case RULE_REF:
{
rr = LT(1);
match(RULE_REF);
{
switch ( LA(1)) {
case ARG_ACTION:
{
aa = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
args=aa;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case BANG:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_BANG;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refRule(assignId, rr, label, args, autoGen);
}
break;
}
case TOKEN_REF:
{
tr = LT(1);
match(TOKEN_REF);
{
switch ( LA(1)) {
case ARG_ACTION:
{
aa2 = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
args=aa2;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refToken(assignId, tr, label, args, false, autoGen, lastInRule());
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
else if ((_tokenSet_4.member(LA(1))) && (_tokenSet_5.member(LA(2)))) {
{
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF) && (LA(2)==COLON)) {
label=id();
match(COLON);
if ( inputState.guessing==0 ) {
checkForMissingEndRule(label);
}
}
else if ((_tokenSet_4.member(LA(1))) && (_tokenSet_6.member(LA(2)))) {
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
{
switch ( LA(1)) {
case RULE_REF:
{
r2 = LT(1);
match(RULE_REF);
{
switch ( LA(1)) {
case ARG_ACTION:
{
aa3 = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
args=aa3;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case BANG:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_BANG;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refRule(assignId, r2, label, args, autoGen);
}
break;
}
case NOT_OP:
{
match(NOT_OP);
{
switch ( LA(1)) {
case CHAR_LITERAL:
case TOKEN_REF:
{
notTerminal(label);
break;
}
case LPAREN:
{
ebnf(label,true);
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
break;
}
case LPAREN:
{
ebnf(label,false);
break;
}
default:
if ((LA(1)==STRING_LITERAL||LA(1)==CHAR_LITERAL||LA(1)==TOKEN_REF) && (LA(2)==RANGE)) {
range(label);
}
else if ((_tokenSet_7.member(LA(1))) && (_tokenSet_8.member(LA(2)))) {
terminal(label);
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
}
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
}
public final void elementOptionSpec() throws RecognitionException, TokenStreamException {
Token o=null, v=null;
match(OPEN_ELEMENT_OPTION);
o=id();
match(ASSIGN);
v=optionValue();
if ( inputState.guessing==0 ) {
behavior.refElementOption(o,v);
}
{
_loop108:
do {
if ((LA(1)==SEMI)) {
match(SEMI);
o=id();
match(ASSIGN);
v=optionValue();
if ( inputState.guessing==0 ) {
behavior.refElementOption(o,v);
}
}
else {
break _loop108;
}
} while (true);
}
match(CLOSE_ELEMENT_OPTION);
}
public final void range(
Token label
) throws RecognitionException, TokenStreamException {
Token crLeft = null;
Token crRight = null;
Token t = null;
Token u = null;
Token v = null;
Token w = null;
Token trLeft=null;
Token trRight=null;
int autoGen=GrammarElement.AUTO_GEN_NONE;
switch ( LA(1)) {
case CHAR_LITERAL:
{
crLeft = LT(1);
match(CHAR_LITERAL);
match(RANGE);
crRight = LT(1);
match(CHAR_LITERAL);
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_BANG;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refCharRange(crLeft, crRight, label, autoGen, lastInRule());
}
break;
}
case STRING_LITERAL:
case TOKEN_REF:
{
{
switch ( LA(1)) {
case TOKEN_REF:
{
t = LT(1);
match(TOKEN_REF);
if ( inputState.guessing==0 ) {
trLeft=t;
}
break;
}
case STRING_LITERAL:
{
u = LT(1);
match(STRING_LITERAL);
if ( inputState.guessing==0 ) {
trLeft=u;
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
match(RANGE);
{
switch ( LA(1)) {
case TOKEN_REF:
{
v = LT(1);
match(TOKEN_REF);
if ( inputState.guessing==0 ) {
trRight=v;
}
break;
}
case STRING_LITERAL:
{
w = LT(1);
match(STRING_LITERAL);
if ( inputState.guessing==0 ) {
trRight=w;
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
autoGen=ast_type_spec();
if ( inputState.guessing==0 ) {
behavior.refTokenRange(trLeft, trRight, label, autoGen, lastInRule());
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
public final void terminal(
Token label
) throws RecognitionException, TokenStreamException {
Token cl = null;
Token tr = null;
Token aa = null;
Token sl = null;
Token wi = null;
int autoGen=GrammarElement.AUTO_GEN_NONE;
Token args=null;
switch ( LA(1)) {
case CHAR_LITERAL:
{
cl = LT(1);
match(CHAR_LITERAL);
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_BANG;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refCharLiteral(cl, label, false, autoGen, lastInRule());
}
break;
}
case TOKEN_REF:
{
tr = LT(1);
match(TOKEN_REF);
autoGen=ast_type_spec();
{
switch ( LA(1)) {
case ARG_ACTION:
{
aa = LT(1);
match(ARG_ACTION);
if ( inputState.guessing==0 ) {
args=aa;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refToken(null, tr, label, args, false, autoGen, lastInRule());
}
break;
}
case STRING_LITERAL:
{
sl = LT(1);
match(STRING_LITERAL);
autoGen=ast_type_spec();
if ( inputState.guessing==0 ) {
behavior.refStringLiteral(sl, label, autoGen, lastInRule());
}
break;
}
case WILDCARD:
{
wi = LT(1);
match(WILDCARD);
autoGen=ast_type_spec();
if ( inputState.guessing==0 ) {
behavior.refWildcard(wi, label, autoGen);
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
public final void notTerminal(
Token label
) throws RecognitionException, TokenStreamException {
Token cl = null;
Token tr = null;
int autoGen=GrammarElement.AUTO_GEN_NONE;
switch ( LA(1)) {
case CHAR_LITERAL:
{
cl = LT(1);
match(CHAR_LITERAL);
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_BANG;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.refCharLiteral(cl, label, true, autoGen, lastInRule());
}
break;
}
case TOKEN_REF:
{
tr = LT(1);
match(TOKEN_REF);
autoGen=ast_type_spec();
if ( inputState.guessing==0 ) {
behavior.refToken(null, tr, label, null, true, autoGen, lastInRule());
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
public final void ebnf(
Token label, boolean not
) throws RecognitionException, TokenStreamException {
Token lp = null;
Token aa = null;
Token ab = null;
lp = LT(1);
match(LPAREN);
if ( inputState.guessing==0 ) {
behavior.beginSubRule(label, lp.getLine(), not);
}
{
if ((LA(1)==OPTIONS)) {
subruleOptionsSpec();
{
switch ( LA(1)) {
case ACTION:
{
aa = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refInitAction(aa);
}
break;
}
case COLON:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
match(COLON);
}
else if ((LA(1)==ACTION) && (LA(2)==COLON)) {
ab = LT(1);
match(ACTION);
if ( inputState.guessing==0 ) {
behavior.refInitAction(ab);
}
match(COLON);
}
else if ((_tokenSet_9.member(LA(1))) && (_tokenSet_10.member(LA(2)))) {
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
block();
match(RPAREN);
{
switch ( LA(1)) {
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case BANG:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case QUESTION:
case STAR:
case PLUS:
case WILDCARD:
{
{
switch ( LA(1)) {
case QUESTION:
{
match(QUESTION);
if ( inputState.guessing==0 ) {
behavior.optionalSubRule();
}
break;
}
case STAR:
{
match(STAR);
if ( inputState.guessing==0 ) {
behavior.zeroOrMoreSubRule();;
}
break;
}
case PLUS:
{
match(PLUS);
if ( inputState.guessing==0 ) {
behavior.oneOrMoreSubRule();
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case BANG:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
{
switch ( LA(1)) {
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
behavior.noASTSubRule();
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
break;
}
case IMPLIES:
{
match(IMPLIES);
if ( inputState.guessing==0 ) {
behavior.synPred();
}
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
if ( inputState.guessing==0 ) {
behavior.endSubRule();
}
}
public final void tree() throws RecognitionException, TokenStreamException {
Token lp = null;
lp = LT(1);
match(TREE_BEGIN);
if ( inputState.guessing==0 ) {
behavior.beginTree(lp.getLine());
}
rootNode();
if ( inputState.guessing==0 ) {
behavior.beginChildList();
}
{
int _cnt122=0;
_loop122:
do {
if ((_tokenSet_2.member(LA(1)))) {
element();
}
else {
if ( _cnt122>=1 ) { break _loop122; } else {throw new NoViableAltException(LT(1), getFilename());}
}
_cnt122++;
} while (true);
}
if ( inputState.guessing==0 ) {
behavior.endChildList();
}
match(RPAREN);
if ( inputState.guessing==0 ) {
behavior.endTree();
}
}
public final void rootNode() throws RecognitionException, TokenStreamException {
Token label = null;
{
if ((LA(1)==TOKEN_REF||LA(1)==RULE_REF) && (LA(2)==COLON)) {
label=id();
match(COLON);
if ( inputState.guessing==0 ) {
checkForMissingEndRule(label);
}
}
else if ((_tokenSet_7.member(LA(1))) && (_tokenSet_11.member(LA(2)))) {
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
terminal(label);
}
public final int ast_type_spec() throws RecognitionException, TokenStreamException {
int autoGen ;
autoGen = GrammarElement.AUTO_GEN_NONE;
{
switch ( LA(1)) {
case CARET:
{
match(CARET);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_CARET;
}
break;
}
case BANG:
{
match(BANG);
if ( inputState.guessing==0 ) {
autoGen = GrammarElement.AUTO_GEN_BANG;
}
break;
}
case STRING_LITERAL:
case ACTION:
case SEMI:
case CHAR_LITERAL:
case OR:
case TOKEN_REF:
case OPEN_ELEMENT_OPTION:
case LPAREN:
case RULE_REF:
case RPAREN:
case ARG_ACTION:
case LITERAL_exception:
case NOT_OP:
case SEMPRED:
case TREE_BEGIN:
case WILDCARD:
{
break;
}
default:
{
throw new NoViableAltException(LT(1), getFilename());
}
}
}
return autoGen ;
}
public static final String[] _tokenNames = {
"<0>",
"EOF",
"<2>",
"NULL_TREE_LOOKAHEAD",
"\"tokens\"",
"\"header\"",
"STRING_LITERAL",
"ACTION",
"DOC_COMMENT",
"\"lexclass\"",
"\"class\"",
"\"extends\"",
"\"Lexer\"",
"\"TreeParser\"",
"OPTIONS",
"ASSIGN",
"SEMI",
"RCURLY",
"\"charVocabulary\"",
"CHAR_LITERAL",
"INT",
"OR",
"RANGE",
"TOKENS",
"TOKEN_REF",
"OPEN_ELEMENT_OPTION",
"CLOSE_ELEMENT_OPTION",
"LPAREN",
"RULE_REF",
"RPAREN",
"\"Parser\"",
"\"protected\"",
"\"public\"",
"\"private\"",
"BANG",
"ARG_ACTION",
"\"returns\"",
"COLON",
"\"throws\"",
"COMMA",
"\"exception\"",
"\"catch\"",
"NOT_OP",
"SEMPRED",
"TREE_BEGIN",
"QUESTION",
"STAR",
"PLUS",
"IMPLIES",
"CARET",
"WILDCARD",
"\"options\"",
"WS",
"COMMENT",
"SL_COMMENT",
"ML_COMMENT",
"ESC",
"DIGIT",
"XDIGIT",
"VOCAB",
"NESTED_ARG_ACTION",
"NESTED_ACTION",
"WS_LOOP",
"INTERNAL_RULE_REF",
"WS_OPT",
"NOT_USEFUL"
};
private static final long _tokenSet_0_data_[] = { 15317598464L, 0L };
public static final BitSet _tokenSet_0 = new BitSet(_tokenSet_0_data_);
private static final long _tokenSet_1_data_[] = { 547893559424L, 0L };
public static final BitSet _tokenSet_1 = new BitSet(_tokenSet_1_data_);
private static final long _tokenSet_2_data_[] = { 1156686652375232L, 0L };
public static final BitSet _tokenSet_2 = new BitSet(_tokenSet_2_data_);
private static final long _tokenSet_3_data_[] = { 1157838276198592L, 0L };
public static final BitSet _tokenSet_3 = new BitSet(_tokenSet_3_data_);
private static final long _tokenSet_4_data_[] = { 1130298373308480L, 0L };
public static final BitSet _tokenSet_4 = new BitSet(_tokenSet_4_data_);
private static final long _tokenSet_5_data_[] = { 1720925672784064L, 0L };
public static final BitSet _tokenSet_5 = new BitSet(_tokenSet_5_data_);
private static final long _tokenSet_6_data_[] = { 1720788233830592L, 0L };
public static final BitSet _tokenSet_6 = new BitSet(_tokenSet_6_data_);
private static final long _tokenSet_7_data_[] = { 1125899924144192L, 0L };
public static final BitSet _tokenSet_7 = new BitSet(_tokenSet_7_data_);
private static final long _tokenSet_8_data_[] = { 1720788229619904L, 0L };
public static final BitSet _tokenSet_8 = new BitSet(_tokenSet_8_data_);
private static final long _tokenSet_9_data_[] = { 1157803882840256L, 0L };
public static final BitSet _tokenSet_9 = new BitSet(_tokenSet_9_data_);
private static final long _tokenSet_10_data_[] = { 2250890277404864L, 0L };
public static final BitSet _tokenSet_10 = new BitSet(_tokenSet_10_data_);
private static final long _tokenSet_11_data_[] = { 1719688145404096L, 0L };
public static final BitSet _tokenSet_11 = new BitSet(_tokenSet_11_data_);
}
1.1 e/src/jsrc/antlr/ANTLRStringBuffer.java
Index: ANTLRStringBuffer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ANTLRStringBuffer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
// Implementation of a StringBuffer-like object that does not have the
// unfortunate side-effect of creating Strings with very large buffers.
public class ANTLRStringBuffer {
protected char[] buffer = new char[8];
protected int length = 0; // length and also where to store next char
public ANTLRStringBuffer() {}
public final void append(char c) {
// This would normally be an "ensureCapacity" method, but inlined
// here for speed.
if (length >= buffer.length) {
// Compute a new length that is at least double old length
int newSize = buffer.length;
while (length >= newSize) {
newSize *= 2;
}
// Allocate new array and copy buffer
char[] newBuffer = new char[newSize];
for (int i = 0; i < length; i++) {
newBuffer[i] = buffer[i];
}
buffer = newBuffer;
}
buffer[length] = c;
length++;
}
public final void append(String s) {
for (int i = 0; i < s.length(); i++) {
append(s.charAt(i));
}
}
public final char charAt(int index) { return buffer[index]; }
final public char[] getBuffer() { return buffer; }
public final int length() { return length; }
public final void setCharAt(int index, char ch) { buffer[index] = ch; }
public final void setLength(int newLength) {
if (newLength < length) {
length = newLength;
} else {
while (newLength > length) {
append('\0');
}
}
}
public final String toString() {
return new String(buffer, 0, length);
}
}
1.1 e/src/jsrc/antlr/ANTLRTokdefLexer.java
Index: ANTLRTokdefLexer.java
===================================================================
package antlr;
/*
* ANTLR-generated file resulting from grammar tokdef.g
*
* Terence Parr, MageLang Institute
* ANTLR Version 2.7.0a2; 1989-1999
*/
import java.io.InputStream;
import java.io.Reader;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.CharStreamException;
import antlr.CharStreamIOException;
import java.util.Hashtable;
import antlr.CharScanner;
import antlr.InputBuffer;
import antlr.ByteBuffer;
import antlr.CharBuffer;
import antlr.Token;
import antlr.CommonToken;
import antlr.RecognitionException;
import antlr.NoViableAltForCharException;
import antlr.MismatchedCharException;
import antlr.TokenStream;
import antlr.ANTLRHashString;
import antlr.LexerSharedInputState;
import antlr.collections.impl.BitSet;
public class ANTLRTokdefLexer extends antlr.CharScanner implements ANTLRTokdefParserTokenTypes, TokenStream
{
private static final long _tokenSet_0_data_[] = { -9224L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_0 = new BitSet(_tokenSet_0_data_);
private static final long _tokenSet_1_data_[] = { -140737488355336L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_1 = new BitSet(_tokenSet_1_data_);
public ANTLRTokdefLexer(InputBuffer ib) {
this(new LexerSharedInputState(ib));
}
public ANTLRTokdefLexer(LexerSharedInputState state) {
super(state);
literals = new Hashtable();
caseSensitiveLiterals = true;
setCaseSensitive(true);
}
public ANTLRTokdefLexer(InputStream in) {
this(new ByteBuffer(in));
}
public ANTLRTokdefLexer(Reader in) {
this(new CharBuffer(in));
}
public final void mASSIGN(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ASSIGN;
int _saveIndex;
match('=');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mDIGIT(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = DIGIT;
int _saveIndex;
matchRange('0','9');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mESC(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ESC;
int _saveIndex;
match('\\');
{
switch ( LA(1)) {
case 'n':
{
match('n');
break;
}
case 'r':
{
match('r');
break;
}
case 't':
{
match('t');
break;
}
case 'b':
{
match('b');
break;
}
case 'f':
{
match('f');
break;
}
case '"':
{
match('"');
break;
}
case '\'':
{
match('\'');
break;
}
case '\\':
{
match('\\');
break;
}
case '0': case '1': case '2': case '3':
{
{
matchRange('0','3');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\3' && LA(2) <= '~'))) {
mDIGIT(false);
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\3' && LA(2) <= '~'))) {
mDIGIT(false);
}
else if (((LA(1) >= '\3' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else if (((LA(1) >= '\3' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
break;
}
case '4': case '5': case '6': case '7':
{
{
matchRange('4','7');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\3' && LA(2) <= '~'))) {
mDIGIT(false);
}
else if (((LA(1) >= '\3' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
break;
}
case 'u':
{
match('u');
mXDIGIT(false);
mXDIGIT(false);
mXDIGIT(false);
mXDIGIT(false);
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mID(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ID;
int _saveIndex;
{
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
_loop37:
do {
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '_':
{
match('_');
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
default:
{
break _loop37;
}
}
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mINT(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = INT;
int _saveIndex;
{
int _cnt40=0;
_loop40:
do {
if (((LA(1) >= '0' && LA(1) <= '9'))) {
mDIGIT(false);
}
else {
if ( _cnt40>=1 ) { break _loop40; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt40++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mLPAREN(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = LPAREN;
int _saveIndex;
match('(');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mML_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ML_COMMENT;
int _saveIndex;
match("/*");
{
_loop17:
do {
switch ( LA(1)) {
case '\n':
{
match('\n');
newline();
break;
}
case '\3': case '\4': case '\5': case '\6':
case '\7': case '\10': case '\t': case '\13':
case '\14': case '\r': case '\16': case '\17':
case '\20': case '\21': case '\22': case '\23':
case '\24': case '\25': case '\26': case '\27':
case '\30': case '\31': case '\32': case '\33':
case '\34': case '\35': case '\36': case '\37':
case ' ': case '!': case '"': case '#':
case '$': case '%': case '&': case '\'':
case '(': case ')': case '+': case ',':
case '-': case '.': case '/': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case ':': case ';': case '<':
case '=': case '>': case '?': case '@':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '[': case '\\':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('*');
break;
}
default:
if ((LA(1)=='*') && (_tokenSet_1.member(LA(2)))) {
match('*');
matchNot('/');
}
else {
break _loop17;
}
}
} while (true);
}
match("*/");
_ttype = Token.SKIP;
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mRPAREN(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = RPAREN;
int _saveIndex;
match(')');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mSL_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = SL_COMMENT;
int _saveIndex;
match("//");
{
_loop12:
do {
if ((_tokenSet_0.member(LA(1)))) {
{
match(_tokenSet_0);
}
}
else {
break _loop12;
}
} while (true);
}
{
switch ( LA(1)) {
case '\n':
{
match('\n');
break;
}
case '\r':
{
match('\r');
{
if ((LA(1)=='\n')) {
match('\n');
}
else {
}
}
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_ttype = Token.SKIP; newline();
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mSTRING(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STRING;
int _saveIndex;
match('"');
{
_loop23:
do {
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\3': case '\4': case '\5': case '\6':
case '\7': case '\10': case '\t': case '\n':
case '\13': case '\14': case '\r': case '\16':
case '\17': case '\20': case '\21': case '\22':
case '\23': case '\24': case '\25': case '\26':
case '\27': case '\30': case '\31': case '\32':
case '\33': case '\34': case '\35': case '\36':
case '\37': case ' ': case '!': case '#':
case '$': case '%': case '&': case '\'':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('"');
break;
}
default:
{
break _loop23;
}
}
} while (true);
}
match('"');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mVOCAB(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = VOCAB;
int _saveIndex;
matchRange('\3','\176');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public final void mWS(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WS;
int _saveIndex;
{
switch ( LA(1)) {
case ' ':
{
match(' ');
break;
}
case '\t':
{
match('\t');
break;
}
case '\r':
{
match('\r');
{
if ((LA(1)=='\n')) {
match('\n');
}
else {
}
}
newline();
break;
}
case '\n':
{
match('\n');
newline();
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_ttype = Token.SKIP;
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mXDIGIT(boolean _createToken) throws RecognitionException, CharStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = XDIGIT;
int _saveIndex;
switch ( LA(1)) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f':
{
matchRange('a','f');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F':
{
matchRange('A','F');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
public Token nextToken() throws TokenStreamException {
Token _rettoken=null;
tryAgain:
for (;;) {
Token _token = null;
int _ttype = Token.INVALID_TYPE;
resetText();
try {
try { // for error handling
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(true);
_rettoken=_returnToken;
break;
}
case '(':
{
mLPAREN(true);
_rettoken=_returnToken;
break;
}
case ')':
{
mRPAREN(true);
_rettoken=_returnToken;
break;
}
case '=':
{
mASSIGN(true);
_rettoken=_returnToken;
break;
}
case '"':
{
mSTRING(true);
_rettoken=_returnToken;
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case 'a': case 'b':
case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v':
case 'w': case 'x': case 'y': case 'z':
{
mID(true);
_rettoken=_returnToken;
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
mINT(true);
_rettoken=_returnToken;
break;
}
default:
if ((LA(1)=='/') && (LA(2)=='/')) {
mSL_COMMENT(true);
_rettoken=_returnToken;
}
else if ((LA(1)=='/') && (LA(2)=='*')) {
mML_COMMENT(true);
_rettoken=_returnToken;
}
else {
if (LA(1)==EOF_CHAR) {_returnToken = makeToken(Token.EOF_TYPE);}
else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
}
if ( _returnToken==null ) continue tryAgain; // found SKIP token
_ttype = _returnToken.getType();
_returnToken.setType(_ttype);
return _returnToken;
}
catch (RecognitionException e) {
reportError(e);
consume();
}
}
catch (CharStreamException cse) {
if ( cse instanceof CharStreamIOException ) {
throw new TokenStreamIOException(((CharStreamIOException)cse).io);
}
else {
throw new TokenStreamException(cse.getMessage());
}
}
}
}
}
1.1 e/src/jsrc/antlr/ANTLRTokdefParser.java
Index: ANTLRTokdefParser.java
===================================================================
package antlr;
/*
* ANTLR-generated file resulting from grammar tokdef.g
*
* Terence Parr, MageLang Institute
* ANTLR Version 2.7.0a2; 1989-1999
*/
import antlr.TokenStreamException;
import antlr.TokenBuffer;
import antlr.LLkParser;
import antlr.Token;
import antlr.TokenStream;
import antlr.RecognitionException;
import antlr.NoViableAltException;
import antlr.MismatchedTokenException;
import antlr.SemanticException;
import antlr.ParserSharedInputState;
import antlr.collections.impl.BitSet;
public class ANTLRTokdefParser extends antlr.LLkParser
implements ANTLRTokdefParserTokenTypes
{
public static final String[] _tokenNames = {
"<0>",
"EOF",
"<2>",
"NULL_TREE_LOOKAHEAD",
"ID",
"STRING",
"ASSIGN",
"LPAREN",
"RPAREN",
"INT",
"WS",
"SL_COMMENT",
"ML_COMMENT",
"ESC",
"DIGIT",
"XDIGIT",
"VOCAB"
};
private static final long _tokenSet_0_data_[] = { 2L, 0L };
public static final BitSet _tokenSet_0 = new BitSet(_tokenSet_0_data_);
private static final long _tokenSet_1_data_[] = { 50L, 0L };
public static final BitSet _tokenSet_1 = new BitSet(_tokenSet_1_data_);
public ANTLRTokdefParser(ParserSharedInputState state) {
super(state,3);
tokenNames = _tokenNames;
}
public ANTLRTokdefParser(TokenBuffer tokenBuf) {
this(tokenBuf,3);
}
protected ANTLRTokdefParser(TokenBuffer tokenBuf, int k) {
super(tokenBuf,k);
tokenNames = _tokenNames;
}
public ANTLRTokdefParser(TokenStream lexer) {
this(lexer,3);
}
protected ANTLRTokdefParser(TokenStream lexer, int k) {
super(lexer,k);
tokenNames = _tokenNames;
}
public final void file(
ImportVocabTokenManager tm
) throws RecognitionException, TokenStreamException {
Token name = null;
try { // for error handling
name = LT(1);
match(ID);
{
_loop3:
do {
if ((LA(1)==ID||LA(1)==STRING)) {
line(tm);
}
else {
break _loop3;
}
} while (true);
}
}
catch (RecognitionException ex) {
reportError(ex);
consume();
consumeUntil(_tokenSet_0);
}
}
public final void line(
ImportVocabTokenManager tm
) throws RecognitionException, TokenStreamException {
Token s1 = null;
Token lab = null;
Token s2 = null;
Token id = null;
Token para = null;
Token id2 = null;
Token i = null;
Token t=null; Token s=null;
try { // for error handling
{
if ((LA(1)==STRING)) {
s1 = LT(1);
match(STRING);
s = s1;
}
else if ((LA(1)==ID) && (LA(2)==ASSIGN) && (LA(3)==STRING)) {
lab = LT(1);
match(ID);
t = lab;
match(ASSIGN);
s2 = LT(1);
match(STRING);
s = s2;
}
else if ((LA(1)==ID) && (LA(2)==LPAREN)) {
id = LT(1);
match(ID);
t=id;
match(LPAREN);
para = LT(1);
match(STRING);
match(RPAREN);
}
else if ((LA(1)==ID) && (LA(2)==ASSIGN) && (LA(3)==INT)) {
id2 = LT(1);
match(ID);
t=id2;
}
else {
throw new NoViableAltException(LT(1), getFilename());
}
}
match(ASSIGN);
i = LT(1);
match(INT);
Integer value = Integer.valueOf(i.getText());
// if literal found, define as a string literal
if ( s!=null ) {
tm.define(s.getText(), value.intValue());
// if label, then label the string and map label to token symbol also
if ( t!=null ) {
StringLiteralSymbol sl =
(StringLiteralSymbol) tm.getTokenSymbol(s.getText());
sl.setLabel(t.getText());
tm.mapToTokenSymbol(t.getText(), sl);
}
}
// define token (not a literal)
else if ( t!=null ) {
tm.define(t.getText(), value.intValue());
if ( para!=null ) {
TokenSymbol ts = tm.getTokenSymbol(t.getText());
ts.setParaphrase(
para.getText()
);
}
}
}
catch (RecognitionException ex) {
reportError(ex);
consume();
consumeUntil(_tokenSet_1);
}
}
}
1.1 e/src/jsrc/antlr/ANTLRTokdefParserTokenTypes.java
Index: ANTLRTokdefParserTokenTypes.java
===================================================================
package antlr;
/*
* ANTLR-generated file resulting from grammar tokdef.g
*
* Terence Parr, MageLang Institute
* ANTLR Version 2.7.0a2; 1989-1999
*/
public interface ANTLRTokdefParserTokenTypes {
int EOF = 1;
int NULL_TREE_LOOKAHEAD = 3;
int ID = 4;
int STRING = 5;
int ASSIGN = 6;
int LPAREN = 7;
int RPAREN = 8;
int INT = 9;
int WS = 10;
int SL_COMMENT = 11;
int ML_COMMENT = 12;
int ESC = 13;
int DIGIT = 14;
int XDIGIT = 15;
int VOCAB = 16;
}
1.1 e/src/jsrc/antlr/ANTLRTokdefParserTokenTypes.txt
Index: ANTLRTokdefParserTokenTypes.txt
===================================================================
ANTLRTokdefParser // output token vocab name
ID=4
STRING=5
ASSIGN=6
LPAREN=7
RPAREN=8
INT=9
WS=10
SL_COMMENT=11
ML_COMMENT=12
ESC=13
DIGIT=14
XDIGIT=15
VOCAB=16
1.1 e/src/jsrc/antlr/ANTLRTokenTypes.java
Index: ANTLRTokenTypes.java
===================================================================
// $ANTLR 2.7.1: "antlr.g" -> "ANTLRLexer.java"$
package antlr;
public interface ANTLRTokenTypes {
int EOF = 1;
int NULL_TREE_LOOKAHEAD = 3;
int LITERAL_tokens = 4;
int LITERAL_header = 5;
int STRING_LITERAL = 6;
int ACTION = 7;
int DOC_COMMENT = 8;
int LITERAL_lexclass = 9;
int LITERAL_class = 10;
int LITERAL_extends = 11;
int LITERAL_Lexer = 12;
int LITERAL_TreeParser = 13;
int OPTIONS = 14;
int ASSIGN = 15;
int SEMI = 16;
int RCURLY = 17;
int LITERAL_charVocabulary = 18;
int CHAR_LITERAL = 19;
int INT = 20;
int OR = 21;
int RANGE = 22;
int TOKENS = 23;
int TOKEN_REF = 24;
int OPEN_ELEMENT_OPTION = 25;
int CLOSE_ELEMENT_OPTION = 26;
int LPAREN = 27;
int RULE_REF = 28;
int RPAREN = 29;
int LITERAL_Parser = 30;
int LITERAL_protected = 31;
int LITERAL_public = 32;
int LITERAL_private = 33;
int BANG = 34;
int ARG_ACTION = 35;
int LITERAL_returns = 36;
int COLON = 37;
int LITERAL_throws = 38;
int COMMA = 39;
int LITERAL_exception = 40;
int LITERAL_catch = 41;
int NOT_OP = 42;
int SEMPRED = 43;
int TREE_BEGIN = 44;
int QUESTION = 45;
int STAR = 46;
int PLUS = 47;
int IMPLIES = 48;
int CARET = 49;
int WILDCARD = 50;
int LITERAL_options = 51;
int WS = 52;
int COMMENT = 53;
int SL_COMMENT = 54;
int ML_COMMENT = 55;
int ESC = 56;
int DIGIT = 57;
int XDIGIT = 58;
int VOCAB = 59;
int NESTED_ARG_ACTION = 60;
int NESTED_ACTION = 61;
int WS_LOOP = 62;
int INTERNAL_RULE_REF = 63;
int WS_OPT = 64;
int NOT_USEFUL = 65;
}
1.1 e/src/jsrc/antlr/ANTLRTokenTypes.txt
Index: ANTLRTokenTypes.txt
===================================================================
// $ANTLR 2.7.1: antlr.g -> ANTLRTokenTypes.txt$
ANTLR // output token vocab name
LITERAL_tokens="tokens"=4
LITERAL_header="header"=5
STRING_LITERAL=6
ACTION=7
DOC_COMMENT=8
LITERAL_lexclass="lexclass"=9
LITERAL_class="class"=10
LITERAL_extends="extends"=11
LITERAL_Lexer="Lexer"=12
LITERAL_TreeParser="TreeParser"=13
OPTIONS=14
ASSIGN=15
SEMI=16
RCURLY=17
LITERAL_charVocabulary="charVocabulary"=18
CHAR_LITERAL=19
INT=20
OR=21
RANGE=22
TOKENS=23
TOKEN_REF=24
OPEN_ELEMENT_OPTION=25
CLOSE_ELEMENT_OPTION=26
LPAREN=27
RULE_REF=28
RPAREN=29
LITERAL_Parser="Parser"=30
LITERAL_protected="protected"=31
LITERAL_public="public"=32
LITERAL_private="private"=33
BANG=34
ARG_ACTION=35
LITERAL_returns="returns"=36
COLON=37
LITERAL_throws="throws"=38
COMMA=39
LITERAL_exception="exception"=40
LITERAL_catch="catch"=41
NOT_OP=42
SEMPRED=43
TREE_BEGIN=44
QUESTION=45
STAR=46
PLUS=47
IMPLIES=48
CARET=49
WILDCARD=50
LITERAL_options="options"=51
WS=52
COMMENT=53
SL_COMMENT=54
ML_COMMENT=55
ESC=56
DIGIT=57
XDIGIT=58
VOCAB=59
NESTED_ARG_ACTION=60
NESTED_ACTION=61
WS_LOOP=62
INTERNAL_RULE_REF=63
WS_OPT=64
NOT_USEFUL=65
1.1 e/src/jsrc/antlr/ASTFactory.java
Index: ASTFactory.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ASTFactory.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
import antlr.collections.impl.ASTArray;
/** AST Support code shared by TreeParser and Parser.
* We use delegation to share code (and have only one
* bit of code to maintain) rather than subclassing
* or superclassing (forces AST support code to be
* loaded even when you don't want to do AST stuff).
*
* Typically, setASTNodeType is used to specify the
* type of node to create, but you can override
* create to make heterogeneous nodes etc...
*/
public class ASTFactory {
/** Name of AST class to create during tree construction.
* Null implies that the create method should create
* a default AST type such as CommonAST.
*/
protected String theASTNodeType = null;
protected Class theASTNodeTypeClass = null;
/** Add a child to the current AST */
public void addASTChild(ASTPair currentAST, AST child) {
if (child != null) {
if (currentAST.root == null) {
// Make new child the current root
currentAST.root = child;
}
else {
if (currentAST.child == null) {
// Add new child to current root
currentAST.root.setFirstChild(child);
}
else {
currentAST.child.setNextSibling(child);
}
}
// Make new child the current child
currentAST.child = child;
currentAST.advanceChildToEnd();
}
}
/** Create a new empty AST node; if the user did not specify
* an AST node type, then create a default one: CommonAST.
*/
public AST create() {
AST t = null;
if (theASTNodeTypeClass == null) {
t = new CommonAST();
} else {
try {
t = (AST) theASTNodeTypeClass.newInstance(); // make a new one
} catch (Exception e) {
antlr.Tool.warning("Can't create AST Node " + theASTNodeType);
return null;
}
}
return t;
}
public AST create(int type) {
AST t = create();
t.initialize(type,"");
return t;
}
public AST create(int type, String txt) {
AST t = create();
t.initialize(type,txt);
return t;
}
/** Create a new empty AST node; if the user did not specify
* an AST node type, then create a default one: CommonAST.
*/
public AST create(AST tr) {
if ( tr==null ) return null; // create(null) == null
AST t = create();
t.initialize(tr);
return t;
}
public AST create(Token tok) {
AST t = create();
t.initialize(tok);
return t;
}
/** Copy a single node. clone() is not used because
* we want to return an AST not a plain object...a type
* safety issue. Further, we want to have all AST node
* creation go through the factory so creation can be
* tracked. Returns null if t is null.
*/
public AST dup(AST t) {
return create(t); // if t==null, create returns null
}
/** Duplicate tree including siblings of root. */
public AST dupList(AST t) {
AST result = dupTree(t); // if t == null, then result==null
AST nt = result;
while (t != null) { // for each sibling of the root
t = t.getNextSibling();
nt.setNextSibling(dupTree(t)); // dup each subtree, building new tree
nt = nt.getNextSibling();
}
return result;
}
/**Duplicate a tree, assuming this is a root node of a tree--
* duplicate that node and what's below; ignore siblings of root node.
*/
public AST dupTree(AST t) {
AST result = dup(t); // make copy of root
// copy all children of root.
if ( t!=null ) {
result.setFirstChild( dupList(t.getFirstChild()) );
}
return result;
}
/** Make a tree from a list of nodes. The first element in the
* array is the root. If the root is null, then the tree is
* a simple list not a tree. Handles null children nodes correctly.
* For example, build(a, b, null, c) yields tree (a b c). build(null,a,b)
* yields tree (nil a b).
*/
public AST make(AST[] nodes) {
if ( nodes==null || nodes.length==0 ) return null;
AST root = nodes[0];
AST tail = null;
if (root != null) {
root.setFirstChild(null); // don't leave any old pointers set
}
// link in children;
for (int i=1; i<nodes.length; i++) {
if ( nodes[i]==null ) continue; // ignore null nodes
if (root == null) {
// Set the root and set it up for a flat list
root = tail = nodes[i];
}
else if ( tail==null ) {
root.setFirstChild(nodes[i]);
tail = root.getFirstChild();
}
else {
tail.setNextSibling(nodes[i]);
tail = tail.getNextSibling();
}
// Chase tail to last sibling
while (tail.getNextSibling() != null) {
tail = tail.getNextSibling();
}
}
return root;
}
/** Make a tree from a list of nodes, where the nodes are contained
* in an ASTArray object
*/
public AST make(ASTArray nodes) {
return make(nodes.array);
}
/** Make an AST the root of current AST */
public void makeASTRoot(ASTPair currentAST, AST root) {
if (root != null) {
// Add the current root as a child of new root
root.addChild(currentAST.root);
// The new current child is the last sibling of the old root
currentAST.child = currentAST.root;
currentAST.advanceChildToEnd();
// Set the new root
currentAST.root = root;
}
}
public void setASTNodeType(String t) {
theASTNodeType = t;
try {
theASTNodeTypeClass = Class.forName(t); // get class def
} catch (Exception e) {
// either class not found,
// class is interface/abstract, or
// class or initializer is not accessible.
antlr.Tool.warning("Can't find/access AST Node type"+t);
}
}
}
1.1 e/src/jsrc/antlr/ASTIterator.java
Index: ASTIterator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ASTIterator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
public class ASTIterator {
protected AST cursor = null;
protected AST original = null;
public ASTIterator(AST t) {
original = cursor = t;
}
/** Is 'sub' a subtree of 't' beginning at the root? */
public boolean isSubtree(AST t, AST sub) {
AST sibling;
// the empty tree is always a subset of any tree.
if ( sub==null ) {
return true;
}
// if the tree is empty, return true if the subtree template is too.
if ( t==null ) {
if ( sub!=null ) return false;
return true;
}
// Otherwise, start walking sibling lists. First mismatch, return false.
for (sibling=t;
sibling!=null&&sub!=null;
sibling=sibling.getNextSibling(), sub=sub.getNextSibling())
{
// as a quick optimization, check roots first.
if ( sibling.getType() != sub.getType() ) return false;
// if roots match, do full match test on children.
if ( sibling.getFirstChild()!=null ) {
if ( !isSubtree(sibling.getFirstChild(), sub.getFirstChild()) ) return false;
}
}
return true;
}
/** Find the next subtree with structure and token types equal to
* those of 'template'.
*/
public AST next(AST template) {
AST t = null;
AST sibling = null;
if ( cursor==null ) { // do nothing if no tree to work on
return null;
}
// Start walking sibling list looking for subtree matches.
for ( ; cursor!=null; cursor=cursor.getNextSibling())
{
// as a quick optimization, check roots first.
if ( cursor.getType() == template.getType() ) {
// if roots match, do full match test on children.
if ( cursor.getFirstChild()!=null ) {
if ( isSubtree(cursor.getFirstChild(), template.getFirstChild()) ) {
return cursor;
}
}
}
}
return t;
}
}
1.1 e/src/jsrc/antlr/ASTNULLType.java
Index: ASTNULLType.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ASTNULLType.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
import antlr.collections.ASTEnumeration;
import antlr.Token;
/** There is only one instance of this class **/
public class ASTNULLType implements AST {
public void addChild(AST c) {;}
public boolean equals(AST t) {return false;}
public boolean equalsList(AST t) {return false;}
public boolean equalsListPartial(AST t) {return false;}
public boolean equalsTree(AST t) {return false;}
public boolean equalsTreePartial(AST t) {return false;}
public ASTEnumeration findAll(AST tree) {return null;}
public ASTEnumeration findAllPartial(AST subtree) {
return null;
}
public AST getFirstChild() { return this; }
public AST getNextSibling() { return this; }
public String getText() { return "<ASTNULL>"; }
public int getType() { return Token.NULL_TREE_LOOKAHEAD; }
public void initialize(int t, String txt) {}
public void initialize(AST t) {}
public void initialize(Token t) {}
public void setFirstChild(AST c) {;}
public void setNextSibling(AST n) {;}
public void setText(String text) {;}
public void setType(int ttype) {;}
public String toString() {return getText();}
public String toStringList() {return getText();}
public String toStringTree() {return getText();}
}
1.1 e/src/jsrc/antlr/ASTPair.java
Index: ASTPair.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ASTPair.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
/** ASTPair: utility class used for manipulating a pair of ASTs
* representing the current AST root and current AST sibling.
* This exists to compensate for the lack of pointers or 'var'
* arguments in Java.
*/
public class ASTPair {
public AST root; // current root of tree
public AST child; // current child to which siblings are added
/** Make sure that child is the last sibling */
public final void advanceChildToEnd() {
if (child != null) {
while (child.getNextSibling() != null) {
child = child.getNextSibling();
}
}
}
/** Copy an ASTPair. Don't call it clone() because we want type-safety */
public ASTPair copy() {
ASTPair tmp = new ASTPair();
tmp.root = root;
tmp.child = child;
return tmp;
}
public String toString() {
String r = root==null ? "null" : root.getText();
String c = child==null ? "null" : child.getText();
return "["+r+","+c+"]";
}
}
1.1 e/src/jsrc/antlr/ASTVisitor.java
Index: ASTVisitor.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ASTVisitor.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
public interface ASTVisitor{
public void visit(AST node);
}
1.1 e/src/jsrc/antlr/ActionElement.java
Index: ActionElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ActionElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class ActionElement extends AlternativeElement {
protected String actionText;
protected boolean isSemPred = false;
public ActionElement(Grammar g, Token t) {
super(g);
actionText = t.getText();
line = t.getLine();
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
return " "+actionText + (isSemPred?"?":"");
}
}
1.1 e/src/jsrc/antlr/ActionTransInfo.java
Index: ActionTransInfo.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ActionTransInfo.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**
* This class contains information about how an action
* was translated (using the AST conversion rules).
*/
public class ActionTransInfo {
public boolean assignToRoot = false; // somebody did a "#rule = "
public String refRuleRoot = null; // somebody referenced #rule; string is translated var
public String toString() {
return "assignToRoot:"+assignToRoot+", refRuleRoot:"+refRuleRoot;
}
}
1.1 e/src/jsrc/antlr/Alternative.java
Index: Alternative.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: Alternative.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
/** Intermediate data class holds information about an alternative */
class Alternative {
// Tracking alternative linked list
AlternativeElement head; // head of alt element list
AlternativeElement tail; // last element added
// Syntactic predicate block if non-null
protected SynPredBlock synPred;
// Semantic predicate action if non-null
protected String semPred;
// Exception specification if non-null
protected ExceptionSpec exceptionSpec;
// Init action if non-null;
protected Lookahead[] cache; // lookahead for alt. Filled in by
// deterministic() only!!!!!!! Used for
// code gen after calls to deterministic()
// and used by deterministic for (...)*, (..)+,
// and (..)? blocks. 1..k
protected int lookaheadDepth; // each alt has different look depth possibly.
// depth can be NONDETERMINISTIC too.
// 0..n-1
// If non-null, Tree specification ala -> A B C (not implemented)
protected Token treeSpecifier = null;
// True of AST generation is on for this alt
private boolean doAutoGen;
public Alternative() {
}
public Alternative(AlternativeElement firstElement) {
addElement(firstElement);
}
public void addElement(AlternativeElement e)
{
// Link the element into the list
if ( head == null ) {
head = tail = e;
}
else {
tail.next = e;
tail = e;
}
}
public boolean atStart() { return head == null; }
public boolean getAutoGen() {
// Don't build an AST if there is a tree-rewrite-specifier
return doAutoGen && treeSpecifier == null;
}
public Token getTreeSpecifier() {
return treeSpecifier;
}
public void setAutoGen(boolean doAutoGen_) {
doAutoGen = doAutoGen_;
}
}
1.1 e/src/jsrc/antlr/AlternativeBlock.java
Index: AlternativeBlock.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: AlternativeBlock.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.Vector;
/**A list of alternatives */
class AlternativeBlock extends AlternativeElement {
protected String initAction = null; // string for init action {...}
protected Vector alternatives; // Contains Alternatives
protected String label; // can label a looping block to break out of it.
protected int alti, altj; // which alts are being compared at the moment with
// deterministic()?
protected int analysisAlt; // which alt are we computing look on? Must be alti or altj
protected boolean hasAnAction = false; // does any alt have an action?
protected boolean hasASynPred = false; // does any alt have a syntactic predicate?
protected int ID=0; // used to generate unique variables
protected static int nblks; // how many blocks have we allocated?
boolean not = false; // true if block is inverted.
boolean greedy = true; // Blocks are greedy by default
boolean greedySet=false; // but, if not explicitly greedy, warning might be generated
protected boolean doAutoGen=true; // false if no AST (or text) to be generated for block
protected boolean warnWhenFollowAmbig = true; // warn when an empty path or exit path
protected boolean generateAmbigWarnings = true; // the general warning "shut-up" mechanism
// conflicts with alt of subrule.
// Turning this off will suppress stuff
// like the if-then-else ambig.
public AlternativeBlock(Grammar g) {
this(g,0,false);
}
public AlternativeBlock(Grammar g, int line, boolean not) {
super(g);
alternatives = new Vector(5);
this.line = line;
this.not = not;
nblks++;
ID = nblks;
}
public void addAlternative(Alternative alt) {
alternatives.appendElement(alt);
}
public void generate() {
grammar.generator.gen(this);
}
public Alternative getAlternativeAt(int i)
{
return (Alternative)alternatives.elementAt(i);
}
public Vector getAlternatives() {
return alternatives;
}
public boolean getAutoGen() {
return doAutoGen;
}
public String getInitAction() {
return initAction;
}
public String getLabel() {
return label;
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public void prepareForAnalysis() {
for (int i=0; i<alternatives.size(); i++) {
// deterministic() uses an alternative cache and sets lookahead depth
Alternative a = (Alternative)alternatives.elementAt(i);
a.cache = new Lookahead[grammar.maxk+1];
a.lookaheadDepth = GrammarAnalyzer.LOOKAHEAD_DEPTH_INIT;
}
}
/**Walk the syntactic predicate and, for a rule ref R, remove
* the ref from the list of FOLLOW references for R (stored
* in the symbol table.
*/
public void removeTrackingOfRuleRefs(Grammar g) {
for (int i=0; i<alternatives.size(); i++) {
Alternative alt = getAlternativeAt(i);
AlternativeElement elem = alt.head;
while ( elem!=null ) {
if ( elem instanceof RuleRefElement ) {
RuleRefElement rr = (RuleRefElement)elem;
RuleSymbol rs = (RuleSymbol)g.getSymbol(rr.targetRule);
if ( rs==null ) {
grammar.tool.error("rule "+rr.targetRule+" referenced in (...)=>, but not defined");
}
else {
rs.references.removeElement(rr);
}
}
else if ( elem instanceof AlternativeBlock ) {// recurse into subrules
((AlternativeBlock)elem).removeTrackingOfRuleRefs(g);
}
elem = elem.next;
}
}
}
public void setAlternatives(Vector v) {
alternatives = v;
}
public void setAutoGen(boolean doAutoGen_) {
doAutoGen = doAutoGen_;
}
public void setInitAction(String initAction_) {
initAction = initAction_;
}
public void setLabel(String label_) {
label = label_;
}
public void setOption(Token key, Token value) {
if (key.getText().equals("warnWhenFollowAmbig")) {
if (value.getText().equals("true")) {
warnWhenFollowAmbig = true;
} else if (value.getText().equals("false")) {
warnWhenFollowAmbig = false;
} else {
grammar.tool.error("Value for warnWhenFollowAmbig must be true or false", grammar.getFilename(), key.getLine());
}
}
else if (key.getText().equals("generateAmbigWarnings")) {
if (value.getText().equals("true")) {
generateAmbigWarnings = true;
} else if (value.getText().equals("false")) {
generateAmbigWarnings = false;
} else {
grammar.tool.error("Value for generateAmbigWarnings must be true or false", grammar.getFilename(), key.getLine());
}
}
else if (key.getText().equals("greedy")) {
if (value.getText().equals("true")) {
greedy = true;
greedySet = true;
} else if (value.getText().equals("false")) {
greedy = false;
greedySet = true;
} else {
grammar.tool.error("Value for greedy must be true or false", grammar.getFilename(), key.getLine());
}
}
else {
grammar.tool.error("Invalid subrule option: " + key.getText(), grammar.getFilename(), key.getLine());
}
}
public String toString() {
String s=" (";
if ( initAction!=null ) {
s += initAction;
}
for (int i=0; i<alternatives.size(); i++) {
Alternative alt = getAlternativeAt(i);
Lookahead cache[] = alt.cache;
int k = alt.lookaheadDepth;
// dump lookahead set
if ( k==GrammarAnalyzer.LOOKAHEAD_DEPTH_INIT ) {
}
else if ( k==GrammarAnalyzer.NONDETERMINISTIC ) {
s += "{?}:";
}
else {
s += " {";
for (int j=1; j<=k; j++) {
s += cache[j].toString(",",grammar.tokenManager.getVocabulary());
if ( j<k && cache[j+1]!=null ) s += ";";
}
s += "}:";
}
// dump alternative including pred (if any)
AlternativeElement p = alt.head;
String pred = alt.semPred;
if ( pred!=null ) {
s += pred;
}
while (p!=null ) {
s += p;
p = p.next;
}
if ( i<(alternatives.size()-1) ) {
s += " |";
}
}
s += " )";
return s;
}
}
1.1 e/src/jsrc/antlr/AlternativeElement.java
Index: AlternativeElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: AlternativeElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
abstract class AlternativeElement extends GrammarElement {
AlternativeElement next;
protected int autoGenType = AUTO_GEN_NONE;
protected String enclosingRuleName;
public AlternativeElement(Grammar g) {
super(g);
}
public AlternativeElement(Grammar g, int autoGenType_) {
super(g);
autoGenType = autoGenType_;
}
public int getAutoGenType() {
return autoGenType;
}
public String getLabel() {
return null;
}
public void setLabel(String label) {}
}
1.1 e/src/jsrc/antlr/BaseAST.java
Index: BaseAST.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: BaseAST.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
import antlr.collections.ASTEnumeration;
import antlr.collections.impl.ASTEnumerator;
import antlr.collections.impl.Vector;
import java.io.Serializable;
import java.io.IOException;
import java.io.Writer;
/**
* A Child-Sibling Tree.
*
* A tree with PLUS at the root and with two children 3 and 4 is
* structured as:
*
* PLUS
* |
* 3 -- 4
*
* and can be specified easily in LISP notation as
*
* (PLUS 3 4)
*
* where every '(' starts a new subtree.
*
* These trees are particular useful for translators because of
* the flexibility of the children lists. They are also very easy
* to walk automatically, whereas trees with specific children
* reference fields can't easily be walked automatically.
*
* This class contains the basic support for an AST.
* Most people will create ASTs that are subclasses of
* BaseAST or of CommonAST.
*/
public abstract class BaseAST implements AST, Serializable {
protected BaseAST down;
protected BaseAST right;
private static boolean verboseStringConversion = false;
private static String[] tokenNames = null;
/**Add a node to the end of the child list for this node */
public void addChild(AST node) {
if ( node==null ) return;
BaseAST t = this.down;
if ( t!=null ) {
while ( t.right!=null ) {
t = t.right;
}
t.right = (BaseAST)node;
}
else {
this.down = (BaseAST)node;
}
}
private void doWorkForFindAll(Vector v, AST target, boolean partialMatch) {
AST sibling;
// Start walking sibling lists, looking for matches.
siblingWalk:
for (sibling=this;
sibling!=null;
sibling=sibling.getNextSibling())
{
if ( (partialMatch && sibling.equalsTreePartial(target)) ||
(!partialMatch && sibling.equalsTree(target)) ) {
v.appendElement(sibling);
}
// regardless of match or not, check any children for matches
if ( sibling.getFirstChild()!=null ) {
((BaseAST)sibling.getFirstChild()).doWorkForFindAll(v, target, partialMatch);
}
}
}
/** Is node t equal to this in terms of token type and text? */
public boolean equals(AST t) {
if ( t==null ) return false;
return this.getText().equals(t.getText()) &&
this.getType() == t.getType();
}
/** Is t an exact structural and equals() match of this tree. The
* 'this' reference is considered the start of a sibling list.
*/
public boolean equalsList(AST t) {
AST sibling;
// the empty tree is not a match of any non-null tree.
if (t == null) {
return false;
}
// Otherwise, start walking sibling lists. First mismatch, return false.
for (sibling = this; sibling != null && t != null; sibling = sibling.getNextSibling(), t = t.getNextSibling()) {
// as a quick optimization, check roots first.
if (!sibling.equals(t)) {
return false;
}
// if roots match, do full list match test on children.
if (sibling.getFirstChild() != null) {
if (!sibling.getFirstChild().equalsList(t.getFirstChild())) {
return false;
}
}
// sibling has no kids, make sure t doesn't either
else if (t.getFirstChild() != null) {
return false;
}
}
if (sibling == null && t == null) {
return true;
}
// one sibling list has more than the other
return false;
}
/** Is 'sub' a subtree of this list?
* The siblings of the root are NOT ignored.
*/
public boolean equalsListPartial(AST sub) {
AST sibling;
// the empty tree is always a subset of any tree.
if ( sub==null ) {
return true;
}
// Otherwise, start walking sibling lists. First mismatch, return false.
for (sibling=this;
sibling!=null&&sub!=null;
sibling=sibling.getNextSibling(), sub=sub.getNextSibling())
{
// as a quick optimization, check roots first.
if ( !sibling.equals(sub) ) return false;
// if roots match, do partial list match test on children.
if ( sibling.getFirstChild()!=null ) {
if ( !sibling.getFirstChild().equalsListPartial(sub.getFirstChild()) ) return false;
}
}
if ( sibling==null && sub!=null ) {
// nothing left to match in this tree, but subtree has more
return false;
}
// either both are null or sibling has more, but subtree doesn't
return true;
}
/** Is tree rooted at 'this' equal to 't'? The siblings
* of 'this' are ignored.
*/
public boolean equalsTree(AST t) {
// check roots first.
if ( !this.equals(t) ) return false;
// if roots match, do full list match test on children.
if ( this.getFirstChild()!=null ) {
if ( !this.getFirstChild().equalsList(t.getFirstChild()) ) return false;
}
// sibling has no kids, make sure t doesn't either
else if (t.getFirstChild() != null) {
return false;
}
return true;
}
/** Is 't' a subtree of the tree rooted at 'this'? The siblings
* of 'this' are ignored.
*/
public boolean equalsTreePartial(AST sub) {
// the empty tree is always a subset of any tree.
if ( sub==null ) {
return true;
}
// check roots first.
if ( !this.equals(sub) ) return false;
// if roots match, do full list partial match test on children.
if ( this.getFirstChild()!=null ) {
if ( !this.getFirstChild().equalsListPartial(sub.getFirstChild()) ) return false;
}
return true;
}
/** Walk the tree looking for all exact subtree matches. Return
* an ASTEnumerator that lets the caller walk the list
* of subtree roots found herein.
*/
public ASTEnumeration findAll(AST target) {
Vector roots = new Vector(10);
AST sibling;
// the empty tree cannot result in an enumeration
if ( target==null ) {
return null;
}
doWorkForFindAll(roots, target, false); // find all matches recursively
return new ASTEnumerator(roots);
}
/** Walk the tree looking for all subtrees. Return
* an ASTEnumerator that lets the caller walk the list
* of subtree roots found herein.
*/
public ASTEnumeration findAllPartial(AST sub) {
Vector roots = new Vector(10);
AST sibling;
// the empty tree cannot result in an enumeration
if ( sub==null ) {
return null;
}
doWorkForFindAll(roots, sub, true); // find all matches recursively
return new ASTEnumerator(roots);
}
/** Get the first child of this node; null if not children */
public AST getFirstChild() {
return down;
}
/** Get the next sibling in line after this one */
public AST getNextSibling() {
return right;
}
/** Get the token text for this node */
public String getText() { return ""; }
/** Get the token type for this node */
public int getType() { return 0; }
public abstract void initialize(int t, String txt);
public abstract void initialize(AST t);
public abstract void initialize(Token t);
/** Remove all children */
public void removeChildren() {
down = null;
}
public void setFirstChild(AST c) {
down = (BaseAST)c;
}
public void setNextSibling(AST n) {
right = (BaseAST)n;
}
/** Set the token text for this node */
public void setText(String text) {;}
/** Set the token type for this node */
public void setType(int ttype) {;}
public static void setVerboseStringConversion(boolean verbose, String[] names) {
verboseStringConversion = verbose;
tokenNames = names;
}
public String toString() {
StringBuffer b = new StringBuffer();
// if verbose and type name not same as text (keyword probably)
if ( verboseStringConversion &&
!getText().equalsIgnoreCase(tokenNames[getType()]) &&
!getText().equalsIgnoreCase(Tool.stripFrontBack(tokenNames[getType()],"\"","\"")) ) {
b.append('[');
b.append(getText());
b.append(",<");
b.append(tokenNames[getType()]);
b.append(">]");
return b.toString();
}
return getText();
}
/** Print out a child-sibling tree in LISP notation */
public String toStringList() {
AST t = this;
String ts="";
if ( t.getFirstChild()!=null ) ts+=" (";
ts += " "+this.toString();
if ( t.getFirstChild()!=null ) {
ts += ((BaseAST)t.getFirstChild()).toStringList();
}
if ( t.getFirstChild()!=null ) ts+=" )";
if ( t.getNextSibling()!=null ) {
ts += ((BaseAST)t.getNextSibling()).toStringList();
}
return ts;
}
public String toStringTree() {
AST t = this;
String ts="";
if ( t.getFirstChild()!=null ) ts+=" (";
ts += " "+this.toString();
if ( t.getFirstChild()!=null ) {
ts += ((BaseAST)t.getFirstChild()).toStringList();
}
if ( t.getFirstChild()!=null ) ts+=" )";
return ts;
}
public static String decode(String text)
{
char c, c1, c2, c3, c4, c5;
StringBuffer n = new StringBuffer();
for (int i=0; i < text.length(); i++)
{
c = text.charAt(i);
if (c == '&') {
c1 = text.charAt(i+1); c2 = text.charAt(i+2);
c3 = text.charAt(i+3); c4 = text.charAt(i+4);
c5 = text.charAt(i+5);
if ( c1 == 'a' && c2 == 'm' && c3 == 'p' && c4 == ';') {
n.append("&");
i += 5;
}
else if ( c1 == 'l' && c2 == 't' && c3 == ';') {
n.append("<");
i += 4;
}
else if ( c1 == 'g' && c2 == 't' && c3 == ';') {
n.append(">");
i += 4;
}
else if ( c1 == 'q' && c2 == 'u' && c3 == 'o' &&
c4 == 't' && c5 == ';') {
n.append("\"");
i += 6;
}
else if ( c1 == 'a' && c2 == 'p' && c3 == 'o' &&
c4 == 's' && c5 == ';') {
n.append("'");
i += 6;
}
else n.append("&");
}
else n.append(c);
}
return new String(n);
}
public static String encode(String text)
{
char c;
StringBuffer n = new StringBuffer();
for (int i=0; i < text.length(); i++)
{
c = text.charAt(i);
switch (c) {
case '&' : { n.append("&"); break; }
case '<' : { n.append("<"); break; }
case '>' : { n.append(">"); break; }
case '"' : { n.append("""); break; }
case '\'' : { n.append("'"); break; }
default : { n.append(c); break; }
}
}
return new String(n);
}
public void xmlSerializeNode(Writer out)
throws IOException
{
StringBuffer buf = new StringBuffer(100);
buf.append("<");
buf.append(getClass().getName()+" ");
buf.append("text=\""+encode(getText())+"\" type=\""+
getType()+"\"/>");
out.write(buf.toString());
}
public void xmlSerializeRootOpen(Writer out)
throws IOException
{
StringBuffer buf = new StringBuffer(100);
buf.append("<");
buf.append(getClass().getName()+" ");
buf.append("text=\""+encode(getText())+"\" type=\""+
getType()+"\">\n");
out.write(buf.toString());
}
public void xmlSerializeRootClose(Writer out)
throws IOException
{
out.write("</"+getClass().getName()+">\n");
}
public void xmlSerialize(Writer out) throws IOException
{
// print out this node and all siblings
for (AST node = this;
node != null;
node = node.getNextSibling())
{
if (node.getFirstChild() == null) {
// print guts (class name, attributes)
((BaseAST)node).xmlSerializeNode(out);
}
else {
((BaseAST)node).xmlSerializeRootOpen(out);
// print children
((BaseAST)node.getFirstChild()).xmlSerialize(out);
// print end tag
((BaseAST)node).xmlSerializeRootClose(out);
}
}
}
}
1.1 e/src/jsrc/antlr/BlockContext.java
Index: BlockContext.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: BlockContext.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**BlockContext stores the information needed when creating an
* alternative (list of elements). Entering a subrule requires
* that we save this state as each block of alternatives
* requires state such as "tail of current alternative."
*/
class BlockContext {
AlternativeBlock block; // current block of alternatives
int altNum; // which alt are we accepting 0..n-1
BlockEndElement blockEnd; // used if nested
public void addAlternativeElement(AlternativeElement e) {
currentAlt().addElement(e);
}
public Alternative currentAlt() {
return (Alternative)block.alternatives.elementAt(altNum);
}
public AlternativeElement currentElement() {
return currentAlt().tail;
}
}
1.1 e/src/jsrc/antlr/BlockEndElement.java
Index: BlockEndElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: BlockEndElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**All alternative blocks are "terminated" by BlockEndElements unless
* they are rule blocks (in which case they use RuleEndElement).
*/
class BlockEndElement extends AlternativeElement {
protected boolean[] lock; // for analysis; used to avoid infinite loops
protected AlternativeBlock block;// ending blocks know what block they terminate
public BlockEndElement(Grammar g) {
super(g);
lock = new boolean[g.maxk+1];
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
//return " [BlkEnd]";
return "";
}
}
1.1 e/src/jsrc/antlr/BlockWithImpliedExitPath.java
Index: BlockWithImpliedExitPath.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: BlockWithImpliedExitPath.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
abstract class BlockWithImpliedExitPath extends AlternativeBlock {
protected int exitLookaheadDepth; // lookahead needed to handle optional path
/** lookahead to bypass block; set
* by deterministic(). 1..k of Lookahead
*/
protected Lookahead[] exitCache = new Lookahead[grammar.maxk+1];
public BlockWithImpliedExitPath(Grammar g) {
super(g);
}
public BlockWithImpliedExitPath(Grammar g, int line) {
super(g, line, false);
}
}
1.1 e/src/jsrc/antlr/ByteBuffer.java
Index: ByteBuffer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ByteBuffer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A Stream of characters fed to the lexer from a InputStream that can
* be rewound via mark()/rewind() methods.
* <p>
* A dynamic array is used to buffer up all the input characters. Normally,
* "k" characters are stored in the buffer. More characters may be stored during
* guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
* Consumption of characters is deferred. In other words, reading the next
* character is not done by conume(), but deferred until needed by LA or LT.
* <p>
*
* @see antlr.CharQueue
*/
// SAS: added this class to handle Binary input w/ FileInputStream
import java.io.InputStream;
import java.io.IOException;
public class ByteBuffer extends InputBuffer{
// char source
transient InputStream input;
/** Create a character buffer */
public ByteBuffer(InputStream input_) {
super();
input = input_;
}
/** Ensure that the character buffer is sufficiently full */
public void fill(int amount) throws CharStreamException {
try {
syncConsume();
// Fill the buffer sufficiently to hold needed characters
while (queue.nbrEntries < amount + markerOffset) {
// Append the next character
queue.append((char) input.read());
}
} catch (IOException io) {
throw new CharStreamIOException(io);
}
}
}
1.1 e/src/jsrc/antlr/CharBuffer.java
Index: CharBuffer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharBuffer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A Stream of characters fed to the lexer from a InputStream that can
* be rewound via mark()/rewind() methods.
* <p>
* A dynamic array is used to buffer up all the input characters. Normally,
* "k" characters are stored in the buffer. More characters may be stored during
* guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
* Consumption of characters is deferred. In other words, reading the next
* character is not done by conume(), but deferred until needed by LA or LT.
* <p>
*
* @see antlr.CharQueue
*/
import java.io.Reader; // SAS: changed to properly read text files
import java.io.IOException;
// SAS: Move most functionality into InputBuffer -- just the file-specific
// stuff is in here
public class CharBuffer extends InputBuffer {
// char source
transient Reader input;
/** Create a character buffer */
public CharBuffer(Reader input_) { // SAS: for proper text i/o
super();
input = input_;
}
/** Ensure that the character buffer is sufficiently full */
public void fill(int amount) throws CharStreamException {
try {
syncConsume();
// Fill the buffer sufficiently to hold needed characters
while (queue.nbrEntries < amount + markerOffset) {
// Append the next character
queue.append((char) input.read());
}
} catch (IOException io) {
throw new CharStreamIOException(io);
}
}
}
1.1 e/src/jsrc/antlr/CharFormatter.java
Index: CharFormatter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharFormatter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** Interface used by BitSet to format elements of the set when
* converting to string
*/
public interface CharFormatter {
public String escapeChar(int c, boolean forCharLiteral);
public String escapeString(String s);
public String literalChar(int c);
public String literalString(String s);
}
1.1 e/src/jsrc/antlr/CharLiteralElement.java
Index: CharLiteralElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharLiteralElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class CharLiteralElement extends GrammarAtom {
public CharLiteralElement(LexerGrammar g, Token t, boolean inverted, int autoGenType) {
super(g, t, AUTO_GEN_NONE);
tokenType = ANTLRLexer.tokenTypeForCharLiteral(t.getText());
g.charVocabulary.add(tokenType);
line = t.getLine();
not = inverted;
this.autoGenType = autoGenType;
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
}
1.1 e/src/jsrc/antlr/CharQueue.java
Index: CharQueue.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharQueue.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** A circular buffer object used by CharBuffer */
public class CharQueue {
// Physical circular buffer of characters
protected char[] buffer;
// buffer.length-1 for quick modulous
protected int sizeLessOne;
// physical index of front token
protected int offset;
// number of characters in the queue
protected int nbrEntries;
public CharQueue(int minSize) {
// Find first power of 2 >= to requested size
int size;
for (size = 2; size < minSize; size *= 2) {;}
init(size);
}
/** Add token to end of the queue
* @param tok The token to add
*/
public final void append(char tok)
{
if (nbrEntries == buffer.length)
{
expand();
}
buffer[(offset + nbrEntries) & sizeLessOne] = tok;
nbrEntries++;
}
/** Fetch a token from the queue by index
* @param idx The index of the token to fetch, where zero is the token at the front of the queue
*/
public final char elementAt(int idx) {
return buffer[(offset + idx) & sizeLessOne];
}
/** Expand the token buffer by doubling its capacity */
private final void expand()
{
char[] newBuffer = new char[buffer.length * 2];
// Copy the contents to the new buffer
// Note that this will store the first logical item in the
// first physical array element.
for (int i = 0; i < buffer.length; i++)
{
newBuffer[i] = elementAt(i);
}
// Re-initialize with new contents, keep old nbrEntries
buffer = newBuffer;
sizeLessOne = buffer.length - 1;
offset = 0;
}
/** Initialize the queue.
* @param size The initial size of the queue
*/
private final void init(int size) {
// Allocate buffer
buffer = new char[size];
// Other initialization
sizeLessOne = size - 1;
offset = 0;
nbrEntries = 0;
}
/** Remove char from front of queue */
public final void removeFirst() {
offset = (offset+1) & sizeLessOne;
nbrEntries--;
}
}
1.1 e/src/jsrc/antlr/CharRangeElement.java
Index: CharRangeElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharRangeElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class CharRangeElement extends AlternativeElement {
String label;
protected char begin=0;
protected char end =0;
protected String beginText;
protected String endText;
public CharRangeElement(LexerGrammar g, Token t1, Token t2, int autoGenType) {
super(g);
begin = (char)ANTLRLexer.tokenTypeForCharLiteral(t1.getText());
beginText = t1.getText();
end = (char)ANTLRLexer.tokenTypeForCharLiteral(t2.getText());
endText = t2.getText();
line = t1.getLine();
// track which characters are referenced in the grammar
for (int i=begin; i<=end; i++) {
g.charVocabulary.add(i);
}
this.autoGenType = autoGenType;
}
public void generate() {
grammar.generator.gen(this);
}
public String getLabel() {
return label;
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public void setLabel(String label_) {
label = label_;
}
public String toString() {
if ( label!=null ) return " "+label+":"+beginText+".."+endText;
else return " "+beginText+".."+endText;
}
}
1.1 e/src/jsrc/antlr/CharScanner.java
Index: CharScanner.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharScanner.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import antlr.collections.impl.BitSet;
import java.io.IOException;
public abstract class CharScanner implements TokenStream {
static final char NO_CHAR = 0;
public static final char EOF_CHAR = (char) - 1;
protected ANTLRStringBuffer text; // text of current token
protected boolean saveConsumedInput = true; // does consume() save characters?
protected Class tokenObjectClass; // what kind of tokens to create?
protected boolean caseSensitive = true;
protected boolean caseSensitiveLiterals = true;
protected Hashtable literals; // set by subclass
protected Token _returnToken = null; // used to return tokens w/o using return val.
// Hash string used so we don't new one every time to check literals table
protected ANTLRHashString hashString;
protected LexerSharedInputState inputState;
/** Used during filter mode to indicate that path is desired.
* A subsequent scan error will report an error as usual if
* acceptPath=true;
*/
protected boolean commitToPath = false;
/** Used to keep track of indentdepth for traceIn/Out */
protected int traceDepth = 0;
public CharScanner() {
text = new ANTLRStringBuffer();
hashString = new ANTLRHashString(this);
setTokenObjectClass("antlr.CommonToken");
}
public CharScanner(InputBuffer cb) { // SAS: use generic buffer
this();
inputState = new LexerSharedInputState(cb);
}
public CharScanner(LexerSharedInputState sharedState) {
this();
inputState = sharedState;
}
public void append(char c) {
if ( saveConsumedInput ) {
text.append(c);
}
}
public void append(String s) {
if ( saveConsumedInput ) {
text.append(s);
}
}
public void commit() {
inputState.input.commit();
}
public void consume() throws CharStreamException {
if (inputState.guessing == 0) {
char c = LA(1);
if (caseSensitive) {
append(c);
} else {
// use input.LA(), not LA(), to get original case
// CharScanner.LA() would toLower it.
append(inputState.input.LA(1));
}
if ( c=='\t' ) {
tab();
}
else {
inputState.column++;
}
}
inputState.input.consume();
}
/** Consume chars until one matches the given char */
public void consumeUntil(int c) throws CharStreamException {
while (LA(1) != EOF_CHAR && LA(1) != c)
{
consume();
}
}
/** Consume chars until one matches the given set */
public void consumeUntil(BitSet set) throws CharStreamException {
while (LA(1) != EOF_CHAR && !set.member(LA(1))) {
consume();
}
}
public boolean getCaseSensitive() { return caseSensitive; }
public final boolean getCaseSensitiveLiterals() { return caseSensitiveLiterals; }
public int getColumn() {
return inputState.column;
}
public void setColumn(int c) {
inputState.column = c;
}
public boolean getCommitToPath() { return commitToPath; }
public String getFilename() {return inputState.filename;}
public InputBuffer getInputBuffer() {
return inputState.input;
}
public LexerSharedInputState getInputState() {
return inputState;
}
public void setInputState(LexerSharedInputState state) {
inputState = state;
}
public int getLine() { return inputState.line; }
/** return a copy of the current text buffer */
public String getText() {
return text.toString();
}
public Token getTokenObject() {
return _returnToken;
}
public char LA(int i) throws CharStreamException {
if (caseSensitive) {
return inputState.input.LA(i);
} else {
return toLower(inputState.input.LA(i));
}
}
protected Token makeToken(int t) {
try {
Token tok = (Token)tokenObjectClass.newInstance();
tok.setType(t);
tok.setColumn(inputState.tokenStartColumn);
tok.setLine(inputState.tokenStartLine);
// tracking real start line now: tok.setLine(inputState.line);
return tok;
}
catch (InstantiationException ie) {
panic("can't instantiate token: "+tokenObjectClass);
}
catch (IllegalAccessException iae) {
panic("Token class is not accessible"+tokenObjectClass);
}
return Token.badToken;
}
public int mark() {
return inputState.input.mark();
}
public void match(char c) throws MismatchedCharException, CharStreamException {
if ( LA(1) != c ) {
throw new MismatchedCharException(LA(1), c, false, this);
}
consume();
}
public void match(BitSet b) throws MismatchedCharException, CharStreamException {
if ( !b.member(LA(1)) ) {
throw new MismatchedCharException(LA(1), b, false, this);
} else {
consume();
}
}
public void match(String s) throws MismatchedCharException, CharStreamException {
int len = s.length();
for (int i=0; i<len; i++) {
if ( LA(1) != s.charAt(i) ) {
throw new MismatchedCharException(LA(1), s.charAt(i), false, this);
}
consume();
}
}
public void matchNot(char c) throws MismatchedCharException, CharStreamException {
if ( LA(1) == c ) {
throw new MismatchedCharException(LA(1), c, true, this);
}
consume();
}
public void matchRange(char c1, char c2) throws MismatchedCharException, CharStreamException {
if ( LA(1) < c1 || LA(1) > c2 ) throw new MismatchedCharException(LA(1), c1, c2, false, this);
consume();
}
public void newline() {
inputState.line++;
inputState.column = 1;
}
/** advance the current column number by an appropriate amount.
* If you do not override this to specify how much to jump for
* a tab, then tabs are counted as one char. This method is
* called from consume().
*/
public void tab() {
// update inputState.column as function of
// inputState.column and tab stops.
// For example, if tab stops are columns 1 and 5 etc...
// and column is 3, then add 2 to column.
inputState.column++;
}
public void panic() {
System.err.println("CharScanner: panic");
System.exit(1);
}
public void panic(String s) {
System.err.println("CharScanner; panic: "+s);
System.exit(1);
}
/** Parser error-reporting function can be overridden in subclass */
public void reportError(RecognitionException ex) {
System.err.println(ex);
}
/** Parser error-reporting function can be overridden in subclass */
public void reportError(String s) {
if ( getFilename()==null ) {
System.err.println("error: " + s);
}
else {
System.err.println(getFilename()+": error: " + s);
}
}
/** Parser warning-reporting function can be overridden in subclass */
public void reportWarning(String s) {
if ( getFilename()==null ) {
System.err.println("warning: "+s);
}
else {
System.err.println(getFilename()+": warning: " + s);
}
}
public void resetText() {
text.setLength(0);
inputState.tokenStartColumn = inputState.column;
inputState.tokenStartLine = inputState.line;
}
public void rewind(int pos) {
inputState.input.rewind(pos);
}
public void setCaseSensitive(boolean t) { caseSensitive = t; }
public void setCommitToPath(boolean commit) { commitToPath = commit; }
public void setFilename(String f) {inputState.filename=f;}
public void setLine(int line) { inputState.line = line; }
public void setText(String s) {
resetText();
text.append(s);
}
public void setTokenObjectClass(String cl) {
try {
tokenObjectClass = Class.forName(cl);
}
catch (ClassNotFoundException ce) {
panic("ClassNotFoundException: "+cl);
}
}
// Test the token text against the literals table
// Override this method to perform a different literals test
public int testLiteralsTable(int ttype) {
hashString.setBuffer(text.getBuffer(), text.length());
Integer literalsIndex = (Integer)literals.get(hashString);
if (literalsIndex != null) {
ttype = literalsIndex.intValue();
}
return ttype;
}
/** Test the text passed in against the literals table
* Override this method to perform a different literals test
* This is used primarily when you want to test a portion of
* a token.
*/
public int testLiteralsTable(String text, int ttype) {
ANTLRHashString s = new ANTLRHashString(text, this);
Integer literalsIndex = (Integer)literals.get(s);
if (literalsIndex != null) {
ttype = literalsIndex.intValue();
}
return ttype;
}
// Override this method to get more specific case handling
public char toLower(char c) {
return Character.toLowerCase(c);
}
public void traceIndent() {
for( int i = 0; i < traceDepth; i++ )
System.out.print(" ");
}
public void traceIn(String rname) throws CharStreamException {
traceDepth += 1;
traceIndent();
System.out.println("> lexer "+rname+"; c==" + LA(1));
}
public void traceOut(String rname) throws CharStreamException {
traceIndent();
System.out.println("< lexer "+rname+"; c==" + LA(1));
traceDepth -= 1;
}
/** This method is called by YourLexer.nextToken() when the lexer has
* hit EOF condition. EOF is NOT a character.
* This method is not called if EOF is reached during
* syntactic predicate evaluation or during evaluation
* of normal lexical rules, which presumably would be
* an IOException. This traps the "normal" EOF condition.
*
* uponEOF() is called after the complete evaluation of
* the previous token and only if your parser asks
* for another token beyond that last non-EOF token.
*
* You might want to throw token or char stream exceptions
* like: "Heh, premature eof" or a retry stream exception
* ("I found the end of this file, go back to referencing file").
*/
public void uponEOF() throws TokenStreamException, CharStreamException {
}
}
1.1 e/src/jsrc/antlr/CharStreamException.java
Index: CharStreamException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharStreamException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**
* Anything that goes wrong while generating a stream of characters
*/
public class CharStreamException extends ANTLRException {
/**
* CharStreamException constructor comment.
* @param s java.lang.String
*/
public CharStreamException(String s) {
super(s);
}
}
1.1 e/src/jsrc/antlr/CharStreamIOException.java
Index: CharStreamIOException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CharStreamIOException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.IOException;
/**
* Wrap an IOException in a CharStreamException
*/
public class CharStreamIOException extends CharStreamException {
public IOException io;
public CharStreamIOException(IOException io) {
super(io.getMessage());
this.io = io;
}
}
1.1 e/src/jsrc/antlr/CodeGenerator.java
Index: CodeGenerator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CodeGenerator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.PrintWriter; // SAS: for proper text i/o
import java.io.IOException;
import java.io.FileWriter; // SAS: for proper text i/o
import antlr.collections.impl.Vector;
import antlr.collections.impl.BitSet;
/**A generic ANTLR code generator. All code generators
* Derive from this class.
*
* <p>
* A CodeGenerator knows about a Grammar data structure and
* a grammar analyzer. The Grammar is walked to generate the
* appropriate code for both a parser and lexer (if present).
* This interface may change slightly so that the lexer is
* itself living inside of a Grammar object (in which case,
* this class generates only one recognizer). The main method
* to call is <tt>gen()</tt>, which initiates all code gen.
*
* <p>
* The interaction of the code generator with the analyzer is
* simple: each subrule block calls deterministic() before generating
* code for the block. Method deterministic() sets lookahead caches
* in each Alternative object. Technically, a code generator
* doesn't need the grammar analyzer if all lookahead analysis
* is done at runtime, but this would result in a slower parser.
*
* <p>
* This class provides a set of support utilities to handle argument
* list parsing and so on.
*
* @author Terence Parr, John Lilley
* @version 2.00a
* @see antlr.JavaCodeGenerator
* @see antlr.DiagnosticCodeGenerator
* @see antlr.LLkAnalyzer
* @see antlr.Grammar
* @see antlr.AlternativeElement
* @see antlr.Lookahead
*/
public abstract class CodeGenerator {
/** Current tab indentation for code output */
protected int tabs=0;
/** Current output Stream */
transient protected PrintWriter currentOutput; // SAS: for proper text i/o
/** The grammar for which we generate code */
protected Grammar grammar = null;
/** List of all bitsets that must be dumped. These are Vectors of BitSet. */
protected Vector bitsetsUsed;
/** The antlr Tool */
protected Tool tool;
/** The grammar behavior */
protected DefineGrammarSymbols behavior;
/** The LLk analyzer */
protected LLkGrammarAnalyzer analyzer;
/** Object used to format characters in the target language.
* subclass must initialize this to the language-specific formatter
*/
protected CharFormatter charFormatter;
/** Use option "codeGenDebug" to generate debugging output */
protected boolean DEBUG_CODE_GENERATOR = false;
/** Default values for code-generation thresholds */
protected static final int DEFAULT_MAKE_SWITCH_THRESHOLD = 2;
protected static final int DEFAULT_BITSET_TEST_THRESHOLD = 4;
/** This is a hint for the language-specific code generator.
* A switch() or language-specific equivalent will be generated instead
* of a series of if/else statements for blocks with number of alternates
* greater than or equal to this number of non-predicated LL(1) alternates.
* This is modified by the grammar option "codeGenMakeSwitchThreshold"
*/
protected int makeSwitchThreshold = DEFAULT_MAKE_SWITCH_THRESHOLD;
/** This is a hint for the language-specific code generator.
* A bitset membership test will be generated instead of an
* ORed series of LA(k) comparisions for lookahead sets with
* degree greater than or equal to this value.
* This is modified by the grammar option "codeGenBitsetTestThreshold"
*/
protected int bitsetTestThreshold = DEFAULT_BITSET_TEST_THRESHOLD;
private static boolean OLD_ACTION_TRANSLATOR = true;
public static String TokenTypesFileSuffix = "TokenTypes";
public static String TokenTypesFileExt = ".txt";
/** Construct code generator base class */
public CodeGenerator() {}
/** Output a String to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output
*/
protected void _print(String s) {
if (s != null) {
currentOutput.print(s);
}
}
/** Print an action without leading tabs, attempting to
* preserve the current indentation level for multi-line actions
* Ignored if string is null.
* @param s The action string to output
*/
protected void _printAction(String s) {
if (s == null) {
return;
}
// Skip leading newlines, tabs and spaces
int start = 0;
while (start < s.length() && Character.isSpaceChar(s.charAt(start)) )
{
start++;
}
// Skip leading newlines, tabs and spaces
int end = s.length()-1;
while ( end > start && Character.isSpaceChar(s.charAt(end)) )
{
end--;
}
char c=0;
for (int i = start; i <= end;)
{
c = s.charAt(i);
i++;
boolean newline = false;
switch (c)
{
case '\n':
newline=true;
break;
case '\r':
if ( i<=end && s.charAt(i)=='\n' ) {
i++;
}
newline=true;
break;
default:
currentOutput.print(c);
break;
}
if ( newline ) {
currentOutput.println();
printTabs();
// Absorb leading whitespace
while (i <= end && Character.isSpaceChar(s.charAt(i)) ) {
i++;
}
newline=false;
}
}
currentOutput.println();
}
/** Output a String followed by newline, to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output
*/
protected void _println(String s) {
if (s != null) {
currentOutput.println(s);
}
}
/** Test if a set element array represents a contiguous range.
* @param elems The array of elements representing the set, usually from BitSet.toArray().
* @return true if the elements are a contiguous range (with two or more).
*/
public static boolean elementsAreRange(int[] elems) {
if (elems.length==0) {
return false;
}
int begin = elems[0];
int end = elems[elems.length-1];
if ( elems.length<=2 ) {
// Not enough elements for a range expression
return false;
}
if ( end-begin+1 > elems.length ) {
// The set does not represent a contiguous range
return false;
}
int v = begin+1;
for (int i=1; i<elems.length-1; i++) {
if ( v != elems[i] ) {
// The set does not represent a contiguous range
return false;
}
v++;
}
return true;
}
/** Get the identifier portion of an argument-action token.
* The ID of an action is assumed to be a trailing identifier.
* Specific code-generators may want to override this
* if the language has unusual declaration syntax.
* @param t The action token
* @return A string containing the text of the identifier
*/
protected String extractIdOfAction(Token t) {
return extractIdOfAction(t.getText(), t.getLine());
}
/** Get the identifier portion of an argument-action.
* The ID of an action is assumed to be a trailing identifier.
* Specific code-generators may want to override this
* if the language has unusual declaration syntax.
* @param s The action text
* @param line Line used for error reporting.
* @return A string containing the text of the identifier
*/
protected String extractIdOfAction(String s, int line) {
s = removeAssignmentFromDeclaration(s);
// Search back from the end for a non alphanumeric. That marks the
// beginning of the identifier
for (int i = s.length()-2; i >=0; i--)
{
// TODO: make this work for language-independent identifiers?
if (!Character.isLetterOrDigit(s.charAt(i)) && s.charAt(i) != '_')
{
// Found end of type part
return s.substring(i+1);
}
}
// Something is bogus, but we cannot parse the language-specific
// actions any better. The compiler will have to catch the problem.
tool.warning("Ill-formed action", grammar.getFilename(), line);
return "";
}
/** Get the type string out of an argument-action token.
* The type of an action is assumed to precede a trailing identifier
* Specific code-generators may want to override this
* if the language has unusual declaration syntax.
* @param t The action token
* @return A string containing the text of the type
*/
protected String extractTypeOfAction(Token t) {
return extractTypeOfAction(t.getText(), t.getLine());
}
/** Get the type portion of an argument-action.
* The type of an action is assumed to precede a trailing identifier
* Specific code-generators may want to override this
* if the language has unusual declaration syntax.
* @param s The action text
* @param line Line used for error reporting.
* @return A string containing the text of the type
*/
protected String extractTypeOfAction(String s, int line) {
s = removeAssignmentFromDeclaration(s);
// Search back from the end for a non alphanumeric. That marks the
// beginning of the identifier
for (int i = s.length()-2; i >=0; i--)
{
// TODO: make this work for language-independent identifiers?
if (!Character.isLetterOrDigit(s.charAt(i)) && s.charAt(i) != '_')
{
// Found end of type part
return s.substring(0,i+1);
}
}
// Something is bogus, but we cannot parse the language-specific
// actions any better. The compiler will have to catch the problem.
tool.warning("Ill-formed action", grammar.getFilename(), line);
return "";
}
/** Generate the code for all grammars
*/
public abstract void gen();
/** Generate code for the given grammar element.
* @param action The {...} action to generate
*/
public abstract void gen(ActionElement action);
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public abstract void gen(AlternativeBlock blk);
/** Generate code for the given grammar element.
* @param end The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public abstract void gen(BlockEndElement end);
/** Generate code for the given grammar element.
* @param atom The character literal reference to generate
*/
public abstract void gen(CharLiteralElement atom);
/** Generate code for the given grammar element.
* @param r The character-range reference to generate
*/
public abstract void gen(CharRangeElement r);
/** Generate the code for a parser */
public abstract void gen(LexerGrammar g) throws IOException;
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public abstract void gen(OneOrMoreBlock blk);
/** Generate the code for a parser */
public abstract void gen(ParserGrammar g) throws IOException;
/** Generate code for the given grammar element.
* @param rr The rule-reference to generate
*/
public abstract void gen(RuleRefElement rr);
/** Generate code for the given grammar element.
* @param atom The string-literal reference to generate
*/
public abstract void gen(StringLiteralElement atom);
/** Generate code for the given grammar element.
* @param r The token-range reference to generate
*/
public abstract void gen(TokenRangeElement r);
/** Generate code for the given grammar element.
* @param atom The token-reference to generate
*/
public abstract void gen(TokenRefElement atom);
/** Generate code for the given grammar element.
* @param blk The tree to generate code for.
*/
public abstract void gen(TreeElement t);
/** Generate the code for a parser */
public abstract void gen(TreeWalkerGrammar g) throws IOException;
/** Generate code for the given grammar element.
* @param wc The wildcard element to generate
*/
public abstract void gen(WildcardElement wc);
/** Generate code for the given grammar element.
* @param blk The (...)* block to generate
*/
public abstract void gen(ZeroOrMoreBlock blk);
/** Generate the token types as a text file for persistence across shared lexer/parser */
protected void genTokenInterchange(TokenManager tm) throws IOException {
// Open the token output Java file and set the currentOutput stream
String fName = tm.getName() + TokenTypesFileSuffix+TokenTypesFileExt;
currentOutput = antlr.Tool.openOutputFile(fName);
println("// $ANTLR "+Tool.version+": "+
Tool.fileMinusPath(tool.grammarFile)+
" -> "+
fName+
"$");
tabs = 0;
// Header
println(tm.getName() + " // output token vocab name");
// Generate a definition for each token type
Vector v = tm.getVocabulary();
for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("gen persistence file entry for: "+s);
}
if (s != null && !s.startsWith("<") ) {
// if literal, find label
if ( s.startsWith("\"") ) {
StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
if ( sl!=null && sl.label != null ) {
print(sl.label+"=");
}
println(s + "=" + i);
}
else {
print(s);
// check for a paraphrase
TokenSymbol ts = (TokenSymbol)tm.getTokenSymbol(s);
if ( ts==null ) {
tool.warning("undefined token symbol: "+s);
}
else {
if ( ts.getParaphrase()!=null ) {
print("("+ts.getParaphrase()+")");
}
}
println("=" + i);
}
}
}
// Close the tokens output file
currentOutput.close();
currentOutput = null;
}
/** Process a string for an simple expression for use in xx/action.g
* it is used to cast simple tokens/references to the right type for
* the generated language.
* @param str A String.
*/
public String processStringForASTConstructor( String str )
{
return str;
}
/** Get a string for an expression to generate creation of an AST subtree.
* @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
*/
public abstract String getASTCreateString(Vector v);
/** Get a string for an expression to generate creating of an AST node
* @param str The text of the arguments to the AST construction
*/
public abstract String getASTCreateString(GrammarAtom atom, String str);
/** Given the index of a bitset in the bitset list, generate a unique name.
* Specific code-generators may want to override this
* if the language does not allow '_' or numerals in identifiers.
* @param index The index of the bitset in the bitset list.
*/
protected String getBitsetName(int index)
{
return "_tokenSet_" + index;
}
public static String lexerRuleName(String id) {
return "m"+id;
}
/** Map an identifier to it's corresponding tree-node variable.
* This is context-sensitive, depending on the rule and alternative
* being generated
* @param id The identifier name to map
* @param forInput true if the input tree node variable is to be returned, otherwise the output variable is returned.
* @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
*/
public abstract String mapTreeId(String id, ActionTransInfo tInfo);
/** Add a bitset to the list of bitsets to be generated.
* if the bitset is already in the list, ignore the request.
* Always adds the bitset to the end of the list, so the
* caller can rely on the position of bitsets in the list.
* The returned position can be used to format the bitset
* name, since it is invariant.
* @param p Bit set to mark for code generation
* @param forParser true if the bitset is used for the parser, false for the lexer
* @return The position of the bitset in the list.
*/
protected int markBitsetForGen(BitSet p) {
// Is the bitset (or an identical one) already marked for gen?
for (int i = 0; i < bitsetsUsed.size(); i++)
{
BitSet set = (BitSet)bitsetsUsed.elementAt(i);
if (p.equals(set))
{
// Use the identical one already stored
return i;
}
}
// Add the new bitset
bitsetsUsed.appendElement(p.clone());
return bitsetsUsed.size()-1;
}
/** Output tab indent followed by a String, to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output.
*/
protected void print(String s) {
if (s != null) {
printTabs();
currentOutput.print(s);
}
}
/** Print an action with leading tabs, attempting to
* preserve the current indentation level for multi-line actions
* Ignored if string is null.
* @param s The action string to output
*/
protected void printAction(String s) {
if (s != null) {
printTabs();
_printAction(s);
}
}
/** Output tab indent followed by a String followed by newline,
* to the currentOutput stream. Ignored if string is null.
* @param s The string to output
*/
protected void println(String s) {
if (s != null) {
printTabs();
currentOutput.println(s);
}
}
/** Output the current tab indentation. This outputs the number of tabs
* indicated by the "tabs" variable to the currentOutput stream.
*/
protected void printTabs() {
for (int i=1; i<=tabs; i++) {
currentOutput.print("\t");
}
}
/** Lexically process tree-specifiers in the action.
* This will replace #id and #(...) with the appropriate
* function calls and/or variables.
*
* This is the default Java action translator, but I have made
* it work for C++ also.
*/
protected String processActionForTreeSpecifiers(String actionStr, int line, RuleBlock currentRule, ActionTransInfo tInfo) {
if ( actionStr==null || actionStr.length()==0 ) return null;
// The action trans info tells us (at the moment) whether an
// assignment was done to the rule's tree root.
if (grammar==null) return actionStr;
if ( (grammar.buildAST && actionStr.indexOf('#') != -1) ||
grammar instanceof TreeWalkerGrammar ||
(grammar instanceof LexerGrammar && actionStr.indexOf('$') != -1) ) {
// Create a lexer to read an action and return the translated version
antlr.actions.java.ActionLexer lexer = new antlr.actions.java.ActionLexer(actionStr, currentRule, this, tInfo);
lexer.setLineOffset(line);
lexer.setTool(tool);
try {
lexer.mACTION(true);
actionStr = lexer.getTokenObject().getText();
// System.out.println("action translated: "+actionStr);
// System.out.println("trans info is "+tInfo);
}
catch (RecognitionException ex) {
lexer.reportError(ex);
return actionStr;
}
catch (TokenStreamException tex) {
antlr.Tool.panic("Error reading action:"+actionStr);
return actionStr;
}
catch (CharStreamException io) {
antlr.Tool.panic("Error reading action:"+actionStr);
return actionStr;
}
}
return actionStr;
}
/**
* Remove the assignment portion of a declaration, if any.
* @param d the declaration
* @return the declaration without any assignment portion
*/
protected String removeAssignmentFromDeclaration(String d) {
// If d contains an equal sign, then it's a declaration
// with an initialization. Strip off the initialization part.
if (d.indexOf('=') >= 0) d = d.substring(0, d.indexOf('=')).trim();
return d;
}
/** Set all fields back like one just created */
private void reset() {
tabs = 0;
// Allocate list of bitsets tagged for code generation
bitsetsUsed = new Vector();
currentOutput = null;
grammar = null;
DEBUG_CODE_GENERATOR = false;
makeSwitchThreshold = DEFAULT_MAKE_SWITCH_THRESHOLD;
bitsetTestThreshold = DEFAULT_BITSET_TEST_THRESHOLD;
}
public static String reverseLexerRuleName(String id) {
return id.substring(1,id.length());
}
public void setAnalyzer(LLkGrammarAnalyzer analyzer_) {
analyzer = analyzer_;
}
public void setBehavior(DefineGrammarSymbols behavior_) {
behavior = behavior_;
}
/** Set a grammar for the code generator to use */
protected void setGrammar(Grammar g) {
reset();
grammar = g;
// Lookup make-switch threshold in the grammar generic options
if (grammar.hasOption("codeGenMakeSwitchThreshold")) {
try {
makeSwitchThreshold = grammar.getIntegerOption("codeGenMakeSwitchThreshold");
//System.out.println("setting codeGenMakeSwitchThreshold to " + makeSwitchThreshold);
} catch (NumberFormatException e) {
tool.error(
"option 'codeGenMakeSwitchThreshold' must be an integer",
grammar.getClassName(),
grammar.getOption("codeGenMakeSwitchThreshold").getLine()
);
}
}
// Lookup bitset-test threshold in the grammar generic options
if (grammar.hasOption("codeGenBitsetTestThreshold")) {
try {
bitsetTestThreshold = grammar.getIntegerOption("codeGenBitsetTestThreshold");
//System.out.println("setting codeGenBitsetTestThreshold to " + bitsetTestThreshold);
} catch (NumberFormatException e) {
tool.error(
"option 'codeGenBitsetTestThreshold' must be an integer",
grammar.getClassName(),
grammar.getOption("codeGenBitsetTestThreshold").getLine()
);
}
}
// Lookup debug code-gen in the grammar generic options
if (grammar.hasOption("codeGenDebug")) {
Token t = grammar.getOption("codeGenDebug");
if (t.getText().equals("true")) {
//System.out.println("setting code-generation debug ON");
DEBUG_CODE_GENERATOR = true;
}
else if (t.getText().equals("false")) {
//System.out.println("setting code-generation debug OFF");
DEBUG_CODE_GENERATOR = false;
}
else {
tool.error("option 'codeGenDebug' must be true or false", grammar.getClassName(), t.getLine());
}
}
}
public void setTool(Tool tool_) {
tool = tool_;
}
}
1.1 e/src/jsrc/antlr/CommonAST.java
Index: CommonAST.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CommonAST.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
/** Common AST node implementation */
public class CommonAST extends BaseAST {
int ttype = Token.INVALID_TYPE;
String text;
/** Get the token text for this node */
public String getText() { return text; }
/** Get the token type for this node */
public int getType() { return ttype; }
public void initialize(int t, String txt) {
setType(t);
setText(txt);
}
public void initialize(AST t) {
setText(t.getText());
setType(t.getType());
}
public CommonAST() {
}
public CommonAST(Token tok) {
initialize(tok);
}
public void initialize(Token tok) {
setText(tok.getText());
setType(tok.getType());
}
/** Set the token text for this node */
public void setText(String text_) {
text = text_;
}
/** Set the token type for this node */
public void setType(int ttype_) {
ttype = ttype_;
}
}
1.1 e/src/jsrc/antlr/CommonASTWithHiddenTokens.java
Index: CommonASTWithHiddenTokens.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CommonASTWithHiddenTokens.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** A CommonAST whose initialization copies hidden token
* information from the Token used to create a node.
*/
public class CommonASTWithHiddenTokens extends CommonAST {
protected CommonHiddenStreamToken hiddenBefore, hiddenAfter; // references to hidden tokens
public CommonASTWithHiddenTokens() {
super();
}
public CommonASTWithHiddenTokens(Token tok) {
super(tok);
}
public CommonHiddenStreamToken getHiddenAfter() { return hiddenAfter; }
public CommonHiddenStreamToken getHiddenBefore() { return hiddenBefore; }
public void initialize(Token tok) {
CommonHiddenStreamToken t = (CommonHiddenStreamToken)tok;
super.initialize(t);
hiddenBefore = t.getHiddenBefore();
hiddenAfter = t.getHiddenAfter();
}
}
1.1 e/src/jsrc/antlr/CommonHiddenStreamToken.java
Index: CommonHiddenStreamToken.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CommonHiddenStreamToken.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class CommonHiddenStreamToken extends CommonToken {
protected CommonHiddenStreamToken hiddenBefore;
protected CommonHiddenStreamToken hiddenAfter;
public CommonHiddenStreamToken() {
super();
}
public CommonHiddenStreamToken(int t, String txt) {
super(t, txt);
}
public CommonHiddenStreamToken(String s) {
super(s);
}
public CommonHiddenStreamToken getHiddenAfter() {
return hiddenAfter;
}
public CommonHiddenStreamToken getHiddenBefore() {
return hiddenBefore;
}
protected void setHiddenAfter(CommonHiddenStreamToken t) {
hiddenAfter = t;
}
protected void setHiddenBefore(CommonHiddenStreamToken t) {
hiddenBefore = t;
}
}
1.1 e/src/jsrc/antlr/CommonToken.java
Index: CommonToken.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CommonToken.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class CommonToken extends Token {
// most tokens will want line and text information
protected int line;
protected String text = null;
protected int col;
public CommonToken() {}
public CommonToken(int t, String txt) {
type = t;
setText(txt);
}
public CommonToken(String s) { text = s; }
public int getLine() { return line; }
public String getText() { return text; }
public void setLine(int l) { line = l; }
public void setText(String s) { text = s; }
public String toString() {
return "[\""+getText()+"\",<"+type+">,line="+line+",col="+col+"]";
}
/** Return token's start column */
public int getColumn() { return col; }
public void setColumn(int c) { col = c; }
}
1.1 e/src/jsrc/antlr/CppBlockFinishingInfo.java
Index: CppBlockFinishingInfo.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CppBlockFinishingInfo.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
// C++ code generator by Pete Wells: pete@yamuna.demon.co.uk
class CppBlockFinishingInfo {
String postscript; // what to generate to terminate block
boolean generatedSwitch;// did block finish with "default:" of switch?
boolean generatedAnIf;
/** When generating an if or switch, end-of-token lookahead sets
* will become the else or default clause, don't generate an
* error clause in this case.
*/
boolean needAnErrorClause;
public CppBlockFinishingInfo() {
postscript=null;
generatedSwitch=false;
needAnErrorClause = true;
}
public CppBlockFinishingInfo(String ps, boolean genS, boolean generatedAnIf, boolean n) {
postscript = ps;
generatedSwitch = genS;
this.generatedAnIf = generatedAnIf;
needAnErrorClause = n;
}
}
1.1 e/src/jsrc/antlr/CppCharFormatter.java
Index: CppCharFormatter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CppCharFormatter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
// C++ code generator by Pete Wells: pete@yamuna.demon.co.uk
class CppCharFormatter implements CharFormatter {
/** Given a character value, return a string representing the character
* that can be embedded inside a string literal or character literal
* This works for Java/C/C++ code-generation and languages with compatible
* special-character-escapment.
* Code-generators for languages should override this method.
* @param c The character of interest.
* @param forCharLiteral true to escape for char literal, false for string literal
*/
public String escapeChar(int c, boolean forCharLiteral) {
switch (c) {
case '\n' : return "\\n";
case '\t' : return "\\t";
case '\r' : return "\\r";
case '\\' : return "\\\\";
case '\'' : return forCharLiteral ? "\\'" : "'";
case '"' : return forCharLiteral ? "\"" : "\\\"";
default :
if ( c<' '||c>126 ) {
if (c > 255) {
return "\\u" + Integer.toString(c,16);
}
else {
return "\\" + Integer.toString(c,8);
}
}
else {
return String.valueOf((char)c);
}
}
}
/** Converts a String into a representation that can be use as a literal
* when surrounded by double-quotes.
* @param s The String to be changed into a literal
*/
public String escapeString(String s)
{
String retval = new String();
for (int i = 0; i < s.length(); i++)
{
retval += escapeChar(s.charAt(i), false);
}
return retval;
}
/** Given a character value, return a string representing the character
* literal that can be recognized by the target language compiler.
* This works for languages that use single-quotes for character literals.
* Code-generators for languages should override this method.
* @param c The character of interest.
*/
public String literalChar(int c) {
return "static_cast<unsigned char>('" + escapeChar(c, true) + "')";
}
/** Converts a String into a string literal
* This works for languages that use double-quotes for string literals.
* Code-generators for languages should override this method.
* @param s The String to be changed into a literal
*/
public String literalString(String s)
{
return "\"" + escapeString(s) + "\"";
}
}
1.1 e/src/jsrc/antlr/CppCodeGenerator.java
Index: CppCodeGenerator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: CppCodeGenerator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
// C++ code generator by Pete Wells: pete@yamuna.demon.co.uk
// #line generation contributed by: Ric Klaren <klaren@cs.utwente.nl>
import java.util.Enumeration;
import java.util.Hashtable;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;
/**Generate MyParser.cpp, MyParser.hpp, MyLexer.cpp, MyLexer.hpp and MyParserTokenTypes.hpp */
public class CppCodeGenerator extends CodeGenerator {
// non-zero if inside syntactic predicate generation
protected int syntacticPredLevel = 0;
// Are we generating ASTs (for parsers and tree parsers) right now?
protected boolean genAST = false;
// Are we saving the text consumed (for lexers) right now?
protected boolean saveText = false;
// Generate #line's
protected boolean genHashLines = true;
// Used to keep track of lineno in output
protected int outputLine;
protected String outputFile;
// Grammar parameters set up to handle different grammar classes.
// These are used to get instanceof tests out of code generation
boolean usingCustomAST = false;
String labeledElementType;
String labeledElementASTType; // mostly the same as labeledElementType except in parsers
String labeledElementASTInit;
String labeledElementInit;
String commonExtraArgs;
String commonExtraParams;
String commonLocalVars;
String lt1Value;
String exceptionThrown;
String throwNoViable;
// Tracks the rule being generated. Used for mapTreeId
RuleBlock currentRule;
// Tracks the rule or labeled subrule being generated. Used for AST generation.
String currentASTResult;
// Mapping between the ids used in the current alt, and the
// names of variables used to represent their AST values.
Hashtable treeVariableMap = new Hashtable();
// Count of unnamed generated variables
int astVarNumber = 1;
// Special value used to mark duplicate in treeVariableMap
protected static final String NONUNIQUE = new String();
public static final int caseSizeThreshold = 127; // ascii is max
private Vector semPreds;
private static String namespaceStd = "ANTLR_USE_NAMESPACE(std)";
private static String namespaceAntlr = "ANTLR_USE_NAMESPACE(antlr)";
private static NameSpace nameSpace = null;
private static final String preIncludeCpp = "pre_include_cpp";
private static final String preIncludeHpp = "pre_include_hpp";
private static final String postIncludeCpp = "post_include_cpp";
private static final String postIncludeHpp = "post_include_hpp";
/** Create a C++ code-generator using the given Grammar.
* The caller must still call setTool, setBehavior, and setAnalyzer
* before generating code.
*/
public CppCodeGenerator() {
super();
charFormatter = new CppCharFormatter();
}
/** Adds a semantic predicate string to the sem pred vector
These strings will be used to build an array of sem pred names
when building a debugging parser. This method should only be
called when the debug option is specified
*/
protected int addSemPred(String predicate) {
semPreds.appendElement(predicate);
return semPreds.size()-1;
}
public void exitIfError() {
if (tool.hasError) {
System.out.println("Exiting due to errors.");
System.exit(1);
}
}
protected int countLines( String s )
{
int lines = 0;
for( int i = 0; i < s.length(); i++ )
{
if( s.charAt(i) == '\n' )
lines++;
}
return lines;
}
/** Output a String to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output
*/
protected void _print(String s) {
if (s != null) {
outputLine += countLines(s);
currentOutput.print(s);
}
}
/** Print an action without leading tabs, attempting to
* preserve the current indentation level for multi-line actions
* Ignored if string is null.
* @param s The action string to output
*/
protected void _printAction(String s) {
if (s != null) {
outputLine += countLines(s)+1;
super._printAction(s);
}
}
/** Print an action stored in a token surrounded by #line stuff */
public void printAction(Token t) {
if (t != null) {
genLineNo(t.getLine());
printTabs();
_printAction(t.getText());
genLineNo2();
}
}
/** Print a header action by #line stuff
* @param name The name of the header part
*/
public void printHeaderAction(String name) {
Token a = (antlr.Token)behavior.headerActions.get(name);
if (a != null) {
genLineNo(a.getLine());
println(a.getText());
genLineNo2();
}
}
/** Output a String followed by newline, to the currentOutput stream.
* Ignored if string is null.
* @param s The string to output
*/
protected void _println(String s) {
if (s != null) {
outputLine += countLines(s)+1;
currentOutput.println(s);
}
}
/** Output tab indent followed by a String followed by newline,
* to the currentOutput stream. Ignored if string is null.
* @param s The string to output
*/
protected void println(String s) {
if (s != null) {
printTabs();
outputLine += countLines(s)+1;
currentOutput.println(s);
}
}
/** Generate a #line or // line depending on options */
public void genLineNo(int line) {
if ( line == 0 ) {
line++;
}
if( genHashLines )
_println("#line "+line+" \""+Tool.fileMinusPath(tool.grammarFile)+"\"");
else
println("// line "+line+" \""+Tool.fileMinusPath(tool.grammarFile)+"\"");
}
/** Generate a #line or // line depending on options */
public void genLineNo(GrammarElement el)
{
if( el != null )
genLineNo(el.getLine());
}
/** Generate a #line or // line depending on options */
public void genLineNo(Token t)
{
if (t != null)
genLineNo(t.getLine());
}
/** Generate a #line or // line depending on options */
public void genLineNo2()
{
if( genHashLines )
{
_println("#line "+(outputLine+1)+" \""+outputFile+"\"");
}
}
/**Generate the parser, lexer, treeparser, and token types in C++ */
public void gen() {
// Do the code generation
try {
// Loop over all grammars
Enumeration grammarIter = behavior.grammars.elements();
while (grammarIter.hasMoreElements()) {
Grammar g = (Grammar)grammarIter.nextElement();
// Connect all the components to each other
g.setGrammarAnalyzer(analyzer);
g.setCodeGenerator(this);
analyzer.setGrammar(g);
// To get right overloading behavior across hetrogeneous grammars
setupGrammarParameters(g);
g.generate();
exitIfError();
}
// Loop over all token managers (some of which are lexers)
Enumeration tmIter = behavior.tokenManagers.elements();
while (tmIter.hasMoreElements()) {
TokenManager tm = (TokenManager)tmIter.nextElement();
if (!tm.isReadOnly()) {
// Write the token manager tokens as C++
// this must appear before genTokenInterchange so that
// labels are set on string literals
genTokenTypes(tm);
// Write the token manager tokens as plain text
genTokenInterchange(tm);
}
exitIfError();
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
/** Generate code for the given grammar element.
* @param blk The {...} action to generate
*/
public void gen(ActionElement action) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genAction("+action+")");
if ( action.isSemPred ) {
genSemPred(action.actionText, action.line);
}
else {
if ( grammar.hasSyntacticPredicate ) {
println("if ( inputState->guessing==0 ) {");
tabs++;
}
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr = processActionForTreeSpecifiers(action.actionText, action.getLine(), currentRule, tInfo);
if ( tInfo.refRuleRoot!=null ) {
// Somebody referenced "#rule", make sure translated var is valid
// assignment to #rule is left as a ref also, meaning that assignments
// with no other refs like "#rule = foo();" still forces this code to be
// generated (unnecessarily).
println(tInfo.refRuleRoot + " = "+labeledElementASTType+"(currentAST.root);");
}
// dump the translated action
genLineNo(action);
printAction(actionStr);
genLineNo2();
if ( tInfo.assignToRoot ) {
// Somebody did a "#rule=", reset internal currentAST.root
println("currentAST.root = "+tInfo.refRuleRoot+";");
// reset the child pointer too to be last sibling in sibling list
// now use if else in stead of x ? y : z to shut CC 4.2 up.
println("if ( "+tInfo.refRuleRoot+"!="+labeledElementASTInit+" &&");
tabs++;
println(tInfo.refRuleRoot+"->getFirstChild() != "+labeledElementASTInit+" )");
println(" currentAST.child = "+tInfo.refRuleRoot+"->getFirstChild();");
tabs--;
println("else");
tabs++;
println("currentAST.child = "+tInfo.refRuleRoot+";");
tabs--;
println("currentAST.advanceChildToEnd();");
}
if ( grammar.hasSyntacticPredicate ) {
tabs--;
println("}");
}
}
}
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public void gen(AlternativeBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen("+blk+")");
println("{");
genBlockPreamble(blk);
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
CppBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
genBlockFinish(howToFinish, throwNoViable);
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate code for the given grammar element.
* @param blk The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public void gen(BlockEndElement end) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")");
}
/** Generate code for the given grammar element.
* @param blk The character literal reference to generate
*/
public void gen(CharLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genChar("+atom+")");
if ( atom.getLabel()!=null ) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
genMatch(atom);
saveText = oldsaveText;
}
/** Generate code for the given grammar element.
* @param blk The character-range reference to generate
*/
public void gen(CharRangeElement r) {
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " = " + lt1Value + ";");
}
println("matchRange("+textOrChar(r.beginText)+","+textOrChar(r.endText)+");");
}
/** Generate the lexer C++ files */
public void gen(LexerGrammar g) throws IOException {
// If debugging, create a new sempred vector for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof LexerGrammar)) {
tool.panic("Internal error generating lexer");
}
genBody(g);
genInclude(g);
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
String label;
String cnt;
println("{");
genBlockPreamble(blk);
if ( blk.getLabel() != null ) {
cnt = "_cnt_"+blk.getLabel();
}
else {
cnt = "_cnt" + blk.ID;
}
println("int "+cnt+"=0;");
if ( blk.getLabel() != null ) {
label = blk.getLabel();
}
else {
label = "_loop" + blk.ID;
}
println("for (;;) {");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)+ loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("// nongreedy exit test");
println("if ( "+cnt+">=1 && "+predictExit+") goto "+label+";");
}
CppBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(
howToFinish,
"if ( "+cnt+">=1 ) { goto "+label+"; } else {" + throwNoViable + "}"
);
println(cnt+"++;");
tabs--;
println("}");
println(label+":;");
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate the parser C++ file */
public void gen(ParserGrammar g) throws IOException {
// if debugging, set up a new vector to keep track of sempred
// strings for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof ParserGrammar)) {
tool.panic("Internal error generating parser");
}
genBody(g);
genInclude(g);
}
/** Generate code for the given grammar element.
* @param blk The rule-reference to generate
*/
public void gen(RuleRefElement rr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRR("+rr+")");
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rs == null || !rs.isDefined())
{
// Is this redundant???
tool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine());
return;
}
if (!(rs instanceof RuleSymbol))
{
// Is this redundant???
tool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine());
return;
}
genErrorTryForElement(rr);
// AST value for labeled rule refs in tree walker.
// This is not AST construction; it is just the input tree node value.
if ( grammar instanceof TreeWalkerGrammar &&
rr.getLabel() != null &&
syntacticPredLevel == 0 )
{
println(rr.getLabel() + " = (_t == ASTNULL) ? "+labeledElementASTInit+" : "+lt1Value+";");
}
// if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("_saveIndex = text.length();");
}
// Process return value assignment if any
printTabs();
if (rr.idAssign != null)
{
// Warn if the rule has no return type
if (rs.block.returnAction == null)
{
tool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine());
}
_print(rr.idAssign + "=");
} else {
// Warn about return value if any, but not inside syntactic predicate
if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
{
tool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine());
}
}
// Call the rule
GenRuleInvocation(rr);
// if in lexer and ! on element or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text.erase(_saveIndex);");
}
// if not in a syntactic predicate
if (syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
grammar.buildAST && rr.getLabel() != null ||
(genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
)
);
if (doNoGuessTest) {
println("if (inputState->guessing==0) {");
tabs++;
}
if (grammar.buildAST && rr.getLabel() != null) {
// always gen variable for rule return on labeled rules
// FIXME: maybe broken....
println(rr.getLabel() + "_AST = "+labeledElementASTType+"(returnAST);");
}
if (genAST) {
switch (rr.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
// println("theASTFactory.addASTChild(currentAST, returnAST);");
println("astFactory.addASTChild(currentAST, "+namespaceAntlr+"RefAST(returnAST));");
break;
case GrammarElement.AUTO_GEN_CARET:
tool.error("Internal: encountered ^ after rule reference");
break;
default:
break;
}
}
// if a lexer and labeled, Token label defined at rule level, just set it here
if ( grammar instanceof LexerGrammar && rr.getLabel() != null ) {
println(rr.getLabel()+"=_returnToken;");
}
if (doNoGuessTest) {
tabs--;
println("}");
}
}
genErrorCatchForElement(rr);
}
/** Generate code for the given grammar element.
* @param blk The string-literal reference to generate
*/
public void gen(StringLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genString("+atom+")");
// Variable declarations for labeled elements
if (atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(atom);
// is there a bang on the literal?
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
// matching
genMatch(atom);
saveText = oldsaveText;
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t->getNextSibling();");
}
}
/** Generate code for the given grammar element.
* @param blk The token-range reference to generate
*/
public void gen(TokenRangeElement r) {
genErrorTryForElement(r);
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(r);
// match
println("matchRange("+r.beginText+","+r.endText+");");
genErrorCatchForElement(r);
}
/** Generate code for the given grammar element.
* @param blk The token-reference to generate
*/
public void gen(TokenRefElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")");
if ( grammar instanceof LexerGrammar ) {
tool.panic("Token reference found in lexer");
}
genErrorTryForElement(atom);
// Assign Token value to token label variable
if ( atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(atom);
// matching
genMatch(atom);
genErrorCatchForElement(atom);
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t->getNextSibling();");
}
}
public void gen(TreeElement t) {
// save AST cursor
println(labeledElementType+" __t" + t.ID + " = _t;");
// If there is a label on the root, then assign that to the variable
if (t.root.getLabel() != null) {
// println(t.root.getLabel() + " = _t==ASTNULL ? "+namespaceAntlr+"nullAST :"+labeledElementASTType+"(_t);");
println(t.root.getLabel() + " = (_t == ASTNULL) ? "+labeledElementASTInit+" : _t;");
}
// Generate AST variables
genElementAST(t.root);
if (grammar.buildAST) {
// Save the AST construction state
println(namespaceAntlr+"ASTPair __currentAST" + t.ID + " = currentAST;");
// Make the next item added a child of the TreeElement root
println("currentAST.root = currentAST.child;");
println("currentAST.child = "+labeledElementASTInit+";");
}
// match root
genMatch(t.root);
// move to list of children
println("_t = _t->getFirstChild();");
// walk list of children, generating code for each
for (int i=0; i<t.getAlternatives().size(); i++) {
Alternative a = t.getAlternativeAt(i);
AlternativeElement e = a.head;
while ( e != null ) {
e.generate();
e = e.next;
}
}
if (grammar.buildAST) {
// restore the AST construction state to that just after the
// tree root was added
println("currentAST = __currentAST" + t.ID + ";");
}
// restore AST cursor
println("_t = __t" + t.ID + ";");
// move cursor to sibling of tree just parsed
println("_t = _t->getNextSibling();");
}
/** Generate the tree-parser C++ files */
public void gen(TreeWalkerGrammar g) throws IOException {
setGrammar(g);
if (!(grammar instanceof TreeWalkerGrammar)) {
tool.panic("Internal error generating tree-walker");
}
genBody(g);
genInclude(g);
}
/** Generate code for the given grammar element.
* @param wc The wildcard element to generate
*/
public void gen(WildcardElement wc) {
// Variable assignment for labeled elements
if (wc.getLabel()!=null && syntacticPredLevel == 0) {
println(wc.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(wc);
// Match anything but EOF
if (grammar instanceof TreeWalkerGrammar) {
println("if ( _t == "+labeledElementASTInit+" ) throw "+namespaceAntlr+"MismatchedTokenException();");
}
else if (grammar instanceof LexerGrammar) {
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("_saveIndex = text.length();");
}
println("matchNot(EOF/*_CHAR*/);");
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text.erase(_saveIndex);"); // kill text atom put in buffer
}
}
else {
println("matchNot(" + getValueString(Token.EOF_TYPE) + ");");
}
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t->getNextSibling();");
}
}
/** Generate code for the given grammar element.
* @param blk The (...)* block to generate
*/
public void gen(ZeroOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen*("+blk+")");
println("{");
genBlockPreamble(blk);
String label;
if ( blk.getLabel() != null ) {
label = blk.getLabel();
}
else {
label = "_loop" + blk.ID;
}
println("for (;;) {");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)* loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("// nongreedy exit test");
println("if ("+predictExit+") goto "+label+";");
}
CppBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(howToFinish, "goto " + label + ";");
tabs--;
println("}");
println(label+":;");
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate an alternative.
* @param alt The alternative to generate
* @param blk The block to which the alternative belongs
*/
protected void genAlt(Alternative alt, AlternativeBlock blk) {
// Save the AST generation state, and set it to that of the alt
boolean savegenAST = genAST;
genAST = genAST && alt.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && alt.getAutoGen();
// Reset the variable name map for the alternative
Hashtable saveMap = treeVariableMap;
treeVariableMap = new Hashtable();
// Generate try block around the alt for error handling
if (alt.exceptionSpec != null) {
println("try { // for error handling");
tabs++;
}
AlternativeElement elem = alt.head;
while ( !(elem instanceof BlockEndElement) ) {
elem.generate(); // alt can begin with anything. Ask target to gen.
elem = elem.next;
}
if ( genAST) {
if (blk instanceof RuleBlock) {
// Set the AST return value for the rule
RuleBlock rblk = (RuleBlock)blk;
println(rblk.getRuleName() + "_AST = "+labeledElementASTType+"(currentAST.root);");
}
else if (blk.getLabel() != null) {
// ### future: also set AST value for labeled subrules.
// println(blk.getLabel() + "_AST = "+labeledElementASTType+"(currentAST.root);");
}
}
if (alt.exceptionSpec != null) {
// close try block
tabs--;
println("}");
genErrorHandler(alt.exceptionSpec);
}
genAST = savegenAST;
saveText = oldsaveTest;
treeVariableMap = saveMap;
}
/** Generate all the bitsets to be used in the parser or lexer
* Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
* and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
* Note that most languages do not support object initialization inside a
* class definition, so other code-generators may have to separate the
* bitset declarations from the initializations (e.g., put the initializations
* in the generated constructor instead).
* @param bitsetList The list of bitsets to generate.
* @param maxVocabulary Ensure that each generated bitset can contain at least this value.
* @param dumpSets Dump out the token definitions of the contents of the bitset
* only for grammars/parsers.
*/
protected void genBitsets(
Vector bitsetList,
int maxVocabulary,
String prefix,
boolean dumpSets
) {
println("");
for (int i = 0; i < bitsetList.size(); i++)
{
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
// initialization data
println(
"const unsigned long " + prefix + getBitsetName(i) + "_data_" + "[] = { " +
p.toStringOfHalfWords() +
" };"
);
if( dumpSets )
{
// Dump the contents of the bitset in readable format...
String t = "// ";
for( int j = 0; j < p.size(); j++ )
{
if ( p.member( j ) )
{
t += grammar.tokenManager.getTokenStringAt(j)+" ";
if( t.length() > 70 )
{
println(t);
t = "// ";
}
}
}
if ( t != "// " )
println(t);
}
// BitSet object
println(
"const "+namespaceAntlr+"BitSet " + prefix + getBitsetName(i) + "(" +
getBitsetName(i) + "_data_," + p.size()/32 +
");"
);
}
}
protected void genBitsetsHeader(
Vector bitsetList,
int maxVocabulary
) {
println("");
for (int i = 0; i < bitsetList.size(); i++)
{
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
// initialization data
println("static const unsigned long " + getBitsetName(i) + "_data_" + "[];");
// BitSet object
println("static const "+namespaceAntlr+"BitSet " + getBitsetName(i) + ";");
}
}
/** Generate the finish of a block, using a combination of the info
* returned from genCommonBlock() and the action to perform when
* no alts were taken
* @param howToFinish The return of genCommonBlock()
* @param noViableAction What to generate when no alt is taken
*/
private void genBlockFinish(CppBlockFinishingInfo howToFinish, String noViableAction)
{
if (howToFinish.needAnErrorClause &&
(howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
if ( howToFinish.generatedAnIf ) {
println("else {");
}
else {
println("{");
}
tabs++;
println(noViableAction);
tabs--;
println("}");
}
if ( howToFinish.postscript!=null ) {
println(howToFinish.postscript);
}
}
/** Generate the header for a block, which may be a RuleBlock or a
* plain AlternativeBLock. This generates any variable declarations,
* init-actions, and syntactic-predicate-testing variables.
* @blk The block for which the preamble is to be generated.
*/
protected void genBlockPreamble(AlternativeBlock blk) {
// define labels for rule blocks.
if ( blk instanceof RuleBlock ) {
RuleBlock rblk = (RuleBlock)blk;
if ( rblk.labeledElements!=null ) {
for (int i=0; i<rblk.labeledElements.size(); i++) {
AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
//System.out.println("looking at labeled element: "+a);
// Variables for labeled rule refs and subrules are different than
// variables for grammar atoms. This test is a little tricky because
// we want to get all rule refs and ebnf, but not rule blocks or
// syntactic predicates
if (
a instanceof RuleRefElement ||
a instanceof AlternativeBlock &&
!(a instanceof RuleBlock) &&
!(a instanceof SynPredBlock)
) {
if (
!(a instanceof RuleRefElement) &&
((AlternativeBlock)a).not &&
analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
) {
// Special case for inverted subrules that will be inlined.
// Treat these like token or char literal references
println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
if (grammar.buildAST) {
println(labeledElementASTType+" " + a.getLabel() + "_AST = "+labeledElementASTInit+";");
}
}
else {
if (grammar.buildAST) {
// Always gen AST variables for labeled elements, even if the
// element itself is marked with !
println(labeledElementASTType+" " + a.getLabel() + "_AST = "+labeledElementASTInit+";");
}
if ( grammar instanceof LexerGrammar ) {
println(namespaceAntlr+"RefToken "+a.getLabel()+";");
}
if (grammar instanceof TreeWalkerGrammar) {
// always generate rule-ref variables for tree walker
println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
}
}
}
else {
// It is a token or literal reference. Generate the
// correct variable type for this grammar
println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
// In addition, generate *_AST variables if building ASTs
if (grammar.buildAST) {
println(labeledElementASTType+" " + a.getLabel() + "_AST = "+labeledElementASTInit+";");
}
}
}
}
}
// dump out init action
if ( blk.initAction!=null ) {
genLineNo(blk);
printAction(
processActionForTreeSpecifiers(blk.initAction, 0, currentRule, null)
);
genLineNo2();
}
}
public void genBody(LexerGrammar g) throws IOException {
outputFile = grammar.getClassName() + ".cpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
genAST = false; // no way to gen trees.
saveText = true; // save consumed characters.
tabs=0;
// Generate header common to all C++ output files
genHeader(outputFile);
printHeaderAction(preIncludeCpp);
// Generate header specific to lexer C++ file
println("#include \"" + grammar.getClassName() + ".hpp\"");
println("#include \"antlr/CharBuffer.hpp\"");
println("#include \"antlr/TokenStreamException.hpp\"");
println("#include \"antlr/TokenStreamIOException.hpp\"");
println("#include \"antlr/TokenStreamRecognitionException.hpp\"");
println("#include \"antlr/CharStreamException.hpp\"");
println("#include \"antlr/CharStreamIOException.hpp\"");
println("#include \"antlr/NoViableAltForCharException.hpp\"");
if (grammar.debuggingOutput)
println("#include \"antlr/DebuggingInputBuffer.hpp\"");
println("");
printHeaderAction(postIncludeCpp);
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
// Generate user-defined lexer file preamble
printAction(grammar.preambleAction);
// Generate lexer class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
}
else {
sup = grammar.getSuperClass();
if (sup.lastIndexOf('.') != -1)
sup = sup.substring(sup.lastIndexOf('.')+1);
sup = namespaceAntlr + sup;
}
//
// Generate the constructor from InputStream
//
println(grammar.getClassName() + "::" + grammar.getClassName() + "(" + namespaceStd + "istream& in)");
tabs++;
// if debugging, wrap the input buffer in a debugger
if (grammar.debuggingOutput)
println(": " + sup + "(new "+namespaceAntlr+"DebuggingInputBuffer(new "+namespaceAntlr+"CharBuffer(in)))");
else
println(": " + sup + "(new "+namespaceAntlr+"CharBuffer(in))");
tabs--;
println("{");
tabs++;
// if debugging, set up array variables and call user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging();");
}
println("setCaseSensitive("+g.caseSensitive+");");
println("initLiterals();");
tabs--;
println("}");
println("");
// Generate the constructor from InputBuffer
println(grammar.getClassName() + "::" + grammar.getClassName() + "("+namespaceAntlr+"InputBuffer& ib)");
tabs++;
// if debugging, wrap the input buffer in a debugger
if (grammar.debuggingOutput)
println(": " + sup + "(new "+namespaceAntlr+"DebuggingInputBuffer(ib))");
else
println(": " + sup + "(ib)");
tabs--;
println("{");
tabs++;
// if debugging, set up array variables and call user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging();");
}
println("setCaseSensitive("+g.caseSensitive+");");
println("initLiterals();");
tabs--;
println("}");
println("");
// Generate the constructor from LexerSharedInputState
println(grammar.getClassName() + "::" + grammar.getClassName() + "(const "+namespaceAntlr+"LexerSharedInputState& state)");
tabs++;
println(": " + sup + "(state)");
tabs--;
println("{");
tabs++;
// if debugging, set up array variables and call user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging();");
}
println("setCaseSensitive("+g.caseSensitive+");");
println("initLiterals();");
tabs--;
println("}");
println("");
println("void " + grammar.getClassName() + "::initLiterals()");
println("{");
tabs++;
// Generate the initialization of the map
// containing the string literals used in the lexer
// The literals variable itself is in CharScanner
/* TJP: get keys now and check to make sure it's a literal not
* a label to a literal; was dup'ing string literals before
* change.
*
Enumeration ids = grammar.tokenManager.getTokenSymbolElements();
while ( ids.hasMoreElements() ) {
TokenSymbol sym = (TokenSymbol)ids.nextElement();
if ( sym instanceof StringLiteralSymbol ) {
StringLiteralSymbol s = (StringLiteralSymbol)sym;
println("literals["+s.getId()+"] = "+s.getTokenType()+";");
}
}
*/
// TJP changed it to following loop.
Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
while ( keys.hasMoreElements() ) {
String key = (String)keys.nextElement();
if ( key.charAt(0) != '"' ) {
continue;
}
TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
if ( sym instanceof StringLiteralSymbol ) {
StringLiteralSymbol s = (StringLiteralSymbol)sym;
println("literals["+s.getId()+"] = "+s.getTokenType()+";");
}
}
// Generate the setting of various generated options.
tabs--;
println("}");
// Generate getCaseSensitiveLiterals() method
println("bool " + grammar.getClassName() + "::getCaseSensitiveLiterals() const");
println("{");
tabs++;
println("return "+g.caseSensitiveLiterals + ";");
tabs--;
println("}");
Enumeration ids;
// generate the rule name array for debugging
if (grammar.debuggingOutput) {
println("const char* "+grammar.getClassName()+"::_ruleNames[] = {");
tabs++;
ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println("\""+((RuleSymbol)sym).getId()+"\",");
}
println("0");
tabs--;
println("};");
}
// Generate nextToken() rule.
// nextToken() is a synthetic lexer rule that is the implicit OR of all
// user-defined lexer rules.
genNextToken();
// Generate code for each rule in the lexer
ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
RuleSymbol sym = (RuleSymbol) ids.nextElement();
// Don't generate the synthetic rules
if (!sym.getId().equals("mnextToken")) {
genRule(sym, false, ruleNum++, grammar.getClassName() + "::");
}
exitIfError();
}
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap(grammar.getClassName() + "::");
// Generate the bitsets used throughout the lexer
genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size(), grammar.getClassName() + "::", false);
println("");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Close the lexer output stream
currentOutput.close();
currentOutput = null;
}
public void genBody(ParserGrammar g) throws IOException {
// Open the output stream for the parser and set the currentOutput
outputFile = grammar.getClassName() + ".cpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader(outputFile);
printHeaderAction(preIncludeCpp);
// Generate header for the parser
println("#include \"" + grammar.getClassName() + ".hpp\"");
println("#include \"antlr/NoViableAltException.hpp\"");
println("#include \"antlr/SemanticException.hpp\"");
printHeaderAction(postIncludeCpp);
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
// Output the user-defined parser preamble
printAction(grammar.preambleAction);
String sup=null;
if ( grammar.superClass!=null )
sup = grammar.superClass;
else {
sup = grammar.getSuperClass();
if (sup.lastIndexOf('.') != -1)
sup = sup.substring(sup.lastIndexOf('.')+1);
sup = namespaceAntlr + sup;
}
// set up an array of all the rule names so the debugger can
// keep track of them only by number -- less to store in tree...
if (grammar.debuggingOutput) {
println("const char* "+grammar.getClassName()+"::_ruleNames[] = {");
tabs++;
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println("\""+((RuleSymbol)sym).getId()+"\",");
}
println("0");
tabs--;
println("};");
}
// Generate parser class constructor from TokenBuffer
print(grammar.getClassName() + "::" + grammar.getClassName());
println("("+namespaceAntlr+"TokenBuffer& tokenBuf, int k)");
println(": " + sup + "(tokenBuf,k)");
println("{");
tabs++;
println("setTokenNames(_tokenNames);");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging();");
}
tabs--;
println("}");
println("");
print(grammar.getClassName() + "::" + grammar.getClassName());
println("("+namespaceAntlr+"TokenBuffer& tokenBuf)");
println(": " + sup + "(tokenBuf," + grammar.maxk + ")");
println("{");
tabs++;
println("setTokenNames(_tokenNames);");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging();");
}
tabs--;
println("}");
println("");
// Generate parser class constructor from TokenStream
print(grammar.getClassName() + "::" + grammar.getClassName());
println("("+namespaceAntlr+"TokenStream& lexer, int k)");
println(": " + sup + "(lexer,k)");
println("{");
tabs++;
println("setTokenNames(_tokenNames);");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging(&lexer);");
}
tabs--;
println("}");
println("");
print(grammar.getClassName() + "::" + grammar.getClassName());
println("("+namespaceAntlr+"TokenStream& lexer)");
println(": " + sup + "(lexer," + grammar.maxk + ")");
println("{");
tabs++;
println("setTokenNames(_tokenNames);");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging(&lexer);");
}
tabs--;
println("}");
println("");
print(grammar.getClassName() + "::" + grammar.getClassName());
println("(const "+namespaceAntlr+"ParserSharedInputState& state)");
println(": " + sup + "(state," + grammar.maxk + ")");
println("{");
tabs++;
println("setTokenNames(_tokenNames);");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("setRuleNames(_ruleNames);");
println("setSemPredNames(_semPredNames);");
println("setupDebugging(&lexer);");
}
tabs--;
println("}");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++, grammar.getClassName() + "::");
}
exitIfError();
}
if ( usingCustomAST )
{
// println("void "+grammar.getClassName()+"::setASTNodeFactory("+labeledElementASTType+" (*factory)() )");
// println("{");
// println("}");
// println("");
// when we are using a custom ast override Parser::getAST to return the
// custom AST type
println(labeledElementASTType+" "+grammar.getClassName()+"::getAST()");
println("{");
println("\treturn returnAST;");
println("}");
println("");
}
// Generate the token names
genTokenStrings(grammar.getClassName() + "::");
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType(), grammar.getClassName() + "::", true);
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap(grammar.getClassName() + "::");
// Close class definition
println("");
println("");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
public void genBody(TreeWalkerGrammar g) throws IOException {
// Open the output stream for the parser and set the currentOutput
outputFile = grammar.getClassName() + ".cpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader(outputFile);
printHeaderAction(preIncludeCpp);
// Generate header for the parser
println("#include \"" + grammar.getClassName() + ".hpp\"");
println("#include \"antlr/Token.hpp\"");
println("#include \"antlr/AST.hpp\"");
println("#include \"antlr/NoViableAltException.hpp\"");
println("#include \"antlr/MismatchedTokenException.hpp\"");
println("#include \"antlr/SemanticException.hpp\"");
println("#include \"antlr/BitSet.hpp\"");
printHeaderAction(postIncludeCpp);
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
// Output the user-defined parser premamble
printAction(grammar.preambleAction);
// Generate parser class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
}
else {
sup = grammar.getSuperClass();
if (sup.lastIndexOf('.') != -1)
sup = sup.substring(sup.lastIndexOf('.')+1);
sup = namespaceAntlr + sup;
}
// Generate default parser class constructor
println(grammar.getClassName() + "::" + grammar.getClassName() + "()");
println("\t: "+namespaceAntlr+"TreeParser() {");
tabs++;
println("setTokenNames(_tokenNames);");
tabs--;
println("}");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
String ruleNameInits = "";
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++, grammar.getClassName() + "::");
}
exitIfError();
}
if ( usingCustomAST )
{
// when we are using a custom ast override Parser::getAST to return the
// custom AST type
println(labeledElementASTType+" "+grammar.getClassName()+"::getAST()");
println("{");
println("\treturn returnAST;");
println("}");
println("");
}
// Generate the token names
genTokenStrings(grammar.getClassName() + "::");
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType(), grammar.getClassName() + "::", true);
// Close class definition
println("");
println("");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate a series of case statements that implement a BitSet test.
* @param p The Bitset for which cases are to be generated
*/
protected void genCases(BitSet p) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCases("+p+")");
int[] elems;
elems = p.toArray();
// Wrap cases four-per-line for lexer, one-per-line for parser
int wrap = 1; //(grammar instanceof LexerGrammar) ? 4 : 1;
int j=1;
boolean startOfLine = true;
for (int i = 0; i < elems.length; i++) {
if (j==1) {
print("");
} else {
_print(" ");
}
_print("case " + getValueString(elems[i]) + ":");
if (j==wrap) {
_println("");
startOfLine = true;
j=1;
}
else {
j++;
startOfLine = false;
}
}
if (!startOfLine) {
_println("");
}
}
/**Generate common code for a block of alternatives; return a postscript
* that needs to be generated at the end of the block. Other routines
* may append else-clauses and such for error checking before the postfix
* is generated.
* If the grammar is a lexer, then generate alternatives in an order where
* alternatives requiring deeper lookahead are generated first, and
* EOF in the lookahead set reduces the depth of the lookahead.
* @param blk The block to generate
* @param noTestForSingle If true, then it does not generate a test for a single alternative.
*/
public CppBlockFinishingInfo genCommonBlock(
AlternativeBlock blk,
boolean noTestForSingle)
{
int nIF=0;
boolean createdLL1Switch = false;
int closingBracesOfIFSequence = 0;
CppBlockFinishingInfo finishingInfo = new CppBlockFinishingInfo();
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCommonBlk("+blk+")");
// Save the AST generation state, and set it to that of the block
boolean savegenAST = genAST;
genAST = genAST && blk.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && blk.getAutoGen();
// Is this block inverted? If so, generate special-case code
if (
blk.not &&
analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar)
) {
Lookahead p = analyzer.look(1, blk);
// Variable assignment for labeled elements
if (blk.getLabel() != null && syntacticPredLevel == 0) {
println(blk.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(blk);
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
if( usingCustomAST )
astArgs="static_cast<"+namespaceAntlr+"RefAST"+">(_t),";
else
astArgs="_t,";
}
// match the bitset for the alternative
println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t->getNextSibling();");
}
return finishingInfo;
}
// Special handling for single alt
if (blk.getAlternatives().size() == 1) {
Alternative alt = blk.getAlternativeAt(0);
// Generate a warning if there is a synPred for single alt.
if (alt.synPred != null)
{
tool.warning(
"Syntactic predicate superfluous for single alternative",
grammar.getFilename(),
blk.getAlternativeAt(0).synPred.getLine()
);
}
if (noTestForSingle) {
if (alt.semPred != null) {
// Generate validating predicate
genSemPred(alt.semPred, blk.line);
}
genAlt(alt, blk);
return finishingInfo;
}
}
// count number of simple LL(1) cases; only do switch for
// many LL(1) cases (no preds, no end of token refs)
// We don't care about exit paths for (...)*, (...)+
// because we don't explicitly have a test for them
// as an alt in the loop.
//
// Also, we now count how many unicode lookahead sets
// there are--they must be moved to DEFAULT or ELSE
// clause.
int nLL1 = 0;
for (int i=0; i<blk.getAlternatives().size(); i++) {
Alternative a = blk.getAlternativeAt(i);
if ( suitableForCaseExpression(a) ) {
nLL1++;
}
}
// do LL(1) cases
if ( nLL1 >= makeSwitchThreshold) {
// Determine the name of the item to be compared
String testExpr = lookaheadString(1);
createdLL1Switch = true;
// when parsing trees, convert null to valid tree node with NULL lookahead
if ( grammar instanceof TreeWalkerGrammar ) {
println("if (_t == "+labeledElementASTInit+" )");
tabs++;
println("_t = ASTNULL;");
tabs--;
}
println("switch ( "+testExpr+") {");
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
// ignore any non-LL(1) alts, predicated alts or end-of-token alts
// or end-of-token alts for case expressions
if ( !suitableForCaseExpression(alt) ) {
continue;
}
Lookahead p = alt.cache[1];
if (p.fset.degree() == 0 && !p.containsEpsilon()) {
tool.warning("Alternate omitted due to empty prediction set",
grammar.getFilename(),
alt.head.getLine());
}
else {
genCases(p.fset);
println("{");
tabs++;
genAlt(alt, blk);
println("break;");
tabs--;
println("}");
}
}
println("default:");
tabs++;
}
// do non-LL(1) and nondeterministic cases
// This is tricky in the lexer, because of cases like:
// STAR : '*' ;
// ASSIGN_STAR : "*=";
// Since nextToken is generated without a loop, then the STAR will
// have end-of-token as it's lookahead set for LA(2). So, we must generate the
// alternatives containing trailing end-of-token in their lookahead sets *after*
// the alternatives without end-of-token. This implements the usual
// lexer convention that longer matches come before shorter ones, e.g.
// "*=" matches ASSIGN_STAR not STAR
//
// For non-lexer grammars, this does not sort the alternates by depth
// Note that alts whose lookahead is purely end-of-token at k=1 end up
// as default or else clauses.
int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("checking depth "+altDepth);
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
if ( DEBUG_CODE_GENERATOR ) System.out.println("genAlt: "+i);
// if we made a switch above, ignore what we already took care
// of. Specifically, LL(1) alts with no preds
// that do not have end-of-token in their prediction set
if ( createdLL1Switch &&
suitableForCaseExpression(alt) ) {
if ( DEBUG_CODE_GENERATOR )
System.out.println("ignoring alt because it was in the switch");
continue;
}
String e;
boolean unpredicted = false;
if (grammar instanceof LexerGrammar) {
// Calculate the "effective depth" of the alt, which is the max
// depth at which cache[depth]!=end-of-token
int effectiveDepth = alt.lookaheadDepth;
if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) {
// use maximum lookahead
effectiveDepth = grammar.maxk;
}
while ( effectiveDepth >= 1 &&
alt.cache[effectiveDepth].containsEpsilon() )
{
effectiveDepth--;
}
// Ignore alts whose effective depth is other than the ones we
// are generating for this iteration.
if (effectiveDepth != altDepth) {
if ( DEBUG_CODE_GENERATOR )
System.out.println("ignoring alt because effectiveDepth!=altDepth;"+effectiveDepth+"!="+altDepth);
continue;
}
unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
e = getLookaheadTestExpression(alt, effectiveDepth);
} else {
unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
e = getLookaheadTestExpression(alt, grammar.maxk);
}
// Was it a big unicode range that forced unsuitability
// for a case expression?
if ( alt.cache[1].fset.degree() > caseSizeThreshold )
{
if ( nIF==0 )
{
// generate this only for the first if the elseif's
// are covered by this one
if ( grammar instanceof TreeWalkerGrammar ) {
println("if (_t == "+labeledElementASTInit+" )");
tabs++;
println("_t = ASTNULL;");
tabs--;
}
println("if " + e + " {");
}
else
println("else if " + e + " {");
}
else if (unpredicted &&
alt.semPred==null &&
alt.synPred==null)
{
// The alt has empty prediction set and no
// predicate to help out. if we have not
// generated a previous if, just put {...} around
// the end-of-token clause
if ( nIF==0 ) {
println("{");
}
else {
println("else {");
}
finishingInfo.needAnErrorClause = false;
}
else
{
// check for sem and syn preds
// Add any semantic predicate expression to the lookahead test
if ( alt.semPred != null ) {
// if debugging, wrap the evaluation of the predicate in a method
//
// translate $ and # references
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr = processActionForTreeSpecifiers(alt.semPred,
blk.line,
currentRule,
tInfo);
// ignore translation info...we don't need to do anything with it.
// call that will inform SemanticPredicateListeners of the result
if (((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)) && grammar.debuggingOutput)
e = "("+e+"&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING,"+ //FIXME
addSemPred(charFormatter.escapeString(actionStr))+","+actionStr+"))";
else
e = "("+e+"&&("+actionStr +"))";
}
// Generate any syntactic predicates
if ( nIF>0 ) {
if ( alt.synPred != null ) {
println("else {");
tabs++;
genSynPred( alt.synPred, e );
closingBracesOfIFSequence++;
}
else {
println("else if " + e + " {");
}
}
else {
if ( alt.synPred != null ) {
genSynPred( alt.synPred, e );
}
else {
// when parsing trees, convert null to valid tree node
// with NULL lookahead.
if ( grammar instanceof TreeWalkerGrammar ) {
println("if (_t == "+labeledElementASTInit+" )");
tabs++;
println("_t = ASTNULL;");
tabs--;
}
println("if " + e + " {");
}
}
}
nIF++;
tabs++;
genAlt(alt, blk);
tabs--;
println("}");
}
}
String ps = "";
for (int i=1; i<=closingBracesOfIFSequence; i++) {
tabs--; // does JavaCodeGenerator need this?
ps+="}";
}
// Restore the AST generation state
genAST = savegenAST;
// restore save text state
saveText=oldsaveTest;
// Return the finishing info.
if ( createdLL1Switch ) {
tabs--;
finishingInfo.postscript = ps+"}";
finishingInfo.generatedSwitch = true;
finishingInfo.generatedAnIf = nIF>0;
//return new CppBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
}
else {
finishingInfo.postscript = ps;
finishingInfo.generatedSwitch = false;
finishingInfo.generatedAnIf = nIF>0;
//return new CppBlockFinishingInfo(ps, false,nIF>0);
}
return finishingInfo;
}
private static boolean suitableForCaseExpression(Alternative a) {
return a.lookaheadDepth == 1 &&
a.semPred == null &&
!a.cache[1].containsEpsilon() &&
a.cache[1].fset.degree()<=caseSizeThreshold;
}
/** Generate code to link an element reference into the AST */
private void genElementAST(AlternativeElement el) {
// handle case where you're not building trees, but are in tree walker.
// Just need to get labels set up.
if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST ) {
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() == null) {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_AST";
astVarNumber++;
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
// Generate an "input" AST variable also
println(labeledElementASTType+" "+astName+"_in = "+elementRef+";");
}
return;
}
if (grammar.buildAST && syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
el.getLabel() != null ||
el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG
)
);
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() != null) {
elementRef = el.getLabel();
astName = el.getLabel() + "_AST";
} else {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_AST";
astVarNumber++;
// Generate the declaration
if ( el instanceof GrammarAtom ) {
GrammarAtom ga = (GrammarAtom)el;
if ( ga.getASTNodeType()!=null ) {
println("Ref"+ga.getASTNodeType()+" " + astName + ";");
}
else {
println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";");
}
}
else {
println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";");
}
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
if (grammar instanceof TreeWalkerGrammar) {
// Generate an "input" AST variable also
println(labeledElementASTType+" " + astName + "_in = "+labeledElementASTInit+";");
}
}
// Enclose actions with !guessing
if (doNoGuessTest) {
println("if (inputState->guessing==0) {");
tabs++;
}
if (el.getLabel() != null) {
if ( el instanceof GrammarAtom ) {
println(astName + " = "+
getASTCreateString((GrammarAtom)el,elementRef) + ";");
}
else {
println(astName + " = "+
getASTCreateString(elementRef) + ";");
}
} else {
elementRef = lt1Value;
if ( el instanceof GrammarAtom ) {
println(astName + " = "+
getASTCreateString((GrammarAtom)el,elementRef) + ";");
}
else {
println(astName + " = "+
getASTCreateString(elementRef) + ";");
}
// Map the generated AST variable in the alternate
if (grammar instanceof TreeWalkerGrammar) {
// set "input" AST variable also
println(astName + "_in = " + elementRef + ";");
}
}
if (genAST) {
switch (el.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
println("astFactory.addASTChild(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));");
break;
case GrammarElement.AUTO_GEN_CARET:
// println("astFactory.makeASTRoot(currentAST, " + astName + ");");
println("astFactory.makeASTRoot(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));");
break;
default:
break;
}
}
if (doNoGuessTest) {
tabs--;
println("}");
}
}
}
/** Close the try block and generate catch phrases
* if the element has a labeled handler in the rule
*/
private void genErrorCatchForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
tabs--;
println("}");
genErrorHandler(ex);
}
}
/** Generate the catch phrases for a user-specified error handler */
private void genErrorHandler(ExceptionSpec ex) {
// Each ExceptionHandler in the ExceptionSpec is a separate catch
for (int i = 0; i < ex.handlers.size(); i++)
{
ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i);
// Generate catch phrase
println("catch (" + handler.exceptionTypeAndName.getText() + ") {");
tabs++;
if (grammar.hasSyntacticPredicate) {
println("if (inputState->guessing==0) {");
tabs++;
}
// When not guessing, execute user handler action
genLineNo(handler.action);
printAction(
processActionForTreeSpecifiers(handler.action.getText(), 0, currentRule, null)
);
genLineNo2();
if (grammar.hasSyntacticPredicate) {
tabs--;
println("} else {");
tabs++;
// When guessing, rethrow exception
println(
"throw " +
extractIdOfAction(handler.exceptionTypeAndName) +
";"
);
tabs--;
println("}");
}
// Close catch phrase
tabs--;
println("}");
}
}
/** Generate a try { opening if the element has a labeled handler in the rule */
private void genErrorTryForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
println("try { // for error handling");
tabs++;
}
}
/** Generate a header that is common to all C++ files */
protected void genHeader(String fileName)
{
println("/* $ANTLR "+Tool.version+": "+
"\""+Tool.fileMinusPath(tool.grammarFile)+"\""+
" -> "+
"\""+fileName+"\"$ */");
}
// these are unique to C++ mode
public void genInclude(LexerGrammar g) throws IOException {
outputFile = grammar.getClassName() + ".hpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
genAST = false; // no way to gen trees.
saveText = true; // save consumed characters.
tabs=0;
// Generate a guard wrapper
println("#ifndef INC_"+grammar.getClassName()+"_hpp_");
println("#define INC_"+grammar.getClassName()+"_hpp_");
println("");
printHeaderAction(preIncludeHpp);
println("#include \"antlr/config.hpp\"");
// Generate header common to all C++ output files
genHeader(outputFile);
// Generate header specific to lexer header file
println("#include \"antlr/CommonToken.hpp\"");
println("#include \"antlr/InputBuffer.hpp\"");
println("#include \"antlr/BitSet.hpp\"");
println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\"");
// Find the name of the super class
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
println("#include \""+sup+".hpp\"");
}
else {
sup = grammar.getSuperClass();
if (sup.lastIndexOf('.') != -1)
sup = sup.substring(sup.lastIndexOf('.')+1);
println("#include \"antlr/"+sup+".hpp\"");
sup = namespaceAntlr + sup;
}
// Do not use printAction because we assume tabs==0
printHeaderAction(postIncludeHpp);
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
printHeaderAction("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
// Generate lexer class definition
print("class " + grammar.getClassName() + " : public " + sup);
println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
print(", "+suffix); // must be an interface name for Java
}
}
println(" {");
// Generate user-defined lexer class members
if (grammar.classMemberAction != null) {
genLineNo(grammar.classMemberAction);
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
genLineNo2();
}
// Generate initLiterals() method
tabs=0;
println("private:");
tabs=1;
println("void initLiterals();");
// Generate getCaseSensitiveLiterals() method
tabs=0;
println("public:");
tabs=1;
println("bool getCaseSensitiveLiterals() const;");
// Make constructors public
tabs=0;
println("public:");
tabs=1;
// Generate the constructor from std::istream
println(grammar.getClassName() + "(" + namespaceStd + "istream& in);");
// Generate the constructor from InputBuffer
println(grammar.getClassName() + "("+namespaceAntlr+"InputBuffer& ib);");
println(grammar.getClassName() + "(const "+namespaceAntlr+"LexerSharedInputState& state);");
// Generate nextToken() rule.
// nextToken() is a synthetic lexer rule that is the implicit OR of all
// user-defined lexer rules.
println(namespaceAntlr+"RefToken nextToken();");
// Generate code for each rule in the lexer
Enumeration ids = grammar.rules.elements();
while ( ids.hasMoreElements() ) {
RuleSymbol sym = (RuleSymbol) ids.nextElement();
// Don't generate the synthetic rules
if (!sym.getId().equals("mnextToken")) {
genRuleHeader(sym, false);
}
exitIfError();
}
// Make the rest private
tabs=0;
println("private:");
tabs=1;
// generate the rule name array for debugging
if ( grammar.debuggingOutput ) {
println("static const char* _ruleNames[];");
}
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
println("static const char* _semPredNames[];");
// Generate the bitsets used throughout the lexer
genBitsetsHeader(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size());
tabs=0;
println("};");
println("");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Generate a guard wrapper
println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/");
// Close the lexer output stream
currentOutput.close();
currentOutput = null;
}
public void genInclude(ParserGrammar g) throws IOException {
// Open the output stream for the parser and set the currentOutput
outputFile = grammar.getClassName() + ".hpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
genAST = grammar.buildAST;
tabs = 0;
// Generate a guard wrapper
println("#ifndef INC_"+grammar.getClassName()+"_hpp_");
println("#define INC_"+grammar.getClassName()+"_hpp_");
println("");
printHeaderAction(preIncludeHpp);
println("#include \"antlr/config.hpp\"");
// Generate the header common to all output files.
genHeader(outputFile);
// Generate header for the parser
println("#include \"antlr/TokenStream.hpp\"");
println("#include \"antlr/TokenBuffer.hpp\"");
println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\"");
// Generate parser class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
println("#include \""+sup+".hpp\"");
}
else {
sup = grammar.getSuperClass();
if (sup.lastIndexOf('.') != -1)
sup = sup.substring(sup.lastIndexOf('.')+1);
println("#include \"antlr/"+sup+".hpp\"");
sup = namespaceAntlr + sup;
}
println("");
// Do not use printAction because we assume tabs==0
printHeaderAction(postIncludeHpp);
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
printHeaderAction("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
// generate the actual class definition
print("class " + grammar.getClassName() + " : public " + sup);
println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null )
print(", "+suffix); // must be an interface name for Java
}
println(" {");
// set up an array of all the rule names so the debugger can
// keep track of them only by number -- less to store in tree...
if (grammar.debuggingOutput) {
println("public: static const char* _ruleNames[];");
}
// Generate user-defined parser class members
if (grammar.classMemberAction != null) {
genLineNo(grammar.classMemberAction.getLine());
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
genLineNo2();
}
// Generate parser class constructor from TokenBuffer
tabs=0;
println("protected:");
tabs=1;
println(grammar.getClassName() + "("+namespaceAntlr+"TokenBuffer& tokenBuf, int k);");
tabs=0;
println("public:");
tabs=1;
println(grammar.getClassName() + "("+namespaceAntlr+"TokenBuffer& tokenBuf);");
// Generate parser class constructor from TokenStream
tabs=0;
println("protected:");
tabs=1;
println(grammar.getClassName()+"("+namespaceAntlr+"TokenStream& lexer, int k);");
tabs=0;
println("public:");
tabs=1;
println(grammar.getClassName()+"("+namespaceAntlr+"TokenStream& lexer);");
println(grammar.getClassName()+"(const "+namespaceAntlr+"ParserSharedInputState& state);");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRuleHeader(rs, rs.references.size()==0);
}
exitIfError();
}
if ( usingCustomAST )
{
// when we are using a custom ast override Parser::getAST to return the
// custom AST type
tabs=0; println("public:"); tabs=1;
println(labeledElementASTType+" getAST();");
println("");
tabs=0; println("protected:"); tabs=1;
println(labeledElementASTType+" returnAST;");
}
// Make the rest private
tabs=0;
println("private:");
tabs=1;
// Generate the token names
println("static const char* _tokenNames[];");
// Generate the bitsets used throughout the grammar
genBitsetsHeader(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
println("static const char* _semPredNames[];");
// Close class definition
tabs=0;
println("};");
println("");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Generate a guard wrapper
println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
public void genInclude(TreeWalkerGrammar g) throws IOException {
// Open the output stream for the parser and set the currentOutput
outputFile = grammar.getClassName() + ".hpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
genAST = grammar.buildAST;
tabs = 0;
// Generate a guard wrapper
println("#ifndef INC_"+grammar.getClassName()+"_hpp_");
println("#define INC_"+grammar.getClassName()+"_hpp_");
println("");
printHeaderAction(preIncludeHpp);
println("#include \"antlr/config.hpp\"");
println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\"");
// Generate the header common to all output files.
genHeader(outputFile);
// Find the name of the super class
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
println("#include \""+sup+".hpp\"");
}
else {
sup = grammar.getSuperClass();
if (sup.lastIndexOf('.') != -1)
sup = sup.substring(sup.lastIndexOf('.')+1);
println("#include \"antlr/"+sup+".hpp\"");
sup = namespaceAntlr + sup;
}
println("");
// Generate header for the parser
// Do not use printAction because we assume tabs==0
printHeaderAction(postIncludeHpp);
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
printHeaderAction("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
// Generate parser class definition
print("class " + grammar.getClassName() + " : public "+sup);
println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
print(", "+suffix); // must be an interface name for Java
}
}
println(" {");
// Generate user-defined parser class members
if (grammar.classMemberAction != null) {
genLineNo(grammar.classMemberAction.getLine());
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
genLineNo2();
}
// Generate default parser class constructor
tabs=0;
println("public:");
tabs=1;
println(grammar.getClassName() + "();");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
String ruleNameInits = "";
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRuleHeader(rs, rs.references.size()==0);
}
exitIfError();
}
if ( usingCustomAST )
{
// when we are using a custom ast override TreeParser::getAST to return the
// custom AST type
tabs=0; println("public:"); tabs=1;
println(labeledElementASTType+" getAST();");
println("");
tabs=0; println("protected:"); tabs=1;
println(labeledElementASTType+" returnAST;");
println(labeledElementASTType+" _retTree;");
}
// Make the rest private
tabs=0;
println("private:");
tabs=1;
// Generate the token names
println("static const char* _tokenNames[];");
// Generate the bitsets used throughout the grammar
genBitsetsHeader(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Close class definition
tabs=0;
println("};");
println("");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Generate a guard wrapper
println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
private void genLiteralsTest() {
println("_ttype = testLiteralsTable(_ttype);");
}
private void genLiteralsTestForPartialToken() {
println("_ttype = testLiteralsTable(text.substr(_begin, text.length()-_begin),_ttype);");
}
protected void genMatch(BitSet b) {
}
protected void genMatch(GrammarAtom atom) {
if ( atom instanceof StringLiteralElement ) {
if ( grammar instanceof LexerGrammar ) {
genMatchUsingAtomText(atom);
}
else {
genMatchUsingAtomTokenType(atom);
}
}
else if ( atom instanceof CharLiteralElement ) {
if ( grammar instanceof LexerGrammar ) {
genMatchUsingAtomText(atom);
}
else {
tool.error("cannot ref character literals in grammar: "+atom);
}
}
else if ( atom instanceof TokenRefElement ) {
genMatchUsingAtomText(atom);
}
}
protected void genMatchUsingAtomText(GrammarAtom atom) {
// match() for trees needs the _t cursor
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
if( usingCustomAST )
astArgs="static_cast<"+namespaceAntlr+"RefAST"+">(_t),";
else
astArgs="_t,";
}
// if in lexer and ! on element, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("_saveIndex=text.length();");
}
print(atom.not ? "matchNot(" : "match(");
_print(astArgs);
// print out what to match
if (atom.atomText.equals("EOF")) {
// horrible hack to handle EOF case
_print(namespaceAntlr+"Token::EOF_TYPE");
}
else {
_print(textOrChar(atom.atomText));
}
_println(");");
if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text.erase(_saveIndex);"); // kill text atom put in buffer
}
}
protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
// match() for trees needs the _t cursor
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
if( usingCustomAST )
astArgs="static_cast<"+namespaceAntlr+"RefAST"+">(_t),";
else
astArgs="_t,";
}
// If the literal can be mangled, generate the symbolic constant instead
String mangledName = null;
String s = astArgs + getValueString(atom.getType());
// matching
println( (atom.not ? "matchNot(" : "match(") + s + ");");
}
/** Generate the nextToken() rule.
* nextToken() is a synthetic lexer rule that is the implicit OR of all
* user-defined lexer rules.
* @param RuleBlock
*/
public void genNextToken() {
// Are there any public rules? If not, then just generate a
// fake nextToken().
boolean hasPublicRules = false;
for (int i = 0; i < grammar.rules.size(); i++) {
RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i);
if ( rs.isDefined() && rs.access.equals("public") ) {
hasPublicRules = true;
break;
}
}
if (!hasPublicRules) {
println("");
println(namespaceAntlr+"RefToken "+grammar.getClassName()+"::nextToken() { return "+namespaceAntlr+"RefToken(new "+namespaceAntlr+"CommonToken("+namespaceAntlr+"Token::EOF_TYPE, \"\")); }");
println("");
return;
}
// Create the synthesized nextToken() rule
RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
// Define the nextToken rule symbol
RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
nextTokenRs.setDefined();
nextTokenRs.setBlock(nextTokenBlk);
nextTokenRs.access = "private";
grammar.define(nextTokenRs);
// Analyze the nextToken rule
boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);
// Generate the next token rule
String filterRule=null;
if ( ((LexerGrammar)grammar).filterMode ) {
filterRule = ((LexerGrammar)grammar).filterRule;
}
println("");
println(namespaceAntlr+"RefToken "+grammar.getClassName()+"::nextToken()");
println("{");
tabs++;
println(namespaceAntlr+"RefToken theRetToken;");
println("for (;;) {");
tabs++;
println(namespaceAntlr+"RefToken theRetToken;");
println("int _ttype = "+namespaceAntlr+"Token::INVALID_TYPE;");
if ( ((LexerGrammar)grammar).filterMode ) {
println("setCommitToPath(false);");
if ( filterRule!=null ) {
// Here's a good place to ensure that the filter rule actually exists
if ( !grammar.isDefined(CodeGenerator.lexerRuleName(filterRule)) ) {
grammar.tool.error("Filter rule "+filterRule+" does not exist in this lexer");
}
else {
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.lexerRuleName(filterRule));
if ( !rs.isDefined() ) {
grammar.tool.error("Filter rule "+filterRule+" does not exist in this lexer");
}
else if ( rs.access.equals("public") ) {
grammar.tool.error("Filter rule "+filterRule+" must be protected");
}
}
println("int _m;");
println("_m = mark();");
}
}
println("resetText();");
println("try { // for char stream error handling");
tabs++;
// Generate try around whole thing to trap scanner errors
println("try { // for lexical error handling");
tabs++;
// Test for public lexical rules with empty paths
for (int i=0; i<nextTokenBlk.getAlternatives().size(); i++) {
Alternative a = nextTokenBlk.getAlternativeAt(i);
if ( a.cache[1].containsEpsilon() ) {
tool.warning("found optional path in nextToken()");
}
}
// Generate the block
String newline = System.getProperty("line.separator");
CppBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false);
String errFinish = "if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken("+namespaceAntlr+"Token::EOF_TYPE);}";
errFinish += newline+"\t\t\t\t";
if ( ((LexerGrammar)grammar).filterMode ) {
if ( filterRule==null ) {
errFinish += "else {consume(); goto tryAgain;}";
}
else {
errFinish += "else {"+newline+
"\t\t\t\t\tcommit();"+newline+
"\t\t\t\t\ttry {m"+filterRule+"(false);}"+newline+
"\t\t\t\t\tcatch("+namespaceAntlr+"RecognitionException& e) {"+newline+
"\t\t\t\t\t // catastrophic failure"+newline+
"\t\t\t\t\t reportError(e);"+newline+
"\t\t\t\t\t consume();"+newline+
"\t\t\t\t\t}"+newline+
"\t\t\t\t\tgoto tryAgain;"+newline+
"\t\t\t\t}";
}
}
else {
errFinish += "else {"+throwNoViable+"}";
}
genBlockFinish(howToFinish, errFinish);
// at this point a valid token has been matched, undo "mark" that was done
if ( ((LexerGrammar)grammar).filterMode && filterRule!=null ) {
println("commit();");
}
// Generate literals test if desired
// make sure _ttype is set first; note _returnToken must be
// non-null as the rule was required to create it.
println("if ( !_returnToken ) goto tryAgain; // found SKIP token");
println("_ttype = _returnToken->getType();");
if ( ((LexerGrammar)grammar).getTestLiterals()) {
genLiteralsTest();
}
// return token created by rule reference in switch
println("_returnToken->setType(_ttype);");
println("return _returnToken;");
// Close try block
tabs--;
println("}");
println("catch ("+namespaceAntlr+"RecognitionException& e) {");
tabs++;
if ( ((LexerGrammar)grammar).filterMode ) {
if ( filterRule==null ) {
println("if ( !getCommitToPath() ) {consume(); goto tryAgain;}");
}
else {
println("if ( !getCommitToPath() ) {");
tabs++;
println("rewind(_m);");
println("resetText();");
println("try {m"+filterRule+"(false);}");
println("catch("+namespaceAntlr+"RecognitionException& ee) {");
println(" // horrendous failure: error in filter rule");
println(" reportError(ee);");
println(" consume();");
println("}");
println("goto tryAgain;");
tabs--;
println("}");
}
}
if ( nextTokenBlk.getDefaultErrorHandler() ) {
println("reportError(e);");
println("consume();");
}
else {
// pass on to invoking routine
println("throw "+namespaceAntlr+"TokenStreamRecognitionException(e);");
}
tabs--;
println("}");
// close CharStreamException try
tabs--;
println("}");
println("catch ("+namespaceAntlr+"CharStreamIOException& csie) {");
println(" throw "+namespaceAntlr+"TokenStreamIOException(csie.io);");
println("}");
println("catch ("+namespaceAntlr+"CharStreamException& cse) {");
println(" throw "+namespaceAntlr+"TokenStreamException(cse.getMessage());");
println("}");
// close for-loop
_println("tryAgain:;");
tabs--;
println("}");
// close method nextToken
tabs--;
println("}");
println("");
}
/** Gen a named rule block.
* ASTs are generated for each element of an alternative unless
* the rule or the alternative have a '!' modifier.
*
* If an alternative defeats the default tree construction, it
* must set <rule>_AST to the root of the returned AST.
*
* Each alternative that does automatic tree construction, builds
* up root and child list pointers in an ASTPair structure.
*
* A rule finishes by setting the returnAST variable from the
* ASTPair.
*
* @param rule The name of the rule to generate
* @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
*/
public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum, String prefix) {
// tabs=1; // JavaCodeGenerator needs this
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRule("+ s.getId() +")");
if ( !s.isDefined() ) {
tool.error("undefined rule: "+ s.getId());
return;
}
// Generate rule return type, name, arguments
RuleBlock rblk = s.getBlock();
currentRule = rblk;
currentASTResult = s.getId();
// Save the AST generation state, and set it to that of the rule
boolean savegenAST = genAST;
genAST = genAST && rblk.getAutoGen();
// boolean oldsaveTest = saveText;
saveText = rblk.getAutoGen();
// print javadoc comment if any
if ( s.comment!=null ) {
_println(s.comment);
}
// Gen method access and final qualifier
// print(s.access + " final ");
// Gen method return type (note lexer return action set at rule creation)
if (rblk.returnAction != null)
{
// Has specified return value
_print(extractTypeOfAction(rblk.returnAction, rblk.getLine()) + " ");
} else {
// No specified return value
_print("void ");
}
// Gen method name
_print(prefix + s.getId() + "(");
// Additional rule parameters common to all rules for this grammar
_print(commonExtraParams);
if (commonExtraParams.length() != 0 && rblk.argAction != null ) {
_print(",");
}
// Gen arguments
if (rblk.argAction != null)
{
// Has specified arguments
_println("");
// FIXME: make argAction also a token? Hmmmmm
// genLineNo(rblk);
tabs++;
println(rblk.argAction);
tabs--;
print(")");
// genLineNo2(); // gcc gives error on the brace... hope it works for the others too
} else {
// No specified arguments
_print(")");
}
// Gen throws clause and open curly
// _print(" throws " + exceptionThrown);
// if ( !(grammar instanceof TreeWalkerGrammar) ) {
// _print(", IOException");
// }
_println(" {");
tabs++;
// Convert return action to variable declaration
if (rblk.returnAction != null)
{
genLineNo(rblk);
println(rblk.returnAction + ";");
genLineNo2();
}
// print out definitions needed by rules for various grammar types
if (!commonLocalVars.equals(""))
println(commonLocalVars);
if (grammar.traceRules) {
if ( grammar instanceof TreeWalkerGrammar ) {
if ( usingCustomAST )
println("Tracer traceInOut(this,\""+ s.getId() +"\",static_cast<"+namespaceAntlr+"RefAST"+">(_t));");
else
println("Tracer traceInOut(this,\""+ s.getId() +"\",_t);");
}
else {
println("Tracer traceInOut(this, \""+ s.getId() +"\");");
}
}
if ( grammar instanceof LexerGrammar ) {
// lexer rule default return value is the rule's token name
// This is a horrible hack to support the built-in EOF lexer rule.
if (s.getId().equals("mEOF"))
println("_ttype = "+namespaceAntlr+"Token::EOF_TYPE;");
else
println("_ttype = "+ s.getId().substring(1)+";");
println("int _saveIndex;"); // used for element! (so we can kill text matched for element)
/*
println("boolean old_saveConsumedInput=saveConsumedInput;");
if ( !rblk.getAutoGen() ) { // turn off "save input" if ! on rule
println("saveConsumedInput=false;");
}
*/
}
// if debugging, write code to mark entry to the rule
if ( grammar.debuggingOutput)
if (grammar instanceof ParserGrammar)
println("fireEnterRule(" + ruleNum + ",0);");
else if (grammar instanceof LexerGrammar)
println("fireEnterRule(" + ruleNum + ",_ttype);");
// Generate trace code if desired
// if ( grammar.debuggingOutput || grammar.traceRules) {
// println("try { // debugging");
// tabs++;
// }
// Initialize AST variables
if (grammar instanceof TreeWalkerGrammar) {
// "Input" value for rule
// println(labeledElementASTType+" " + s.getId() + "_AST_in = "+labeledElementASTType+"(_t);");
println(labeledElementASTType+" " + s.getId() + "_AST_in = _t;");
}
if (grammar.buildAST) {
// Parser member used to pass AST returns from rule invocations
println("returnAST = "+labeledElementASTInit+";");
// Tracks AST construction
println(namespaceAntlr+"ASTPair currentAST;"); // = new ASTPair();");
// User-settable return value for rule.
println(labeledElementASTType+" " + s.getId() + "_AST = "+labeledElementASTInit+";");
}
genBlockPreamble(rblk);
println("");
// Search for an unlabeled exception specification attached to the rule
ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
// Generate try block around the entire rule for error handling
if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
println("try { // for error handling");
tabs++;
}
// Generate the alternatives
if ( rblk.alternatives.size()==1 ) {
// One alternative -- use simple form
Alternative alt = rblk.getAlternativeAt(0);
String pred = alt.semPred;
if ( pred!=null )
genSemPred(pred, currentRule.line);
if (alt.synPred != null) {
tool.warning(
"Syntactic predicate ignored for single alternative",
grammar.getFilename(),
alt.synPred.getLine()
);
}
genAlt(alt, rblk);
}
else {
// Multiple alternatives -- generate complex form
boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
CppBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
genBlockFinish(howToFinish, throwNoViable);
}
// Generate catch phrase for error handling
if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
// Close the try block
tabs--;
println("}");
}
// Generate user-defined or default catch phrases
if (unlabeledUserSpec != null) {
genErrorHandler(unlabeledUserSpec);
}
else if (rblk.getDefaultErrorHandler()) {
// Generate default catch phrase
println("catch (" + exceptionThrown + "& ex) {");
tabs++;
// Generate code to handle error if not guessing
if (grammar.hasSyntacticPredicate) {
println("if( inputState->guessing == 0 ) {");
tabs++;
}
println("reportError(ex);");
if ( !(grammar instanceof TreeWalkerGrammar) ) {
// Generate code to consume until token in k==1 follow set
Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
String followSetName = getBitsetName(markBitsetForGen(follow.fset));
println("consume();");
println("consumeUntil(" + followSetName + ");");
} else {
// Just consume one token
println("if ( _t != "+labeledElementASTInit+" )");
tabs++;
println("_t = _t->getNextSibling();");
tabs--;
}
if (grammar.hasSyntacticPredicate) {
tabs--;
// When guessing, rethrow exception
println("} else {");
tabs++;
println("throw ex;");
tabs--;
println("}");
}
// Close catch phrase
tabs--;
println("}");
}
// Squirrel away the AST "return" value
if (grammar.buildAST) {
println("returnAST = " + s.getId() + "_AST;");
}
// Set return tree value for tree walkers
if ( grammar instanceof TreeWalkerGrammar ) {
println("_retTree = _t;");
}
// Generate literals test for lexer rules so marked
if (rblk.getTestLiterals()) {
if ( s.access.equals("protected") ) {
genLiteralsTestForPartialToken();
}
else {
genLiteralsTest();
}
}
// if doing a lexer rule, dump code to create token if necessary
if ( grammar instanceof LexerGrammar ) {
println("if ( _createToken && _token=="+namespaceAntlr+"nullToken && _ttype!="+namespaceAntlr+"Token::SKIP ) {");
println(" _token = makeToken(_ttype);");
println(" _token->setText(text.substr(_begin, text.length()-_begin));");
println("}");
println("_returnToken = _token;");
// It should be easy for an optimizing compiler to realize this does nothing
// but it avoids the warning about the variable being unused.
println("_saveIndex=0;");
}
// Gen the return statement if there is one (lexer has hard-wired return action)
if (rblk.returnAction != null) {
println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine()) + ";");
}
// if ( grammar.debuggingOutput || grammar.traceRules) {
//// tabs--;
//// println("} finally { // debugging");
//// tabs++;
//
// // Generate trace code if desired
// if ( grammar.debuggingOutput)
// if (grammar instanceof ParserGrammar)
// println("fireExitRule(" + ruleNum + ",0);");
// else if (grammar instanceof LexerGrammar)
// println("fireExitRule(" + ruleNum + ",_ttype);");
//
//// if (grammar.traceRules) {
//// if ( grammar instanceof TreeWalkerGrammar ) {
//// println("traceOut(\""+ s.getId() +"\",_t);");
//// }
//// else {
//// println("traceOut(\""+ s.getId() +"\");");
//// }
//// }
////
//// tabs--;
//// println("}");
// }
tabs--;
println("}");
println("");
// Restore the AST generation state
genAST = savegenAST;
// restore char save state
// saveText = oldsaveTest;
}
public void genRuleHeader(RuleSymbol s, boolean startSymbol) {
tabs=1;
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRuleHeader("+ s.getId() +")");
if ( !s.isDefined() ) {
tool.error("undefined rule: "+ s.getId());
return;
}
// Generate rule return type, name, arguments
RuleBlock rblk = s.getBlock();
currentRule = rblk;
currentASTResult = s.getId();
// Save the AST generation state, and set it to that of the rule
boolean savegenAST = genAST;
genAST = genAST && rblk.getAutoGen();
// boolean oldsaveTest = saveText;
saveText = rblk.getAutoGen();
// Gen method access
print(s.access + ": ");
// Gen method return type (note lexer return action set at rule creation)
if (rblk.returnAction != null)
{
// Has specified return value
_print(extractTypeOfAction(rblk.returnAction, rblk.getLine()) + " ");
} else {
// No specified return value
_print("void ");
}
// Gen method name
_print(s.getId() + "(");
// Additional rule parameters common to all rules for this grammar
_print(commonExtraParams);
if (commonExtraParams.length() != 0 && rblk.argAction != null ) {
_print(",");
}
// Gen arguments
if (rblk.argAction != null)
{
// Has specified arguments
_println("");
tabs++;
println(rblk.argAction);
tabs--;
print(")");
} else {
// No specified arguments
_print(")");
}
_println(";");
tabs--;
// Restore the AST generation state
genAST = savegenAST;
// restore char save state
// saveText = oldsaveTest;
}
private void GenRuleInvocation(RuleRefElement rr) {
// dump rule name
_print(rr.targetRule + "(");
// lexers must tell rule if it should set _returnToken
if ( grammar instanceof LexerGrammar ) {
// if labeled, could access Token, so tell rule to create
if ( rr.getLabel() != null ) {
_print("true");
}
else {
_print("false");
}
if (commonExtraArgs.length() != 0 || rr.args!=null ) {
_print(",");
}
}
// Extra arguments common to all rules for this grammar
_print(commonExtraArgs);
if (commonExtraArgs.length() != 0 && rr.args!=null ) {
_print(",");
}
// Process arguments to method, if any
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rr.args != null)
{
// When not guessing, execute user arg action
ActionTransInfo tInfo = new ActionTransInfo();
String args = processActionForTreeSpecifiers(rr.args, 0, currentRule, tInfo);
if ( tInfo.assignToRoot || tInfo.refRuleRoot!=null ) {
tool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #"+
currentRule.getRuleName()+" on line "+rr.getLine());
}
_print(args);
// Warn if the rule accepts no arguments
if (rs.block.argAction == null)
{
tool.warning("Rule '" + rr.targetRule + "' accepts no arguments",
grammar.getFilename(),
rr.getLine());
}
} else {
// For C++, no warning if rule has parameters, because there may be default
// values for all of the parameters
//if (rs.block.argAction != null) {
// tool.warning("Missing parameters on reference to rule "+rr.targetRule, rr.getLine());
//}
}
_println(");");
// move down to the first child while parsing
if ( grammar instanceof TreeWalkerGrammar ) {
println("_t = _retTree;");
}
}
protected void genSemPred(String pred, int line) {
// translate $ and # references
ActionTransInfo tInfo = new ActionTransInfo();
pred = processActionForTreeSpecifiers(pred, line, currentRule, tInfo);
// ignore translation info...we don't need to do anything with it.
String escapedPred = charFormatter.escapeString(pred);
// if debugging, wrap the semantic predicate evaluation in a method
// that can tell SemanticPredicateListeners the result
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar)))
pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING," //FIXME
+ addSemPred(escapedPred) + "," + pred + ")";
println("if (!(" + pred + "))");
tabs++;
println("throw "+namespaceAntlr+"SemanticException(\"" + escapedPred + "\");");
tabs--;
}
/** Write an array of Strings which are the semantic predicate
* expressions. The debugger will reference them by number only
*/
protected void genSemPredMap(String prefix) {
Enumeration e = semPreds.elements();
println("const char* " + prefix + "_semPredNames[] = {");
tabs++;
while(e.hasMoreElements())
println("\""+e.nextElement()+"\",");
println("0");
tabs--;
println("};");
}
protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen=>("+blk+")");
// Dump synpred result variable
println("bool synPredMatched" + blk.ID + " = false;");
// Gen normal lookahead test
println("if (" + lookaheadExpr + ") {");
tabs++;
// Save input state
if ( grammar instanceof TreeWalkerGrammar ) {
println(labeledElementType + " __t" + blk.ID + " = _t;");
}
else {
println("int _m" + blk.ID + " = mark();");
}
// Once inside the try, assume synpred works unless exception caught
println("synPredMatched" + blk.ID + " = true;");
println("inputState->guessing++;");
// if debugging, tell listeners that a synpred has started
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar))) {
println("fireSyntacticPredicateStarted();");
}
syntacticPredLevel++;
println("try {");
tabs++;
gen((AlternativeBlock)blk); // gen code to test predicate
tabs--;
//println("System.out.println(\"pred "+blk+" succeeded\");");
println("}");
println("catch (" + exceptionThrown + "& pe) {");
tabs++;
println("synPredMatched"+blk.ID+" = false;");
//println("System.out.println(\"pred "+blk+" failed\");");
tabs--;
println("}");
// Restore input state
if ( grammar instanceof TreeWalkerGrammar ) {
println("_t = __t"+blk.ID+";");
}
else {
println("rewind(_m"+blk.ID+");");
}
println("inputState->guessing--;");
// if debugging, tell listeners how the synpred turned out
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar))) {
println("if (synPredMatched" + blk.ID +")");
println(" fireSyntacticPredicateSucceeded();");
println("else");
println(" fireSyntacticPredicateFailed();");
}
syntacticPredLevel--;
tabs--;
// Close lookahead test
println("}");
// Test synpred result
println("if ( synPredMatched"+blk.ID+" ) {");
}
/** Generate a static array containing the names of the tokens,
* indexed by the token type values. This static array is used
* to format error messages so that the token identifers or literal
* strings are displayed instead of the token numbers.
*
* If a lexical rule has a paraphrase, use it rather than the
* token label.
*/
public void genTokenStrings(String prefix) {
// Generate a string for each token. This creates a static
// array of Strings indexed by token type.
// println("");
println("const char* " + prefix + "_tokenNames[] = {");
tabs++;
// Walk the token vocabulary and generate a Vector of strings
// from the tokens.
Vector v = grammar.tokenManager.getVocabulary();
for (int i = 0; i < v.size(); i++)
{
String s = (String)v.elementAt(i);
if (s == null)
{
s = "<"+String.valueOf(i)+">";
}
if ( !s.startsWith("\"") && !s.startsWith("<") ) {
TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s);
if ( ts!=null && ts.getParaphrase()!=null ) {
s = antlr.Tool.stripFrontBack(ts.getParaphrase(), "\"", "\"");
}
}
print(charFormatter.literalString(s));
_println(",");
}
println("0");
// Close the string array initailizer
tabs--;
println("};");
}
/** Generate the token types C++ file */
protected void genTokenTypes(TokenManager tm) throws IOException {
// Open the token output header file and set the currentOutput stream
outputFile = tm.getName() + TokenTypesFileSuffix+".hpp";
outputLine = 1;
currentOutput = antlr.Tool.openOutputFile(outputFile);
//SAS: changed for proper text file io
tabs = 0;
// Generate a guard wrapper
println("#ifndef INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_");
println("#define INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_");
println("");
if (nameSpace != null)
nameSpace.emitDeclarations(currentOutput);
// Generate the header common to all C++ files
genHeader(outputFile);
// Encapsulate the definitions in an interface. This can be done
// because they are all constants.
println("struct " + tm.getName() + TokenTypesFileSuffix+" {");
tabs++;
println("enum {");
tabs++;
// Generate a definition for each token type
Vector v = tm.getVocabulary();
// Do special tokens manually
println("EOF_ = " + Token.EOF_TYPE + ",");
// Move the other special token to the end, so we can solve
// the superfluous comma problem easily
for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if (s != null) {
if ( s.startsWith("\"") ) {
// a string literal
StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
if ( sl==null ) {
antlr.Tool.panic("String literal "+s+" not in symbol table");
}
else if ( sl.label != null ) {
println(sl.label + " = " + i + ",");
}
else {
String mangledName = mangleLiteral(s);
if (mangledName != null) {
// We were able to create a meaningful mangled token name
println(mangledName + " = " + i + ",");
// if no label specified, make the label equal to the mangled name
sl.label = mangledName;
}
else {
println("// " + s + " = " + i);
}
}
}
else if ( !s.startsWith("<") ) {
println(s + " = " + i + ",");
}
}
}
// Moved from above
println("NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD);
// Close the enum
tabs--;
println("};");
// Close the interface
tabs--;
println("};");
if (nameSpace != null)
nameSpace.emitClosures(currentOutput);
// Generate a guard wrapper
println("#endif /*INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_*/");
// Close the tokens output file
currentOutput.close();
currentOutput = null;
exitIfError();
}
/** Process a string for an simple expression for use in xx/action.g
* it is used to cast simple tokens/references to the right type for
* the generated language. Basically called for every element in
* the vector to getASTCreateString(vector V)
* @param str A String.
*/
public String processStringForASTConstructor( String str )
{
if( usingCustomAST &&
((grammar instanceof TreeWalkerGrammar) ||
(grammar instanceof ParserGrammar)) &&
!(grammar.tokenManager.tokenDefined(str) ) )
{
// System.out.println("processStringForASTConstructor: "+str+" with cast");
return "static_cast<"+namespaceAntlr+"RefAST>("+str+")";
}
else
{
// System.out.println("processStringForASTConstructor: "+str);
return str;
}
}
/** Get a string for an expression to generate creation of an AST subtree.
* @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
*/
public String getASTCreateString(Vector v) {
if (v.size() == 0) {
return "";
}
StringBuffer buf = new StringBuffer();
// the labeledElementASTType here can probably be a cast or nothing
// in the case of ! usingCustomAST
buf.append(labeledElementASTType+
"(astFactory.make((new "+namespaceAntlr+
"ASTArray("+v.size()+"))");
for (int i = 0; i < v.size(); i++) {
buf.append("->add("+ v.elementAt(i) + ")");
}
buf.append("))");
return buf.toString();
}
/** Get a string for an expression to generate creating of an AST node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(GrammarAtom atom, String str) {
if ( atom!=null && atom.getASTNodeType() != null ) {
// RK: I guess this is heterogeneous ast stuff...
return "Ref"+atom.getASTNodeType()+"(new "+atom.getASTNodeType()+"("+str+"))";
}
else
{
// This is *SO* ugly... but it will have to do for now... 2.7.2 will
// have better.
boolean is_constructor = false;
if( str.indexOf(',') != -1 )
is_constructor = grammar.tokenManager.tokenDefined(str.substring(0,str.indexOf(',')));
// System.out.println("getAstCreateString(as): "+str+" "+grammar.tokenManager.tokenDefined(str));
if( usingCustomAST &&
(grammar instanceof TreeWalkerGrammar) &&
!(grammar.tokenManager.tokenDefined(str) ) &&
! is_constructor )
return "astFactory.create(static_cast<"+namespaceAntlr+"RefAST>("+str+"))";
else
return "astFactory.create("+str+")";
}
}
/** Get a string for an expression to generate creating of an AST node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(String str) {
// System.out.println("getAstCreateString(str): "+str+" "+grammar.tokenManager.tokenDefined(str));
if( usingCustomAST )
return "static_cast<"+labeledElementASTType+">(astFactory.create(static_cast<"+namespaceAntlr+"RefAST>( /*ss*/ "+str+")))";
else
return "astFactory.create("+str+")";
}
protected String getLookaheadTestExpression(Lookahead[] look, int k) {
StringBuffer e = new StringBuffer(100);
boolean first = true;
e.append("(");
for (int i = 1; i <= k; i++) {
BitSet p = look[i].fset;
if (!first) {
e.append(") && (");
}
first = false;
// Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
// There is no way to predict what that token would be. Just
// allow anything instead.
if (look[i].containsEpsilon()) {
e.append("true");
} else {
e.append(getLookaheadTestTerm(i, p));
}
}
e.append(")");
return e.toString();
}
/** Generate a lookahead test expression for an alternate. This
* will be a series of tests joined by '&&' and enclosed by '()',
* the number of such tests being determined by the depth of the lookahead.
*/
protected String getLookaheadTestExpression(Alternative alt, int maxDepth) {
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
// if the decision is nondeterministic, do the best we can: LL(k)
// any predicates that are around will be generated later.
depth = grammar.maxk;
}
if ( maxDepth==0 ) {
// empty lookahead can result from alt with sem pred
// that can see end of token. E.g., A : {pred}? ('a')? ;
return "true";
}
/*
boolean first = true;
for (int i=1; i<=depth && i<=maxDepth; i++) {
BitSet p = alt.cache[i].fset;
if (!first) {
e.append(") && (");
}
first = false;
// Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
// There is no way to predict what that token would be. Just
// allow anything instead.
if ( alt.cache[i].containsEpsilon() ) {
e.append("true");
}
else {
e.append(getLookaheadTestTerm(i, p));
}
}
e.append(")");
*/
return "(" + getLookaheadTestExpression(alt.cache,depth) + ")";
}
/**Generate a depth==1 lookahead test expression given the BitSet.
* This may be one of:
* 1) a series of 'x==X||' tests
* 2) a range test using >= && <= where possible,
* 3) a bitset membership test for complex comparisons
* @param k The lookahead level
* @param p The lookahead set for level k
*/
protected String getLookaheadTestTerm(int k, BitSet p) {
// Determine the name of the item to be compared
String ts = lookaheadString(k);
// Generate a range expression if possible
int[] elems = p.toArray();
if (elementsAreRange(elems)) {
return getRangeExpression(k, elems);
}
// Generate a bitset membership test if possible
StringBuffer e;
int degree = p.degree();
if ( degree == 0 ) {
return "true";
}
if (degree >= bitsetTestThreshold) {
int bitsetIdx = markBitsetForGen(p);
return getBitsetName(bitsetIdx) + ".member(" + ts + ")";
}
// Otherwise, generate the long-winded series of "x==X||" tests
e = new StringBuffer();
for (int i = 0; i < elems.length; i++) {
// Get the compared-to item (token or character value)
String cs = getValueString(elems[i]);
// Generate the element comparison
if ( i>0 ) e.append("||");
e.append(ts);
e.append("==");
e.append(cs);
}
return e.toString();
}
/** Return an expression for testing a contiguous renage of elements
* @param k The lookahead level
* @param elems The elements representing the set, usually from BitSet.toArray().
* @return String containing test expression.
*/
public String getRangeExpression(int k, int[] elems) {
if (!elementsAreRange(elems)) {
tool.panic("getRangeExpression called with non-range");
}
int begin = elems[0];
int end = elems[elems.length-1];
return
"(" + lookaheadString(k) + " >= " + getValueString(begin) + " && " +
lookaheadString(k) + " <= " + getValueString(end) + ")";
}
/** getValueString: get a string representation of a token or char value
* @param value The token or char value
*/
private String getValueString(int value) {
String cs;
if ( grammar instanceof LexerGrammar ) {
cs = charFormatter.literalChar(value);
}
else {
TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value);
if ( ts == null ) {
return ""+value; // return token type as string
// tool.panic("vocabulary for token type " + value + " is null");
}
String tId = ts.getId();
if ( ts instanceof StringLiteralSymbol ) {
// if string literal, use predefined label if any
// if no predefined, try to mangle into LITERAL_xxx.
// if can't mangle, use int value as last resort
StringLiteralSymbol sl = (StringLiteralSymbol)ts;
String label = sl.getLabel();
if ( label!=null ) {
cs = label;
}
else {
cs = mangleLiteral(tId);
if (cs == null) {
cs = String.valueOf(value);
}
}
}
else {
if ( tId.equals("EOF") )
cs = namespaceAntlr+"Token::EOF_TYPE";
else
cs = tId;
}
}
return cs;
}
/**Is the lookahead for this alt empty? */
protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
depth = grammar.maxk;
}
for (int i=1; i<=depth && i<=maxDepth; i++) {
BitSet p = alt.cache[i].fset;
if (p.degree() != 0) {
return false;
}
}
return true;
}
private String lookaheadString(int k) {
if (grammar instanceof TreeWalkerGrammar) {
return "_t->getType()";
}
return "LA(" + k + ")";
}
/** Mangle a string literal into a meaningful token name. This is
* only possible for literals that are all characters. The resulting
* mangled literal name is literalsPrefix with the text of the literal
* appended.
* @return A string representing the mangled literal, or null if not possible.
*/
private String mangleLiteral(String s) {
String mangled = antlr.Tool.literalsPrefix;
for (int i = 1; i < s.length()-1; i++) {
if (!Character.isLetter(s.charAt(i)) &&
s.charAt(i) != '_') {
return null;
}
mangled += s.charAt(i);
}
if ( antlr.Tool.upperCaseMangledLiterals ) {
mangled = mangled.toUpperCase();
}
return mangled;
}
/** Map an identifier to it's corresponding tree-node variable.
* This is context-sensitive, depending on the rule and alternative
* being generated
* @param idParam The identifier name to map
* @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
*/
public String mapTreeId(String idParam, ActionTransInfo transInfo) {
// if not in an action of a rule, nothing to map.
if ( currentRule==null ) return idParam;
// System.out.print("mapTreeId: "+idParam+" ");
boolean in_var = false;
String id = idParam;
if (grammar instanceof TreeWalkerGrammar) {
if ( !grammar.buildAST ) {
in_var = true;
// System.out.println("in_var1");
}
// If the id ends with "_in", then map it to the input variable
else if (id.length() > 3 && id.lastIndexOf("_in") == id.length()-3) {
// Strip off the "_in"
id = id.substring(0, id.length()-3);
in_var = true;
// System.out.println("in_var2");
}
}
// System.out.print(in_var+"\t");
// Check the rule labels. If id is a label, then the output
// variable is label_AST, and the input variable is plain label.
for (int i = 0; i < currentRule.labeledElements.size(); i++) {
AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i);
if (elt.getLabel().equals(id)) {
// if( in_var )
// System.out.println("returning (vec) "+(in_var ? id : id + "_AST"));
return in_var ? id : id + "_AST";
}
}
// Failing that, check the id-to-variable map for the alternative.
// If the id is in the map, then output variable is the name in the
// map, and input variable is name_in
String s = (String)treeVariableMap.get(id);
if (s != null) {
if (s == NONUNIQUE) {
// if( in_var )
// System.out.println("returning null (nonunique)");
// There is more than one element with this id
return null;
} else if (s.equals(currentRule.getRuleName())) {
// a recursive call to the enclosing rule is
// ambiguous with the rule itself.
// if( in_var )
// System.out.println("returning null (rulename)");
return null;
} else {
// if( in_var )
// System.out.println("returning "+(in_var?s+"_in":s));
return in_var ? s + "_in" : s;
}
}
// Failing that, check the rule name itself. Output variable
// is rule_AST; input variable is rule_AST_in (treeparsers).
if (id.equals(currentRule.getRuleName())) {
String r = in_var ? id + "_AST_in" : id + "_AST";
if ( transInfo!=null ) {
if ( !in_var ) {
transInfo.refRuleRoot = r;
}
}
// if( in_var )
// System.out.println("returning (r) "+r);
return r;
} else {
// if( in_var )
// System.out.println("returning (last) "+id);
// id does not map to anything -- return itself.
return id;
}
}
/** Given an element and the name of an associated AST variable,
* create a mapping between the element "name" and the variable name.
*/
private void mapTreeVariable(AlternativeElement e, String name)
{
// For tree elements, defer to the root
if (e instanceof TreeElement) {
mapTreeVariable( ((TreeElement)e).root, name);
return;
}
// Determine the name of the element, if any, for mapping purposes
String elName = null;
// Don't map labeled items
if (e.getLabel() == null) {
if (e instanceof TokenRefElement) {
// use the token id
elName = ((TokenRefElement)e).atomText;
}
else if (e instanceof RuleRefElement) {
// use the rule name
elName = ((RuleRefElement)e).targetRule;
}
}
// Add the element to the tree variable map if it has a name
if (elName != null) {
if (treeVariableMap.get(elName) != null) {
// Name is already in the map -- mark it as duplicate
treeVariableMap.remove(elName);
treeVariableMap.put(elName, NONUNIQUE);
}
else {
treeVariableMap.put(elName, name);
}
}
}
/** Lexically process tree-specifiers in the action.
* This will replace #id and #(...) with the appropriate
* function calls and/or variables.
*/
protected String processActionForTreeSpecifiers(String actionStr, int line, RuleBlock currentRule, ActionTransInfo tInfo) {
if ( actionStr==null || actionStr.length()==0 )
return null;
// The action trans info tells us (at the moment) whether an
// assignment was done to the rule's tree root.
if (grammar==null)
return actionStr;
if ( (grammar.buildAST && actionStr.indexOf('#') != -1) ||
grammar instanceof TreeWalkerGrammar ||
(grammar instanceof LexerGrammar && actionStr.indexOf('$') != -1) ) {
// Create a lexer to read an action and return the translated version
antlr.actions.cpp.ActionLexer lexer =
new antlr.actions.cpp.ActionLexer(actionStr, currentRule,
this, tInfo);
lexer.setLineOffset(line);
lexer.setTool(tool);
try {
lexer.mACTION(true);
actionStr = lexer.getTokenObject().getText();
// System.out.println("action translated: "+actionStr);
// System.out.println("trans info is "+tInfo);
}
catch (RecognitionException ex) {
lexer.reportError(ex);
return actionStr;
}
catch (TokenStreamException tex) {
antlr.Tool.panic("Error reading action:"+actionStr);
return actionStr;
}
catch (CharStreamException io) {
antlr.Tool.panic("Error reading action:"+actionStr);
return actionStr;
}
}
return actionStr;
}
private String fixNameSpaceOption( String ns )
{
ns = Tool.stripFrontBack(ns,"\"","\"");
if( ns.length() > 2 &&
!ns.substring(ns.length()-2, ns.length()).equals("::") )
ns += "::";
return ns;
}
private void setupGrammarParameters(Grammar g) {
if (g instanceof ParserGrammar ||
g instanceof LexerGrammar ||
g instanceof TreeWalkerGrammar
)
{
/* RK: options also have to be added to Grammar.java and for options
* on the file level entries have to be defined in
* DefineGrammarSymbols.java and passed around via 'globals' in Tool.java
*/
if( Tool.nameSpace != null )
nameSpace = Tool.nameSpace;
if( Tool.namespaceStd != null )
namespaceStd = fixNameSpaceOption(Tool.namespaceStd);
if( Tool.namespaceAntlr != null )
namespaceAntlr = fixNameSpaceOption(Tool.namespaceAntlr);
genHashLines = Tool.genHashLines;
/* let grammar level options override filelevel ones...
*/
if( g.hasOption("namespace") ) {
Token t = g.getOption("namespace");
if( t != null ) {
nameSpace = new NameSpace(t.getText());
}
}
if( g.hasOption("namespaceAntlr") ) {
Token t = g.getOption("namespaceAntlr");
if( t != null ) {
String ns = Tool.stripFrontBack(t.getText(),"\"","\"");
if ( ns != null ) {
if( ns.length() > 2 &&
!ns.substring(ns.length()-2, ns.length()).equals("::") )
ns += "::";
namespaceAntlr = ns;
}
}
}
if( g.hasOption("namespaceStd") ) {
Token t = g.getOption("namespaceStd");
if( t != null ) {
String ns = Tool.stripFrontBack(t.getText(),"\"","\"");
if ( ns != null ) {
if( ns.length() > 2 &&
!ns.substring(ns.length()-2, ns.length()).equals("::") )
ns += "::";
namespaceStd = ns;
}
}
}
if( g.hasOption("genHashLines") ) {
Token t = g.getOption("genHashLines");
if( t != null ) {
String val = Tool.stripFrontBack(t.getText(),"\"","\"");
genHashLines = val.equals("true");
}
}
}
if (g instanceof ParserGrammar) {
labeledElementASTType = namespaceAntlr+"RefAST";
labeledElementASTInit = namespaceAntlr+"nullAST";
if ( g.hasOption("ASTLabelType") ) {
Token tsuffix = g.getOption("ASTLabelType");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
usingCustomAST = true;
labeledElementASTType = suffix;
labeledElementASTInit = "static_cast<"+suffix+">("+namespaceAntlr+"nullAST)";
}
}
}
labeledElementType = namespaceAntlr+"RefToken ";
labeledElementInit = namespaceAntlr+"nullToken";
commonExtraArgs = "";
commonExtraParams = "";
commonLocalVars = "";
lt1Value = "LT(1)";
exceptionThrown = namespaceAntlr+"RecognitionException";
throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(LT(1), getFilename());";
}
else if (g instanceof LexerGrammar) {
labeledElementType = "char ";
labeledElementInit = "'\\0'";
commonExtraArgs = "";
commonExtraParams = "bool _createToken";
commonLocalVars = "int _ttype; "+namespaceAntlr+"RefToken _token; int _begin=text.length();";
lt1Value = "LA(1)";
exceptionThrown = namespaceAntlr+"RecognitionException";
throwNoViable = "throw "+namespaceAntlr+"NoViableAltForCharException(LA(1), getFilename(), getLine());";
}
else if (g instanceof TreeWalkerGrammar) {
labeledElementInit = namespaceAntlr+"nullAST";
labeledElementASTInit = namespaceAntlr+"nullAST";
labeledElementASTType = namespaceAntlr+"RefAST";
labeledElementType = namespaceAntlr+"RefAST";
commonExtraParams = namespaceAntlr+"RefAST _t";
throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(_t);";
lt1Value = "_t";
if ( g.hasOption("ASTLabelType") ) {
Token tsuffix = g.getOption("ASTLabelType");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
usingCustomAST = true;
labeledElementASTType = suffix;
labeledElementType = suffix;
labeledElementInit = "static_cast<"+suffix+">("+namespaceAntlr+"nullAST)";
labeledElementASTInit = labeledElementInit;
commonExtraParams = suffix+" _t";
throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(static_cast<"+namespaceAntlr+"RefAST>(_t));";
lt1Value = "_t";
}
}
}
if ( !g.hasOption("ASTLabelType") ) {
g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL,namespaceAntlr+"RefAST"));
}
commonExtraArgs = "_t";
commonLocalVars = "";
exceptionThrown = namespaceAntlr+"RecognitionException";
}
else {
tool.panic("Unknown grammar type");
}
}
private String textOrChar(String text) {
// check to see if the text is a single character
if (text.startsWith("'")) {
// assume it also ends with '
return charFormatter.literalChar(ANTLRLexer.tokenTypeForCharLiteral(text));
}
else
return text;
}
}
1.1 e/src/jsrc/antlr/DefaultFileLineFormatter.java
Index: DefaultFileLineFormatter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: DefaultFileLineFormatter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class DefaultFileLineFormatter extends FileLineFormatter {
public String getFormatString(String fileName, int line) {
if ( fileName != null ) {
return fileName+":"+line+": ";
}
else {
return "line "+line+": ";
}
}
};
1.1 e/src/jsrc/antlr/DefaultToolErrorHandler.java
Index: DefaultToolErrorHandler.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: DefaultToolErrorHandler.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
class DefaultToolErrorHandler implements ToolErrorHandler {
CharFormatter javaCharFormatter = new JavaCharFormatter();
/** Dump token/character sets to System.out
* @param lexicalAnalysis true for lexical rule
* @param depth The depth of the ambiguity
* @param sets An array of bitsets containing the ambiguities
*/
private void dumpSets(Grammar grammar,
boolean lexicalAnalysis,
int depth,
Lookahead[] sets,
String linePrefix)
{
for (int i = 1; i <= depth; i++) {
System.out.print(linePrefix+"\tk==" + i + ":");
if (lexicalAnalysis) {
String bits = sets[i].fset.toStringWithRanges(",", javaCharFormatter);
if ( sets[i].containsEpsilon() ) {
System.out.print("<end-of-token>");
if ( bits.length()>0 ) {
System.out.print(",");
}
}
System.out.println(bits);
}
else {
System.out.println(sets[i].fset.toString(",", grammar.tokenManager.getVocabulary()));
}
}
}
/** Issue a warning about ambiguity between a alternates
* @param blk The block being analyzed
* @param lexicalAnalysis true for lexical rule
* @param depth The depth of the ambiguity
* @param sets An array of bitsets containing the ambiguities
* @param altIdx1 The zero-based index of the first ambiguous alternative
* @param altIdx2 The zero-based index of the second ambiguous alternative
*/
public void warnAltAmbiguity(Grammar grammar,
AlternativeBlock blk,
boolean lexicalAnalysis,
int depth,
Lookahead[] sets,
int altIdx1,
int altIdx2)
{
String fileline = FileLineFormatter.getFormatter().getFormatString(grammar.getFilename(),blk.getLine());
if ( blk instanceof RuleBlock && ((RuleBlock)blk).isLexerAutoGenRule() ) {
System.out.print("warning: lexical nondeterminism between rules ");
Alternative ai = blk.getAlternativeAt(altIdx1);
Alternative aj = blk.getAlternativeAt(altIdx2);
RuleRefElement rri = (RuleRefElement)ai.head;
RuleRefElement rrj = (RuleRefElement)aj.head;
String ri = CodeGenerator.reverseLexerRuleName(rri.targetRule);
String rj = CodeGenerator.reverseLexerRuleName(rrj.targetRule);
System.out.println(ri+" and "+rj+" upon");
dumpSets(grammar, lexicalAnalysis, depth, sets, fileline);
return;
}
System.out.println(
// "warning: line " + blk.getLine() + ": " +
fileline+"warning: "+
(lexicalAnalysis ? "lexical " : "") + "nondeterminism upon"
);
dumpSets(grammar, lexicalAnalysis, depth, sets, fileline);
System.out.println(fileline+"\tbetween alts " + (altIdx1+1) + " and " + (altIdx2+1) + " of block");
}
/** Issue a warning about ambiguity between an alternate and exit path.
* @param blk The block being analyzed
* @param lexicalAnalysis true for lexical rule
* @param depth The depth of the ambiguity
* @param sets An array of bitsets containing the ambiguities
* @param altIdx The zero-based index of the ambiguous alternative
*/
public void warnAltExitAmbiguity(Grammar grammar,
BlockWithImpliedExitPath blk,
boolean lexicalAnalysis,
int depth,
Lookahead[] sets,
int altIdx
)
{
String fileline = FileLineFormatter.getFormatter().getFormatString(grammar.getFilename(),blk.getLine());
System.out.println(
// "warning: line " + blk.getLine() + ": " +
fileline+"warning: "+
(lexicalAnalysis ? "lexical " : "") + "nondeterminism upon"
);
dumpSets(grammar, lexicalAnalysis, depth, sets, fileline);
System.out.println(fileline+"\tbetween alt " + (altIdx+1) + " and exit branch of block");
}
}
1.1 e/src/jsrc/antlr/DefineGrammarSymbols.java
Index: DefineGrammarSymbols.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: DefineGrammarSymbols.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import antlr.collections.impl.BitSet;
/**DefineGrammarSymbols is a behavior for the ANTLRParser that adds all
* the token and rule symbols to the grammar symbol table.
*
* Token types are assigned to token symbols in this class also.
* The token type for a token is done in the order seen (lexically).
*/
public class DefineGrammarSymbols implements ANTLRGrammarParseBehavior
{
// Contains all of the defined parser and lexer Grammar's indexed by name
protected Hashtable grammars = new Hashtable();
// Contains all the TokenManagers indexed by name
protected Hashtable tokenManagers = new Hashtable();
// Current grammar (parser or lexer)
protected Grammar grammar;
// The tool under which this is invoked
protected Tool tool;
// The grammar analyzer object
LLkAnalyzer analyzer;
// The command-line arguments passed to the tool.
// This allows each grammar to parse the arguments as it is created
String[] args;
// Name for default token manager does not match any valid name
static final String DEFAULT_TOKENMANAGER_NAME = "*default";
// Header actions apply to all parsers unless redefined
// Contains all of the header actions indexed by name
protected Hashtable headerActions = new Hashtable();
// Place where preamble is stored until a grammar is defined
Token thePreambleAction = new CommonToken(Token.INVALID_TYPE, ""); // init to empty token
// The target language
String language = "Java";
protected int numLexers = 0;
protected int numParsers = 0;
protected int numTreeParsers = 0;
public DefineGrammarSymbols(Tool tool_, String[] args_, LLkAnalyzer analyzer_)
{
tool = tool_;
args = args_;
analyzer = analyzer_;
}
public void _refStringLiteral(Token lit, Token label, int autoGenType, boolean lastInRule)
{
if (!(grammar instanceof LexerGrammar))
{
// String literals are treated like tokens except by the lexer
String str = lit.getText();
if ( grammar.tokenManager.getTokenSymbol(str) != null )
{
// string symbol is already defined
return;
}
StringLiteralSymbol sl = new StringLiteralSymbol(str);
int tt = grammar.tokenManager.nextTokenType();
sl.setTokenType(tt);
grammar.tokenManager.define(sl);
}
}
/** Reference a token */
public void _refToken(Token assignId,
Token t,
Token label,
Token args,
boolean inverted,
int autoGenType,
boolean lastInRule)
{
String id = t.getText();
if (!grammar.tokenManager.tokenDefined(id))
{
int tt = grammar.tokenManager.nextTokenType();
TokenSymbol ts = new TokenSymbol(id);
ts.setTokenType(tt);
grammar.tokenManager.define(ts);
}
}
/** Abort the processing of a grammar due to syntax errors */
public void abortGrammar()
{
if (grammar != null && grammar.getClassName() != null)
{
grammars.remove(grammar.getClassName());
}
grammar = null;
}
public void beginAlt(boolean doAST_)
{
}
public void beginChildList()
{
}
// Exception handling
public void beginExceptionGroup() {
}
public void beginExceptionSpec(Token label) {
}
public void beginSubRule(Token label, int line, boolean not)
{
}
public void beginTree(int line) throws SemanticException
{
}
/** Define a lexer or parser rule */
public void defineRuleName(Token r,
String access,
boolean ruleAutoGen,
String docComment)
throws SemanticException
{
String id = r.getText();
// if ( Character.isUpperCase(id.charAt(0)) ) {
if ( r.type == ANTLRTokenTypes.TOKEN_REF )
{
// lexer rule
id = CodeGenerator.lexerRuleName(id);
// make sure we define it as token identifier also
if ( !grammar.tokenManager.tokenDefined(r.getText()) )
{
int tt = grammar.tokenManager.nextTokenType();
TokenSymbol ts = new TokenSymbol(r.getText());
ts.setTokenType(tt);
grammar.tokenManager.define(ts);
}
}
RuleSymbol rs;
if ( grammar.isDefined(id) )
{
// symbol seen before?
rs = (RuleSymbol) grammar.getSymbol(id);
// rule just referenced or has it been defined yet?
if ( rs.isDefined() )
{
tool.error("redefinition of rule "+id, grammar.getFilename(), r.getLine());
}
}
else
{
rs = new RuleSymbol(id);
grammar.define(rs);
}
rs.setDefined();
rs.access = access;
rs.comment = docComment;
}
/** Define a token from tokens {...}.
* Must be label and literal or just label or just a literal.
*/
public void defineToken(Token tokname, Token tokliteral)
{
String name = null;
String literal = null;
if (tokname != null)
{
name = tokname.getText();
}
if (tokliteral != null)
{
literal = tokliteral.getText();
}
// System.out.println("defining " + name + " with literal " + literal);
//
if (literal != null)
{
StringLiteralSymbol sl=(StringLiteralSymbol)grammar.tokenManager.getTokenSymbol(literal);
if ( sl != null)
{
// This literal is known already.
// If the literal has no label already, but we can provide
// one here, then no problem, just map the label to the literal
// and don't change anything else.
// Otherwise, labels conflict: error.
if ( name==null || sl.getLabel()!=null )
{
tool.warning("Redefinition of literal in tokens {...}: " + literal, grammar.getFilename(), tokliteral.getLine());
return;
}
else if ( name!=null )
{
// The literal had no label, but new def does. Set it.
sl.setLabel(name);
// Also, map the label to the literal.
grammar.tokenManager.mapToTokenSymbol(name, sl);
}
}
// if they provide a name/label and that name/label already
// exists, just hook this literal onto old token.
if (name != null)
{
TokenSymbol ts = (TokenSymbol) grammar.tokenManager.getTokenSymbol(name);
if (ts != null)
{
// watch out that the label is not more than just a token.
// If it already has a literal attached, then: conflict.
if ( ts instanceof StringLiteralSymbol )
{
tool.warning("Redefinition of token in tokens {...}: " + name, grammar.getFilename(), tokliteral.getLine());
return;
}
// a simple token symbol such as DECL is defined
// must convert it to a StringLiteralSymbol with a
// label by co-opting token type and killing old
// TokenSymbol. Kill mapping and entry in vector
// of token manager.
// First, claim token type.
int ttype = ts.getTokenType();
// now, create string literal with label
sl = new StringLiteralSymbol(literal);
sl.setTokenType(ttype);
sl.setLabel(name);
// redefine this critter as a string literal
grammar.tokenManager.define(sl);
// make sure the label can be used also.
grammar.tokenManager.mapToTokenSymbol(name, sl);
return;
}
// here, literal was labeled but not by a known token symbol.
}
sl = new StringLiteralSymbol(literal);
int tt = grammar.tokenManager.nextTokenType();
sl.setTokenType(tt);
sl.setLabel(name);
grammar.tokenManager.define(sl);
if (name != null)
{
// make the label point at token symbol too
grammar.tokenManager.mapToTokenSymbol(name, sl);
}
}
// create a token in the token manager not a literal
else
{
if (grammar.tokenManager.tokenDefined(name))
{
tool.warning("Redefinition of token in tokens {...}: " + name, grammar.getFilename(), tokname.getLine());
return;
}
int tt = grammar.tokenManager.nextTokenType();
TokenSymbol ts = new TokenSymbol(name);
ts.setTokenType(tt);
grammar.tokenManager.define(ts);
}
}
public void endAlt()
{
}
public void endChildList()
{
}
public void endExceptionGroup() {
}
public void endExceptionSpec() {
}
public void endGrammar()
{
}
/** Called after the optional options section, to compensate for
* options that may not have been set.
* This method is bigger than it needs to be, but is much more
* clear if I delineate all the cases.
*/
public void endOptions()
{
// NO VOCAB OPTIONS
if ( grammar.exportVocab==null && grammar.importVocab==null )
{
grammar.exportVocab = grammar.getClassName();
// Can we get initial vocab from default shared vocab?
if (tokenManagers.containsKey(DEFAULT_TOKENMANAGER_NAME))
{
// Use the already-defined token manager
grammar.exportVocab = DEFAULT_TOKENMANAGER_NAME;
TokenManager tm = (TokenManager) tokenManagers.get(DEFAULT_TOKENMANAGER_NAME);
// System.out.println("No tokenVocabulary for '" + grammar.getClassName() + "', using default '" + tm.getName() + "'");
grammar.setTokenManager(tm);
return;
}
// no shared vocab for file, make new one
// System.out.println("No exportVocab for '" + grammar.getClassName() + "', creating default '" + grammar.exportVocab + "'");
TokenManager tm = new SimpleTokenManager(grammar.exportVocab, tool);
grammar.setTokenManager(tm);
// Add the token manager to the list of token managers
tokenManagers.put(grammar.exportVocab, tm);
// no default vocab, so make this the default vocab
tokenManagers.put(DEFAULT_TOKENMANAGER_NAME, tm);
return;
}
// NO OUTPUT, BUT HAS INPUT VOCAB
if ( grammar.exportVocab==null && grammar.importVocab!=null )
{
grammar.exportVocab = grammar.getClassName();
// first make sure input!=output
if ( grammar.importVocab.equals(grammar.exportVocab) )
{
tool.warning("Grammar " + grammar.getClassName() +
" cannot have importVocab same as default output vocab (grammar name); ignored.");
// kill importVocab option and try again: use default vocab
grammar.importVocab = null;
endOptions();
return;
}
// check to see if the vocab is already in memory
// (defined by another grammar in the file). Not normal situation.
if (tokenManagers.containsKey(grammar.importVocab))
{
// make a copy since we'll be generating a new output vocab
// and we don't want to affect this one. Set the name to
// the default output vocab==classname.
TokenManager tm = (TokenManager) tokenManagers.get(grammar.importVocab);
// System.out.println("Duping importVocab of " + grammar.importVocab);
TokenManager dup = (TokenManager)tm.clone();
dup.setName(grammar.exportVocab);
// System.out.println("Setting name to " + grammar.exportVocab);
dup.setReadOnly(false);
grammar.setTokenManager(dup);
tokenManagers.put(grammar.exportVocab, dup);
return;
}
// System.out.println("reading in vocab "+grammar.importVocab);
// Must be a file, go get it.
ImportVocabTokenManager tm =
new ImportVocabTokenManager(grammar,
grammar.importVocab + CodeGenerator.TokenTypesFileSuffix + CodeGenerator.TokenTypesFileExt,
grammar.exportVocab,
tool);
tm.setReadOnly(false); // since renamed, can write out
// Add this token manager to the list so its tokens will be generated
tokenManagers.put(grammar.exportVocab, tm);
// System.out.println("vocab renamed to default output vocab of "+tm.getName());
// Assign the token manager to this grammar.
grammar.setTokenManager(tm);
// set default vocab if none
if (!tokenManagers.containsKey(DEFAULT_TOKENMANAGER_NAME))
{
tokenManagers.put(DEFAULT_TOKENMANAGER_NAME, tm);
}
return;
}
// OUTPUT VOCAB, BUT NO INPUT VOCAB
if ( grammar.exportVocab!=null && grammar.importVocab==null )
{
// share with previous vocab if it exists
if (tokenManagers.containsKey(grammar.exportVocab))
{
// Use the already-defined token manager
TokenManager tm = (TokenManager) tokenManagers.get(grammar.exportVocab);
// System.out.println("Sharing exportVocab of " + grammar.exportVocab);
grammar.setTokenManager(tm);
return;
}
// create new output vocab
// System.out.println("Creating exportVocab " + grammar.exportVocab);
TokenManager tm = new SimpleTokenManager(grammar.exportVocab, tool);
grammar.setTokenManager(tm);
// Add the token manager to the list of token managers
tokenManagers.put(grammar.exportVocab, tm);
// set default vocab if none
if (!tokenManagers.containsKey(DEFAULT_TOKENMANAGER_NAME))
{
tokenManagers.put(DEFAULT_TOKENMANAGER_NAME, tm);
}
return;
}
// BOTH INPUT AND OUTPUT VOCAB
if ( grammar.exportVocab!=null && grammar.importVocab!=null )
{
// don't want input==output
if (grammar.importVocab.equals(grammar.exportVocab))
{
tool.error("exportVocab of " + grammar.exportVocab + " same as importVocab; probably not what you want");
}
// does the input vocab already exist in memory?
if (tokenManagers.containsKey(grammar.importVocab))
{
// make a copy since we'll be generating a new output vocab
// and we don't want to affect this one.
TokenManager tm = (TokenManager) tokenManagers.get(grammar.importVocab);
// System.out.println("Duping importVocab of " + grammar.importVocab);
TokenManager dup = (TokenManager)tm.clone();
dup.setName(grammar.exportVocab);
// System.out.println("Setting name to " + grammar.exportVocab);
dup.setReadOnly(false);
grammar.setTokenManager(dup);
tokenManagers.put(grammar.exportVocab, dup);
return;
}
// Must be a file, go get it.
ImportVocabTokenManager tm =
new ImportVocabTokenManager(grammar,
grammar.importVocab + CodeGenerator.TokenTypesFileSuffix + CodeGenerator.TokenTypesFileExt,
grammar.exportVocab,
tool);
tm.setReadOnly(false); // write it out as we've changed name
// Add this token manager to the list so its tokens will be generated
tokenManagers.put(grammar.exportVocab, tm);
// Assign the token manager to this grammar.
grammar.setTokenManager(tm);
// set default vocab if none
if (!tokenManagers.containsKey(DEFAULT_TOKENMANAGER_NAME))
{
tokenManagers.put(DEFAULT_TOKENMANAGER_NAME, tm);
}
return;
}
}
public void endRule(String r)
{
}
public void endSubRule()
{
}
public void endTree()
{
}
public void hasError()
{
}
public void noASTSubRule()
{
}
public void oneOrMoreSubRule()
{
}
public void optionalSubRule()
{
}
public void setUserExceptions(String thr) {}
public void refAction(Token action)
{
}
public void refArgAction(Token action)
{
}
public void refCharLiteral(Token lit, Token label, boolean inverted, int autoGenType, boolean lastInRule)
{
}
public void refCharRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule)
{
}
public void refElementOption(Token option, Token value) {
}
public void refTokensSpecElementOption(Token tok, Token option, Token value) {
}
public void refExceptionHandler(Token exTypeAndName, Token action) {
}
// Header action applies to all parsers and lexers.
public void refHeaderAction(Token name,Token act)
{
headerActions.put((name==null) ? "" : Tool.stripFrontBack(name.getText(),"\"","\""),
act);
// headerAction = act.getText();
}
public String getHeaderAction(String name)
{
Token t = (Token)headerActions.get(name);
if ( t==null )
{
return "";
}
return t.getText();
}
public void refInitAction(Token action)
{
}
public void refMemberAction(Token act)
{
}
public void refPreambleAction(Token act)
{
thePreambleAction = act;
}
public void refReturnAction(Token returnAction)
{
}
public void refRule(Token idAssign,
Token r,
Token label,
Token args,
int autoGenType)
{
String id = r.getText();
// if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
if ( r.type == ANTLRTokenTypes.TOKEN_REF )
{
// lexer rule?
id = CodeGenerator.lexerRuleName(id);
}
if ( !grammar.isDefined(id) )
{
grammar.define(new RuleSymbol(id));
}
}
public void refSemPred(Token pred)
{
}
public void refStringLiteral(Token lit,
Token label,
int autoGenType,
boolean lastInRule)
{
_refStringLiteral(lit, label, autoGenType, lastInRule);
}
/** Reference a token */
public void refToken(Token assignId, Token t, Token label, Token args,
boolean inverted, int autoGenType, boolean lastInRule)
{
_refToken(assignId, t, label, args, inverted, autoGenType, lastInRule);
}
public void refTokenRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule)
{
// ensure that the DefineGrammarSymbols methods are called; otherwise a range addes more
// token refs to the alternative by calling MakeGrammar.refToken etc...
if ( t1.getText().charAt(0) == '"' )
{
refStringLiteral(t1, null, GrammarElement.AUTO_GEN_NONE, lastInRule);
}
else
{
_refToken(null, t1, null, null, false, GrammarElement.AUTO_GEN_NONE, lastInRule);
}
if ( t2.getText().charAt(0) == '"' )
{
_refStringLiteral(t2, null, GrammarElement.AUTO_GEN_NONE, lastInRule);
}
else
{
_refToken(null, t2, null, null, false, GrammarElement.AUTO_GEN_NONE, lastInRule);
}
}
public void refTreeSpecifier(Token treeSpec) {
}
public void refWildcard(Token t, Token label, int autoGenType)
{
}
/** Get ready to process a new grammar */
public void reset()
{
grammar = null;
}
public void setArgOfRuleRef(Token argaction)
{
}
/** Set the character vocabulary for a lexer */
public void setCharVocabulary(BitSet b)
{
// grammar should enforce that this is only called for lexer
((LexerGrammar)grammar).setCharVocabulary(b);
}
/** setFileOption: Associate an option value with a key.
* This applies to options for an entire grammar file.
* @param key The token containing the option name
* @param value The token containing the option value.
*/
public void setFileOption(Token key, Token value, String filename)
{
if (key.getText().equals("language"))
{
if (value.getType() == ANTLRParser.STRING_LITERAL)
{
language = Tool.stripBack(Tool.stripFront(value.getText(), '"'), '"');
}
else if (value.getType() == ANTLRParser.TOKEN_REF || value.getType() == ANTLRParser.RULE_REF)
{
language = value.getText();
}
else
{
tool.error("language option must be string or identifier", filename, value.getLine());
}
}
else if (key.getText().equals("mangleLiteralPrefix"))
{
if (value.getType() == ANTLRParser.STRING_LITERAL)
{
tool.literalsPrefix = tool.stripFrontBack(value.getText(), "\"","\"");
}
else
{
tool.error("mangleLiteralPrefix option must be string", filename, value.getLine());
}
}
else if (key.getText().equals("upperCaseMangledLiterals"))
{
if (value.getText().equals("true"))
{
tool.upperCaseMangledLiterals = true;
}
else if (value.getText().equals("false"))
{
tool.upperCaseMangledLiterals = false;
}
else
{
grammar.tool.error("Value for upperCaseMangledLiterals must be true or false", filename, key.getLine());
}
}
else if (key.getText().equals("namespace") ||
key.getText().equals("namespaceStd") ||
key.getText().equals("namespaceAntlr") ||
key.getText().equals("genHashLines") )
{
if (!language.equals("Cpp"))
{
tool.error(key.getText() + " option only valid for C++", filename, key.getLine());
}
else
{
if( key.getText().equals("genHashLines") )
{
if(!( value.getText().equals("true") || value.getText().equals("false") ))
tool.error("genHashLines option must be true or false", filename, value.getLine());
tool.genHashLines = value.getText().equals("true");
}
else
{
if ( value.getType() != ANTLRParser.STRING_LITERAL )
{
tool.error(key.getText()+" option must be a string", filename, value.getLine());
}
else
{
if ( key.getText().equals("namespace") )
tool.setNameSpace(value.getText());
else if( key.getText().equals("namespaceStd") )
tool.namespaceStd = value.getText();
else if( key.getText().equals("namespaceAntlr") )
tool.namespaceAntlr = value.getText();
}
}
}
}
else
{
tool.error("Invalid file-level option: " + key.getText(), filename, key.getLine());
}
}
/** setGrammarOption: Associate an option value with a key.
* This function forwards to Grammar.setOption for some options.
* @param key The token containing the option name
* @param value The token containing the option value.
*/
public void setGrammarOption(Token key, Token value)
{
if (key.getText().equals("tokdef")||key.getText().equals("tokenVocabulary"))
{
tool.error("tokdef/tokenVocabulary options are invalid >= ANTLR 2.6.0.\n"+
" Use importVocab/exportVocab instead. Please see the documentation.\n"+
" The previous options were so heinous that Terence changed the whole\n"+
" vocabulary mechanism; it was better to change the names rather than\n"+
" subtly change the functionality of the known options. Sorry!", grammar.getFilename(), value.getLine());
}
else if (key.getText().equals("literal") &&
grammar instanceof LexerGrammar )
{
tool.error("the literal option is invalid >= ANTLR 2.6.0.\n"+
" Use the \"tokens {...}\" mechanism instead.",
grammar.getFilename(), value.getLine());
}
else if (key.getText().equals("exportVocab"))
{
// Set the token manager associated with the parser
if (value.getType() == ANTLRParser.RULE_REF || value.getType() == ANTLRParser.TOKEN_REF)
{
grammar.exportVocab = value.getText();
}
else
{
tool.error("exportVocab must be an identifier", grammar.getFilename(), value.getLine());
}
}
else if (key.getText().equals("importVocab"))
{
if (value.getType() == ANTLRParser.RULE_REF || value.getType() == ANTLRParser.TOKEN_REF)
{
grammar.importVocab = value.getText();
}
else
{
tool.error("importVocab must be an identifier", grammar.getFilename(), value.getLine());
}
}
else
{
// Forward all unrecognized options to the grammar
grammar.setOption(key.getText(), value);
}
}
public void setRuleOption(Token key, Token value)
{
}
public void setSubruleOption(Token key, Token value)
{
}
/** Start a new lexer */
public void startLexer(String file, Token name, String superClass, String doc)
{
if ( numLexers>0 )
{
tool.panic("You may only have one lexer per grammar file: class "+ name.getText());
}
numLexers++;
reset();
//System.out.println("Processing lexer '" + name.getText() + "'");
// Does the lexer already exist?
Grammar g = (Grammar)grammars.get(name);
if (g != null)
{
if (!(g instanceof LexerGrammar))
{
tool.panic("'" + name.getText() + "' is already defined as a non-lexer");
}
else
{
tool.panic("Lexer '" + name.getText() + "' is already defined");
}
}
else
{
// Create a new lexer grammar
LexerGrammar lg = new LexerGrammar(name.getText(), tool, superClass);
lg.comment = doc;
lg.processArguments(args);
lg.setFilename(file);
grammars.put(lg.getClassName(), lg);
// Use any preamble action
lg.preambleAction = thePreambleAction;
thePreambleAction = new CommonToken(Token.INVALID_TYPE, "");
// This is now the current grammar
grammar = lg;
}
}
/** Start a new parser */
public void startParser(String file, Token name, String superClass, String doc)
{
if ( numParsers>0 )
{
tool.panic("You may only have one parser per grammar file: class "+ name.getText());
}
numParsers++;
reset();
//System.out.println("Processing parser '" + name.getText() + "'");
// Is this grammar already defined?
Grammar g = (Grammar)grammars.get(name);
if (g != null)
{
if (!(g instanceof ParserGrammar))
{
tool.panic("'" + name.getText() + "' is already defined as a non-parser");
}
else
{
tool.panic("Parser '" + name.getText() + "' is already defined");
}
}
else
{
// Create a new grammar
grammar = new ParserGrammar(name.getText(), tool, superClass);
grammar.comment = doc;
grammar.processArguments(args);
grammar.setFilename(file);
grammars.put(grammar.getClassName(), grammar);
// Use any preamble action
grammar.preambleAction = thePreambleAction;
thePreambleAction = new CommonToken(Token.INVALID_TYPE, "");
}
}
/** Start a new tree-walker */
public void startTreeWalker(String file, Token name, String superClass, String doc)
{
if ( numTreeParsers>0 )
{
tool.panic("You may only have one tree parser per grammar file: class "+ name.getText());
}
numTreeParsers++;
reset();
//System.out.println("Processing tree-walker '" + name.getText() + "'");
// Is this grammar already defined?
Grammar g = (Grammar)grammars.get(name);
if (g != null)
{
if (!(g instanceof TreeWalkerGrammar))
{
tool.panic("'" + name.getText() + "' is already defined as a non-tree-walker");
}
else
{
tool.panic("Tree-walker '" + name.getText() + "' is already defined");
}
}
else
{
// Create a new grammar
grammar = new TreeWalkerGrammar(name.getText(), tool, superClass);
grammar.comment = doc;
grammar.processArguments(args);
grammar.setFilename(file);
grammars.put(grammar.getClassName(), grammar);
// Use any preamble action
grammar.preambleAction = thePreambleAction;
thePreambleAction = new CommonToken(Token.INVALID_TYPE, "");
}
}
public void synPred()
{
}
public void zeroOrMoreSubRule()
{
}
}
1.1 e/src/jsrc/antlr/DiagnosticCodeGenerator.java
Index: DiagnosticCodeGenerator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: DiagnosticCodeGenerator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Enumeration;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;
/**Generate MyParser.txt, MyLexer.txt and MyParserTokenTypes.txt */
public class DiagnosticCodeGenerator extends CodeGenerator {
/** non-zero if inside syntactic predicate generation */
protected int syntacticPredLevel = 0;
/** true during lexer generation, false during parser generation */
protected boolean doingLexRules = false;
/** Create a Diagnostic code-generator using the given Grammar
* The caller must still call setTool, setBehavior, and setAnalyzer
* before generating code.
*/
public DiagnosticCodeGenerator() {
super();
charFormatter = new JavaCharFormatter();
}
/**Generate the parser, lexer, and token types documentation */
public void gen() {
// Do the code generation
try {
// Loop over all grammars
Enumeration grammarIter = behavior.grammars.elements();
while (grammarIter.hasMoreElements()) {
Grammar g = (Grammar)grammarIter.nextElement();
// Connect all the components to each other
g.setGrammarAnalyzer(analyzer);
g.setCodeGenerator(this);
analyzer.setGrammar(g);
// To get right overloading behavior across hetrogeneous grammars
g.generate();
if (tool.hasError) {
System.out.println("Exiting due to errors.");
System.exit(1);
}
}
// Loop over all token managers (some of which are lexers)
Enumeration tmIter = behavior.tokenManagers.elements();
while (tmIter.hasMoreElements()) {
TokenManager tm = (TokenManager)tmIter.nextElement();
if (!tm.isReadOnly()) {
// Write the token manager tokens as Java
genTokenTypes(tm);
}
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
/** Generate code for the given grammar element.
* @param blk The {...} action to generate
*/
public void gen(ActionElement action) {
if (action.isSemPred) {
// handled elsewhere
}
else {
print("ACTION: ");
_printAction(action.actionText);
}
}
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public void gen(AlternativeBlock blk) {
println("Start of alternative block.");
tabs++;
genBlockPreamble(blk);
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
if (!ok) {
println("Warning: This alternative block is non-deterministic");
}
genCommonBlock(blk);
tabs--;
}
/** Generate code for the given grammar element.
* @param blk The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public void gen(BlockEndElement end) {
// no-op
}
/** Generate code for the given grammar element.
* @param blk The character literal reference to generate
*/
public void gen(CharLiteralElement atom) {
print("Match character ");
if (atom.not) {
_print("NOT ");
}
_print(atom.atomText);
if (atom.label != null) {
_print(", label=" + atom.label);
}
_println("");
}
/** Generate code for the given grammar element.
* @param blk The character-range reference to generate
*/
public void gen(CharRangeElement r) {
print("Match character range: " + r.beginText + ".." + r.endText);
if ( r.label!=null ) {
_print(", label = " + r.label);
}
_println("");
}
/** Generate the lexer TXT file */
public void gen(LexerGrammar g) throws IOException {
setGrammar(g);
System.out.println("Generating " + grammar.getClassName() + TokenTypesFileExt);
currentOutput = antlr.Tool.openOutputFile(grammar.getClassName() + TokenTypesFileExt);
//SAS: changed for proper text file io
tabs=0;
doingLexRules = true;
// Generate header common to all TXT output files
genHeader();
// Output the user-defined lexer premamble
println("");
println("*** Lexer Preamble Action.");
println("This action will appear before the declaration of your lexer class:");
tabs++;
println(grammar.preambleAction.getText());
tabs--;
println("*** End of Lexer Preamble Action");
// Generate lexer class definition
println("");
println("*** Your lexer class is called '" + grammar.getClassName() + "' and is a subclass of '" + grammar.getSuperClass() + "'.");
// Generate user-defined parser class members
println("");
println("*** User-defined lexer class members:");
println("These are the member declarations that you defined for your class:");
tabs++;
printAction(grammar.classMemberAction.getText());
tabs--;
println("*** End of user-defined lexer class members");
// Generate string literals
println("");
println("*** String literals used in the parser");
println("The following string literals were used in the parser.");
println("An actual code generator would arrange to place these literals");
println("into a table in the generated lexer, so that actions in the");
println("generated lexer could match token text against the literals.");
println("String literals used in the lexer are not listed here, as they");
println("are incorporated into the mainstream lexer processing.");
tabs++;
// Enumerate all of the symbols and look for string literal symbols
Enumeration ids = grammar.getSymbols();
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
// Only processing string literals -- reject other symbol entries
if ( sym instanceof StringLiteralSymbol ) {
StringLiteralSymbol s = (StringLiteralSymbol)sym;
println(s.getId() + " = " + s.getTokenType());
}
}
tabs--;
println("*** End of string literals used by the parser");
// Generate nextToken() rule.
// nextToken() is a synthetic lexer rule that is the implicit OR of all
// user-defined lexer rules.
genNextToken();
// Generate code for each rule in the lexer
println("");
println("*** User-defined Lexer rules:");
tabs++;
ids = grammar.rules.elements();
while ( ids.hasMoreElements() ) {
RuleSymbol rs = (RuleSymbol)ids.nextElement();
if (!rs.id.equals("mnextToken")) {
genRule(rs);
}
}
tabs--;
println("");
println("*** End User-defined Lexer rules:");
// Close the lexer output file
currentOutput.close();
currentOutput = null;
doingLexRules = false;
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
println("Start ONE-OR-MORE (...)+ block:");
tabs++;
genBlockPreamble(blk);
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
if (!ok) {
println("Warning: This one-or-more block is non-deterministic");
}
genCommonBlock(blk);
tabs--;
println("End ONE-OR-MORE block.");
}
/** Generate the parser TXT file */
public void gen(ParserGrammar g) throws IOException {
setGrammar(g);
// Open the output stream for the parser and set the currentOutput
System.out.println("Generating " + grammar.getClassName() + TokenTypesFileExt);
currentOutput = antlr.Tool.openOutputFile(grammar.getClassName()+TokenTypesFileExt);
//SAS: changed for proper text file io
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Output the user-defined parser premamble
println("");
println("*** Parser Preamble Action.");
println("This action will appear before the declaration of your parser class:");
tabs++;
println(grammar.preambleAction.getText());
tabs--;
println("*** End of Parser Preamble Action");
// Generate parser class definition
println("");
println("*** Your parser class is called '" + grammar.getClassName() + "' and is a subclass of '" + grammar.getSuperClass() + "'.");
// Generate user-defined parser class members
println("");
println("*** User-defined parser class members:");
println("These are the member declarations that you defined for your class:");
tabs++;
printAction(grammar.classMemberAction.getText());
tabs--;
println("*** End of user-defined parser class members");
// Generate code for each rule in the grammar
println("");
println("*** Parser rules:");
tabs++;
// Enumerate the parser rules
Enumeration rules = grammar.rules.elements();
while ( rules.hasMoreElements() ) {
println("");
// Get the rules from the list and downcast it to proper type
GrammarSymbol sym = (GrammarSymbol) rules.nextElement();
// Only process parser rules
if ( sym instanceof RuleSymbol) {
genRule((RuleSymbol)sym);
}
}
tabs--;
println("");
println("*** End of parser rules");
println("");
println("*** End of parser");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The rule-reference to generate
*/
public void gen(RuleRefElement rr) {
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
// Generate the actual rule description
print("Rule Reference: " + rr.targetRule);
if (rr.idAssign != null) {
_print(", assigned to '" + rr.idAssign + "'");
}
if (rr.args != null) {
_print(", arguments = " + rr.args);
}
_println("");
// Perform diagnostics
if (rs == null || !rs.isDefined())
{
println("Rule '" + rr.targetRule + "' is referenced, but that rule is not defined.");
println("\tPerhaps the rule is misspelled, or you forgot to define it.");
return;
}
if (!(rs instanceof RuleSymbol))
{
// Should this ever happen??
println("Rule '" + rr.targetRule + "' is referenced, but that is not a grammar rule.");
return;
}
if (rr.idAssign != null)
{
// Warn if the rule has no return type
if (rs.block.returnAction == null)
{
println("Error: You assigned from Rule '" + rr.targetRule + "', but that rule has no return type.");
}
} else {
// Warn about return value if any, but not inside syntactic predicate
if (!(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
{
println("Warning: Rule '" + rr.targetRule + "' returns a value");
}
}
if (rr.args != null && rs.block.argAction == null) {
println("Error: Rule '" + rr.targetRule + "' accepts no arguments.");
}
}
/** Generate code for the given grammar element.
* @param blk The string-literal reference to generate
*/
public void gen(StringLiteralElement atom) {
print("Match string literal ");
_print(atom.atomText);
if (atom.label != null) {
_print(", label=" + atom.label);
}
_println("");
}
/** Generate code for the given grammar element.
* @param blk The token-range reference to generate
*/
public void gen(TokenRangeElement r) {
print("Match token range: " + r.beginText + ".." + r.endText);
if ( r.label!=null ) {
_print(", label = " + r.label);
}
_println("");
}
/** Generate code for the given grammar element.
* @param blk The token-reference to generate
*/
public void gen(TokenRefElement atom) {
print("Match token ");
if (atom.not) {
_print("NOT ");
}
_print(atom.atomText);
if (atom.label != null) {
_print(", label=" + atom.label);
}
_println("");
}
public void gen(TreeElement t) {
print("Tree reference: "+t);
}
/** Generate the tree-walker TXT file */
public void gen(TreeWalkerGrammar g) throws IOException {
setGrammar(g);
// Open the output stream for the parser and set the currentOutput
System.out.println("Generating " + grammar.getClassName() + TokenTypesFileExt);
currentOutput = antlr.Tool.openOutputFile(grammar.getClassName()+TokenTypesFileExt);
//SAS: changed for proper text file io
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Output the user-defined parser premamble
println("");
println("*** Tree-walker Preamble Action.");
println("This action will appear before the declaration of your tree-walker class:");
tabs++;
println(grammar.preambleAction.getText());
tabs--;
println("*** End of tree-walker Preamble Action");
// Generate tree-walker class definition
println("");
println("*** Your tree-walker class is called '" + grammar.getClassName() + "' and is a subclass of '" + grammar.getSuperClass() + "'.");
// Generate user-defined tree-walker class members
println("");
println("*** User-defined tree-walker class members:");
println("These are the member declarations that you defined for your class:");
tabs++;
printAction(grammar.classMemberAction.getText());
tabs--;
println("*** End of user-defined tree-walker class members");
// Generate code for each rule in the grammar
println("");
println("*** tree-walker rules:");
tabs++;
// Enumerate the tree-walker rules
Enumeration rules = grammar.rules.elements();
while ( rules.hasMoreElements() ) {
println("");
// Get the rules from the list and downcast it to proper type
GrammarSymbol sym = (GrammarSymbol) rules.nextElement();
// Only process tree-walker rules
if ( sym instanceof RuleSymbol) {
genRule((RuleSymbol)sym);
}
}
tabs--;
println("");
println("*** End of tree-walker rules");
println("");
println("*** End of tree-walker");
// Close the tree-walker output stream
currentOutput.close();
currentOutput = null;
}
/** Generate a wildcard element */
public void gen(WildcardElement wc) {
print("Match wildcard");
if ( wc.getLabel()!=null ) {
_print(", label = " + wc.getLabel());
}
_println("");
}
/** Generate code for the given grammar element.
* @param blk The (...)* block to generate
*/
public void gen(ZeroOrMoreBlock blk) {
println("Start ZERO-OR-MORE (...)+ block:");
tabs++;
genBlockPreamble(blk);
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
if (!ok) {
println("Warning: This zero-or-more block is non-deterministic");
}
genCommonBlock(blk);
tabs--;
println("End ZERO-OR-MORE block.");
}
protected void genAlt(Alternative alt) {
for (
AlternativeElement elem = alt.head;
!(elem instanceof BlockEndElement);
elem = elem.next
)
{
elem.generate();
}
if (alt.getTreeSpecifier() != null)
{
println("AST will be built as: " + alt.getTreeSpecifier().getText());
}
}
/** Generate the header for a block, which may be a RuleBlock or a
* plain AlternativeBLock. This generates any variable declarations,
* init-actions, and syntactic-predicate-testing variables.
* @blk The block for which the preamble is to be generated.
*/
protected void genBlockPreamble(AlternativeBlock blk) {
// dump out init action
if ( blk.initAction!=null ) {
printAction("Init action: " + blk.initAction);
}
}
/**Generate common code for a block of alternatives; return a postscript
* that needs to be generated at the end of the block. Other routines
* may append else-clauses and such for error checking before the postfix
* is generated.
*/
public void genCommonBlock(AlternativeBlock blk) {
boolean singleAlt = (blk.alternatives.size() == 1);
println("Start of an alternative block.");
tabs++;
println("The lookahead set for this block is:");
tabs++;
genLookaheadSetForBlock(blk);
tabs--;
if (singleAlt) {
println("This block has a single alternative");
if (blk.getAlternativeAt(0).synPred != null)
{
// Generate a warning if there is one alt and it has a synPred
println("Warning: you specified a syntactic predicate for this alternative,");
println("and it is the only alternative of a block and will be ignored.");
}
}
else {
println("This block has multiple alternatives:");
tabs++;
}
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
AlternativeElement elem = alt.head;
// Print lookahead set for alternate
println("");
if (i != 0) {
print("Otherwise, ");
} else {
print("");
}
_println("Alternate(" + (i+1) + ") will be taken IF:");
println("The lookahead set: ");
tabs++;
genLookaheadSetForAlt(alt);
tabs--;
if ( alt.semPred != null || alt.synPred != null ) {
print("is matched, AND ");
} else {
println("is matched.");
}
// Dump semantic predicates
if ( alt.semPred != null ) {
_println("the semantic predicate:");
tabs++;
println(alt.semPred);
if ( alt.synPred != null ) {
print("is true, AND ");
} else {
println("is true.");
}
}
// Dump syntactic predicate
if ( alt.synPred != null ) {
_println("the syntactic predicate:");
tabs++;
genSynPred( alt.synPred );
tabs--;
println("is matched.");
}
// Dump the alternative
genAlt(alt);
}
println("");
println("OTHERWISE, a NoViableAlt exception will be thrown");
println("");
if (!singleAlt) {
tabs--;
println("End of alternatives");
}
tabs--;
println("End of alternative block.");
}
/** Generate a textual representation of the follow set
* for a block.
* @param blk The rule block of interest
*/
public void genFollowSetForRuleBlock(RuleBlock blk)
{
Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, blk.endNode);
printSet(grammar.maxk, 1, follow);
}
/** Generate a header that is common to all TXT files */
protected void genHeader()
{
println("ANTLR-generated file resulting from grammar " + tool.grammarFile);
println("Diagnostic output");
println("");
println("Terence Parr, MageLang Institute");
println("with John Lilley, Empathy Software");
println("ANTLR Version "+Tool.version+"; 1996,1997");
println("");
println("*** Header Action.");
println("This action will appear at the top of all generated files.");
tabs++;
printAction(behavior.getHeaderAction(""));
tabs--;
println("*** End of Header Action");
println("");
}
/**Generate the lookahead set for an alternate. */
protected void genLookaheadSetForAlt(Alternative alt) {
if ( doingLexRules && alt.cache[1].containsEpsilon() ) {
println("MATCHES ALL");
return;
}
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
// if the decision is nondeterministic, do the best we can: LL(k)
// any predicates that are around will be generated later.
depth = grammar.maxk;
}
for (int i = 1; i <= depth; i++)
{
Lookahead lookahead = alt.cache[i];
printSet(depth, i, lookahead);
}
}
/** Generate a textual representation of the lookahead set
* for a block.
* @param blk The block of interest
*/
public void genLookaheadSetForBlock(AlternativeBlock blk)
{
// Find the maximal lookahead depth over all alternatives
int depth = 0;
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
if (alt.lookaheadDepth == GrammarAnalyzer.NONDETERMINISTIC) {
depth = grammar.maxk;
break;
}
else if (depth < alt.lookaheadDepth) {
depth = alt.lookaheadDepth;
}
}
for (int i = 1; i <= depth; i++)
{
Lookahead lookahead = grammar.theLLkAnalyzer.look(i, blk);
printSet(depth, i, lookahead);
}
}
/** Generate the nextToken rule.
* nextToken is a synthetic lexer rule that is the implicit OR of all
* user-defined lexer rules.
*/
public void genNextToken() {
println("");
println("*** Lexer nextToken rule:");
println("The lexer nextToken rule is synthesized from all of the user-defined");
println("lexer rules. It logically consists of one big alternative block with");
println("each user-defined rule being an alternative.");
println("");
// Create the synthesized rule block for nextToken consisting
// of an alternate block containing all the user-defined lexer rules.
RuleBlock blk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
// Define the nextToken rule symbol
RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
nextTokenRs.setDefined();
nextTokenRs.setBlock(blk);
nextTokenRs.access = "private";
grammar.define(nextTokenRs);
// Analyze the synthesized block
if (!grammar.theLLkAnalyzer.deterministic(blk))
{
println("The grammar analyzer has determined that the synthesized");
println("nextToken rule is non-deterministic (i.e., it has ambiguities)");
println("This means that there is some overlap of the character");
println("lookahead for two or more of your lexer rules.");
}
genCommonBlock(blk);
println("*** End of nextToken lexer rule.");
}
/** Generate code for a named rule block
* @param s The RuleSymbol describing the rule to generate
*/
public void genRule(RuleSymbol s) {
println("");
String ruleType = (doingLexRules ? "Lexer" : "Parser");
println("*** " + ruleType + " Rule: " + s.getId());
if (!s.isDefined() ) {
println("This rule is undefined.");
println("This means that the rule was referenced somewhere in the grammar,");
println("but a definition for the rule was not encountered.");
println("It is also possible that syntax errors during the parse of");
println("your grammar file prevented correct processing of the rule.");
println("*** End " + ruleType + " Rule: " + s.getId());
return;
}
tabs++;
if (s.access.length() != 0) {
println("Access: " + s.access);
}
// Get rule return type and arguments
RuleBlock rblk = s.getBlock();
// Gen method return value(s)
if (rblk.returnAction != null) {
println("Return value(s): " + rblk.returnAction);
if ( doingLexRules ) {
println("Error: you specified return value(s) for a lexical rule.");
println("\tLexical rules have an implicit return type of 'int'.");
}
} else {
if ( doingLexRules ) {
println("Return value: lexical rule returns an implicit token type");
} else {
println("Return value: none");
}
}
// Gen arguments
if (rblk.argAction != null)
{
println("Arguments: " + rblk.argAction);
}
// Dump any init-action
genBlockPreamble(rblk);
// Analyze the rule
boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
if (!ok) {
println("Error: This rule is non-deterministic");
}
// Dump the alternates of the rule
genCommonBlock(rblk);
// Search for an unlabeled exception specification attached to the rule
ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
// Generate user-defined or default catch phrases
if (unlabeledUserSpec != null) {
println("You specified error-handler(s) for this rule:");
tabs++;
for (int i = 0; i < unlabeledUserSpec.handlers.size(); i++)
{
if (i != 0) {
println("");
}
ExceptionHandler handler = (ExceptionHandler)unlabeledUserSpec.handlers.elementAt(i);
println("Error-handler(" + (i+1) + ") catches [" + handler.exceptionTypeAndName.getText() + "] and executes:");
printAction(handler.action.getText());
}
tabs--;
println("End error-handlers.");
}
else if (!doingLexRules) {
println("Default error-handling will be generated, which catches all");
println("parser exceptions and consumes tokens until the follow-set is seen.");
}
// Dump the follow set
// Doesn't seem to work for lexical rules...
if (!doingLexRules) {
println("The follow set for this rule is:");
tabs++;
genFollowSetForRuleBlock(rblk);
tabs--;
}
tabs--;
println("*** End " + ruleType + " Rule: " + s.getId());
}
/** Generate the syntactic predicate. This basically generates
* the alternative block, buts tracks if we are inside a synPred
* @param blk The syntactic predicate block
*/
protected void genSynPred(SynPredBlock blk) {
syntacticPredLevel++;
gen((AlternativeBlock)blk);
syntacticPredLevel--;
}
/** Generate the token types TXT file */
protected void genTokenTypes(TokenManager tm) throws IOException {
// Open the token output TXT file and set the currentOutput stream
System.out.println("Generating " + tm.getName() + TokenTypesFileSuffix+TokenTypesFileExt);
currentOutput = antlr.Tool.openOutputFile(tm.getName() + TokenTypesFileSuffix+TokenTypesFileExt);
//SAS: changed for proper text file io
tabs = 0;
// Generate the header common to all diagnostic files
genHeader();
// Generate a string for each token. This creates a static
// array of Strings indexed by token type.
println("");
println("*** Tokens used by the parser");
println("This is a list of the token numeric values and the corresponding");
println("token identifiers. Some tokens are literals, and because of that");
println("they have no identifiers. Literals are double-quoted.");
tabs++;
// Enumerate all the valid token types
Vector v = tm.getVocabulary();
for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if (s != null) {
println(s + " = " + i);
}
}
// Close the interface
tabs--;
println("*** End of tokens used by the parser");
// Close the tokens output file
currentOutput.close();
currentOutput = null;
}
/** Get a string for an expression to generate creation of an AST subtree.
* @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
*/
public String getASTCreateString(Vector v) {
return "***Create an AST from a vector here***"+System.getProperty("line.separator");
}
/** Get a string for an expression to generate creating of an AST node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(GrammarAtom atom, String str) {
return "[" + str + "]";
}
/** Map an identifier to it's corresponding tree-node variable.
* This is context-sensitive, depending on the rule and alternative
* being generated
* @param id The identifier name to map
* @param forInput true if the input tree node variable is to be returned, otherwise the output variable is returned.
*/
public String mapTreeId(String id, ActionTransInfo tInfo) {
return id;
}
/** Format a lookahead or follow set.
* @param depth The depth of the entire lookahead/follow
* @param k The lookahead level to print
* @param lookahead The lookahead/follow set to print
*/
public void printSet(int depth, int k, Lookahead lookahead) {
int numCols = 5;
int[] elems = lookahead.fset.toArray();
if (depth != 1) {
print("k==" + k + ": {");
} else {
print("{ ");
}
if (elems.length > numCols) {
_println("");
tabs++;
print("");
}
int column = 0;
for (int i = 0; i < elems.length; i++)
{
column++;
if (column > numCols) {
_println("");
print("");
column = 0;
}
if (doingLexRules) {
_print(charFormatter.literalChar(elems[i]));
} else {
_print((String)grammar.tokenManager.getVocabulary().elementAt(elems[i]));
}
if (i != elems.length-1) {
_print(", ");
}
}
if (elems.length > numCols) {
_println("");
tabs--;
print("");
}
_println(" }");
}
}
1.1 e/src/jsrc/antlr/DumpASTVisitor.java
Index: DumpASTVisitor.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: DumpASTVisitor.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.*;
import antlr.collections.AST;
/** Simple class to dump the contents of an AST to the output */
public class DumpASTVisitor implements ASTVisitor {
protected int level = 0;
private void tabs() {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
}
public void visit(AST node) {
// Flatten this level of the tree if it has no children
boolean flatten = /*true*/ false;
AST node2;
for (node2 = node; node2 != null ; node2 = node2.getNextSibling()) {
if (node2.getFirstChild() != null) {
flatten = false;
break;
}
}
for (node2 = node; node2 != null; node2 = node2.getNextSibling()) {
if (!flatten || node2 == node) {
tabs();
}
if ( node2.getText()==null ) {
System.out.print("nil");
}
else {
System.out.print(node2.getText());
}
System.out.print(" [" + node2.getType() + "] ");
if (flatten) {
System.out.print(" ");
}
else {
System.out.println("");
}
if ( node2.getFirstChild() != null ) {
level++;
visit(node2.getFirstChild());
level--;
}
}
if (flatten) {
System.out.println("");
}
}
}
1.1 e/src/jsrc/antlr/ExceptionHandler.java
Index: ExceptionHandler.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ExceptionHandler.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class ExceptionHandler {
// Type of the ANTLR exception class to catch and the variable decl
protected Token exceptionTypeAndName;
// The action to be executed when the exception is caught
protected Token action;
public ExceptionHandler(Token exceptionTypeAndName_,
Token action_) {
exceptionTypeAndName = exceptionTypeAndName_;
action = action_;
}
}
1.1 e/src/jsrc/antlr/ExceptionSpec.java
Index: ExceptionSpec.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ExceptionSpec.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.Vector;
class ExceptionSpec
{
// Non-null if this refers to a labeled rule
// Use a token instead of a string to get the line information
protected Token label;
// List of ExceptionHandler (catch phrases)
protected Vector handlers;
public ExceptionSpec(Token label_) {
label = label_;
handlers = new Vector();
}
public void addHandler(ExceptionHandler handler) {
handlers.appendElement(handler);
}
}
1.1 e/src/jsrc/antlr/FileCopyException.java
Index: FileCopyException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: FileCopyException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class FileCopyException extends java.io.IOException {
public FileCopyException(String msg) { super(msg); }
}
1.1 e/src/jsrc/antlr/FileLineFormatter.java
Index: FileLineFormatter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: FileLineFormatter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public abstract class FileLineFormatter {
private static FileLineFormatter formatter = new DefaultFileLineFormatter();
public static FileLineFormatter getFormatter() {
return formatter;
}
public static void setFormatter(FileLineFormatter f) {
formatter = f;
}
public abstract String getFormatString(String fileName, int line);
}
1.1 e/src/jsrc/antlr/Grammar.java
Index: Grammar.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: Grammar.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
/**A Grammar holds a set of rules (which are stored
* in a symbol table). Most of the time a grammar
* needs a code generator and an LLkAnalyzer too.
*/
public abstract class Grammar {
protected Tool tool;
protected CodeGenerator generator;
protected LLkGrammarAnalyzer theLLkAnalyzer;
protected Hashtable symbols;
protected boolean buildAST = false;
protected boolean analyzerDebug = false;
protected boolean interactive = false;
protected String superClass = null;
/** The token manager associated with the grammar, if any.
// The token manager is responsible for maintaining the set of valid tokens, and
// is conceptually shared between the lexer and parser. This may be either a
// LexerGrammar or a ImportVocabTokenManager.
*/
protected TokenManager tokenManager;
/** The name of the export vocabulary...used to generate the output
* token types interchange file.
*/
protected String exportVocab = null;
/** The name of the import vocabulary. "Initial conditions"
*/
protected String importVocab = null;
// Mapping from String keys to Token option values
protected Hashtable options;
// Vector of RuleSymbol entries
protected Vector rules;
protected Token preambleAction = new CommonToken(Token.INVALID_TYPE, "");
protected String className = null;
protected String fileName = null;
protected Token classMemberAction = new CommonToken(Token.INVALID_TYPE, "");
protected boolean hasSyntacticPredicate = false;
protected boolean hasUserErrorHandling = false;
// max lookahead that can be attempted for this parser.
protected int maxk=1;
// options
protected boolean traceRules = false;
protected boolean debuggingOutput = false;
protected boolean defaultErrorHandler = true;
protected String comment = null; // javadoc comment
public Grammar(String className_, Tool tool_, String superClass) {
className = className_;
tool = tool_;
symbols = new Hashtable();
options = new Hashtable();
rules = new Vector(100);
this.superClass = superClass;
}
/** Define a rule */
public void define(RuleSymbol rs) {
rules.appendElement(rs);
// add the symbol to the rules hash table
symbols.put(rs.getId(), rs);
}
/** Top-level call to generate the code for this grammar */
public abstract void generate() throws IOException;
protected String getClassName() { return className; }
/* Does this grammar have a default error handler? */
public boolean getDefaultErrorHandler() {
return defaultErrorHandler;
}
public String getFilename() {
return fileName;
}
/** Get an integer option. Given the name of the option find its
* associated integer value. If the associated value is not an integer or
* is not in the table, then throw an exception of type NumberFormatException.
* @param key The name of the option
* @return The value associated with the key.
*/
public int getIntegerOption(String key) throws NumberFormatException {
Token t = (Token)options.get(key);
if (t == null || t.getType() != ANTLRTokenTypes.INT) {
throw new NumberFormatException();
}
else {
return Integer.parseInt(t.getText());
}
}
/** Get an option. Given the name of the option find its associated value.
* @param key The name of the option
* @return The value associated with the key, or null if the key has not been set.
*/
public Token getOption(String key) {
return (Token)options.get(key);
}
// Get name of class from which generated parser/lexer inherits
protected abstract String getSuperClass();
public GrammarSymbol getSymbol(String s) {
return (GrammarSymbol) symbols.get(s);
}
public Enumeration getSymbols() {
return symbols.elements();
}
/** Check the existence of an option in the table
* @param key The name of the option
* @return true if the option is in the table
*/
public boolean hasOption(String key) {
return options.containsKey(key);
}
/** Is a rule symbol defined? (not used for tokens) */
public boolean isDefined(String s) {
return symbols.containsKey(s);
}
/**Process command line arguments. Implemented in subclasses */
public abstract void processArguments(String[] args);
public void setCodeGenerator(CodeGenerator gen) {
generator = gen;
}
public void setFilename(String s) {
fileName = s;
}
public void setGrammarAnalyzer(LLkGrammarAnalyzer a) {
theLLkAnalyzer = a;
}
/** Set a generic option.
* This associates a generic option key with a Token value.
* No validation is performed by this method, although users of the value
* (code generation and/or analysis) may require certain formats.
* The value is stored as a token so that the location of an error
* can be reported.
* @param key The name of the option.
* @param value The value to associate with the key.
* @return true if the option was a valid generic grammar option, false o/w
*/
public boolean setOption(String key, Token value) {
options.put(key, value);
String s = value.getText();
int i;
if (key.equals("k")) {
try {
maxk = getIntegerOption("k");
//System.out.println("setting lookahead to " + maxk);
} catch (NumberFormatException e) {
tool.error("option 'k' must be an integer (was "+value.getText()+")", getFilename(), value.getLine());
}
return true;
}
if (key.equals("codeGenMakeSwitchThreshold")) {
try {
i = getIntegerOption("codeGenMakeSwitchThreshold");
} catch (NumberFormatException e) {
tool.error("option 'codeGenMakeSwitchThreshold' must be an integer", getFilename(), value.getLine());
}
return true;
}
if (key.equals("codeGenBitsetTestThreshold")) {
try {
i = getIntegerOption("codeGenBitsetTestThreshold");
} catch (NumberFormatException e) {
tool.error("option 'codeGenBitsetTestThreshold' must be an integer", getFilename(), value.getLine());
}
return true;
}
if (key.equals("defaultErrorHandler")) {
if (s.equals("true")) {
defaultErrorHandler = true;
} else if (s.equals("false")) {
defaultErrorHandler = false;
} else {
tool.error("Value for defaultErrorHandler must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("analyzerDebug")) {
if (s.equals("true")) {
analyzerDebug = true;
}
else if (s.equals("false")) {
analyzerDebug = false;
}
else {
tool.error("option 'analyzerDebug' must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("codeGenDebug")) {
if (s.equals("true")) {
analyzerDebug = true;
}
else if (s.equals("false")) {
analyzerDebug = false;
}
else {
tool.error("option 'codeGenDebug' must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("classHeaderSuffix")) {
return true;
}
if (key.equals("namespaceAntlr")) {
return true;
}
if (key.equals("namespaceStd")) {
return true;
}
if (key.equals("genHashLines")) {
return true;
}
return false;
}
public void setTokenManager(TokenManager tokenManager_) {
tokenManager = tokenManager_;
}
/** Print out the grammar without actions */
public String toString() {
StringBuffer buf = new StringBuffer(20000);
Enumeration ids = rules.elements();
while ( ids.hasMoreElements() ) {
RuleSymbol rs = (RuleSymbol)ids.nextElement();
if (!rs.id.equals("mnextToken")) {
buf.append(rs.getBlock().toString());
buf.append("\n\n");
}
}
return buf.toString();
}
}
1.1 e/src/jsrc/antlr/GrammarAnalyzer.java
Index: GrammarAnalyzer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: GrammarAnalyzer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A GrammarAnalyzer computes lookahead from Grammar (which contains
* a grammar symbol table) and can then answer questions about the
* grammar.
*
* To access the RuleBlock for a rule name, the grammar symbol table
* is consulted.
*
* There should be no distinction between static & dynamic analysis.
* In other words, some of the easy analysis can be done statically
* and then the part that is hard statically can be deferred to
* parse-time. Interestingly, computing LL(k) for k>1 lookahead
* statically is O(|T|^k) where T is the grammar vocabulary, but,
* is O(k) at run-time (ignoring the large constant associated with
* the size of the grammar). In English, the difference can be
* described as "find the set of all possible k-sequences of input"
* versus "does this specific k-sequence match?".
*/
public interface GrammarAnalyzer {
/**The epsilon token type is an imaginary type used
* during analysis. It indicates an incomplete look() computation.
* Must be kept consistent with Token constants to be between
* MIN_USER_TYPE and INVALID_TYPE.
*/
// public static final int EPSILON_TYPE = 2;
public static final int NONDETERMINISTIC = Integer.MAX_VALUE; // lookahead depth
public static final int LOOKAHEAD_DEPTH_INIT = -1;
}
1.1 e/src/jsrc/antlr/GrammarAtom.java
Index: GrammarAtom.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: GrammarAtom.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A GrammarAtom is either a token ref, a character ref, or string.
* The analysis doesn't care.
*/
abstract class GrammarAtom extends AlternativeElement {
protected String label;
protected String atomText;
protected int tokenType = Token.INVALID_TYPE;
protected boolean not = false; // ~T or ~'c' or ~"foo"
/** Set to type of AST node to create during parse. Defaults to what is
* set in the TokenSymbol.
*/
protected String ASTNodeType = null;
public GrammarAtom(Grammar g, Token t, int autoGenType) {
super(g, autoGenType);
atomText = t.getText();
}
public String getLabel() {
return label;
}
public String getText() {
return atomText;
}
public int getType() {
return tokenType;
}
public void setLabel(String label_) {
label = label_;
}
public String getASTNodeType() {
return ASTNodeType;
}
public void setASTNodeType(String type) {
ASTNodeType = type;
}
public void setOption(Token option, Token value) {
if ( option.getText().equals("AST") ) {
setASTNodeType(value.getText());
}
else {
grammar.tool.error("Invalid element option:"+option.getText(),
grammar.getFilename(), option.getLine());
}
}
public String toString() {
String s = " ";
if ( label!=null ) s += label+":";
if ( not ) s += "~";
return s+atomText;
}
}
1.1 e/src/jsrc/antlr/GrammarElement.java
Index: GrammarElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: GrammarElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A GrammarElement is a generic node in our
* data structure that holds a grammar in memory.
* This data structure can be used for static
* analysis or for dynamic analysis (during parsing).
* Every node must know which grammar owns it, how
* to generate code, and how to do analysis.
*/
abstract class GrammarElement {
public static final int AUTO_GEN_NONE = 1;
public static final int AUTO_GEN_CARET = 2;
public static final int AUTO_GEN_BANG = 3;
/*
* Note that Java does static argument type matching to
* determine which function to execute on the receiver.
* Here, that implies that we cannot simply say
* grammar.generator.gen(this) in GrammarElement or
* only CodeGenerator.gen(GrammarElement ge) would
* ever be called.
*/
protected Grammar grammar;
protected int line;
public GrammarElement(Grammar g) {
grammar = g;
}
public void generate() {;}
public int getLine() {
return line;
}
public Lookahead look(int k) { return null; }
public abstract String toString();
}
1.1 e/src/jsrc/antlr/GrammarSymbol.java
Index: GrammarSymbol.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: GrammarSymbol.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A GrammarSymbol is a generic symbol that can be
* added to the symbol table for a grammar.
*/
abstract class GrammarSymbol {
protected String id;
public GrammarSymbol() {}
public GrammarSymbol(String s) { id = s; }
public String getId() { return id; }
public void setId(String s) { id = s; }
}
1.1 e/src/jsrc/antlr/HTMLCodeGenerator.java
Index: HTMLCodeGenerator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: HTMLCodeGenerator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Enumeration;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;
/**Generate P.html, a cross-linked representation of P with or without actions */
public class HTMLCodeGenerator extends CodeGenerator {
/** non-zero if inside syntactic predicate generation */
protected int syntacticPredLevel = 0;
/** true during lexer generation, false during parser generation */
protected boolean doingLexRules = false;
protected boolean firstElementInAlt;
protected AlternativeElement prevAltElem = null; // what was generated last?
/** Create a Diagnostic code-generator using the given Grammar
* The caller must still call setTool, setBehavior, and setAnalyzer
* before generating code.
*/
public HTMLCodeGenerator() {
super();
charFormatter = new JavaCharFormatter();
}
public void gen() {
// Do the code generation
try {
// Loop over all grammars
Enumeration grammarIter = behavior.grammars.elements();
while (grammarIter.hasMoreElements()) {
Grammar g = (Grammar)grammarIter.nextElement();
// Connect all the components to each other
/*
g.setGrammarAnalyzer(analyzer);
analyzer.setGrammar(g);
*/
g.setCodeGenerator(this);
// To get right overloading behavior across hetrogeneous grammars
g.generate();
if (tool.hasError) {
System.out.println("Exiting due to errors.");
System.exit(1);
}
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
/** Generate code for the given grammar element.
* @param blk The {...} action to generate
*/
public void gen(ActionElement action) {
/*
_print("{");
_printAction(action.actionText);
_print("} ");
*/
}
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public void gen(AlternativeBlock blk) {
genGenericBlock(blk, "");
}
/** Generate code for the given grammar element.
* @param blk The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public void gen(BlockEndElement end) {
// no-op
}
/** Generate code for the given grammar element.
* @param blk The character literal reference to generate
*/
public void gen(CharLiteralElement atom) {
/*
if (atom.label != null) {
_print(atom.label+"=");
}
*/
if (atom.not) {
_print("~");
}
_print(atom.atomText+" ");
}
/** Generate code for the given grammar element.
* @param blk The character-range reference to generate
*/
public void gen(CharRangeElement r) {
/*
if ( r.label!=null ) {
_print(r.label+"=");
}
*/
print(r.beginText + ".." + r.endText+" ");
}
/** Generate the lexer TXT file */
public void gen(LexerGrammar g) throws IOException {
setGrammar(g);
System.out.println("Generating " + grammar.getClassName() + TokenTypesFileExt);
currentOutput = antlr.Tool.openOutputFile(grammar.getClassName() + TokenTypesFileExt);
//SAS: changed for proper text file io
tabs=0;
doingLexRules = true;
// Generate header common to all TXT output files
genHeader();
/*
// Output the user-defined lexer premamble
println(grammar.preambleAction.getText());
*/
// Generate lexer class definition
println("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + " extends " + grammar.getSuperClass() + " {");
// Generate user-defined parser class members
// printAction(grammar.classMemberAction.getText());
/*
// Generate string literals
println("");
println("*** String literals used in the parser");
println("The following string literals were used in the parser.");
println("An actual code generator would arrange to place these literals");
println("into a table in the generated lexer, so that actions in the");
println("generated lexer could match token text against the literals.");
println("String literals used in the lexer are not listed here, as they");
println("are incorporated into the mainstream lexer processing.");
tabs++;
// Enumerate all of the symbols and look for string literal symbols
Enumeration ids = grammar.getSymbols();
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol)ids.nextElement();
// Only processing string literals -- reject other symbol entries
if ( sym instanceof StringLiteralSymbol ) {
StringLiteralSymbol s = (StringLiteralSymbol)sym;
println(s.getId() + " = " + s.getTokenType());
}
}
tabs--;
println("*** End of string literals used by the parser");
*/
// Generate nextToken() rule.
// nextToken() is a synthetic lexer rule that is the implicit OR of all
// user-defined lexer rules.
genNextToken();
// Generate code for each rule in the lexer
Enumeration ids = grammar.rules.elements();
while ( ids.hasMoreElements() ) {
RuleSymbol rs = (RuleSymbol)ids.nextElement();
if (!rs.id.equals("mnextToken")) {
genRule(rs);
}
}
// Close the lexer output file
currentOutput.close();
currentOutput = null;
doingLexRules = false;
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
genGenericBlock(blk, "+");
}
/** Generate the parser TXT file */
public void gen(ParserGrammar g) throws IOException {
setGrammar(g);
// Open the output stream for the parser and set the currentOutput
System.out.println("Generating " + grammar.getClassName() + ".html");
currentOutput = antlr.Tool.openOutputFile(grammar.getClassName()+".html");
tabs = 0;
// Generate the header common to all output files.
genHeader();
/*
_print("{");
printAction(grammar.preambleAction.getText());
_print("}");
*/
// Generate parser class definition
println("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + " extends " + grammar.getSuperClass());
/*
// Generate user-defined parser class members
println("");
_print("{");
printAction(grammar.classMemberAction.getText());
_print("}");
*/
// Enumerate the parser rules
Enumeration rules = grammar.rules.elements();
while ( rules.hasMoreElements() ) {
println("");
// Get the rules from the list and downcast it to proper type
GrammarSymbol sym = (GrammarSymbol) rules.nextElement();
// Only process parser rules
if ( sym instanceof RuleSymbol) {
genRule((RuleSymbol)sym);
}
}
tabs--;
println("");
genTail();
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The rule-reference to generate
*/
public void gen(RuleRefElement rr) {
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
// Generate the actual rule description
/*
if ( rr.idAssign!=null ) {
_print(rr.idAssign+"=");
}
*/
_print("<a href="+grammar.getClassName() + ".html#"+rr.targetRule+">");
_print(rr.targetRule);
_print("</a>");
if (rr.args != null) {
_print("["+rr.args+"]");
}
_print(" ");
}
/** Generate code for the given grammar element.
* @param blk The string-literal reference to generate
*/
public void gen(StringLiteralElement atom) {
/*
if (atom.label != null) {
_print(atom.label+"=");
}
*/
if (atom.not) {
_print("~");
}
_print(atom.atomText);
_print(" ");
}
/** Generate code for the given grammar element.
* @param blk The token-range reference to generate
*/
public void gen(TokenRangeElement r) {
/*
if ( r.label!=null ) {
_print(r.label+"=");
}
*/
print(r.beginText + ".." + r.endText+" ");
}
/** Generate code for the given grammar element.
* @param blk The token-reference to generate
*/
public void gen(TokenRefElement atom) {
/*
if (atom.label != null) {
_print(atom.label+"=");
}
*/
if (atom.not) {
_print("~");
}
_print(atom.atomText);
_print(" ");
}
public void gen(TreeElement t) {
print(t+" ");
}
/** Generate the tree-walker TXT file */
public void gen(TreeWalkerGrammar g) throws IOException {
setGrammar(g);
// Open the output stream for the parser and set the currentOutput
System.out.println("Generating " + grammar.getClassName() + ".txt");
currentOutput = antlr.Tool.openOutputFile(grammar.getClassName()+".txt");
//SAS: changed for proper text file io
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Output the user-defined parser premamble
println("");
println("*** Tree-walker Preamble Action.");
println("This action will appear before the declaration of your tree-walker class:");
tabs++;
println(grammar.preambleAction.getText());
tabs--;
println("*** End of tree-walker Preamble Action");
// Generate tree-walker class definition
println("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + " extends " + grammar.getSuperClass() + "{");
// Generate user-defined tree-walker class members
println("");
println("*** User-defined tree-walker class members:");
println("These are the member declarations that you defined for your class:");
tabs++;
printAction(grammar.classMemberAction.getText());
tabs--;
println("*** End of user-defined tree-walker class members");
// Generate code for each rule in the grammar
println("");
println("*** tree-walker rules:");
tabs++;
// Enumerate the tree-walker rules
Enumeration rules = grammar.rules.elements();
while ( rules.hasMoreElements() ) {
println("");
// Get the rules from the list and downcast it to proper type
GrammarSymbol sym = (GrammarSymbol) rules.nextElement();
// Only process tree-walker rules
if ( sym instanceof RuleSymbol) {
genRule((RuleSymbol)sym);
}
}
tabs--;
println("");
println("*** End of tree-walker rules");
println("");
println("*** End of tree-walker");
// Close the tree-walker output stream
currentOutput.close();
currentOutput = null;
}
/** Generate a wildcard element */
public void gen(WildcardElement wc) {
/*
if ( wc.getLabel()!=null ) {
_print(wc.getLabel()+"=");
}
*/
_print(". ");
}
/** Generate code for the given grammar element.
* @param blk The (...)* block to generate
*/
public void gen(ZeroOrMoreBlock blk) {
genGenericBlock(blk, "*");
}
protected void genAlt(Alternative alt) {
if (alt.getTreeSpecifier() != null) {
_print(alt.getTreeSpecifier().getText());
}
prevAltElem = null;
for (AlternativeElement elem = alt.head; !(elem instanceof BlockEndElement); elem = elem.next) {
elem.generate();
firstElementInAlt = false;
prevAltElem = elem;
}
}
/** Generate the header for a block, which may be a RuleBlock or a
* plain AlternativeBLock. This generates any variable declarations,
* init-actions, and syntactic-predicate-testing variables.
* @blk The block for which the preamble is to be generated.
*/
protected void genBlockPreamble(AlternativeBlock blk) {
// dump out init action
if ( blk.initAction!=null ) {
printAction("{" + blk.initAction + "}");
}
}
/**Generate common code for a block of alternatives; return a postscript
* that needs to be generated at the end of the block. Other routines
* may append else-clauses and such for error checking before the postfix
* is generated.
*/
public void genCommonBlock(AlternativeBlock blk) {
for (int i = 0; i < blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
AlternativeElement elem = alt.head;
// dump alt operator |
if ( i>0 && blk.alternatives.size()>1 ) {
/*
// only do newline if the last element wasn't a multi-line block
if ( prevAltElem==null ||
!(prevAltElem instanceof AlternativeBlock) ||
((AlternativeBlock)prevAltElem).alternatives.size()==1 )
{
_println("");
}
*/
_println("");
print("|\t");
}
// Dump the alternative, starting with predicates
boolean save = firstElementInAlt;
firstElementInAlt = true;
tabs++; // in case we do a newline in alt, increase the tab indent
// Dump semantic predicates
if (alt.semPred != null) {
println("{" + alt.semPred + "}?");
}
// Dump syntactic predicate
if (alt.synPred != null) {
genSynPred(alt.synPred);
}
genAlt(alt);
tabs--;
firstElementInAlt = save;
}
}
/** Generate a textual representation of the follow set
* for a block.
* @param blk The rule block of interest
*/
public void genFollowSetForRuleBlock(RuleBlock blk)
{
Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, blk.endNode);
printSet(grammar.maxk, 1, follow);
}
protected void genGenericBlock(AlternativeBlock blk, String blkOp) {
if (blk.alternatives.size() > 1) {
// make sure we start on a new line
if (!firstElementInAlt) {
// only do newline if the last element wasn't a multi-line block
if ( prevAltElem==null ||
!(prevAltElem instanceof AlternativeBlock) ||
((AlternativeBlock)prevAltElem).alternatives.size()==1 )
{
_println("");
print("(\t");
}
else {
_print("(\t");
}
// _println("");
// print("(\t");
}
else {
_print("(\t");
}
} else {
_print("( ");
}
genBlockPreamble(blk);
genCommonBlock(blk);
if (blk.alternatives.size() > 1) {
_println("");
print(")" + blkOp + " ");
// if not last element of alt, need newline & to indent
if ( !(blk.next instanceof BlockEndElement) ) {
_println("");
print("");
}
} else {
_print(")" + blkOp + " ");
}
}
/** Generate a header that is common to all TXT files */
protected void genHeader()
{
println("<HTML>");
println("<HEAD>");
println("<TITLE>Grammar "+tool.grammarFile+"</TITLE>");
println("</HEAD>");
println("<BODY>");
println("<table border=1 cellpadding=5>");
println("<tr>");
println("<td>");
println("<font size=+2>Grammar "+grammar.getClassName()+"</font><br>");
println("<a href=http://www.ANTLR.org>ANTLR</a>-generated HTML file from "+tool.grammarFile);
println("<p>");
println("Terence Parr, <a href=http://www.magelang.com>MageLang Institute</a>");
println("<br>ANTLR Version "+Tool.version+"; 1989-1999");
println("</td>");
println("</tr>");
println("</table>");
println("<PRE>");
tabs++;
printAction(behavior.getHeaderAction(""));
tabs--;
}
/**Generate the lookahead set for an alternate. */
protected void genLookaheadSetForAlt(Alternative alt) {
if ( doingLexRules && alt.cache[1].containsEpsilon() ) {
println("MATCHES ALL");
return;
}
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
// if the decision is nondeterministic, do the best we can: LL(k)
// any predicates that are around will be generated later.
depth = grammar.maxk;
}
for (int i = 1; i <= depth; i++)
{
Lookahead lookahead = alt.cache[i];
printSet(depth, i, lookahead);
}
}
/** Generate a textual representation of the lookahead set
* for a block.
* @param blk The block of interest
*/
public void genLookaheadSetForBlock(AlternativeBlock blk)
{
// Find the maximal lookahead depth over all alternatives
int depth = 0;
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
if (alt.lookaheadDepth == GrammarAnalyzer.NONDETERMINISTIC) {
depth = grammar.maxk;
break;
}
else if (depth < alt.lookaheadDepth) {
depth = alt.lookaheadDepth;
}
}
for (int i = 1; i <= depth; i++)
{
Lookahead lookahead = grammar.theLLkAnalyzer.look(i, blk);
printSet(depth, i, lookahead);
}
}
/** Generate the nextToken rule.
* nextToken is a synthetic lexer rule that is the implicit OR of all
* user-defined lexer rules.
*/
public void genNextToken() {
println("");
println("/** Lexer nextToken rule:");
println(" * The lexer nextToken rule is synthesized from all of the user-defined");
println(" * lexer rules. It logically consists of one big alternative block with");
println(" * each user-defined rule being an alternative.");
println(" */");
// Create the synthesized rule block for nextToken consisting
// of an alternate block containing all the user-defined lexer rules.
RuleBlock blk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
// Define the nextToken rule symbol
RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
nextTokenRs.setDefined();
nextTokenRs.setBlock(blk);
nextTokenRs.access = "private";
grammar.define(nextTokenRs);
/*
// Analyze the synthesized block
if (!grammar.theLLkAnalyzer.deterministic(blk))
{
println("The grammar analyzer has determined that the synthesized");
println("nextToken rule is non-deterministic (i.e., it has ambiguities)");
println("This means that there is some overlap of the character");
println("lookahead for two or more of your lexer rules.");
}
*/
genCommonBlock(blk);
}
/** Generate code for a named rule block
* @param s The RuleSymbol describing the rule to generate
*/
public void genRule(RuleSymbol s) {
if ( s==null || !s.isDefined() ) return; // undefined rule
println("");
if ( s.comment!=null ) {
_println(s.comment);
}
if (s.access.length() != 0) {
if ( !s.access.equals("public") ) {
_print(s.access+" ");
}
}
_print("<a name="+s.getId()+">");
_print(s.getId());
_print("</a>");
// Get rule return type and arguments
RuleBlock rblk = s.getBlock();
// Gen method return value(s)
if (rblk.returnAction != null) {
_print("["+rblk.returnAction+"]");
}
// Gen arguments
if (rblk.argAction != null)
{
_print(" returns [" + rblk.argAction+"]");
}
_println("");
tabs++;
print(":\t");
// Dump any init-action
// genBlockPreamble(rblk);
// Dump the alternates of the rule
genCommonBlock(rblk);
_println("");
println(";");
tabs--;
}
/** Generate the syntactic predicate. This basically generates
* the alternative block, buts tracks if we are inside a synPred
* @param blk The syntactic predicate block
*/
protected void genSynPred(SynPredBlock blk) {
syntacticPredLevel++;
genGenericBlock(blk, " =>");
syntacticPredLevel--;
}
public void genTail() {
println("</PRE>");
println("</BODY>");
println("</HTML>");
}
/** Generate the token types TXT file */
protected void genTokenTypes(TokenManager tm) throws IOException {
// Open the token output TXT file and set the currentOutput stream
System.out.println("Generating " + tm.getName() + TokenTypesFileSuffix+TokenTypesFileExt);
currentOutput = antlr.Tool.openOutputFile(tm.getName() + TokenTypesFileSuffix+TokenTypesFileExt);
//SAS: changed for proper text file io
tabs = 0;
// Generate the header common to all diagnostic files
genHeader();
// Generate a string for each token. This creates a static
// array of Strings indexed by token type.
println("");
println("*** Tokens used by the parser");
println("This is a list of the token numeric values and the corresponding");
println("token identifiers. Some tokens are literals, and because of that");
println("they have no identifiers. Literals are double-quoted.");
tabs++;
// Enumerate all the valid token types
Vector v = tm.getVocabulary();
for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if (s != null) {
println(s + " = " + i);
}
}
// Close the interface
tabs--;
println("*** End of tokens used by the parser");
// Close the tokens output file
currentOutput.close();
currentOutput = null;
}
/** Get a string for an expression to generate creation of an AST subtree.
* @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
*/
public String getASTCreateString(Vector v) {
return null;
}
/** Get a string for an expression to generate creating of an AST node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(GrammarAtom atom, String str) {
return null;
}
/** Map an identifier to it's corresponding tree-node variable.
* This is context-sensitive, depending on the rule and alternative
* being generated
* @param id The identifier name to map
* @param forInput true if the input tree node variable is to be returned, otherwise the output variable is returned.
*/
public String mapTreeId(String id, ActionTransInfo tInfo) {
return id;
}
/** Format a lookahead or follow set.
* @param depth The depth of the entire lookahead/follow
* @param k The lookahead level to print
* @param lookahead The lookahead/follow set to print
*/
public void printSet(int depth, int k, Lookahead lookahead) {
int numCols = 5;
int[] elems = lookahead.fset.toArray();
if (depth != 1) {
print("k==" + k + ": {");
} else {
print("{ ");
}
if (elems.length > numCols) {
_println("");
tabs++;
print("");
}
int column = 0;
for (int i = 0; i < elems.length; i++)
{
column++;
if (column > numCols) {
_println("");
print("");
column = 0;
}
if (doingLexRules) {
_print(charFormatter.literalChar(elems[i]));
} else {
_print((String)grammar.tokenManager.getVocabulary().elementAt(elems[i]));
}
if (i != elems.length-1) {
_print(", ");
}
}
if (elems.length > numCols) {
_println("");
tabs--;
print("");
}
_println(" }");
}
}
1.1 e/src/jsrc/antlr/ImportVocabTokenManager.java
Index: ImportVocabTokenManager.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ImportVocabTokenManager.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.*;
import java.util.Hashtable;
import java.util.Enumeration;
import antlr.collections.impl.Vector;
/** Static implementation of the TokenManager, used for importVocab option */
class ImportVocabTokenManager extends SimpleTokenManager implements Cloneable {
private String filename;
protected Grammar grammar;
ImportVocabTokenManager(Grammar grammar, String filename_, String name_, Tool tool_) {
// initialize
super(name_, tool_);
this.grammar = grammar;
// Figure out exactly where the file lives. Check $PWD first,
// and then search in -o <output_dir>.
File grammarFile = new File(filename_);
if ( ! grammarFile.exists() ) {
grammarFile = new File( Tool.getOutputDirectory(), filename_);
if ( ! grammarFile.exists() ) {
tool.panic("Cannot find importVocab file '" + filename);
}
}
filename = filename_;
setReadOnly(true);
// Read a file with lines of the form ID=number
try {
// SAS: changed the following for proper text io
FileReader fileIn = new FileReader(grammarFile);
ANTLRTokdefLexer tokdefLexer = new ANTLRTokdefLexer(fileIn);
ANTLRTokdefParser tokdefParser = new ANTLRTokdefParser(tokdefLexer);
tokdefParser.setFilename(filename);
tokdefParser.file(this);
}
catch (FileNotFoundException fnf) {
tool.panic("Cannot find importVocab file '" + filename);
}
catch (RecognitionException ex) {
tool.panic("Error parsing importVocab file '" + filename + "': " + ex.toString());
}
catch (TokenStreamException ex) {
tool.panic("Error reading importVocab file '" + filename + "'");
}
}
public Object clone() {
ImportVocabTokenManager tm;
tm = (ImportVocabTokenManager)super.clone();
tm.filename = this.filename;
tm.grammar = this.grammar;
return tm;
}
/** define a token. */
public void define(TokenSymbol ts) {
super.define(ts);
}
/** define a token. Intended for use only when reading the importVocab file. */
public void define(String s, int ttype) {
TokenSymbol ts=null;
if ( s.startsWith("\"") ) {
ts = new StringLiteralSymbol(s);
}
else {
ts = new TokenSymbol(s);
}
ts.setTokenType(ttype);
super.define(ts);
maxToken = (ttype+1)>maxToken ? (ttype+1) : maxToken; // record maximum token type
}
/** importVocab token manager is read-only if output would be same as input */
public boolean isReadOnly() {
return readOnly;
}
/** Get the next unused token type. */
public int nextTokenType() {
return super.nextTokenType();
}
}
1.1 e/src/jsrc/antlr/InputBuffer.java
Index: InputBuffer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: InputBuffer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
// SAS: Added this class to genericise the input buffers for scanners
// This allows a scanner to use a binary (FileInputStream) or
// text (FileReader) stream of data; the generated scanner
// subclass will define the input stream
// There are two subclasses to this: CharBuffer and ByteBuffer
import java.io.IOException;
/**A Stream of characters fed to the lexer from a InputStream that can
* be rewound via mark()/rewind() methods.
* <p>
* A dynamic array is used to buffer up all the input characters. Normally,
* "k" characters are stored in the buffer. More characters may be stored during
* guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
* Consumption of characters is deferred. In other words, reading the next
* character is not done by conume(), but deferred until needed by LA or LT.
* <p>
*
* @see antlr.CharQueue
*/
public abstract class InputBuffer {
// char source
// transient Reader input; // leave to subclasses
// Number of active markers
protected int nMarkers = 0;
// Additional offset used when markers are active
protected int markerOffset = 0;
// Number of calls to consume() since last LA() or LT() call
protected int numToConsume = 0;
// Circular queue
protected CharQueue queue;
/** Create an input buffer */
public InputBuffer() {
queue = new CharQueue(1);
}
/** This method updates the state of the input buffer so that
* the text matched since the most recent mark() is no longer
* held by the buffer. So, you either do a mark/rewind for
* failed predicate or mark/commit to keep on parsing without
* rewinding the input.
*/
public void commit() {
nMarkers--;
}
/** Mark another character for deferred consumption */
public void consume() {
numToConsume++;
}
/** Ensure that the input buffer is sufficiently full */
public abstract void fill(int amount) throws CharStreamException;
public String getLAChars() {
StringBuffer la = new StringBuffer();
for(int i = markerOffset; i < queue.nbrEntries; i++)
la.append(queue.elementAt(i));
return la.toString();
}
public String getMarkedChars() {
StringBuffer marked = new StringBuffer();
for(int i = 0; i < markerOffset; i++)
marked.append(queue.elementAt(i));
return marked.toString();
}
public boolean isMarked() {
return (nMarkers != 0);
}
/** Get a lookahead character */
public char LA(int i) throws CharStreamException {
fill(i);
return queue.elementAt(markerOffset + i - 1);
}
/**Return an integer marker that can be used to rewind the buffer to
* its current state.
*/
public int mark() {
syncConsume();
nMarkers++;
return markerOffset;
}
/**Rewind the character buffer to a marker.
* @param mark Marker returned previously from mark()
*/
public void rewind(int mark) {
syncConsume();
markerOffset = mark;
nMarkers--;
}
/** Sync up deferred consumption */
protected void syncConsume() {
while (numToConsume > 0) {
if (nMarkers > 0)
{
// guess mode -- leave leading characters and bump offset.
markerOffset++;
} else {
// normal mode -- remove first character
queue.removeFirst();
}
numToConsume--;
}
}
}
1.1 e/src/jsrc/antlr/JavaBlockFinishingInfo.java
Index: JavaBlockFinishingInfo.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: JavaBlockFinishingInfo.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class JavaBlockFinishingInfo {
String postscript; // what to generate to terminate block
boolean generatedSwitch;// did block finish with "default:" of switch?
boolean generatedAnIf;
/** When generating an if or switch, end-of-token lookahead sets
* will become the else or default clause, don't generate an
* error clause in this case.
*/
boolean needAnErrorClause;
public JavaBlockFinishingInfo() {
postscript=null;
generatedSwitch=generatedSwitch = false;
needAnErrorClause = true;
}
public JavaBlockFinishingInfo(String ps, boolean genS, boolean generatedAnIf, boolean n) {
postscript = ps;
generatedSwitch = genS;
this.generatedAnIf = generatedAnIf;
needAnErrorClause = n;
}
}
1.1 e/src/jsrc/antlr/JavaCharFormatter.java
Index: JavaCharFormatter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: JavaCharFormatter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class JavaCharFormatter implements CharFormatter {
/** Given a character value, return a string representing the character
* that can be embedded inside a string literal or character literal
* This works for Java/C/C++ code-generation and languages with compatible
* special-character-escapment.
* Code-generators for languages should override this method.
* @param c The character of interest.
* @param forCharLiteral true to escape for char literal, false for string literal
*/
public String escapeChar(int c, boolean forCharLiteral) {
switch (c) {
// case GrammarAnalyzer.EPSILON_TYPE : return "<end-of-token>";
case '\n' : return "\\n";
case '\t' : return "\\t";
case '\r' : return "\\r";
case '\\' : return "\\\\";
case '\'' : return forCharLiteral ? "\\'" : "'";
case '"' : return forCharLiteral ? "\"" : "\\\"";
default :
if ( c<' '||c>126 ) {
if ( ( 0x0000 <= c ) && ( c <= 0x000F ) ) {
return "\\u000" + Integer.toString(c,16);
} else if ( ( 0x0010 <= c ) && ( c <= 0x00FF ) ) {
return "\\u00" + Integer.toString(c,16);
} else if ( ( 0x0100 <= c ) && ( c <= 0x0FFF )) {
return "\\u0" + Integer.toString(c,16);
} else {
return "\\u" + Integer.toString(c,16);
}
}
else {
return String.valueOf((char)c);
}
}
}
/** Converts a String into a representation that can be use as a literal
* when surrounded by double-quotes.
* @param s The String to be changed into a literal
*/
public String escapeString(String s)
{
String retval = new String();
for (int i = 0; i < s.length(); i++)
{
retval += escapeChar(s.charAt(i), false);
}
return retval;
}
/** Given a character value, return a string representing the character
* literal that can be recognized by the target language compiler.
* This works for languages that use single-quotes for character literals.
* Code-generators for languages should override this method.
* @param c The character of interest.
*/
public String literalChar(int c) {
return "'" + escapeChar(c, true) + "'";
}
/** Converts a String into a string literal
* This works for languages that use double-quotes for string literals.
* Code-generators for languages should override this method.
* @param s The String to be changed into a literal
*/
public String literalString(String s)
{
return "\"" + escapeString(s) + "\"";
}
}
1.1 e/src/jsrc/antlr/JavaCodeGenerator.java
Index: JavaCodeGenerator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: JavaCodeGenerator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Enumeration;
import java.util.Hashtable;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;
/**Generate MyParser.java, MyLexer.java and MyParserTokenTypes.java */
public class JavaCodeGenerator extends CodeGenerator {
// non-zero if inside syntactic predicate generation
protected int syntacticPredLevel = 0;
// Are we generating ASTs (for parsers and tree parsers) right now?
protected boolean genAST = false;
// Are we saving the text consumed (for lexers) right now?
protected boolean saveText = false;
// Grammar parameters set up to handle different grammar classes.
// These are used to get instanceof tests out of code generation
String labeledElementType;
String labeledElementASTType;
String labeledElementInit;
String commonExtraArgs;
String commonExtraParams;
String commonLocalVars;
String lt1Value;
String exceptionThrown;
String throwNoViable;
/** Tracks the rule being generated. Used for mapTreeId */
RuleBlock currentRule;
/** Tracks the rule or labeled subrule being generated. Used for
AST generation. */
String currentASTResult;
/** Mapping between the ids used in the current alt, and the
* names of variables used to represent their AST values.
*/
Hashtable treeVariableMap = new Hashtable();
/* Count of unnamed generated variables */
int astVarNumber = 1;
/** Special value used to mark duplicate in treeVariableMap */
protected static final String NONUNIQUE = new String();
public static final int caseSizeThreshold = 127; // ascii is max
private Vector semPreds;
/** Create a Java code-generator using the given Grammar.
* The caller must still call setTool, setBehavior, and setAnalyzer
* before generating code.
*/
public JavaCodeGenerator() {
super();
charFormatter = new JavaCharFormatter();
}
/** Adds a semantic predicate string to the sem pred vector
These strings will be used to build an array of sem pred names
when building a debugging parser. This method should only be
called when the debug option is specified
*/
protected int addSemPred(String predicate) {
semPreds.appendElement(predicate);
return semPreds.size()-1;
}
public void exitIfError() {
if (tool.hasError) {
System.out.println("Exiting due to errors.");
System.exit(1);
}
}
/**Generate the parser, lexer, treeparser, and token types in Java */
public void gen() {
// Do the code generation
try {
// Loop over all grammars
Enumeration grammarIter = behavior.grammars.elements();
while (grammarIter.hasMoreElements()) {
Grammar g = (Grammar)grammarIter.nextElement();
// Connect all the components to each other
g.setGrammarAnalyzer(analyzer);
g.setCodeGenerator(this);
analyzer.setGrammar(g);
// To get right overloading behavior across hetrogeneous grammars
setupGrammarParameters(g);
g.generate();
// print out the grammar with lookahead sets (and FOLLOWs)
// System.out.print(g.toString());
exitIfError();
}
// Loop over all token managers (some of which are lexers)
Enumeration tmIter = behavior.tokenManagers.elements();
while (tmIter.hasMoreElements()) {
TokenManager tm = (TokenManager)tmIter.nextElement();
if (!tm.isReadOnly()) {
// Write the token manager tokens as Java
// this must appear before genTokenInterchange so that
// labels are set on string literals
genTokenTypes(tm);
// Write the token manager tokens as plain text
genTokenInterchange(tm);
}
exitIfError();
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
/** Generate code for the given grammar element.
* @param blk The {...} action to generate
*/
public void gen(ActionElement action) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genAction("+action+")");
if ( action.isSemPred ) {
genSemPred(action.actionText, action.line);
}
else {
if ( grammar.hasSyntacticPredicate ) {
println("if ( inputState.guessing==0 ) {");
tabs++;
}
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr = processActionForTreeSpecifiers(action.actionText, action.getLine(), currentRule, tInfo);
if ( tInfo.refRuleRoot!=null ) {
// Somebody referenced "#rule", make sure translated var is valid
// assignment to #rule is left as a ref also, meaning that assignments
// with no other refs like "#rule = foo();" still forces this code to be
// generated (unnecessarily).
println(tInfo.refRuleRoot + " = ("+labeledElementASTType+")currentAST.root;");
}
// dump the translated action
printAction(actionStr);
if ( tInfo.assignToRoot ) {
// Somebody did a "#rule=", reset internal currentAST.root
println("currentAST.root = "+tInfo.refRuleRoot+";");
// reset the child pointer too to be last sibling in sibling list
println("currentAST.child = "+tInfo.refRuleRoot+"!=null &&"+tInfo.refRuleRoot+".getFirstChild()!=null ?");
tabs++;
println(tInfo.refRuleRoot+".getFirstChild() : "+tInfo.refRuleRoot+";");
tabs--;
println("currentAST.advanceChildToEnd();");
}
if ( grammar.hasSyntacticPredicate ) {
tabs--;
println("}");
}
}
}
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public void gen(AlternativeBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen("+blk+")");
println("{");
genBlockPreamble(blk);
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
genBlockFinish(howToFinish, throwNoViable);
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate code for the given grammar element.
* @param blk The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public void gen(BlockEndElement end) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")");
}
/** Generate code for the given grammar element.
* @param blk The character literal reference to generate
*/
public void gen(CharLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genChar("+atom+")");
if ( atom.getLabel()!=null ) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
genMatch(atom);
saveText = oldsaveText;
}
/** Generate code for the given grammar element.
* @param blk The character-range reference to generate
*/
public void gen(CharRangeElement r) {
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " = " + lt1Value + ";");
}
println("matchRange("+r.beginText+","+r.endText+");");
}
/** Generate the lexer Java file */
public void gen(LexerGrammar g) throws IOException {
// If debugging, create a new sempred vector for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof LexerGrammar)) {
tool.panic("Internal error generating lexer");
}
// SAS: moved output creation to method so a subclass can change
// how the output is generated (for VAJ interface)
setupOutput(grammar.getClassName());
genAST = false; // no way to gen trees.
saveText = true; // save consumed characters.
tabs=0;
// Generate header common to all Java output files
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Generate header specific to lexer Java file
// println("import java.io.FileInputStream;");
println("import java.io.InputStream;");
println("import antlr.TokenStreamException;");
println("import antlr.TokenStreamIOException;");
println("import antlr.TokenStreamRecognitionException;");
println("import antlr.CharStreamException;");
println("import antlr.CharStreamIOException;");
println("import antlr.ANTLRException;");
println("import java.io.Reader;");
println("import java.util.Hashtable;");
println("import antlr." + grammar.getSuperClass() + ";");
println("import antlr.InputBuffer;");
println("import antlr.ByteBuffer;");
println("import antlr.CharBuffer;");
println("import antlr.Token;");
println("import antlr.CommonToken;");
println("import antlr.RecognitionException;");
println("import antlr.NoViableAltForCharException;");
println("import antlr.MismatchedCharException;");
println("import antlr.TokenStream;");
println("import antlr.ANTLRHashString;");
println("import antlr.LexerSharedInputState;");
println("import antlr.collections.impl.BitSet;");
println("import antlr.SemanticException;");
// Generate user-defined lexer file preamble
println(grammar.preambleAction.getText());
// Generate lexer class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
}
else {
sup = "antlr." + grammar.getSuperClass();
}
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
print("public class " + grammar.getClassName() + " extends "+sup);
println(" implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix+", TokenStream");
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
print(", "+suffix); // must be an interface name for Java
}
}
println(" {");
// Generate user-defined lexer class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
//
// Generate the constructor from InputStream, which in turn
// calls the ByteBuffer constructor
//
println("public " + grammar.getClassName() + "(InputStream in) {");
tabs++;
println("this(new ByteBuffer(in));");
tabs--;
println("}");
//
// Generate the constructor from Reader, which in turn
// calls the CharBuffer constructor
//
println("public " + grammar.getClassName() + "(Reader in) {");
tabs++;
println("this(new CharBuffer(in));");
tabs--;
println("}");
println("public " + grammar.getClassName() + "(InputBuffer ib) {");
tabs++;
// if debugging, wrap the input buffer in a debugger
if (grammar.debuggingOutput)
println("this(new LexerSharedInputState(new antlr.debug.DebuggingInputBuffer(ib)));");
else
println("this(new LexerSharedInputState(ib));");
tabs--;
println("}");
//
// Generate the constructor from InputBuffer (char or byte)
//
println("public " + grammar.getClassName() + "(LexerSharedInputState state) {");
tabs++;
println("super(state);");
// if debugging, set up array variables and call user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println(" ruleNames = _ruleNames;");
println(" semPredNames = _semPredNames;");
println(" setupDebugging();");
}
// Generate the initialization of a hashtable
// containing the string literals used in the lexer
// The literals variable itself is in CharScanner
println("literals = new Hashtable();");
Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
while ( keys.hasMoreElements() ) {
String key = (String)keys.nextElement();
if ( key.charAt(0) != '"' ) {
continue;
}
TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
if ( sym instanceof StringLiteralSymbol ) {
StringLiteralSymbol s = (StringLiteralSymbol)sym;
println("literals.put(new ANTLRHashString(" + s.getId() + ", this), new Integer(" + s.getTokenType() + "));");
}
}
tabs--;
Enumeration ids;
// Generate the setting of various generated options.
println("caseSensitiveLiterals = " + g.caseSensitiveLiterals + ";");
println("setCaseSensitive("+g.caseSensitive+");");
println("}");
// generate the rule name array for debugging
if (grammar.debuggingOutput) {
println("private static final String _ruleNames[] = {");
ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println(" \""+((RuleSymbol)sym).getId()+"\",");
}
println("};");
}
// Generate nextToken() rule.
// nextToken() is a synthetic lexer rule that is the implicit OR of all
// user-defined lexer rules.
genNextToken();
// Generate code for each rule in the lexer
ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
RuleSymbol sym = (RuleSymbol) ids.nextElement();
// Don't generate the synthetic rules
if (!sym.getId().equals("mnextToken")) {
genRule(sym, false, ruleNum++);
}
exitIfError();
}
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap();
// Generate the bitsets used throughout the lexer
genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size());
println("");
println("}");
// Close the lexer output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
String label;
String cnt;
println("{");
genBlockPreamble(blk);
if ( blk.getLabel() != null ) {
cnt = "_cnt_"+blk.getLabel();
}
else {
cnt = "_cnt" + blk.ID;
}
println("int "+cnt+"=0;");
if ( blk.getLabel() != null ) {
label = blk.getLabel();
}
else {
label = "_loop" + blk.ID;
}
println(label+":");
println("do {");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)+ loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("// nongreedy exit test");
println("if ( "+cnt+">=1 && "+predictExit+") break "+label+";");
}
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(
howToFinish,
"if ( "+cnt+">=1 ) { break "+label+"; } else {" + throwNoViable + "}"
);
println(cnt+"++;");
tabs--;
println("} while (true);");
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate the parser Java file */
public void gen(ParserGrammar g) throws IOException {
// if debugging, set up a new vector to keep track of sempred
// strings for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof ParserGrammar)) {
tool.panic("Internal error generating parser");
}
// Open the output stream for the parser and set the currentOutput
// SAS: moved file setup so subclass could do it (for VAJ interface)
setupOutput(grammar.getClassName());
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Generate header for the parser
println("import antlr.TokenBuffer;");
println("import antlr.TokenStreamException;");
println("import antlr.TokenStreamIOException;");
println("import antlr.ANTLRException;");
println("import antlr." + grammar.getSuperClass() + ";");
println("import antlr.Token;");
println("import antlr.TokenStream;");
println("import antlr.RecognitionException;");
println("import antlr.NoViableAltException;");
println("import antlr.MismatchedTokenException;");
println("import antlr.SemanticException;");
println("import antlr.ParserSharedInputState;");
println("import antlr.collections.impl.BitSet;");
println("import antlr.collections.AST;");
println("import antlr.ASTPair;");
println("import antlr.collections.impl.ASTArray;");
// Output the user-defined parser preamble
println(grammar.preambleAction.getText());
// Generate parser class definition
String sup=null;
if ( grammar.superClass != null )
sup = grammar.superClass;
else
sup = "antlr." + grammar.getSuperClass();
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("public class " + grammar.getClassName() + " extends "+sup);
println(" implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null )
print(", "+suffix); // must be an interface name for Java
}
println(" {");
// set up an array of all the rule names so the debugger can
// keep track of them only by number -- less to store in tree...
if (grammar.debuggingOutput) {
println("private static final String _ruleNames[] = {");
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println(" \""+((RuleSymbol)sym).getId()+"\",");
}
println("};");
}
// Generate user-defined parser class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
// Generate parser class constructor from TokenBuffer
println("");
println("protected " + grammar.getClassName() + "(TokenBuffer tokenBuf, int k) {");
println(" super(tokenBuf,k);");
println(" tokenNames = _tokenNames;");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println(" ruleNames = _ruleNames;");
println(" semPredNames = _semPredNames;");
println(" setupDebugging(tokenBuf);");
}
println("}");
println("");
println("public " + grammar.getClassName() + "(TokenBuffer tokenBuf) {");
println(" this(tokenBuf," + grammar.maxk + ");");
println("}");
println("");
// Generate parser class constructor from TokenStream
println("protected " + grammar.getClassName()+"(TokenStream lexer, int k) {");
println(" super(lexer,k);");
println(" tokenNames = _tokenNames;");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println(" ruleNames = _ruleNames;");
println(" semPredNames = _semPredNames;");
println(" setupDebugging(lexer);");
}
println("}");
println("");
println("public " + grammar.getClassName()+"(TokenStream lexer) {");
println(" this(lexer," + grammar.maxk + ");");
println("}");
println("");
println("public " + grammar.getClassName()+"(ParserSharedInputState state) {");
println(" super(state," + grammar.maxk + ");");
println(" tokenNames = _tokenNames;");
println("}");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++);
}
exitIfError();
}
// Generate the token names
genTokenStrings();
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap();
// Close class definition
println("");
println("}");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The rule-reference to generate
*/
public void gen(RuleRefElement rr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRR("+rr+")");
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rs == null || !rs.isDefined())
{
// Is this redundant???
tool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine());
return;
}
if (!(rs instanceof RuleSymbol))
{
// Is this redundant???
tool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine());
return;
}
genErrorTryForElement(rr);
// AST value for labeled rule refs in tree walker.
// This is not AST construction; it is just the input tree node value.
if ( grammar instanceof TreeWalkerGrammar &&
rr.getLabel() != null &&
syntacticPredLevel == 0 )
{
println(rr.getLabel() + " = _t==ASTNULL ? null : "+lt1Value+";");
}
// if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("_saveIndex=text.length();");
}
// Process return value assignment if any
printTabs();
if (rr.idAssign != null)
{
// Warn if the rule has no return type
if (rs.block.returnAction == null)
{
tool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine());
}
_print(rr.idAssign + "=");
} else {
// Warn about return value if any, but not inside syntactic predicate
if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
{
tool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine());
}
}
// Call the rule
GenRuleInvocation(rr);
// if in lexer and ! on element or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text.setLength(_saveIndex);");
}
// if not in a syntactic predicate
if (syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
grammar.buildAST && rr.getLabel() != null ||
(genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
)
);
if (doNoGuessTest) {
println("if (inputState.guessing==0) {");
tabs++;
}
if (grammar.buildAST && rr.getLabel() != null) {
// always gen variable for rule return on labeled rules
println(rr.getLabel() + "_AST = ("+labeledElementASTType+")returnAST;");
}
if (genAST) {
switch (rr.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
// println("theASTFactory.addASTChild(currentAST, returnAST);");
println("astFactory.addASTChild(currentAST, returnAST);");
break;
case GrammarElement.AUTO_GEN_CARET:
tool.error("Internal: encountered ^ after rule reference");
break;
default:
break;
}
}
// if a lexer and labeled, Token label defined at rule level, just set it here
if ( grammar instanceof LexerGrammar && rr.getLabel() != null ) {
println(rr.getLabel()+"=_returnToken;");
}
if (doNoGuessTest) {
tabs--;
println("}");
}
}
genErrorCatchForElement(rr);
}
/** Generate code for the given grammar element.
* @param blk The string-literal reference to generate
*/
public void gen(StringLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genString("+atom+")");
// Variable declarations for labeled elements
if (atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(atom);
// is there a bang on the literal?
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
// matching
genMatch(atom);
saveText = oldsaveText;
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t.getNextSibling();");
}
}
/** Generate code for the given grammar element.
* @param blk The token-range reference to generate
*/
public void gen(TokenRangeElement r) {
genErrorTryForElement(r);
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(r);
// match
println("matchRange("+r.beginText+","+r.endText+");");
genErrorCatchForElement(r);
}
/** Generate code for the given grammar element.
* @param blk The token-reference to generate
*/
public void gen(TokenRefElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")");
if ( grammar instanceof LexerGrammar ) {
tool.panic("Token reference found in lexer");
}
genErrorTryForElement(atom);
// Assign Token value to token label variable
if ( atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(atom);
// matching
genMatch(atom);
genErrorCatchForElement(atom);
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t.getNextSibling();");
}
}
public void gen(TreeElement t) {
// save AST cursor
println("AST __t" + t.ID + " = _t;");
// If there is a label on the root, then assign that to the variable
if (t.root.getLabel() != null) {
println(t.root.getLabel() + " = _t==ASTNULL ? null :("+labeledElementASTType +")_t;");
}
// Generate AST variables
genElementAST(t.root);
if (grammar.buildAST) {
// Save the AST construction state
println("ASTPair __currentAST" + t.ID + " = currentAST.copy();");
// Make the next item added a child of the TreeElement root
println("currentAST.root = currentAST.child;");
println("currentAST.child = null;");
}
// match root
genMatch(t.root);
// move to list of children
println("_t = _t.getFirstChild();");
// walk list of children, generating code for each
for (int i=0; i<t.getAlternatives().size(); i++) {
Alternative a = t.getAlternativeAt(i);
AlternativeElement e = a.head;
while ( e != null ) {
e.generate();
e = e.next;
}
}
if (grammar.buildAST) {
// restore the AST construction state to that just after the
// tree root was added
println("currentAST = __currentAST" + t.ID + ";");
}
// restore AST cursor
println("_t = __t" + t.ID + ";");
// move cursor to sibling of tree just parsed
println("_t = _t.getNextSibling();");
}
/** Generate the tree-parser Java file */
public void gen(TreeWalkerGrammar g) throws IOException {
// SAS: debugging stuff removed for now...
setGrammar(g);
if (!(grammar instanceof TreeWalkerGrammar)) {
tool.panic("Internal error generating tree-walker");
}
// Open the output stream for the parser and set the currentOutput
// SAS: move file open to method so subclass can override it
// (mainly for VAJ interface)
setupOutput(grammar.getClassName());
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Generate header for the parser
println("import antlr." + grammar.getSuperClass() + ";");
println("import antlr.Token;");
println("import antlr.collections.AST;");
println("import antlr.RecognitionException;");
println("import antlr.ANTLRException;");
println("import antlr.NoViableAltException;");
println("import antlr.MismatchedTokenException;");
println("import antlr.SemanticException;");
println("import antlr.collections.impl.BitSet;");
println("import antlr.ASTPair;");
println("import antlr.collections.impl.ASTArray;");
// Output the user-defined parser premamble
println(grammar.preambleAction.getText());
// Generate parser class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
}
else {
sup = "antlr." + grammar.getSuperClass();
}
println("");
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("public class " + grammar.getClassName() + " extends "+sup);
println(" implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix);
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
print(", "+suffix); // must be an interface name for Java
}
}
println(" {");
// Generate user-defined parser class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
// Generate default parser class constructor
println("public " + grammar.getClassName() + "() {");
tabs++;
println("tokenNames = _tokenNames;");
tabs--;
println("}");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
String ruleNameInits = "";
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++);
}
exitIfError();
}
// Generate the token names
genTokenStrings();
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Close class definition
println("}");
println("");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param wc The wildcard element to generate
*/
public void gen(WildcardElement wc) {
// Variable assignment for labeled elements
if (wc.getLabel()!=null && syntacticPredLevel == 0) {
println(wc.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(wc);
// Match anything but EOF
if (grammar instanceof TreeWalkerGrammar) {
println("if ( _t==null ) throw new MismatchedTokenException();");
}
else if (grammar instanceof LexerGrammar) {
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("_saveIndex=text.length();");
}
println("matchNot(EOF_CHAR);");
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text.setLength(_saveIndex);"); // kill text atom put in buffer
}
}
else {
println("matchNot(" + getValueString(Token.EOF_TYPE) + ");");
}
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t.getNextSibling();");
}
}
/** Generate code for the given grammar element.
* @param blk The (...)* block to generate
*/
public void gen(ZeroOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen*("+blk+")");
println("{");
genBlockPreamble(blk);
String label;
if ( blk.getLabel() != null ) {
label = blk.getLabel();
}
else {
label = "_loop" + blk.ID;
}
println(label+":");
println("do {");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)* loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("// nongreedy exit test");
println("if ("+predictExit+") break "+label+";");
}
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(howToFinish, "break " + label + ";");
tabs--;
println("} while (true);");
println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate an alternative.
* @param alt The alternative to generate
* @param blk The block to which the alternative belongs
*/
protected void genAlt(Alternative alt, AlternativeBlock blk) {
// Save the AST generation state, and set it to that of the alt
boolean savegenAST = genAST;
genAST = genAST && alt.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && alt.getAutoGen();
// Reset the variable name map for the alternative
Hashtable saveMap = treeVariableMap;
treeVariableMap = new Hashtable();
// Generate try block around the alt for error handling
if (alt.exceptionSpec != null) {
println("try { // for error handling");
tabs++;
}
AlternativeElement elem = alt.head;
while ( !(elem instanceof BlockEndElement) ) {
elem.generate(); // alt can begin with anything. Ask target to gen.
elem = elem.next;
}
if ( genAST) {
if (blk instanceof RuleBlock) {
// Set the AST return value for the rule
RuleBlock rblk = (RuleBlock)blk;
println(rblk.getRuleName() + "_AST = ("+labeledElementASTType+")currentAST.root;");
}
else if (blk.getLabel() != null) {
// ### future: also set AST value for labeled subrules.
// println(blk.getLabel() + "_AST = ("+labeledElementASTType+")currentAST.root;");
}
}
if (alt.exceptionSpec != null) {
// close try block
tabs--;
println("}");
genErrorHandler(alt.exceptionSpec);
}
genAST = savegenAST;
saveText = oldsaveTest;
treeVariableMap = saveMap;
}
/** Generate all the bitsets to be used in the parser or lexer
* Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
* and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
* Note that most languages do not support object initialization inside a
* class definition, so other code-generators may have to separate the
* bitset declarations from the initializations (e.g., put the initializations
* in the generated constructor instead).
* @param bitsetList The list of bitsets to generate.
* @param maxVocabulary Ensure that each generated bitset can contain at least this value.
*/
protected void genBitsets(
Vector bitsetList,
int maxVocabulary
) {
println("");
for (int i = 0; i < bitsetList.size(); i++)
{
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
// initialization data
println(
"private static final long " + getBitsetName(i) + "_data_" + "[] = { " +
p.toStringOfWords() +
" };"
);
// BitSet object
println(
"public static final BitSet " + getBitsetName(i) + " = new BitSet(" +
getBitsetName(i) + "_data_" +
");"
);
}
}
/** Generate the finish of a block, using a combination of the info
* returned from genCommonBlock() and the action to perform when
* no alts were taken
* @param howToFinish The return of genCommonBlock()
* @param noViableAction What to generate when no alt is taken
*/
private void genBlockFinish(JavaBlockFinishingInfo howToFinish, String noViableAction)
{
if (howToFinish.needAnErrorClause &&
(howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
if ( howToFinish.generatedAnIf ) {
println("else {");
}
else {
println("{");
}
tabs++;
println(noViableAction);
tabs--;
println("}");
}
if ( howToFinish.postscript!=null ) {
println(howToFinish.postscript);
}
}
/** Generate the header for a block, which may be a RuleBlock or a
* plain AlternativeBLock. This generates any variable declarations,
* init-actions, and syntactic-predicate-testing variables.
* @blk The block for which the preamble is to be generated.
*/
protected void genBlockPreamble(AlternativeBlock blk) {
// define labels for rule blocks.
if ( blk instanceof RuleBlock ) {
RuleBlock rblk = (RuleBlock)blk;
if ( rblk.labeledElements!=null ) {
for (int i=0; i<rblk.labeledElements.size(); i++) {
AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
//System.out.println("looking at labeled element: "+a);
//Variables for labeled rule refs and
//subrules are different than variables for
//grammar atoms. This test is a little tricky
//because we want to get all rule refs and ebnf,
//but not rule blocks or syntactic predicates
if (
a instanceof RuleRefElement ||
a instanceof AlternativeBlock &&
!(a instanceof RuleBlock) &&
!(a instanceof SynPredBlock)
) {
if (
!(a instanceof RuleRefElement) &&
((AlternativeBlock)a).not &&
analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
) {
// Special case for inverted subrules that
// will be inlined. Treat these like
// token or char literal references
println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
if (grammar.buildAST) {
println(labeledElementASTType+" " + a.getLabel() + "_AST = null;");
}
}
else {
if (grammar.buildAST) {
// Always gen AST variables for
// labeled elements, even if the
// element itself is marked with !
println(labeledElementASTType+" " + a.getLabel() + "_AST = null;");
}
if ( grammar instanceof LexerGrammar ) {
println("Token "+a.getLabel()+"=null;");
}
if (grammar instanceof TreeWalkerGrammar) {
// always generate rule-ref variables
// for tree walker
println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
}
}
}
else {
// It is a token or literal reference. Generate the
// correct variable type for this grammar
println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
// In addition, generate *_AST variables if
// building ASTs
if (grammar.buildAST) {
if (a instanceof GrammarAtom &&
((GrammarAtom)a).getASTNodeType()!=null ) {
GrammarAtom ga = (GrammarAtom)a;
println(ga.getASTNodeType()+" " +
a.getLabel() +
"_AST = null;");
}
else {
println(labeledElementASTType+" " +
a.getLabel() +
"_AST = null;");
}
}
}
}
}
}
// dump out init action
if ( blk.initAction!=null ) {
printAction(
processActionForTreeSpecifiers(blk.initAction, 0, currentRule, null)
);
}
}
/** Generate a series of case statements that implement a BitSet test.
* @param p The Bitset for which cases are to be generated
*/
protected void genCases(BitSet p) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCases("+p+")");
int[] elems;
elems = p.toArray();
// Wrap cases four-per-line for lexer, one-per-line for parser
int wrap = (grammar instanceof LexerGrammar) ? 4 : 1;
int j=1;
boolean startOfLine = true;
for (int i = 0; i < elems.length; i++) {
if (j==1) {
print("");
} else {
_print(" ");
}
_print("case " + getValueString(elems[i]) + ":");
if (j==wrap) {
_println("");
startOfLine = true;
j=1;
}
else {
j++;
startOfLine = false;
}
}
if (!startOfLine) {
_println("");
}
}
/**Generate common code for a block of alternatives; return a
* postscript that needs to be generated at the end of the
* block. Other routines may append else-clauses and such for
* error checking before the postfix is generated. If the
* grammar is a lexer, then generate alternatives in an order
* where alternatives requiring deeper lookahead are generated
* first, and EOF in the lookahead set reduces the depth of
* the lookahead. @param blk The block to generate @param
* noTestForSingle If true, then it does not generate a test
* for a single alternative.
*/
public JavaBlockFinishingInfo genCommonBlock(AlternativeBlock blk,
boolean noTestForSingle)
{
int nIF=0;
boolean createdLL1Switch = false;
int closingBracesOfIFSequence = 0;
JavaBlockFinishingInfo finishingInfo = new JavaBlockFinishingInfo();
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCommonBlock("+blk+")");
// Save the AST generation state, and set it to that of the block
boolean savegenAST = genAST;
genAST = genAST && blk.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && blk.getAutoGen();
// Is this block inverted? If so, generate special-case code
if (
blk.not &&
analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar)
) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("special case: ~(subrule)");
Lookahead p = analyzer.look(1, blk);
// Variable assignment for labeled elements
if (blk.getLabel() != null && syntacticPredLevel == 0) {
println(blk.getLabel() + " = " + lt1Value + ";");
}
// AST
genElementAST(blk);
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
astArgs="_t,";
}
// match the bitset for the alternative
println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("_t = _t.getNextSibling();");
}
return finishingInfo;
}
// Special handling for single alt
if (blk.getAlternatives().size() == 1) {
Alternative alt = blk.getAlternativeAt(0);
// Generate a warning if there is a synPred for single alt.
if (alt.synPred != null)
{
tool.warning(
"Syntactic predicate superfluous for single alternative",
grammar.getFilename(),
blk.getAlternativeAt(0).synPred.getLine()
);
}
if (noTestForSingle) {
if (alt.semPred != null) {
// Generate validating predicate
genSemPred(alt.semPred, blk.line);
}
genAlt(alt, blk);
return finishingInfo;
}
}
// count number of simple LL(1) cases; only do switch for
// many LL(1) cases (no preds, no end of token refs)
// We don't care about exit paths for (...)*, (...)+
// because we don't explicitly have a test for them
// as an alt in the loop.
//
// Also, we now count how many unicode lookahead sets
// there are--they must be moved to DEFAULT or ELSE
// clause.
int nLL1 = 0;
for (int i=0; i<blk.getAlternatives().size(); i++) {
Alternative a = blk.getAlternativeAt(i);
if ( suitableForCaseExpression(a) ) {
nLL1++;
}
}
// do LL(1) cases
if ( nLL1 >= makeSwitchThreshold) {
// Determine the name of the item to be compared
String testExpr = lookaheadString(1);
createdLL1Switch = true;
// when parsing trees, convert null to valid tree node with NULL lookahead
if ( grammar instanceof TreeWalkerGrammar ) {
println("if (_t==null) _t=ASTNULL;");
}
println("switch ( "+testExpr+") {");
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
// ignore any non-LL(1) alts, predicated alts,
// or end-of-token alts for case expressions
if ( !suitableForCaseExpression(alt) ) {
continue;
}
Lookahead p = alt.cache[1];
if (p.fset.degree() == 0 && !p.containsEpsilon()) {
tool.warning("Alternate omitted due to empty prediction set",
grammar.getFilename(),
alt.head.getLine());
}
else {
genCases(p.fset);
println("{");
tabs++;
genAlt(alt, blk);
println("break;");
tabs--;
println("}");
}
}
println("default:");
tabs++;
}
// do non-LL(1) and nondeterministic cases This is tricky in
// the lexer, because of cases like: STAR : '*' ; ASSIGN_STAR
// : "*="; Since nextToken is generated without a loop, then
// the STAR will have end-of-token as it's lookahead set for
// LA(2). So, we must generate the alternatives containing
// trailing end-of-token in their lookahead sets *after* the
// alternatives without end-of-token. This implements the
// usual lexer convention that longer matches come before
// shorter ones, e.g. "*=" matches ASSIGN_STAR not STAR
//
// For non-lexer grammars, this does not sort the alternates
// by depth Note that alts whose lookahead is purely
// end-of-token at k=1 end up as default or else clauses.
int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("checking depth "+altDepth);
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
if ( DEBUG_CODE_GENERATOR ) System.out.println("genAlt: "+i);
// if we made a switch above, ignore what we already took care
// of. Specifically, LL(1) alts with no preds
// that do not have end-of-token in their prediction set
// and that are not giant unicode sets.
if ( createdLL1Switch && suitableForCaseExpression(alt) ) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("ignoring alt because it was in the switch");
continue;
}
String e;
boolean unpredicted = false;
if (grammar instanceof LexerGrammar) {
// Calculate the "effective depth" of the alt,
// which is the max depth at which
// cache[depth]!=end-of-token
int effectiveDepth = alt.lookaheadDepth;
if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) {
// use maximum lookahead
effectiveDepth = grammar.maxk;
}
while ( effectiveDepth >= 1 &&
alt.cache[effectiveDepth].containsEpsilon() ) {
effectiveDepth--;
}
// Ignore alts whose effective depth is other than
// the ones we are generating for this iteration.
if (effectiveDepth != altDepth) {
if ( DEBUG_CODE_GENERATOR )
System.out.println("ignoring alt because effectiveDepth!=altDepth;"+effectiveDepth+"!="+altDepth);
continue;
}
unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
e = getLookaheadTestExpression(alt, effectiveDepth);
} else {
unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
e = getLookaheadTestExpression(alt, grammar.maxk);
}
// Was it a big unicode range that forced unsuitability
// for a case expression?
if ( alt.cache[1].fset.degree()>caseSizeThreshold ) {
if ( nIF==0 ) {
println("if " + e + " {");
}
else {
println("else if " + e + " {");
}
}
else if (unpredicted &&
alt.semPred==null &&
alt.synPred==null) {
// The alt has empty prediction set and no
// predicate to help out. if we have not
// generated a previous if, just put {...} around
// the end-of-token clause
if ( nIF==0 ) {
println("{");
}
else {
println("else {");
}
finishingInfo.needAnErrorClause = false;
}
else { // check for sem and syn preds
// Add any semantic predicate expression to the
// lookahead test
if ( alt.semPred != null ) {
// if debugging, wrap the evaluation of the
// predicate in a method translate $ and #
// references
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr =
processActionForTreeSpecifiers(alt.semPred,
blk.line,
currentRule,
tInfo);
// ignore translation info...we don't need to
// do anything with it. call that will inform
// SemanticPredicateListeners of the result
if (((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar)) &&
grammar.debuggingOutput) {
e = "("+e+"&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING,"+
addSemPred(charFormatter.escapeString(actionStr))+","+actionStr+"))";
}
else {
e = "("+e+"&&("+actionStr +"))";
}
}
// Generate any syntactic predicates
if ( nIF>0 ) {
if ( alt.synPred != null ) {
println("else {");
tabs++;
genSynPred( alt.synPred, e );
closingBracesOfIFSequence++;
}
else {
println("else if " + e + " {");
}
}
else {
if ( alt.synPred != null ) {
genSynPred( alt.synPred, e );
}
else {
// when parsing trees, convert null to
// valid tree node with NULL lookahead.
if ( grammar instanceof TreeWalkerGrammar ) {
println("if (_t==null) _t=ASTNULL;");
}
println("if " + e + " {");
}
}
}
nIF++;
tabs++;
genAlt(alt, blk);
tabs--;
println("}");
}
}
String ps = "";
for (int i=1; i<=closingBracesOfIFSequence; i++) {
ps+="}";
}
// Restore the AST generation state
genAST = savegenAST;
// restore save text state
saveText=oldsaveTest;
// Return the finishing info.
if ( createdLL1Switch ) {
tabs--;
finishingInfo.postscript = ps+"}";
finishingInfo.generatedSwitch = true;
finishingInfo.generatedAnIf = nIF>0;
//return new JavaBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
}
else {
finishingInfo.postscript = ps;
finishingInfo.generatedSwitch = false;
finishingInfo.generatedAnIf = nIF>0;
// return new JavaBlockFinishingInfo(ps, false,nIF>0);
}
return finishingInfo;
}
private static boolean suitableForCaseExpression(Alternative a) {
return
a.lookaheadDepth == 1 &&
a.semPred == null &&
!a.cache[1].containsEpsilon() &&
a.cache[1].fset.degree()<=caseSizeThreshold;
}
/** Generate code to link an element reference into the AST */
private void genElementAST(AlternativeElement el) {
// handle case where you're not building trees, but are in tree walker.
// Just need to get labels set up.
if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST ) {
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() == null) {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_AST";
astVarNumber++;
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
// Generate an "input" AST variable also
println(labeledElementASTType+" "+astName+"_in = "+elementRef+";");
}
return;
}
if (grammar.buildAST && syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
el.getLabel() != null ||
el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG
)
);
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() != null) {
elementRef = el.getLabel();
astName = el.getLabel() + "_AST";
} else {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_AST";
astVarNumber++;
// Generate the declaration
if ( el instanceof GrammarAtom ) {
GrammarAtom ga = (GrammarAtom)el;
if ( ga.getASTNodeType()!=null ) {
println(ga.getASTNodeType()+" " + astName+" = null;");
}
else {
println(labeledElementASTType+" " + astName + " = null;");
}
}
else {
println(labeledElementASTType+" " + astName + " = null;");
}
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
if (grammar instanceof TreeWalkerGrammar) {
// Generate an "input" AST variable also
println(labeledElementASTType+" " + astName + "_in = null;");
}
}
// Enclose actions with !guessing
if (doNoGuessTest) {
println("if (inputState.guessing==0) {");
tabs++;
}
if (el.getLabel() != null) {
if ( el instanceof GrammarAtom ) {
println(astName + " = "+ getASTCreateString((GrammarAtom)el, elementRef) + ";");
}
else {
println(astName + " = "+ getASTCreateString(elementRef) + ";");
}
} else {
elementRef = lt1Value;
if ( el instanceof GrammarAtom ) {
println(astName + " = "+ getASTCreateString((GrammarAtom)el, elementRef) + ";");
}
else {
println(astName + " = "+ getASTCreateString(elementRef) + ";");
}
// Map the generated AST variable in the alternate
if (grammar instanceof TreeWalkerGrammar) {
// set "input" AST variable also
println(astName + "_in = " + elementRef + ";");
}
}
if (genAST) {
switch (el.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
println("astFactory.addASTChild(currentAST, " + astName + ");");
break;
case GrammarElement.AUTO_GEN_CARET:
println("astFactory.makeASTRoot(currentAST, " + astName + ");");
break;
default:
break;
}
}
if (doNoGuessTest) {
tabs--;
println("}");
}
}
}
/** Close the try block and generate catch phrases
* if the element has a labeled handler in the rule
*/
private void genErrorCatchForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
tabs--;
println("}");
genErrorHandler(ex);
}
}
/** Generate the catch phrases for a user-specified error handler */
private void genErrorHandler(ExceptionSpec ex) {
// Each ExceptionHandler in the ExceptionSpec is a separate catch
for (int i = 0; i < ex.handlers.size(); i++)
{
ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i);
// Generate catch phrase
println("catch (" + handler.exceptionTypeAndName.getText() + ") {");
tabs++;
if (grammar.hasSyntacticPredicate) {
println("if (inputState.guessing==0) {");
tabs++;
}
// When not guessing, execute user handler action
printAction(
processActionForTreeSpecifiers(handler.action.getText(), 0, currentRule, null)
);
if (grammar.hasSyntacticPredicate) {
tabs--;
println("} else {");
tabs++;
// When guessing, rethrow exception
println(
"throw " +
extractIdOfAction(handler.exceptionTypeAndName) +
";"
);
tabs--;
println("}");
}
// Close catch phrase
tabs--;
println("}");
}
}
/** Generate a try { opening if the element has a labeled handler in the rule */
private void genErrorTryForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
println("try { // for error handling");
tabs++;
}
}
/** Generate a header that is common to all Java files */
protected void genHeader() {
println("// $ANTLR "+Tool.version+": "+
"\""+Tool.fileMinusPath(tool.grammarFile)+"\""+
" -> "+
"\""+grammar.getClassName()+".java\"$");
}
private void genLiteralsTest() {
println("_ttype = testLiteralsTable(_ttype);");
}
private void genLiteralsTestForPartialToken() {
println("_ttype = testLiteralsTable(new String(text.getBuffer(),_begin,text.length()-_begin),_ttype);");
}
protected void genMatch(BitSet b) {
}
protected void genMatch(GrammarAtom atom) {
if ( atom instanceof StringLiteralElement ) {
if ( grammar instanceof LexerGrammar ) {
genMatchUsingAtomText(atom);
}
else {
genMatchUsingAtomTokenType(atom);
}
}
else if ( atom instanceof CharLiteralElement ) {
if ( grammar instanceof LexerGrammar ) {
genMatchUsingAtomText(atom);
}
else {
tool.error("cannot ref character literals in grammar: "+atom);
}
}
else if ( atom instanceof TokenRefElement ) {
genMatchUsingAtomText(atom);
}
}
protected void genMatchUsingAtomText(GrammarAtom atom) {
// match() for trees needs the _t cursor
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
astArgs="_t,";
}
// if in lexer and ! on element, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("_saveIndex=text.length();");
}
print(atom.not ? "matchNot(" : "match(");
_print(astArgs);
// print out what to match
if (atom.atomText.equals("EOF")) {
// horrible hack to handle EOF case
_print("Token.EOF_TYPE");
}
else {
_print(atom.atomText);
}
_println(");");
if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text.setLength(_saveIndex);"); // kill text atom put in buffer
}
}
protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
// match() for trees needs the _t cursor
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
astArgs="_t,";
}
// If the literal can be mangled, generate the symbolic constant instead
String mangledName = null;
String s = astArgs + getValueString(atom.getType());
// matching
println( (atom.not ? "matchNot(" : "match(") + s + ");");
}
/** Generate the nextToken() rule. nextToken() is a synthetic
* lexer rule that is the implicit OR of all user-defined
* lexer rules.
*/
public void genNextToken() {
// Are there any public rules? If not, then just generate a
// fake nextToken().
boolean hasPublicRules = false;
for (int i = 0; i < grammar.rules.size(); i++) {
RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i);
if ( rs.isDefined() && rs.access.equals("public") ) {
hasPublicRules = true;
break;
}
}
if (!hasPublicRules) {
println("");
println("public Token nextToken() throws TokenStreamException {");
println("\ttry {uponEOF();}");
println("\tcatch(CharStreamIOException csioe) {");
println("\t\tthrow new TokenStreamIOException(csioe.io);");
println("\t}");
println("\tcatch(CharStreamException cse) {");
println("\t\tthrow new TokenStreamException(cse.getMessage());");
println("\t}");
println("\treturn new CommonToken(Token.EOF_TYPE, \"\");");
println("}");
println("");
return;
}
// Create the synthesized nextToken() rule
RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
// Define the nextToken rule symbol
RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
nextTokenRs.setDefined();
nextTokenRs.setBlock(nextTokenBlk);
nextTokenRs.access = "private";
grammar.define(nextTokenRs);
// Analyze the nextToken rule
boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);
// Generate the next token rule
String filterRule=null;
if ( ((LexerGrammar)grammar).filterMode ) {
filterRule = ((LexerGrammar)grammar).filterRule;
}
println("");
println("public Token nextToken() throws TokenStreamException {");
tabs++;
println("Token theRetToken=null;");
_println("tryAgain:");
println("for (;;) {");
tabs++;
println("Token _token = null;");
println("int _ttype = Token.INVALID_TYPE;");
if ( ((LexerGrammar)grammar).filterMode ) {
println("setCommitToPath(false);");
if ( filterRule!=null ) {
// Here's a good place to ensure that the filter rule actually exists
if ( !grammar.isDefined(CodeGenerator.lexerRuleName(filterRule)) ) {
grammar.tool.error("Filter rule "+filterRule+" does not exist in this lexer");
}
else {
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.lexerRuleName(filterRule));
if ( !rs.isDefined() ) {
grammar.tool.error("Filter rule "+filterRule+" does not exist in this lexer");
}
else if ( rs.access.equals("public") ) {
grammar.tool.error("Filter rule "+filterRule+" must be protected");
}
}
println("int _m;");
println("_m = mark();");
}
}
println("resetText();");
println("try { // for char stream error handling");
tabs++;
// Generate try around whole thing to trap scanner errors
println("try { // for lexical error handling");
tabs++;
// Test for public lexical rules with empty paths
for (int i=0; i<nextTokenBlk.getAlternatives().size(); i++) {
Alternative a = nextTokenBlk.getAlternativeAt(i);
if ( a.cache[1].containsEpsilon() ) {
tool.warning("found optional path in nextToken()");
}
}
// Generate the block
String newline = System.getProperty("line.separator");
JavaBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false);
String errFinish = "if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}";
errFinish += newline+"\t\t\t\t";
if ( ((LexerGrammar)grammar).filterMode ) {
if ( filterRule==null ) {
errFinish += "else {consume(); continue tryAgain;}";
}
else {
errFinish += "else {"+newline+
"\t\t\t\t\tcommit();"+newline+
"\t\t\t\t\ttry {m"+filterRule+"(false);}"+newline+
"\t\t\t\t\tcatch(RecognitionException e) {"+newline+
"\t\t\t\t\t // catastrophic failure"+newline+
"\t\t\t\t\t reportError(e);"+newline+
"\t\t\t\t\t consume();"+newline+
"\t\t\t\t\t}"+newline+
"\t\t\t\t\tcontinue tryAgain;"+newline+
"\t\t\t\t}";
}
}
else {
errFinish += "else {"+throwNoViable+"}";
}
genBlockFinish(howToFinish, errFinish);
// at this point a valid token has been matched, undo "mark" that was done
if ( ((LexerGrammar)grammar).filterMode && filterRule!=null ) {
println("commit();");
}
// Generate literals test if desired
// make sure _ttype is set first; note _returnToken must be
// non-null as the rule was required to create it.
println("if ( _returnToken==null ) continue tryAgain; // found SKIP token");
println("_ttype = _returnToken.getType();");
if ( ((LexerGrammar)grammar).getTestLiterals()) {
genLiteralsTest();
}
// return token created by rule reference in switch
println("_returnToken.setType(_ttype);");
println("return _returnToken;");
// Close try block
tabs--;
println("}");
println("catch (RecognitionException e) {");
tabs++;
if ( ((LexerGrammar)grammar).filterMode ) {
if ( filterRule==null ) {
println("if ( !getCommitToPath() ) {consume(); continue tryAgain;}");
}
else {
println("if ( !getCommitToPath() ) {");
tabs++;
println("rewind(_m);");
println("resetText();");
println("try {m"+filterRule+"(false);}");
println("catch(RecognitionException ee) {");
println(" // horrendous failure: error in filter rule");
println(" reportError(ee);");
println(" consume();");
println("}");
println("continue tryAgain;");
tabs--;
println("}");
}
}
if ( nextTokenBlk.getDefaultErrorHandler() ) {
println("reportError(e);");
println("consume();");
}
else {
// pass on to invoking routine
println("throw new TokenStreamRecognitionException(e);");
}
tabs--;
println("}");
// close CharStreamException try
tabs--;
println("}");
println("catch (CharStreamException cse) {");
println(" if ( cse instanceof CharStreamIOException ) {");
println(" throw new TokenStreamIOException(((CharStreamIOException)cse).io);");
println(" }");
println(" else {");
println(" throw new TokenStreamException(cse.getMessage());");
println(" }");
println("}");
// close for-loop
tabs--;
println("}");
// close method nextToken
tabs--;
println("}");
println("");
}
/** Gen a named rule block.
* ASTs are generated for each element of an alternative unless
* the rule or the alternative have a '!' modifier.
*
* If an alternative defeats the default tree construction, it
* must set <rule>_AST to the root of the returned AST.
*
* Each alternative that does automatic tree construction, builds
* up root and child list pointers in an ASTPair structure.
*
* A rule finishes by setting the returnAST variable from the
* ASTPair.
*
* @param rule The name of the rule to generate
* @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
*/
public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum) {
tabs=1;
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRule("+ s.getId() +")");
if ( !s.isDefined() ) {
tool.error("undefined rule: "+ s.getId());
return;
}
// Generate rule return type, name, arguments
RuleBlock rblk = s.getBlock();
currentRule = rblk;
currentASTResult = s.getId();
// Save the AST generation state, and set it to that of the rule
boolean savegenAST = genAST;
genAST = genAST && rblk.getAutoGen();
// boolean oldsaveTest = saveText;
saveText = rblk.getAutoGen();
// print javadoc comment if any
if ( s.comment!=null ) {
_println(s.comment);
}
// Gen method access and final qualifier
print(s.access + " final ");
// Gen method return type (note lexer return action set at rule creation)
if (rblk.returnAction != null)
{
// Has specified return value
_print(extractTypeOfAction(rblk.returnAction, rblk.getLine()) + " ");
} else {
// No specified return value
_print("void ");
}
// Gen method name
_print(s.getId() + "(");
// Additional rule parameters common to all rules for this grammar
_print(commonExtraParams);
if (commonExtraParams.length() != 0 && rblk.argAction != null ) {
_print(",");
}
// Gen arguments
if (rblk.argAction != null)
{
// Has specified arguments
_println("");
tabs++;
println(rblk.argAction);
tabs--;
print(")");
} else {
// No specified arguments
_print(")");
}
// Gen throws clause and open curly
_print(" throws " + exceptionThrown);
if ( grammar instanceof ParserGrammar ) {
_print(", TokenStreamException");
}
else if ( grammar instanceof LexerGrammar ) {
_print(", CharStreamException, TokenStreamException");
}
// Add user-defined exceptions unless lexer (for now)
if ( rblk.throwsSpec!=null ) {
if ( grammar instanceof LexerGrammar ) {
tool.error("user-defined throws spec not allowed (yet) for lexer rule "+rblk.ruleName);
}
else {
_print(", "+rblk.throwsSpec);
}
}
_println(" {");
tabs++;
// Convert return action to variable declaration
if (rblk.returnAction != null)
println(rblk.returnAction + ";");
// print out definitions needed by rules for various grammar types
println(commonLocalVars);
if (grammar.traceRules) {
if ( grammar instanceof TreeWalkerGrammar ) {
println("traceIn(\""+ s.getId() +"\",_t);");
}
else {
println("traceIn(\""+ s.getId() +"\");");
}
}
if ( grammar instanceof LexerGrammar ) {
// lexer rule default return value is the rule's token name
// This is a horrible hack to support the built-in EOF lexer rule.
if (s.getId().equals("mEOF"))
println("_ttype = Token.EOF_TYPE;");
else
println("_ttype = "+ s.getId().substring(1)+";");
println("int _saveIndex;"); // used for element! (so we can kill text matched for element)
/*
println("boolean old_saveConsumedInput=saveConsumedInput;");
if ( !rblk.getAutoGen() ) { // turn off "save input" if ! on rule
println("saveConsumedInput=false;");
}
*/
}
// if debugging, write code to mark entry to the rule
if ( grammar.debuggingOutput)
if (grammar instanceof ParserGrammar)
println("fireEnterRule(" + ruleNum + ",0);");
else if (grammar instanceof LexerGrammar)
println("fireEnterRule(" + ruleNum + ",_ttype);");
// Generate trace code if desired
if ( grammar.debuggingOutput || grammar.traceRules) {
println("try { // debugging");
tabs++;
}
// Initialize AST variables
if (grammar instanceof TreeWalkerGrammar) {
// "Input" value for rule
println(labeledElementASTType+" " + s.getId() + "_AST_in = ("+labeledElementASTType+")_t;");
}
if (grammar.buildAST) {
// Parser member used to pass AST returns from rule invocations
println("returnAST = null;");
// Tracks AST construction
println("ASTPair currentAST = new ASTPair();");
// User-settable return value for rule.
println(labeledElementASTType+" " + s.getId() + "_AST = null;");
}
genBlockPreamble(rblk);
println("");
// Search for an unlabeled exception specification attached to the rule
ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
// Generate try block around the entire rule for error handling
if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
println("try { // for error handling");
tabs++;
}
// Generate the alternatives
if ( rblk.alternatives.size()==1 ) {
// One alternative -- use simple form
Alternative alt = rblk.getAlternativeAt(0);
String pred = alt.semPred;
if ( pred!=null )
genSemPred(pred, currentRule.line);
if (alt.synPred != null) {
tool.warning(
"Syntactic predicate ignored for single alternative",
grammar.getFilename(), alt.synPred.getLine()
);
}
genAlt(alt, rblk);
}
else {
// Multiple alternatives -- generate complex form
boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
JavaBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
genBlockFinish(howToFinish, throwNoViable);
}
// Generate catch phrase for error handling
if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
// Close the try block
tabs--;
println("}");
}
// Generate user-defined or default catch phrases
if (unlabeledUserSpec != null) {
genErrorHandler(unlabeledUserSpec);
}
else if (rblk.getDefaultErrorHandler()) {
// Generate default catch phrase
println("catch (" + exceptionThrown + " ex) {");
tabs++;
// Generate code to handle error if not guessing
if (grammar.hasSyntacticPredicate) {
println("if (inputState.guessing==0) {");
tabs++;
}
println("reportError(ex);");
if ( !(grammar instanceof TreeWalkerGrammar) ) {
// Generate code to consume until token in k==1 follow set
Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
String followSetName = getBitsetName(markBitsetForGen(follow.fset));
println("consume();");
println("consumeUntil(" + followSetName + ");");
} else {
// Just consume one token
println("if (_t!=null) {_t = _t.getNextSibling();}");
}
if (grammar.hasSyntacticPredicate) {
tabs--;
// When guessing, rethrow exception
println("} else {");
println(" throw ex;");
println("}");
}
// Close catch phrase
tabs--;
println("}");
}
// Squirrel away the AST "return" value
if (grammar.buildAST) {
println("returnAST = " + s.getId() + "_AST;");
}
// Set return tree value for tree walkers
if ( grammar instanceof TreeWalkerGrammar ) {
println("_retTree = _t;");
}
// Generate literals test for lexer rules so marked
if (rblk.getTestLiterals()) {
if ( s.access.equals("protected") ) {
genLiteralsTestForPartialToken();
}
else {
genLiteralsTest();
}
}
// if doing a lexer rule, dump code to create token if necessary
if ( grammar instanceof LexerGrammar ) {
println("if ( _createToken && _token==null && _ttype!=Token.SKIP ) {");
println(" _token = makeToken(_ttype);");
println(" _token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));");
println("}");
println("_returnToken = _token;");
}
// Gen the return statement if there is one (lexer has hard-wired return action)
if (rblk.returnAction != null) {
println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine()) + ";");
}
if ( grammar.debuggingOutput || grammar.traceRules) {
tabs--;
println("} finally { // debugging");
tabs++;
// If debugging, generate calls to mark exit of rule
if ( grammar.debuggingOutput)
if (grammar instanceof ParserGrammar)
println("fireExitRule(" + ruleNum + ",0);");
else if (grammar instanceof LexerGrammar)
println("fireExitRule(" + ruleNum + ",_ttype);");
if (grammar.traceRules) {
if ( grammar instanceof TreeWalkerGrammar ) {
println("traceOut(\""+ s.getId() +"\",_t);");
}
else {
println("traceOut(\""+ s.getId() +"\");");
}
}
tabs--;
println("}");
}
tabs--;
println("}");
println("");
// Restore the AST generation state
genAST = savegenAST;
// restore char save state
// saveText = oldsaveTest;
}
private void GenRuleInvocation(RuleRefElement rr) {
// dump rule name
_print(rr.targetRule + "(");
// lexers must tell rule if it should set _returnToken
if ( grammar instanceof LexerGrammar ) {
// if labeled, could access Token, so tell rule to create
if ( rr.getLabel() != null ) {
_print("true");
}
else {
_print("false");
}
if (commonExtraArgs.length() != 0 || rr.args!=null ) {
_print(",");
}
}
// Extra arguments common to all rules for this grammar
_print(commonExtraArgs);
if (commonExtraArgs.length() != 0 && rr.args!=null ) {
_print(",");
}
// Process arguments to method, if any
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rr.args != null)
{
// When not guessing, execute user arg action
ActionTransInfo tInfo = new ActionTransInfo();
String args = processActionForTreeSpecifiers(rr.args, 0, currentRule, tInfo);
if ( tInfo.assignToRoot || tInfo.refRuleRoot!=null ) {
tool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #"+
currentRule.getRuleName()+" on line "+rr.getLine());
}
_print(args);
// Warn if the rule accepts no arguments
if (rs.block.argAction == null) {
tool.warning("Rule '" + rr.targetRule + "' accepts no arguments", grammar.getFilename(), rr.getLine());
}
} else {
// For C++, no warning if rule has parameters, because there may be default
// values for all of the parameters
if (rs.block.argAction != null) {
tool.warning("Missing parameters on reference to rule "+rr.targetRule, grammar.getFilename(), rr.getLine());
}
}
_println(");");
// move down to the first child while parsing
if ( grammar instanceof TreeWalkerGrammar ) {
println("_t = _retTree;");
}
}
protected void genSemPred(String pred, int line) {
// translate $ and # references
ActionTransInfo tInfo = new ActionTransInfo();
pred = processActionForTreeSpecifiers(pred, line, currentRule, tInfo);
// ignore translation info...we don't need to do anything with it.
String escapedPred = charFormatter.escapeString(pred);
// if debugging, wrap the semantic predicate evaluation in a method
// that can tell SemanticPredicateListeners the result
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)))
pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING,"
+ addSemPred(escapedPred) + "," + pred + ")";
println("if (!(" + pred + "))");
println(" throw new SemanticException(\"" + escapedPred + "\");");
}
/** Write an array of Strings which are the semantic predicate
* expressions. The debugger will reference them by number only
*/
protected void genSemPredMap() {
Enumeration e = semPreds.elements();
println("private String _semPredNames[] = {");
while(e.hasMoreElements())
println("\""+e.nextElement()+"\",");
println("};");
}
protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen=>("+blk+")");
// Dump synpred result variable
println("boolean synPredMatched" + blk.ID + " = false;");
// Gen normal lookahead test
println("if (" + lookaheadExpr + ") {");
tabs++;
// Save input state
if ( grammar instanceof TreeWalkerGrammar ) {
println("AST __t" + blk.ID + " = _t;");
}
else {
println("int _m" + blk.ID + " = mark();");
}
// Once inside the try, assume synpred works unless exception caught
println("synPredMatched" + blk.ID + " = true;");
println("inputState.guessing++;");
// if debugging, tell listeners that a synpred has started
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar))) {
println("fireSyntacticPredicateStarted();");
}
syntacticPredLevel++;
println("try {");
tabs++;
gen((AlternativeBlock)blk); // gen code to test predicate
tabs--;
//println("System.out.println(\"pred "+blk+" succeeded\");");
println("}");
println("catch (" + exceptionThrown + " pe) {");
tabs++;
println("synPredMatched"+blk.ID+" = false;");
//println("System.out.println(\"pred "+blk+" failed\");");
tabs--;
println("}");
// Restore input state
if ( grammar instanceof TreeWalkerGrammar ) {
println("_t = __t"+blk.ID+";");
}
else {
println("rewind(_m"+blk.ID+");");
}
println("inputState.guessing--;");
// if debugging, tell listeners how the synpred turned out
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar))) {
println("if (synPredMatched" + blk.ID +")");
println(" fireSyntacticPredicateSucceeded();");
println("else");
println(" fireSyntacticPredicateFailed();");
}
syntacticPredLevel--;
tabs--;
// Close lookahead test
println("}");
// Test synred result
println("if ( synPredMatched"+blk.ID+" ) {");
}
/** Generate a static array containing the names of the tokens,
* indexed by the token type values. This static array is used
* to format error messages so that the token identifers or literal
* strings are displayed instead of the token numbers.
*
* If a lexical rule has a paraphrase, use it rather than the
* token label.
*/
public void genTokenStrings() {
// Generate a string for each token. This creates a static
// array of Strings indexed by token type.
println("");
println("public static final String[] _tokenNames = {");
tabs++;
// Walk the token vocabulary and generate a Vector of strings
// from the tokens.
Vector v = grammar.tokenManager.getVocabulary();
for (int i = 0; i < v.size(); i++)
{
String s = (String)v.elementAt(i);
if (s == null)
{
s = "<"+String.valueOf(i)+">";
}
if ( !s.startsWith("\"") && !s.startsWith("<") ) {
TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s);
if ( ts!=null && ts.getParaphrase()!=null ) {
s = antlr.Tool.stripFrontBack(ts.getParaphrase(), "\"", "\"");
}
}
print(charFormatter.literalString(s));
if (i != v.size()-1) {
_print(",");
}
_println("");
}
// Close the string array initailizer
tabs--;
println("};");
}
/** Generate the token types Java file */
protected void genTokenTypes(TokenManager tm) throws IOException {
// Open the token output Java file and set the currentOutput stream
// SAS: file open was moved to a method so a subclass can override
// This was mainly for the VAJ interface
setupOutput(tm.getName() + TokenTypesFileSuffix);
tabs = 0;
// Generate the header common to all Java files
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Encapsulate the definitions in an interface. This can be done
// because they are all constants.
println("public interface " + tm.getName() + TokenTypesFileSuffix+" {");
tabs++;
// Generate a definition for each token type
Vector v = tm.getVocabulary();
// Do special tokens manually
println("int EOF = " + Token.EOF_TYPE + ";");
println("int NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD + ";");
for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if (s != null) {
if ( s.startsWith("\"") ) {
// a string literal
StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
if ( sl==null ) {
antlr.Tool.panic("String literal "+s+" not in symbol table");
}
else if ( sl.label != null ) {
println("int " + sl.label + " = " + i + ";");
}
else {
String mangledName = mangleLiteral(s);
if (mangledName != null) {
// We were able to create a meaningful mangled token name
println("int " + mangledName + " = " + i + ";");
// if no label specified, make the label equal to the mangled name
sl.label = mangledName;
}
else {
println("// " + s + " = " + i);
}
}
}
else if ( !s.startsWith("<") ) {
println("int " + s + " = " + i + ";");
}
}
}
// Close the interface
tabs--;
println("}");
// Close the tokens output file
currentOutput.close();
currentOutput = null;
exitIfError();
}
/** Get a string for an expression to generate creation of an AST subtree.
* @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
*/
public String getASTCreateString(Vector v) {
if (v.size() == 0) {
return "";
}
StringBuffer buf = new StringBuffer();
buf.append("("+labeledElementASTType+
")astFactory.make( (new ASTArray(" + v.size() +
"))");
for (int i = 0; i < v.size(); i++) {
buf.append(".add(" + v.elementAt(i) + ")");
}
buf.append(")");
return buf.toString();
}
/** Get a string for an expression to generate creating of an AST node
* @param atom The grammar node for which you are creating the node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(GrammarAtom atom, String str) {
// System.out.println("ASTNodeType for "+atom+" is "+atom.getASTNodeType());
if ( atom!=null && atom.getASTNodeType() != null ) {
return "new "+atom.getASTNodeType()+"("+str+")";
}
else {
return "("+labeledElementASTType+")astFactory.create(" + str + ")";
}
}
/** Get a string for an expression to generate creating of an AST node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(String str) {
// System.out.println("ASTNodeType for "+atom+" is "+atom.getASTNodeType());
return "("+labeledElementASTType+")astFactory.create(" + str + ")";
}
protected String getLookaheadTestExpression(Lookahead[] look, int k) {
StringBuffer e = new StringBuffer(100);
boolean first = true;
e.append("(");
for (int i = 1; i <= k; i++) {
BitSet p = look[i].fset;
if (!first) {
e.append(") && (");
}
first = false;
// Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
// There is no way to predict what that token would be. Just
// allow anything instead.
if (look[i].containsEpsilon()) {
e.append("true");
} else {
e.append(getLookaheadTestTerm(i, p));
}
}
e.append(")");
return e.toString();
}
/**Generate a lookahead test expression for an alternate. This
* will be a series of tests joined by '&&' and enclosed by '()',
* the number of such tests being determined by the depth of the lookahead.
*/
protected String getLookaheadTestExpression(Alternative alt, int maxDepth) {
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
// if the decision is nondeterministic, do the best we can: LL(k)
// any predicates that are around will be generated later.
depth = grammar.maxk;
}
if ( maxDepth==0 ) {
// empty lookahead can result from alt with sem pred
// that can see end of token. E.g., A : {pred}? ('a')? ;
return "true";
}
/*
boolean first = true;
for (int i=1; i<=depth && i<=maxDepth; i++) {
BitSet p = alt.cache[i].fset;
if (!first) {
e.append(") && (");
}
first = false;
// Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
// There is no way to predict what that token would be. Just
// allow anything instead.
if ( alt.cache[i].containsEpsilon() ) {
e.append("true");
}
else {
e.append(getLookaheadTestTerm(i, p));
}
}
e.append(")");
*/
return "(" + getLookaheadTestExpression(alt.cache,depth) + ")";
}
/**Generate a depth==1 lookahead test expression given the BitSet.
* This may be one of:
* 1) a series of 'x==X||' tests
* 2) a range test using >= && <= where possible,
* 3) a bitset membership test for complex comparisons
* @param k The lookahead level
* @param p The lookahead set for level k
*/
protected String getLookaheadTestTerm(int k, BitSet p) {
// Determine the name of the item to be compared
String ts = lookaheadString(k);
// Generate a range expression if possible
int[] elems = p.toArray();
if (elementsAreRange(elems)) {
return getRangeExpression(k, elems);
}
// Generate a bitset membership test if possible
StringBuffer e;
int degree = p.degree();
if ( degree == 0 ) {
return "true";
}
if (degree >= bitsetTestThreshold) {
int bitsetIdx = markBitsetForGen(p);
return getBitsetName(bitsetIdx) + ".member(" + ts + ")";
}
// Otherwise, generate the long-winded series of "x==X||" tests
e = new StringBuffer();
for (int i = 0; i < elems.length; i++) {
// Get the compared-to item (token or character value)
String cs = getValueString(elems[i]);
// Generate the element comparison
if ( i>0 ) e.append("||");
e.append(ts);
e.append("==");
e.append(cs);
}
return e.toString();
}
/** Return an expression for testing a contiguous renage of elements
* @param k The lookahead level
* @param elems The elements representing the set, usually from BitSet.toArray().
* @return String containing test expression.
*/
public String getRangeExpression(int k, int[] elems) {
if (!elementsAreRange(elems)) {
tool.panic("getRangeExpression called with non-range");
}
int begin = elems[0];
int end = elems[elems.length-1];
return
"(" + lookaheadString(k) + " >= " + getValueString(begin) + " && " +
lookaheadString(k) + " <= " + getValueString(end) + ")";
}
/** getValueString: get a string representation of a token or char value
* @param value The token or char value
*/
private String getValueString(int value) {
String cs;
if ( grammar instanceof LexerGrammar ) {
cs = charFormatter.literalChar(value);
}
else {
TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value);
if ( ts == null ) {
return ""+value; // return token type as string
// tool.panic("vocabulary for token type " + value + " is null");
}
String tId = ts.getId();
if ( ts instanceof StringLiteralSymbol ) {
// if string literal, use predefined label if any
// if no predefined, try to mangle into LITERAL_xxx.
// if can't mangle, use int value as last resort
StringLiteralSymbol sl = (StringLiteralSymbol)ts;
String label = sl.getLabel();
if ( label!=null ) {
cs = label;
}
else {
cs = mangleLiteral(tId);
if (cs == null) {
cs = String.valueOf(value);
}
}
}
else {
cs = tId;
}
}
return cs;
}
/**Is the lookahead for this alt empty? */
protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
depth = grammar.maxk;
}
for (int i=1; i<=depth && i<=maxDepth; i++) {
BitSet p = alt.cache[i].fset;
if (p.degree() != 0) {
return false;
}
}
return true;
}
private String lookaheadString(int k) {
if (grammar instanceof TreeWalkerGrammar) {
return "_t.getType()";
}
return "LA(" + k + ")";
}
/** Mangle a string literal into a meaningful token name. This is
* only possible for literals that are all characters. The resulting
* mangled literal name is literalsPrefix with the text of the literal
* appended.
* @return A string representing the mangled literal, or null if not possible.
*/
private String mangleLiteral(String s) {
String mangled = antlr.Tool.literalsPrefix;
for (int i = 1; i < s.length()-1; i++) {
if (!Character.isLetter(s.charAt(i)) &&
s.charAt(i) != '_') {
return null;
}
mangled += s.charAt(i);
}
if ( antlr.Tool.upperCaseMangledLiterals ) {
mangled = mangled.toUpperCase();
}
return mangled;
}
/** Map an identifier to it's corresponding tree-node variable.
* This is context-sensitive, depending on the rule and alternative
* being generated
* @param idParam The identifier name to map
* @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
*/
public String mapTreeId(String idParam, ActionTransInfo transInfo) {
// if not in an action of a rule, nothing to map.
if ( currentRule==null ) return idParam;
boolean in_var = false;
String id = idParam;
if (grammar instanceof TreeWalkerGrammar) {
if ( !grammar.buildAST ) {
in_var = true;
}
// If the id ends with "_in", then map it to the input variable
else if (id.length() > 3 && id.lastIndexOf("_in") == id.length()-3) {
// Strip off the "_in"
id = id.substring(0, id.length()-3);
in_var = true;
}
}
// Check the rule labels. If id is a label, then the output
// variable is label_AST, and the input variable is plain label.
for (int i = 0; i < currentRule.labeledElements.size(); i++) {
AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i);
if (elt.getLabel().equals(id)) {
return in_var ? id : id + "_AST";
}
}
// Failing that, check the id-to-variable map for the alternative.
// If the id is in the map, then output variable is the name in the
// map, and input variable is name_in
String s = (String)treeVariableMap.get(id);
if (s != null) {
if (s == NONUNIQUE) {
// There is more than one element with this id
return null;
} else if (s.equals(currentRule.getRuleName())) {
// a recursive call to the enclosing rule is
// ambiguous with the rule itself.
return null;
} else {
return in_var ? s + "_in" : s;
}
}
// Failing that, check the rule name itself. Output variable
// is rule_AST; input variable is rule_AST_in (treeparsers).
if (id.equals(currentRule.getRuleName())) {
String r = in_var ? id + "_AST_in" : id + "_AST";
if ( transInfo!=null ) {
if ( !in_var ) {
transInfo.refRuleRoot = r;
}
}
return r;
} else {
// id does not map to anything -- return itself.
return id;
}
}
/** Given an element and the name of an associated AST variable,
* create a mapping between the element "name" and the variable name.
*/
private void mapTreeVariable(AlternativeElement e, String name)
{
// For tree elements, defer to the root
if (e instanceof TreeElement) {
mapTreeVariable( ((TreeElement)e).root, name);
return;
}
// Determine the name of the element, if any, for mapping purposes
String elName = null;
// Don't map labeled items
if (e.getLabel() == null) {
if (e instanceof TokenRefElement) {
// use the token id
elName = ((TokenRefElement)e).atomText;
}
else if (e instanceof RuleRefElement) {
// use the rule name
elName = ((RuleRefElement)e).targetRule;
}
}
// Add the element to the tree variable map if it has a name
if (elName != null) {
if (treeVariableMap.get(elName) != null) {
// Name is already in the map -- mark it as duplicate
treeVariableMap.remove(elName);
treeVariableMap.put(elName, NONUNIQUE);
}
else {
treeVariableMap.put(elName, name);
}
}
}
private void setupGrammarParameters(Grammar g) {
if (g instanceof ParserGrammar) {
labeledElementASTType = "AST";
if ( g.hasOption("ASTLabelType") ) {
Token tsuffix = g.getOption("ASTLabelType");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
labeledElementASTType = suffix;
}
}
}
labeledElementType = "Token ";
labeledElementInit = "null";
commonExtraArgs = "";
commonExtraParams = "";
commonLocalVars = "";
lt1Value = "LT(1)";
exceptionThrown = "RecognitionException";
throwNoViable = "throw new NoViableAltException(LT(1), getFilename());";
}
else if (g instanceof LexerGrammar) {
labeledElementType = "char ";
labeledElementInit = "'\\0'";
commonExtraArgs = "";
commonExtraParams = "boolean _createToken";
commonLocalVars = "int _ttype; Token _token=null; int _begin=text.length();";
lt1Value = "LA(1)";
exceptionThrown = "RecognitionException";
throwNoViable = "throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());";
}
else if (g instanceof TreeWalkerGrammar) {
labeledElementASTType = "AST";
labeledElementType = "AST";
if ( g.hasOption("ASTLabelType") ) {
Token tsuffix = g.getOption("ASTLabelType");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
labeledElementASTType = suffix;
labeledElementType = suffix;
}
}
}
if ( !g.hasOption("ASTLabelType") ) {
g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL,"AST"));
}
labeledElementInit = "null";
commonExtraArgs = "_t";
commonExtraParams = "AST _t";
commonLocalVars = "";
lt1Value = "("+labeledElementASTType+")_t";
exceptionThrown = "RecognitionException";
throwNoViable = "throw new NoViableAltException(_t);";
}
else {
tool.panic("Unknown grammar type");
}
}
/** This method exists so a subclass, namely VAJCodeGenerator,
* can open the file in its own evil way. JavaCodeGenerator
* simply opens a text file...
*/
public void setupOutput(String className) throws IOException {
currentOutput = antlr.Tool.openOutputFile(className + ".java");
}
}
1.1 e/src/jsrc/antlr/LLkAnalyzer.java
Index: LLkAnalyzer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: LLkAnalyzer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
/**A linear-approximate LL(k) grammar analzyer.
*
* All lookahead elements are sets of token types.
*
* @author Terence Parr, John Lilley
* @see antlr.Grammar
* @see antlr.Lookahead
*/
public class LLkAnalyzer implements LLkGrammarAnalyzer {
// Set "analyzerDebug" to true
public boolean DEBUG_ANALYZER = false;
private AlternativeBlock currentBlock;
protected Tool tool = null;
protected Grammar grammar = null;
// True if analyzing a lexical grammar
protected boolean lexicalAnalysis = false;
// Used for formatting bit sets in default (Java) format
CharFormatter charFormatter = new JavaCharFormatter();
/** Create an LLk analyzer */
public LLkAnalyzer(Tool tool_) {
tool = tool_;
}
/** Return true if someone used the '.' wildcard default idiom.
* Either #(. children) or '.' as an alt by itself.
*/
protected boolean altUsesWildcardDefault(Alternative alt) {
AlternativeElement head = alt.head;
// if element is #(. blah) then check to see if el is root
if (head instanceof TreeElement &&
((TreeElement) head).root instanceof WildcardElement ) {
return true;
}
if (head instanceof WildcardElement && head. next instanceof BlockEndElement) {
return true;
}
return false;
}
/**Is this block of alternatives LL(k)? Fill in alternative cache for this block.
* @return true if the block is deterministic
*/
public boolean deterministic(AlternativeBlock blk) {
/** The lookahead depth for this decision */
int k=1; // start at k=1
if ( DEBUG_ANALYZER ) System.out.println("deterministic("+blk+")");
boolean det = true;
int nalts = blk.alternatives.size();
AlternativeBlock saveCurrentBlock = currentBlock;
Alternative wildcardAlt = null;
currentBlock = blk;
/* don't allow nongreedy (...) blocks */
if ( blk.greedy==false && !(blk instanceof OneOrMoreBlock) && !(blk instanceof ZeroOrMoreBlock) ) {
tool.warning("Being nongreedy only makes sense for (...)+ and (...)*", grammar.getFilename(), blk.getLine());
}
// SPECIAL CASE: only one alternative. We don't need to check the
// determinism, but other code expects the lookahead cache to be
// set for the single alt.
if ( nalts==1 ) {
AlternativeElement e = blk.getAlternativeAt(0).head;
currentBlock.alti = 0;
blk.getAlternativeAt(0).cache[1] = e.look(1);
blk.getAlternativeAt(0).lookaheadDepth = 1; // set lookahead to LL(1)
currentBlock = saveCurrentBlock;
return true; // always deterministic for one alt
}
outer:
for (int i=0; i<nalts-1; i++) {
currentBlock.alti = i;
currentBlock.analysisAlt = i; // which alt are we analyzing?
currentBlock.altj = i+1; // reset this alt. Haven't computed yet,
// but we need the alt number.
inner:
// compare against other alternatives with lookahead depth k
for (int j=i+1; j<nalts; j++) {
currentBlock.altj = j;
if ( DEBUG_ANALYZER ) System.out.println("comparing "+i+" against alt "+j);
currentBlock.analysisAlt = j; // which alt are we analyzing?
k = 1; // always attempt minimum lookahead possible.
// check to see if there is a lookahead depth that distinguishes
// between alternatives i and j.
Lookahead[] r = new Lookahead[grammar.maxk+1];
boolean haveAmbiguity;
do {
haveAmbiguity = false;
if ( DEBUG_ANALYZER ) System.out.println("checking depth "+k+"<="+grammar.maxk);
Lookahead p,q;
p = getAltLookahead(blk, i, k);
q = getAltLookahead(blk, j, k);
// compare LOOK(alt i) with LOOK(alt j). Is there an intersection?
// Lookahead must be disjoint.
if ( DEBUG_ANALYZER ) System.out.println("p is "+p.toString(",", charFormatter, grammar));
if ( DEBUG_ANALYZER ) System.out.println("q is "+q.toString(",", charFormatter, grammar));
// r[i] = p.fset.and(q.fset);
r[k] = p.intersection(q);
if ( DEBUG_ANALYZER ) System.out.println("intersection at depth "+k+" is "+r[k].toString());
if ( !r[k].nil() ) {
haveAmbiguity = true;
k++;
}
// go until no more lookahead to use or no intersection
} while ( haveAmbiguity && k <= grammar.maxk );
Alternative ai = blk.getAlternativeAt(i);
Alternative aj = blk.getAlternativeAt(j);
if ( haveAmbiguity ) {
det = false;
ai.lookaheadDepth = NONDETERMINISTIC;
aj.lookaheadDepth = NONDETERMINISTIC;
/* if ith alt starts with a syntactic predicate, computing the
* lookahead is still done for code generation, but messages
* should not be generated when comparing against alt j.
* Alternatives with syn preds that are unnecessary do
* not result in syn pred try-blocks.
*/
if ( ai.synPred != null ) {
if ( DEBUG_ANALYZER ) {
System.out.println("alt "+i+" has a syn pred");
}
// The alt with the (...)=> block is nondeterministic for sure.
// If the (...)=> conflicts with alt j, j is nondeterministic.
// This prevents alt j from being in any switch statements.
// move on to next alternative=>no possible ambiguity!
// continue inner;
}
/* if ith alt starts with a semantic predicate, computing the
* lookahead is still done for code generation, but messages
* should not be generated when comparing against alt j.
*/
else if ( ai.semPred != null ) {
if ( DEBUG_ANALYZER ) {
System.out.println("alt "+i+" has a sem pred");
}
}
/* if jth alt is exactly the wildcard or wildcard root of tree,
* then remove elements from alt i lookahead from alt j's lookahead.
* Don't do an ambiguity warning.
*/
else if ( altUsesWildcardDefault(aj) ) {
// System.out.println("removing pred sets");
// removeCompetingPredictionSetsFromWildcard(aj.cache, aj.head, grammar.maxk);
wildcardAlt = aj;
}
/* If the user specified warnWhenFollowAmbig=false, then we
* can turn off this warning IFF one of the alts is empty;
* that is, it points immediately at the end block.
*/
else if ( !blk.warnWhenFollowAmbig &&
(ai.head instanceof BlockEndElement ||
aj.head instanceof BlockEndElement) )
{
// System.out.println("ai.head pts to "+ai.head.getClass());
// System.out.println("aj.head pts to "+aj.head.getClass());
}
/* If they have the generateAmbigWarnings option off for the block
* then don't generate a warning.
*/
else if ( !blk.generateAmbigWarnings ) {
}
/* If greedy=true and *one* empty alt shut off warning. */
else if ( blk.greedySet && blk.greedy &&
((ai.head instanceof BlockEndElement &&
!(aj.head instanceof BlockEndElement)) ||
(aj.head instanceof BlockEndElement &&
!(ai.head instanceof BlockEndElement))) ) {
// System.out.println("greedy set to true; one alt empty");
}
/* We have no choice, but to report a nondetermism */
else {
tool.errorHandler.warnAltAmbiguity(
grammar,
blk, // the block
lexicalAnalysis,// true if lexical
grammar.maxk, // depth of ambiguity
r, // set of linear ambiguities
i, // first ambiguous alternative
j // second ambiguous alternative
);
}
}
else {
// a lookahead depth, k, was found where i and j do not conflict
ai.lookaheadDepth = Math.max(ai.lookaheadDepth,k);
aj.lookaheadDepth = Math.max(aj.lookaheadDepth,k);
}
}
}
// finished with block.
// If had wildcard default clause idiom, remove competing lookahead
/*
if ( wildcardAlt!=null ) {
removeCompetingPredictionSetsFromWildcard(wildcardAlt.cache, wildcardAlt.head, grammar.maxk);
}
*/
currentBlock = saveCurrentBlock;
return det;
}
/**Is (...)+ block LL(1)? Fill in alternative cache for this block.
* @return true if the block is deterministic
*/
public boolean deterministic(OneOrMoreBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("deterministic(...)+("+blk+")");
AlternativeBlock saveCurrentBlock = currentBlock;
currentBlock = blk;
boolean blkOk = deterministic((AlternativeBlock)blk);
// block has been checked, now check that what follows does not conflict
// with the lookahead of the (...)+ block.
boolean det = deterministicImpliedPath(blk);
currentBlock = saveCurrentBlock;
return det&&blkOk;
}
/**Is (...)* block LL(1)? Fill in alternative cache for this block.
* @return true if the block is deterministic
*/
public boolean deterministic(ZeroOrMoreBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("deterministic(...)*("+blk+")");
AlternativeBlock saveCurrentBlock = currentBlock;
currentBlock = blk;
boolean blkOk = deterministic((AlternativeBlock)blk);
// block has been checked, now check that what follows does not conflict
// with the lookahead of the (...)* block.
boolean det = deterministicImpliedPath(blk);
currentBlock = saveCurrentBlock;
return det&&blkOk;
}
/**Is this (...)* or (...)+ block LL(k)?
* @return true if the block is deterministic
*/
public boolean deterministicImpliedPath(BlockWithImpliedExitPath blk) {
/** The lookahead depth for this decision considering implied exit path */
int k;
boolean det = true;
Vector alts = blk.getAlternatives();
int nalts = alts.size();
currentBlock.altj = -1; // comparing against implicit optional/exit alt
if ( DEBUG_ANALYZER ) System.out.println("deterministicImpliedPath");
for (int i=0; i<nalts; i++) { // check follow against all alts
Alternative alt = blk.getAlternativeAt(i);
if ( alt.head instanceof BlockEndElement ) {
tool.warning("empty alternative makes no sense in (...)* or (...)+", grammar.getFilename(), blk.getLine());
}
k = 1; // assume eac alt is LL(1) with exit branch
// check to see if there is a lookahead depth that distinguishes
// between alternative i and the exit branch.
Lookahead[] r = new Lookahead[grammar.maxk+1];
boolean haveAmbiguity;
do {
haveAmbiguity = false;
if ( DEBUG_ANALYZER ) System.out.println("checking depth "+k+"<="+grammar.maxk);
Lookahead p;
Lookahead follow = blk.next.look(k);
blk.exitCache[k] = follow;
currentBlock.alti = i;
p = getAltLookahead(blk, i, k);
if ( DEBUG_ANALYZER ) System.out.println("follow is "+follow.toString(",", charFormatter, grammar));
if ( DEBUG_ANALYZER ) System.out.println("p is "+p.toString(",", charFormatter, grammar));
//r[k] = follow.fset.and(p.fset);
r[k] = follow.intersection(p);
if ( DEBUG_ANALYZER ) System.out.println("intersection at depth "+k+" is "+r[k]);
if ( !r[k].nil() ) {
haveAmbiguity = true;
k++;
}
// go until no more lookahead to use or no intersection
} while ( haveAmbiguity && k <= grammar.maxk );
if ( haveAmbiguity )
{
det = false;
alt.lookaheadDepth = NONDETERMINISTIC;
blk.exitLookaheadDepth = NONDETERMINISTIC;
Alternative ambigAlt = blk.getAlternativeAt(currentBlock.alti);
/* If the user specified warnWhenFollowAmbig=false, then we
* can turn off this warning.
*/
if ( !blk.warnWhenFollowAmbig ) {
}
/* If they have the generateAmbigWarnings option off for the block
* then don't generate a warning.
*/
else if ( !blk.generateAmbigWarnings ) {
}
/* If greedy=true and alt not empty, shut off warning */
else if ( blk.greedy==true && blk.greedySet &&
!(ambigAlt.head instanceof BlockEndElement) ) {
if ( DEBUG_ANALYZER ) System.out.println("greedy loop");
}
/* If greedy=false then shut off warning...will have
* to add "if FOLLOW break"
* block during code gen to compensate for removal of warning.
*/
else if( blk.greedy==false &&
!(ambigAlt.head instanceof BlockEndElement) ) {
if ( DEBUG_ANALYZER ) System.out.println("nongreedy loop");
// if FOLLOW not single k-string (|set[k]| can
// be > 1 actually) then must warn them that
// loop may terminate incorrectly.
// For example, ('a'..'d')+ ("ad"|"cb")
if ( !lookaheadEquivForApproxAndFullAnalysis(blk.exitCache, grammar.maxk) ) {
tool.warning(new String[] {
"nongreedy block may exit incorrectly due",
"\tto limitations of linear approximate lookahead (first k-1 sets",
"\tin lookahead not singleton)."},
grammar.getFilename(), blk.getLine());
}
}
// no choice but to generate a warning
else {
tool.errorHandler.warnAltExitAmbiguity(
grammar,
blk, // the block
lexicalAnalysis, // true if lexical
grammar.maxk, // depth of ambiguity
r, // set of linear ambiguities
i // ambiguous alternative
);
}
}
else {
alt.lookaheadDepth = Math.max(alt.lookaheadDepth,k);
blk.exitLookaheadDepth = Math.max(blk.exitLookaheadDepth,k);
}
}
return det;
}
/**Compute the lookahead set of whatever follows references to
* the rule associated witht the FOLLOW block.
*/
public Lookahead FOLLOW(int k, RuleEndElement end) {
// what rule are we trying to compute FOLLOW of?
RuleBlock rb = (RuleBlock)end.block;
// rule name is different in lexer
String rule;
if (lexicalAnalysis) {
rule = CodeGenerator.lexerRuleName(rb.getRuleName());
} else {
rule = rb.getRuleName();
}
if ( DEBUG_ANALYZER ) System.out.println("FOLLOW("+k+","+rule+")");
// are we in the midst of computing this FOLLOW already?
if ( end.lock[k] ) {
if ( DEBUG_ANALYZER ) System.out.println("FOLLOW cycle to "+rule);
return new Lookahead(rule);
}
// Check to see if there is cached value
if ( end.cache[k]!=null ) {
if ( DEBUG_ANALYZER ) {
System.out.println("cache entry FOLLOW("+k+") for "+rule+": "+end.cache[k].toString(",", charFormatter, grammar));
}
// if the cache is a complete computation then simply return entry
if ( end.cache[k].cycle==null ) {
return (Lookahead)end.cache[k].clone();
}
// A cache entry exists, but it is a reference to a cyclic computation.
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(end.cache[k].cycle);
RuleEndElement re = rs.getBlock().endNode;
// The other entry may not exist because it is still being
// computed when this cycle cache entry was found here.
if ( re.cache[k]==null ) {
// return the cycle...that's all we can do at the moment.
return (Lookahead)end.cache[k].clone();
}
else {
// replace this cache entry with the entry from the referenced computation.
// Eventually, this percolates a complete (no cycle reference) cache entry
// to this node (or at least gets it closer and closer). This is not
// crucial, but makes cache lookup faster as we might have to look up
// lots of cycle references before finding a complete reference.
end.cache[k] = re.cache[k];
// Return the cache entry associated with the cycle reference.
return (Lookahead)re.cache[k].clone();
}
}
end.lock[k] = true; // prevent FOLLOW computation cycles
Lookahead p = new Lookahead();
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rule);
// Walk list of references to this rule to compute FOLLOW
for (int i=0; i<rs.numReferences(); i++) {
RuleRefElement rr = rs.getReference(i);
if ( DEBUG_ANALYZER ) System.out.println("next["+rule+"] is "+rr.next.toString());
Lookahead q = rr.next.look(k);
if ( DEBUG_ANALYZER ) System.out.println("FIRST of next["+rule+"] ptr is "+q.toString());
/* If there is a cycle then if the cycle is to the rule for
* this end block, you have a cycle to yourself. Remove the
* cycle indication--the lookahead is complete.
*/
if ( q.cycle!=null && q.cycle.equals(rule) ) {
q.cycle = null; // don't want cycle to yourself!
}
// add the lookahead into the current FOLLOW computation set
p.combineWith(q);
if ( DEBUG_ANALYZER ) System.out.println("combined FOLLOW["+rule+"] is "+p.toString());
}
end.lock[k] = false; // we're not doing FOLLOW anymore
// if no rules follow this, it can be a start symbol or called by a start sym.
// set the follow to be end of file.
if ( p.fset.nil() && p.cycle==null ) {
if ( grammar instanceof TreeWalkerGrammar ) {
// Tree grammars don't see EOF, they see end of sibling list or
// "NULL TREE LOOKAHEAD".
p.fset.add(Token.NULL_TREE_LOOKAHEAD);
}
else if ( grammar instanceof LexerGrammar ) {
// Lexical grammars use Epsilon to indicate that the end of rule has been hit
// EOF would be misleading; any character can follow a token rule not just EOF
// as in a grammar (where a start symbol is followed by EOF). There is no
// sequence info in a lexer between tokens to indicate what is the last token
// to be seen.
// p.fset.add(EPSILON_TYPE);
p.setEpsilon();
}
else {
p.fset.add(Token.EOF_TYPE);
}
}
// Cache the result of the FOLLOW computation
if ( DEBUG_ANALYZER ) {
System.out.println("saving FOLLOW("+k+") for "+rule+": "+p.toString(",", charFormatter, grammar));
}
end.cache[k] = (Lookahead)p.clone();
return p;
}
private Lookahead getAltLookahead(AlternativeBlock blk, int alt, int k) {
Lookahead p;
Alternative a = blk.getAlternativeAt(alt);
AlternativeElement e = a.head;
//System.out.println("getAltLookahead("+k+","+e+"), cache size is "+a.cache.length);
if ( a.cache[k]==null ) {
p = e.look(k);
a.cache[k] = p;
}
else {
p = a.cache[k];
}
return p;
}
/**Actions are ignored */
public Lookahead look(int k, ActionElement action) {
if ( DEBUG_ANALYZER ) System.out.println("lookAction("+k+","+action+")");
return action.next.look(k);
}
/**Combine the lookahead computed for each alternative */
public Lookahead look(int k, AlternativeBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("lookAltBlk(" + k + "," + blk + ")");
AlternativeBlock saveCurrentBlock = currentBlock;
currentBlock = blk;
Lookahead p = new Lookahead();
for (int i=0; i<blk.alternatives.size(); i++) {
if ( DEBUG_ANALYZER ) System.out.println("alt " + i + " of "+blk);
// must set analysis alt
currentBlock.analysisAlt = i;
Alternative alt = blk.getAlternativeAt(i);
AlternativeElement elem = alt.head;
if ( DEBUG_ANALYZER ) {
if ( alt.head == alt.tail ) {
System.out.println("alt " + i + " is empty");
}
}
Lookahead q = elem.look(k);
p.combineWith(q);
}
if (k == 1 && blk.not && subruleCanBeInverted(blk, lexicalAnalysis)) {
// Invert the lookahead set
if (lexicalAnalysis) {
BitSet b = (BitSet)((LexerGrammar)grammar).charVocabulary.clone();
int[] elems = p.fset.toArray();
for (int j = 0; j < elems.length; j++) {
b.remove(elems[j]);
}
p.fset = b;
} else {
p.fset.notInPlace(Token.MIN_USER_TYPE, grammar.tokenManager.maxTokenType());
}
}
currentBlock = saveCurrentBlock;
return p;
}
/**Compute what follows this place-holder node and possibly
* what begins the associated loop unless the
* node is locked.
* <p>
* if we hit the end of a loop, we have to include
* what tokens can begin the loop as well. If the start
* node is locked, then we simply found an empty path
* through this subrule while analyzing it. If the
* start node is not locked, then this node was hit
* during a FOLLOW operation and the FIRST of this
* block must be included in that lookahead computation.
*/
public Lookahead look(int k, BlockEndElement end) {
if ( DEBUG_ANALYZER ) System.out.println("lookBlockEnd("+k+", "+end.block+"); lock is "+end.lock[k]);
if ( end.lock[k] ) {
// computation in progress => the tokens we would have
// computed (had we not been locked) will be included
// in the set by that computation with the lock on this
// node.
return new Lookahead();
}
Lookahead p;
/* Hitting the end of a loop means you can see what begins the loop */
if ( end.block instanceof ZeroOrMoreBlock ||
end.block instanceof OneOrMoreBlock ) {
// compute what can start the block,
// but lock end node so we don't do it twice in same
// computation.
end.lock[k] = true;
p = look(k, end.block);
end.lock[k] = false;
}
else {
p = new Lookahead();
}
/* Tree blocks do not have any follow because they are children
* of what surrounds them. For example, A #(B C) D results in
* a look() for the TreeElement end of NULL_TREE_LOOKAHEAD, which
* indicates that nothing can follow the last node of tree #(B C)
*/
if (end.block instanceof TreeElement) {
p.combineWith(Lookahead.of(Token.NULL_TREE_LOOKAHEAD));
}
/* Syntactic predicates such as ( (A)? )=> have no follow per se.
* We cannot accurately say what would be matched following a
* syntactic predicate (you MIGHT be ok if you said it was whatever
* followed the alternative predicted by the predicate). Hence,
* (like end-of-token) we return Epsilon to indicate "unknown
* lookahead."
*/
else if ( end.block instanceof SynPredBlock ) {
p.setEpsilon();
}
// compute what can follow the block
else {
Lookahead q = end.block.next.look(k);
p.combineWith(q);
}
return p;
}
/**Return this char as the lookahead if k=1.
* <p>### Doesn't work for ( 'a' 'b' | 'a' ~'b' ) yet!!!
* <p>
* If the atom has the <tt>not</tt> flag on, then
* create the set complement of the tokenType
* which is the set of all characters referenced
* in the grammar with this char turned off.
* Also remove characters from the set that
* are currently allocated for predicting
* previous alternatives. This avoids ambiguity
* messages and is more properly what is meant.
* ( 'a' | ~'a' ) implies that the ~'a' is the
* "else" clause.
* <p>
* NOTE: we do <b>NOT</b> include exit path in
* the exclusion set. E.g.,
* ( 'a' | ~'a' )* 'b'
* should exit upon seeing a 'b' during the loop.
*/
public Lookahead look(int k, CharLiteralElement atom) {
if ( DEBUG_ANALYZER ) System.out.println("lookCharLiteral("+k+","+atom+")");
// Skip until analysis hits k==1
if ( k>1 ) {
return atom.next.look(k-1);
}
if ( lexicalAnalysis) {
if (atom.not) {
BitSet b = (BitSet)((LexerGrammar)grammar).charVocabulary.clone();
if ( DEBUG_ANALYZER ) System.out.println("charVocab is "+b.toString());
// remove stuff predicted by preceding alts and follow of block
removeCompetingPredictionSets(b, atom);
if ( DEBUG_ANALYZER ) System.out.println("charVocab after removal of prior alt lookahead "+b.toString());
// now remove element that is stated not to be in the set
b.clear(atom.getType());
return new Lookahead(b);
} else {
return Lookahead.of(atom.getType());
}
}
else {
// Should have been avoided by MakeGrammar
tool.panic("Character literal reference found in parser");
// ... so we make the compiler happy
return Lookahead.of(atom.getType());
}
}
public Lookahead look(int k, CharRangeElement r) {
if ( DEBUG_ANALYZER ) System.out.println("lookCharRange("+k+","+r+")");
// Skip until analysis hits k==1
if ( k>1 ) {
return r.next.look(k-1);
}
BitSet p = BitSet.of(r.begin);
for (int i=r.begin+1; i<=r.end; i++) {
p.add(i);
}
return new Lookahead(p);
}
public Lookahead look(int k, GrammarAtom atom) {
if ( DEBUG_ANALYZER ) System.out.println("look("+k+","+atom+"["+atom.getType()+"])");
if ( lexicalAnalysis ) {
// MakeGrammar should have created a rule reference instead
tool.panic("token reference found in lexer");
}
// Skip until analysis hits k==1
if ( k>1 ) {
return atom.next.look(k-1);
}
Lookahead l = Lookahead.of(atom.getType());
if (atom.not) {
// Invert the lookahead set against the token vocabulary
int maxToken = grammar.tokenManager.maxTokenType();
l.fset.notInPlace(Token.MIN_USER_TYPE, maxToken);
// remove stuff predicted by preceding alts and follow of block
removeCompetingPredictionSets(l.fset, atom);
}
return l;
}
/**The lookahead of a (...)+ block is the combined lookahead of
* all alternatives and, if an empty path is found, the lookahead
* of what follows the block.
*/
public Lookahead look(int k, OneOrMoreBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("look+"+k+","+blk+")");
Lookahead p = look(k, (AlternativeBlock)blk);
return p;
}
/**Combine the lookahead computed for each alternative.
* Lock the node so that no other computation may come back
* on itself--infinite loop. This also implies infinite left-recursion
* in the grammar (or an error in this algorithm ;)).
*/
public Lookahead look(int k, RuleBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("lookRuleBlk("+k+","+blk+")");
Lookahead p = look(k, (AlternativeBlock)blk);
return p;
}
/**If not locked or noFOLLOW set, compute FOLLOW of a rule.
* <p>
* TJP says 8/12/99: not true anymore:
* Lexical rules never compute follow. They set epsilon and
* the code generator gens code to check for any character.
* The code generator must remove the tokens used to predict
* any previous alts in the same block.
* <p>
* When the last node of a rule is reached and noFOLLOW,
* it implies that a "local" FOLLOW will be computed
* after this call. I.e.,
* <pre>
* a : b A;
* b : B | ;
* c : b C;
* </pre>
* Here, when computing the look of rule b from rule a,
* we want only {B,EPSILON_TYPE} so that look(b A) will
* be {B,A} not {B,A,C}.
* <p>
* if the end block is not locked and the FOLLOW is
* wanted, the algorithm must compute the lookahead
* of what follows references to this rule. If
* end block is locked, FOLLOW will return an empty set
* with a cycle to the rule associated with this end block.
*/
public Lookahead look(int k, RuleEndElement end) {
if ( DEBUG_ANALYZER )
System.out.println("lookRuleBlockEnd("+k+"); noFOLLOW="+
end.noFOLLOW+"; lock is "+end.lock[k]);
if ( /*lexicalAnalysis ||*/ end.noFOLLOW ) {
Lookahead p = new Lookahead();
p.setEpsilon();
p.epsilonDepth = BitSet.of(k);
return p;
}
Lookahead p = FOLLOW(k,end);
return p;
}
/**Compute the lookahead contributed by a rule reference.
*
* <p>
* When computing ruleref lookahead, we don't want the FOLLOW
* computation done if an empty path exists for the rule.
* The FOLLOW is too loose of a set...we want only to
* include the "local" FOLLOW or what can follow this
* particular ref to the node. In other words, we use
* context information to reduce the complexity of the
* analysis and strengthen the parser.
*
* The noFOLLOW flag is used as a means of restricting
* the FOLLOW to a "local" FOLLOW. This variable is
* orthogonal to the <tt>lock</tt> variable that prevents
* infinite recursion. noFOLLOW does not care about what k is.
*/
public Lookahead look(int k, RuleRefElement rr) {
if ( DEBUG_ANALYZER ) System.out.println("lookRuleRef("+k+","+rr+")");
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if ( rs==null || !rs.defined ) {
tool.error("no definition of rule "+rr.targetRule, grammar.getFilename(), rr.getLine());
return new Lookahead();
}
RuleBlock rb = rs.getBlock();
RuleEndElement end = rb.endNode;
boolean saveEnd = end.noFOLLOW;
end.noFOLLOW = true;
// go off to the rule and get the lookahead (w/o FOLLOW)
Lookahead p = look(k, rr.targetRule);
if ( DEBUG_ANALYZER ) System.out.println("back from rule ref to "+rr.targetRule);
// restore state of end block
end.noFOLLOW = saveEnd;
// check for infinite recursion. If a cycle is returned: trouble!
if ( p.cycle!=null ) {
tool.error("infinite recursion to rule "+p.cycle+" from rule "+
rr.enclosingRuleName, grammar.getFilename(), rr.getLine());
}
// is the local FOLLOW required?
if ( p.containsEpsilon() ) {
if ( DEBUG_ANALYZER )
System.out.println("rule ref to "+
rr.targetRule+" has eps, depth: "+p.epsilonDepth);
// remove epsilon
p.resetEpsilon();
// fset.clear(EPSILON_TYPE);
// for each lookahead depth that saw epsilon
int[] depths = p.epsilonDepth.toArray();
p.epsilonDepth = null; // clear all epsilon stuff
for (int i=0; i<depths.length; i++) {
int rk = k - (k-depths[i]);
Lookahead q = rr.next.look(rk); // see comments in Lookahead
p.combineWith(q);
}
// note: any of these look() computations for local follow can
// set EPSILON in the set again if the end of this rule is found.
}
return p;
}
public Lookahead look(int k, StringLiteralElement atom) {
if ( DEBUG_ANALYZER ) System.out.println("lookStringLiteral("+k+","+atom+")");
if ( lexicalAnalysis ) {
// need more lookahead than string can provide?
if ( k > atom.processedAtomText.length() ) {
return atom.next.look(k - atom.processedAtomText.length());
}
else {
// get char at lookahead depth k, from the processed literal text
return Lookahead.of(atom.processedAtomText.charAt(k-1));
}
}
else {
// Skip until analysis hits k==1
if ( k>1 ) {
return atom.next.look(k-1);
}
Lookahead l = Lookahead.of(atom.getType());
if (atom.not) {
// Invert the lookahead set against the token vocabulary
int maxToken = grammar.tokenManager.maxTokenType();
l.fset.notInPlace(Token.MIN_USER_TYPE, maxToken);
}
return l;
}
}
/**The lookahead of a (...)=> block is the lookahead of
* what follows the block. By definition, the syntactic
* predicate block defies static analysis (you want to try it
* out at run-time). The LOOK of (a)=>A B is A for LL(1)
* ### is this even called?
*/
public Lookahead look(int k, SynPredBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("look=>("+k+","+blk+")");
return blk.next.look(k);
}
public Lookahead look(int k, TokenRangeElement r) {
if ( DEBUG_ANALYZER ) System.out.println("lookTokenRange("+k+","+r+")");
// Skip until analysis hits k==1
if ( k>1 ) {
return r.next.look(k-1);
}
BitSet p = BitSet.of(r.begin);
for (int i=r.begin+1; i<=r.end; i++) {
p.add(i);
}
return new Lookahead(p);
}
public Lookahead look(int k, TreeElement t) {
if (DEBUG_ANALYZER)
System.out.println("look(" + k + "," + t.root + "[" + t.root.getType() + "])");
if (k > 1) {
return t.next.look(k - 1);
}
Lookahead l = null;
if (t.root instanceof WildcardElement) {
l = t.root.look(1); // compute FIRST set minus previous rows
} else {
l = Lookahead.of(t.root.getType());
if (t.root.not) {
// Invert the lookahead set against the token vocabulary
int maxToken = grammar.tokenManager.maxTokenType();
l.fset.notInPlace(Token.MIN_USER_TYPE, maxToken);
}
}
return l;
}
public Lookahead look(int k, WildcardElement wc) {
if ( DEBUG_ANALYZER ) System.out.println("look(" + k + "," + wc + ")");
// Skip until analysis hits k==1
if ( k>1 ) {
return wc.next.look(k-1);
}
BitSet b;
if ( lexicalAnalysis ) {
// Copy the character vocabulary
b = (BitSet)((LexerGrammar)grammar).charVocabulary.clone();
}
else {
b = new BitSet(1);
// Invert the lookahead set against the token vocabulary
int maxToken = grammar.tokenManager.maxTokenType();
b.notInPlace(Token.MIN_USER_TYPE, maxToken);
if ( DEBUG_ANALYZER ) System.out.println("look(" + k + "," + wc + ") after not: "+b);
}
// Remove prediction sets from competing alternatives
// removeCompetingPredictionSets(b, wc);
return new Lookahead(b);
}
/** The (...)* element is the combined lookahead of the alternatives and what can
* follow the loop.
*/
public Lookahead look(int k, ZeroOrMoreBlock blk) {
if ( DEBUG_ANALYZER ) System.out.println("look*("+k+","+blk+")");
Lookahead p = look(k, (AlternativeBlock)blk);
Lookahead q = blk.next.look(k);
p.combineWith(q);
return p;
}
/**Compute the combined lookahead for all productions of a rule.
* If the lookahead returns with epsilon, at least one epsilon
* path exists (one that consumes no tokens). The noFOLLOW
* flag being set for this endruleblk, indicates that the
* a rule ref invoked this rule.
*
* Currently only look(RuleRef) calls this. There is no need
* for the code generator to call this.
*/
public Lookahead look(int k, String rule) {
if ( DEBUG_ANALYZER ) System.out.println("lookRuleName("+k+","+rule+")");
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rule);
RuleBlock rb = rs.getBlock();
if ( rb.lock[k] ) {
if ( DEBUG_ANALYZER )
System.out.println("infinite recursion to rule "+rb.getRuleName());
return new Lookahead(rule);
}
// have we computed it before?
if ( rb.cache[k]!=null ) {
if ( DEBUG_ANALYZER ) {
System.out.println("found depth "+k+" result in FIRST "+rule+" cache: "+
rb.cache[k].toString(",", charFormatter, grammar));
}
return (Lookahead)rb.cache[k].clone();
}
rb.lock[k] = true;
Lookahead p = look(k, (RuleBlock)rb);
rb.lock[k] = false;
// cache results
rb.cache[k] = (Lookahead)p.clone();
if ( DEBUG_ANALYZER ) {
System.out.println("saving depth "+k+" result in FIRST "+rule+" cache: "+
rb.cache[k].toString(",", charFormatter, grammar));
}
return p;
}
/** If the first k-1 sets are singleton sets, the appoximate
* lookahead analysis is equivalent to full lookahead analysis.
*/
public static boolean lookaheadEquivForApproxAndFullAnalysis(Lookahead[] bset, int k) {
// first k-1 sets degree 1?
for (int i=1; i<=k-1; i++) {
BitSet look = bset[i].fset;
if ( look.degree()>1 ) {
return false;
}
}
return true;
}
/** Remove the prediction sets from preceding alternatives
* and follow set, but *only* if this element is the first element
* of the alternative. The class members currenBlock and
* currentBlock.analysisAlt must be set correctly.
* @param b The prediction bitset to be modified
* @el The element of interest
*/
private void removeCompetingPredictionSets(BitSet b, AlternativeElement el) {
// Only do this if the element is the first element of the alt,
// because we are making an implicit assumption that k==1.
GrammarElement head = currentBlock.getAlternativeAt(currentBlock.analysisAlt).head;
// if element is #(. blah) then check to see if el is root
if ( head instanceof TreeElement ) {
if ( ((TreeElement) head).root != el ) {
return;
}
}
else if ( el != head ) {
return;
}
for (int i = 0; i < currentBlock.analysisAlt; i++) {
AlternativeElement e = currentBlock.getAlternativeAt(i).head;
b.subtractInPlace(e.look(1).fset);
}
}
/** Remove the prediction sets from preceding alternatives
* The class members currenBlock must be set correctly.
* Remove prediction sets from 1..k.
* @param look The prediction lookahead to be modified
* @el The element of interest
* @k How deep into lookahead to modify
*/
private void removeCompetingPredictionSetsFromWildcard(Lookahead[] look, AlternativeElement el, int k) {
for (int d = 1; d <= k; d++) {
for (int i = 0; i < currentBlock.analysisAlt; i++) {
AlternativeElement e = currentBlock.getAlternativeAt(i).head;
look[d].fset.subtractInPlace(e.look(d).fset);
}
}
}
/** reset the analyzer so it looks like a new one */
private void reset() {
grammar = null;
DEBUG_ANALYZER = false;
currentBlock = null;
lexicalAnalysis = false;
}
/** Set the grammar for the analyzer */
public void setGrammar(Grammar g) {
if (grammar != null) {
reset();
}
grammar = g;
// Is this lexical?
lexicalAnalysis = (grammar instanceof LexerGrammar);
DEBUG_ANALYZER = grammar.analyzerDebug;
}
public boolean subruleCanBeInverted(AlternativeBlock blk, boolean forLexer)
{
if (
blk instanceof ZeroOrMoreBlock ||
blk instanceof OneOrMoreBlock ||
blk instanceof SynPredBlock
) {
return false;
}
// Cannot invert an empty subrule
if (blk.alternatives.size() == 0) {
return false;
}
// The block must only contain alternatives with a single element,
// where each element is a char, token, char range, or token range.
for (int i = 0; i < blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
// Cannot have anything interesting in the alternative ...
if (alt.synPred != null || alt.semPred != null || alt.exceptionSpec != null) {
return false;
}
// ... and there must be one simple element
AlternativeElement elt = alt.head;
if (
!(
elt instanceof CharLiteralElement ||
elt instanceof TokenRefElement ||
elt instanceof CharRangeElement ||
elt instanceof TokenRangeElement ||
(elt instanceof StringLiteralElement && !forLexer)
) ||
!(elt.next instanceof BlockEndElement) ||
elt.getAutoGenType() != GrammarElement.AUTO_GEN_NONE
) {
return false;
}
}
return true;
}
}
1.1 e/src/jsrc/antlr/LLkGrammarAnalyzer.java
Index: LLkGrammarAnalyzer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: LLkGrammarAnalyzer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public interface LLkGrammarAnalyzer extends GrammarAnalyzer {
public boolean deterministic(AlternativeBlock blk);
public boolean deterministic(OneOrMoreBlock blk);
public boolean deterministic(ZeroOrMoreBlock blk);
public Lookahead FOLLOW(int k, RuleEndElement end);
public Lookahead look(int k, ActionElement action);
public Lookahead look(int k, AlternativeBlock blk);
public Lookahead look(int k, BlockEndElement end);
public Lookahead look(int k, CharLiteralElement atom);
public Lookahead look(int k, CharRangeElement end);
public Lookahead look(int k, GrammarAtom atom);
public Lookahead look(int k, OneOrMoreBlock blk);
public Lookahead look(int k, RuleBlock blk);
public Lookahead look(int k, RuleEndElement end);
public Lookahead look(int k, RuleRefElement rr);
public Lookahead look(int k, StringLiteralElement atom);
public Lookahead look(int k, SynPredBlock blk);
public Lookahead look(int k, TokenRangeElement end);
public Lookahead look(int k, TreeElement end);
public Lookahead look(int k, WildcardElement wc);
public Lookahead look(int k, ZeroOrMoreBlock blk);
public Lookahead look(int k, String rule);
public void setGrammar(Grammar g);
public boolean subruleCanBeInverted(AlternativeBlock blk, boolean forLexer);
}
1.1 e/src/jsrc/antlr/LLkParser.java
Index: LLkParser.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: LLkParser.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.IOException;
/**An LL(k) parser.
*
* @see antlr.Token
* @see antlr.TokenBuffer
* @see antlr.LL1Parser
*/
public class LLkParser extends Parser {
int k;
public LLkParser(int k_) {
k = k_;
//TokenBuffer tokenBuf = new TokenBuffer(null);
//setTokenBuffer(tokenBuf);
}
public LLkParser(ParserSharedInputState state, int k_) {
k = k_;
inputState = state;
}
public LLkParser(TokenBuffer tokenBuf, int k_) {
k = k_;
setTokenBuffer(tokenBuf);
}
public LLkParser(TokenStream lexer, int k_) {
k = k_;
TokenBuffer tokenBuf = new TokenBuffer(lexer);
setTokenBuffer(tokenBuf);
}
/**Consume another token from the input stream. Can only write sequentially!
* If you need 3 tokens ahead, you must consume() 3 times.
* <p>
* Note that it is possible to overwrite tokens that have not been matched.
* For example, calling consume() 3 times when k=2, means that the first token
* consumed will be overwritten with the 3rd.
*/
public void consume() {
inputState.input.consume();
}
public int LA(int i) throws TokenStreamException {
return inputState.input.LA(i);
}
public Token LT(int i) throws TokenStreamException {
return inputState.input.LT(i);
}
private void trace(String ee, String rname) throws TokenStreamException {
traceIndent();
System.out.print(ee + rname + ((inputState.guessing>0)?"; [guessing]":"; "));
for (int i = 1; i <= k; i++)
{
if (i != 1) {
System.out.print(", ");
}
System.out.print("LA(" + i + ")==" + LT(i).getText());
}
System.out.println("");
}
public void traceIn(String rname) throws TokenStreamException {
traceDepth += 1;
trace("> ", rname);
}
public void traceOut(String rname) throws TokenStreamException {
trace("< ", rname);
traceDepth -= 1;
}
}
1.1 e/src/jsrc/antlr/LexerGrammar.java
Index: LexerGrammar.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: LexerGrammar.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
/** Lexer-specific grammar subclass */
class LexerGrammar extends Grammar {
// character set used by lexer
protected BitSet charVocabulary;
// true if the lexer generates literal testing code for nextToken
protected boolean testLiterals = true;
// true if the lexer generates case-sensitive LA(k) testing
protected boolean caseSensitiveLiterals = true;
/** true if the lexer generates case-sensitive literals testing */
protected boolean caseSensitive = true;
/** true if lexer is to ignore all unrecognized tokens */
protected boolean filterMode = false;
/** if filterMode is true, then filterRule can indicate an optional
* rule to use as the scarf language. If null, programmer used
* plain "filter=true" not "filter=rule".
*/
protected String filterRule = null;
LexerGrammar(String className_, Tool tool_, String superClass) {
super(className_, tool_, superClass);
charVocabulary = new BitSet();
// Lexer usually has no default error handling
defaultErrorHandler = false;
}
/** Top-level call to generate the code */
public void generate() throws IOException {
generator.gen(this);
}
public String getSuperClass() {
// If debugging, use debugger version of scanner
if (debuggingOutput)
return "debug.DebuggingCharScanner";
return "CharScanner";
}
// Get the testLiterals option value
public boolean getTestLiterals() {
return testLiterals;
}
/**Process command line arguments.
* -trace have all rules call traceIn/traceOut
* -traceLexer have lexical rules call traceIn/traceOut
* -debug generate debugging output for parser debugger
*/
public void processArguments(String[] args) {
for (int i=0; i<args.length; i++) {
if ( args[i].equals("-trace") ) {
traceRules = true;
Tool.setArgOK(i);
}
else if ( args[i].equals("-traceLexer") ) {
traceRules = true;
Tool.setArgOK(i);
}
else if ( args[i].equals("-debug") ) {
debuggingOutput = true;
Tool.setArgOK(i);
}
}
}
/** Set the character vocabulary used by the lexer */
public void setCharVocabulary(BitSet b) {
charVocabulary = b;
}
/** Set lexer options */
public boolean setOption(String key, Token value) {
String s = value.getText();
if (key.equals("buildAST")) {
tool.warning("buildAST option is not valid for lexer", getFilename(), value.getLine());
return true;
}
if (key.equals("testLiterals")) {
if (s.equals("true")) {
testLiterals = true;
} else if (s.equals("false")) {
testLiterals = false;
} else {
tool.warning("testLiterals option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("interactive")) {
if (s.equals("true")) {
interactive = true;
} else if (s.equals("false")) {
interactive = false;
} else {
tool.error("interactive option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("caseSensitive")) {
if (s.equals("true")) {
caseSensitive = true;
} else if (s.equals("false")) {
caseSensitive = false;
} else {
tool.warning("caseSensitive option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("caseSensitiveLiterals")) {
if (s.equals("true")) {
caseSensitiveLiterals= true;
} else if (s.equals("false")) {
caseSensitiveLiterals= false;
} else {
tool.warning("caseSensitiveLiterals option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("filter")) {
if (s.equals("true")) {
filterMode = true;
} else if (s.equals("false")) {
filterMode = false;
} else if ( value.getType()==ANTLRTokenTypes.TOKEN_REF) {
filterMode = true;
filterRule = s;
}
else {
tool.warning("filter option must be true, false, or a lexer rule name", getFilename(), value.getLine());
}
return true;
}
if (key.equals("longestPossible")) {
tool.warning("longestPossible option has been deprecated; ignoring it...", getFilename(), value.getLine());
return true;
}
if (super.setOption(key, value)) {
return true;
}
tool.error("Invalid option: " + key, getFilename(), value.getLine());
return false;
}
}
1.1 e/src/jsrc/antlr/LexerSharedInputState.java
Index: LexerSharedInputState.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: LexerSharedInputState.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.Reader;
import java.io.InputStream;
/** This object contains the data associated with an
* input stream of characters. Multiple lexers
* share a single LexerSharedInputState to lex
* the same input stream.
*/
public class LexerSharedInputState {
protected int column=1;
protected int line=1;
protected int tokenStartColumn = 1;
protected int tokenStartLine = 1;
protected InputBuffer input;
/** What file (if known) caused the problem? */
protected String filename;
public int guessing = 0;
public LexerSharedInputState(InputBuffer inbuf) {
input = inbuf;
}
public LexerSharedInputState(InputStream in) {
this(new ByteBuffer(in));
}
public LexerSharedInputState(Reader in) {
this(new CharBuffer(in));
}
}
1.1 e/src/jsrc/antlr/Lookahead.java
Index: Lookahead.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: Lookahead.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
/**This object holds all information needed to represent
* the lookahead for any particular lookahead computation
* for a <b>single</b> lookahead depth. Final lookahead
* information is a simple bit set, but intermediate
* stages need computation cycle and FOLLOW information.
*
* <p>
* Concerning the <tt>cycle</tt> variable.
* If lookahead is computed for a RuleEnd node, then
* computation is part of a FOLLOW cycle for this rule.
* If lookahead is computed for a RuleBlock node, the
* computation is part of a FIRST cycle to this rule.
*
* <p>
* Concerning the <tt>epsilonDepth</tt> variable.
* This is not the depth relative to the rule reference
* that epsilon was encountered. That value is
* <pre>
* initial_k - epsilonDepth + 1
* </pre>
* Also, lookahead depths past rule ref for local follow are:
* <pre>
* initial_k - (initial_k - epsilonDepth)
* </pre>
* Used for rule references. If we try
* to compute look(k, ruleref) and there are fewer
* than k lookahead terminals before the end of the
* the rule, epsilon will be returned (don't want to
* pass the end of the rule). We must track when the
* the lookahead got stuck. For example,
* <pre>
* a : b A B E F G;
* b : C ;
* </pre>
* LOOK(5, ref-to(b)) is {<EPSILON>} with depth = 4, which
* indicates that at 2 (5-4+1) tokens ahead, end of rule was reached.
* Therefore, the token at 4=5-(5-4) past rule ref b must be
* included in the set == F.
* The situation is complicated by the fact that a computation
* may hit the end of a rule at many different depths. For example,
* <pre>
* a : b A B C ;
* b : E F // epsilon depth of 1 relative to initial k=3
* | G // epsilon depth of 2
* ;
* </pre>
* Here, LOOK(3,ref-to(b)) returns epsilon, but the depths are
* {1, 2}; i.e., 3-(3-1) and 3-(3-2). Those are the lookahead depths
* past the rule ref needed for the local follow.
*
* <p>
* This is null unless an epsilon is created.
*
* @see antlr.Lookahead#combineWith(Lookahead)
*/
public class Lookahead implements Cloneable {
/** actual bitset of the lookahead */
BitSet fset;
/** is this computation part of a computation cycle? */
String cycle;
/** What k values were being computed when end of rule hit? */
BitSet epsilonDepth;
/** Does this lookahead depth include Epsilon token type? This
* is used to avoid having a bit in the set for Epsilon as it
* conflicts with parsing binary files.
*/
boolean hasEpsilon = false;
public Lookahead() {
fset = new BitSet();
}
/** create a new lookahead set with the LL(1) set to the parameter */
public Lookahead(BitSet p) {
fset = p;
}
/** create an empty lookahead set, but with cycle */
public Lookahead(String c) {
this();
cycle = c;
}
/** Make a deep copy of everything in this object */
public Object clone() {
Lookahead p=null;
try {
p = (Lookahead)super.clone();
p.fset = (BitSet)fset.clone();
p.cycle = cycle; // strings are immutable
if ( epsilonDepth!=null ) {
p.epsilonDepth = (BitSet)epsilonDepth.clone();
}
}
catch (CloneNotSupportedException e) {
throw new InternalError();
}
return p;
}
public void combineWith(Lookahead q) {
if ( cycle==null ) { // track at least one cycle
cycle = q.cycle;
}
if ( q.containsEpsilon() ) {
hasEpsilon = true;
}
// combine epsilon depths
if ( epsilonDepth!=null ) {
if ( q.epsilonDepth!=null ) {
epsilonDepth.orInPlace(q.epsilonDepth);
}
}
else if ( q.epsilonDepth!=null ) {
epsilonDepth = (BitSet)q.epsilonDepth.clone();
}
fset.orInPlace(q.fset);
}
public boolean containsEpsilon() { return hasEpsilon; }
/** What is the intersection of two lookahead depths?
* Only the Epsilon "bit" and bitset are considered.
*/
public Lookahead intersection(Lookahead q) {
Lookahead p = new Lookahead(fset.and(q.fset));
if ( this.hasEpsilon && q.hasEpsilon ) {
p.setEpsilon();
}
return p;
}
public boolean nil() {
return fset.nil() && !hasEpsilon;
}
public static Lookahead of(int el) {
Lookahead look = new Lookahead();
look.fset.add(el);
return look;
}
public void resetEpsilon() { hasEpsilon=false; }
public void setEpsilon() { hasEpsilon = true; }
public String toString() {
String e="",b,f="",d="";
b = fset.toString(",");
if ( containsEpsilon() ) {
e="+<epsilon>";
}
if ( cycle!=null ) {
f="; FOLLOW("+cycle+")";
}
if ( epsilonDepth != null ) {
d = "; depths="+epsilonDepth.toString(",");
}
return b+e+f+d;
}
public String toString(String separator, CharFormatter formatter) {
String e="",b,f="",d="";
b = fset.toString(separator, formatter);
if ( containsEpsilon() ) {
e="+<epsilon>";
}
if ( cycle!=null ) {
f="; FOLLOW("+cycle+")";
}
if ( epsilonDepth != null ) {
d = "; depths="+epsilonDepth.toString(",");
}
return b+e+f+d;
}
public String toString(String separator, CharFormatter formatter, Grammar g) {
if (g instanceof LexerGrammar) {
return toString(separator, formatter);
}
else {
return toString(separator, g.tokenManager.getVocabulary());
}
}
public String toString(String separator, Vector vocab) {
String b,f="",d="";
b = fset.toString(separator, vocab);
if ( cycle!=null ) {
f="; FOLLOW("+cycle+")";
}
if ( epsilonDepth != null ) {
d = "; depths="+epsilonDepth.toString(",");
}
return b+f+d;
}
}
1.1 e/src/jsrc/antlr/MakeGrammar.java
Index: MakeGrammar.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: MakeGrammar.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.Stack;
import antlr.collections.impl.LList;
import antlr.collections.impl.Vector;
public class MakeGrammar extends DefineGrammarSymbols {
protected Stack blocks = new LList(); // track subrules--Stack<BlockContext>
protected RuleRefElement lastRuleRef;
protected RuleEndElement ruleEnd; // used if not nested
protected RuleBlock ruleBlock; // points to block of current rule.
protected int nested = 0; // nesting inside a subrule
protected boolean grammarError = false;
ExceptionSpec currentExceptionSpec = null;
public MakeGrammar(Tool tool_, String[] args_, LLkAnalyzer analyzer_) {
super(tool_, args_, analyzer_);
}
/** Abort the processing of a grammar (due to syntax errors) */
public void abortGrammar() {
String s = "unknown grammar";
if ( grammar!=null ) {
s = grammar.getClassName();
}
tool.error("aborting grammar '" + s + "' due to errors");
super.abortGrammar();
}
protected void addElementToCurrentAlt(AlternativeElement e) {
e.enclosingRuleName = ruleBlock.ruleName;
context().addAlternativeElement(e);
}
public void beginAlt(boolean doAutoGen_) {
super.beginAlt(doAutoGen_);
Alternative alt = new Alternative();
alt.setAutoGen(doAutoGen_);
context().block.addAlternative(alt);
}
public void beginChildList() {
super.beginChildList();
context().block.addAlternative(new Alternative());
}
/** Add an exception group to a rule (currently a no-op) */
public void beginExceptionGroup() {
super.beginExceptionGroup();
if (!(context().block instanceof RuleBlock))
{
tool.panic("beginExceptionGroup called outside of rule block");
}
}
/** Add an exception spec to an exception group or rule block */
public void beginExceptionSpec(Token label) {
// Hack the label string a bit to remove leading/trailing space.
if (label != null) {
label.setText( Tool.stripFront( Tool.stripBack(label.getText(), " \n\r\t"), " \n\r\t") );
}
super.beginExceptionSpec(label);
// Don't check for currentExceptionSpec!=null because syntax errors
// may leave it set to something.
currentExceptionSpec = new ExceptionSpec(label);
}
public void beginSubRule(Token label, int line, boolean not) {
super.beginSubRule(label,line, not);
// we don't know what kind of subrule it is yet.
// push a dummy one that will allow us to collect the
// alternatives. Later, we'll switch to real object.
blocks.push(new BlockContext());
context().block = new AlternativeBlock(grammar, line, not);
context().altNum = 0; // reset alternative number
nested++;
// create a final node to which the last elememt of each
// alternative will point.
context().blockEnd = new BlockEndElement(grammar);
// make sure end node points to start of block
context().blockEnd.block = context().block;
labelElement(context().block, label);
}
public void beginTree(int line) throws SemanticException {
if (!(grammar instanceof TreeWalkerGrammar)) {
tool.error("Trees only allowed in TreeParser", grammar.getFilename(), line);
throw new SemanticException("Trees only allowed in TreeParser");
}
super.beginTree(line);
blocks.push(new TreeBlockContext());
context().block = new TreeElement(grammar, line);
context().altNum = 0; // reset alternative number
}
public BlockContext context() {
if ( blocks.height()==0 ) {
return null;
}
else {
return (BlockContext)blocks.top();
}
}
/**Used to build nextToken() for the lexer.
* This builds a rule which has every "public" rule in the given Vector of
* rules as it's alternate. Each rule ref generates a Token object.
* @param g The Grammar that is being processed
* @param lexRules A vector of lexer rules that will be used to create an alternate block.
* @param rname The name of the resulting rule.
*/
public static RuleBlock createNextTokenRule(Grammar g, Vector lexRules, String rname) {
// create actual rule data structure
RuleBlock rb = new RuleBlock(g, rname);
rb.setDefaultErrorHandler( g.getDefaultErrorHandler() );
RuleEndElement ruleEnd = new RuleEndElement(g);
rb.setEndElement(ruleEnd);
ruleEnd.block = rb;
// Add an alternative for each element of the rules vector.
for (int i=0; i<lexRules.size(); i++) {
RuleSymbol r = (RuleSymbol)lexRules.elementAt(i);
if (!r.isDefined()) {
g.tool.error("Lexer rule " + r.id.substring(1) + " is not defined");
}
else {
if ( r.access.equals("public") ) {
// create a rule ref to lexer rule
// the Token is a RULE_REF not a TOKEN_REF since the
// conversion to mRulename has already taken place
RuleRefElement rr =
new RuleRefElement(g,
new CommonToken(ANTLRTokenTypes.RULE_REF, r.getId()),
GrammarElement.AUTO_GEN_NONE);
//labelElement(rr, new Token("_rettoken"));
// rr.setIdAssign("_ttype");
rr.setLabel("theRetToken");
rr.enclosingRuleName = "nextToken";
rr.next = ruleEnd;
Alternative alt = new Alternative(rr);
alt.setAutoGen(true); // keep text of elements
rb.addAlternative(alt);
// Add a reference to the rule used for the alt
r.addReference(rr);
}
}
}
rb.setAutoGen(true); // keep text of elements
rb.prepareForAnalysis();
//System.out.println(rb);
return rb;
}
/** Return block as if they had typed: "( rule )?" */
private AlternativeBlock createOptionalRuleRef(String rule, int line) {
// Make the subrule
AlternativeBlock blk = new AlternativeBlock(grammar, line, false);
// Make sure rule is defined
String mrule = CodeGenerator.lexerRuleName(rule); // can only be a lexer rule!
if ( !grammar.isDefined(mrule) ) {
grammar.define(new RuleSymbol(mrule));
}
// Make the rule ref element
Token t = new CommonToken(ANTLRTokenTypes.TOKEN_REF, rule);
t.setLine(line);
RuleRefElement rref =
new RuleRefElement(grammar, t, GrammarElement.AUTO_GEN_NONE);
rref.enclosingRuleName = ruleBlock.ruleName;
// Make the end of block element
BlockEndElement end = new BlockEndElement(grammar);
end.block = blk; // end block points back to start of blk
// Make an alternative, putting the rule ref into it
Alternative alt = new Alternative(rref);
alt.addElement(end); // last element in alt points to end of block
// Add the alternative to this block
blk.addAlternative(alt);
// create an empty (optional) alt and add to blk
Alternative optAlt = new Alternative();
optAlt.addElement(end); // points immediately to end of block
blk.addAlternative(optAlt);
blk.prepareForAnalysis();
return blk;
}
public void defineRuleName(Token r,
String access,
boolean ruleAutoGen,
String docComment)
throws SemanticException
{
// if ( Character.isUpperCase(r.getText().charAt(0)) ) {
if ( r.type == ANTLRTokenTypes.TOKEN_REF ) {
if (!(grammar instanceof LexerGrammar)) {
tool.error("Lexical rule "+r.getText()+
" defined outside of lexer",
grammar.getFilename(), r.getLine());
r.setText(r.getText().toLowerCase());
}
}
else {
if (grammar instanceof LexerGrammar) {
tool.error("Non-lexical rule "+r.getText()+
" defined inside of lexer",
grammar.getFilename(), r.getLine());
r.setText(r.getText().toUpperCase());
}
}
super.defineRuleName(r, access, ruleAutoGen, docComment);
String id = r.getText();
// if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
if ( r.type == ANTLRTokenTypes.TOKEN_REF ) { // lexer rule?
id = CodeGenerator.lexerRuleName(id);
}
RuleSymbol rs = (RuleSymbol) grammar.getSymbol(id);
RuleBlock rb = new RuleBlock(grammar, r.getText(), r.getLine(), ruleAutoGen);
// Lexer rules do not generate default error handling
rb.setDefaultErrorHandler(grammar.getDefaultErrorHandler());
ruleBlock = rb;
blocks.push(new BlockContext()); // enter new context
context().block = rb;
rs.setBlock(rb);
ruleEnd = new RuleEndElement(grammar);
rb.setEndElement(ruleEnd);
nested = 0;
}
public void endAlt() {
super.endAlt();
if ( nested==0 ) { // all rule-level alts link to ruleEnd node
addElementToCurrentAlt(ruleEnd);
}
else {
addElementToCurrentAlt(context().blockEnd);
}
context().altNum++;
}
public void endChildList() {
super.endChildList();
// create a final node to which the last elememt of the single
// alternative will point. Done for compatibility with analyzer.
// Does NOT point to any block like alternative blocks because the
// TreeElement is not a block. This is used only as a placeholder.
BlockEndElement be = new BlockEndElement(grammar);
be.block = context().block;
addElementToCurrentAlt(be);
}
public void endExceptionGroup() {
super.endExceptionGroup();
}
public void endExceptionSpec() {
super.endExceptionSpec();
if (currentExceptionSpec == null)
{
tool.panic("exception processing internal error -- no active exception spec");
}
if (context().block instanceof RuleBlock)
{
// Named rule
((RuleBlock)context().block).addExceptionSpec(currentExceptionSpec);
} else {
// It must be a plain-old alternative block
if (context().currentAlt().exceptionSpec != null) {
tool.error("Alternative already has an exception specification", grammar.getFilename(), context().block.getLine());
}
else {
context().currentAlt().exceptionSpec = currentExceptionSpec;
}
}
currentExceptionSpec = null;
}
/** Called at the end of processing a grammar */
public void endGrammar() {
if (grammarError) {
abortGrammar();
}
else {
super.endGrammar();
}
}
public void endRule(String rule) {
super.endRule(rule);
BlockContext ctx = (BlockContext) blocks.pop(); // remove scope
// record the start of this block in the ending node
ruleEnd.block = ctx.block;
ruleEnd.block.prepareForAnalysis();
//System.out.println(ctx.block);
}
public void endSubRule() {
super.endSubRule();
nested--;
// remove subrule context from scope stack
BlockContext ctx = (BlockContext)blocks.pop();
AlternativeBlock block = ctx.block;
// If the subrule is marked with ~, check that it is
// a valid candidate for analysis
if (
block.not &&
!(block instanceof SynPredBlock) &&
!(block instanceof ZeroOrMoreBlock) &&
!(block instanceof OneOrMoreBlock)
)
{
if (!analyzer.subruleCanBeInverted(block, grammar instanceof LexerGrammar)) {
String newline = System.getProperty("line.separator");
tool.error(
"This subrule cannot be inverted. Only subrules of the form:"+newline +
" (T1|T2|T3...) or" + newline +
" ('c1'|'c2'|'c3'...)" + newline +
"may be inverted (ranges are also allowed).",
grammar.getFilename(),
block.getLine()
);
}
}
// add the subrule as element if not a syn pred
if ( block instanceof SynPredBlock ) {
// record a reference to the recently-recognized syn pred in the
// enclosing block.
SynPredBlock synpred = (SynPredBlock)block;
context().block.hasASynPred = true;
context().currentAlt().synPred = synpred;
grammar.hasSyntacticPredicate = true;
synpred.removeTrackingOfRuleRefs(grammar);
}
else {
addElementToCurrentAlt(block);
}
ctx.blockEnd.block.prepareForAnalysis();
}
public void endTree() {
super.endTree();
BlockContext ctx = (BlockContext) blocks.pop();
addElementToCurrentAlt(ctx.block); // add new TreeElement to enclosing alt.
}
/** Remember that a major error occured in the grammar */
public void hasError() {
grammarError = true;
}
private void labelElement(AlternativeElement el, Token label) {
if ( label != null ) {
// Does this label already exist?
for (int i = 0; i < ruleBlock.labeledElements.size(); i++) {
AlternativeElement altEl = (AlternativeElement)ruleBlock.labeledElements.elementAt(i);
String l = altEl.getLabel();
if (l != null && l.equals(label.getText())) {
tool.error("Label '" + label.getText() + "' has already been defined", grammar.getFilename(), label.getLine());
return;
}
}
// add this node to the list of labeled elements
el.setLabel(label.getText());
ruleBlock.labeledElements.appendElement(el);
}
}
public void noAutoGenSubRule() {
context().block.setAutoGen(false);
}
public void oneOrMoreSubRule() {
if (context().block.not) {
tool.error("'~' cannot be applied to (...)* subrule", grammar.getFilename(), context().block.getLine());
}
// create the right kind of object now that we know what that is
// and switch the list of alternatives. Adjust the stack of blocks.
// copy any init action also.
OneOrMoreBlock b = new OneOrMoreBlock(grammar);
setBlock(b,context().block);
BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
blocks.push(new BlockContext());
context().block = b;
context().blockEnd = old.blockEnd;
context().blockEnd.block = b;
}
public void optionalSubRule() {
if (context().block.not) {
tool.error("'~' cannot be applied to (...)? subrule", grammar.getFilename(), context().block.getLine());
}
// convert (X)? -> (X|) so that we can ignore optional blocks altogether!
// It already thinks that we have a simple subrule, just add option block.
beginAlt(false);
endAlt();
}
public void refAction(Token action) {
super.refAction(action);
context().block.hasAnAction = true;
addElementToCurrentAlt(new ActionElement(grammar,action));
}
public void setUserExceptions(String thr) {
((RuleBlock)context().block).throwsSpec = thr;
}
// Only called for rule blocks
public void refArgAction(Token action) {
((RuleBlock)context().block).argAction = action.getText();
}
public void refCharLiteral(Token lit, Token label, boolean inverted, int autoGenType, boolean lastInRule) {
if (!(grammar instanceof LexerGrammar)) {
tool.error("Character literal only valid in lexer", grammar.getFilename(), lit.getLine());
return;
}
super.refCharLiteral(lit, label, inverted, autoGenType, lastInRule);
CharLiteralElement cl = new CharLiteralElement((LexerGrammar)grammar, lit, inverted, autoGenType);
// Generate a warning for non-lowercase ASCII when case-insensitive
if (
!((LexerGrammar)grammar).caseSensitive && cl.getType() < 128 &&
Character.toLowerCase((char)cl.getType()) != (char)cl.getType()
) {
tool.warning("Character literal must be lowercase when caseSensitive=false", grammar.getFilename(), lit.getLine());
}
addElementToCurrentAlt(cl);
labelElement(cl, label);
// if ignore option is set, must add an optional call to the specified rule.
String ignore = ruleBlock.getIgnoreRule();
if ( !lastInRule && ignore!=null ) {
addElementToCurrentAlt(createOptionalRuleRef(ignore, lit.getLine()));
}
}
public void refCharRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule) {
if (!(grammar instanceof LexerGrammar)) {
tool.error("Character range only valid in lexer", grammar.getFilename(), t1.getLine());
return;
}
int rangeMin = ANTLRLexer.tokenTypeForCharLiteral(t1.getText());
int rangeMax = ANTLRLexer.tokenTypeForCharLiteral(t2.getText());
if (rangeMax < rangeMin) {
tool.error("Malformed range.", grammar.getFilename(), t1.getLine());
return;
}
// Generate a warning for non-lowercase ASCII when case-insensitive
if (!((LexerGrammar)grammar).caseSensitive) {
if (rangeMin < 128 && Character.toLowerCase((char)rangeMin) != (char)rangeMin) {
tool.warning("Character literal must be lowercase when caseSensitive=false", grammar.getFilename(), t1.getLine());
}
if (rangeMax < 128 && Character.toLowerCase((char)rangeMax) != (char)rangeMax) {
tool.warning("Character literal must be lowercase when caseSensitive=false", grammar.getFilename(), t2.getLine());
}
}
super.refCharRange(t1, t2, label, autoGenType, lastInRule);
CharRangeElement cr = new CharRangeElement((LexerGrammar)grammar, t1, t2, autoGenType);
addElementToCurrentAlt(cr);
labelElement(cr, label);
// if ignore option is set, must add an optional call to the specified rule.
String ignore = ruleBlock.getIgnoreRule();
if ( !lastInRule && ignore!=null ) {
addElementToCurrentAlt(createOptionalRuleRef(ignore, t1.getLine()));
}
}
public void refTokensSpecElementOption(Token tok,
Token option,
Token value) {
/*
System.out.println("setting tokens spec option for "+tok.getText());
System.out.println(option.getText()+","+value.getText());
*/
TokenSymbol ts = (TokenSymbol)
grammar.tokenManager.getTokenSymbol(tok.getText());
if ( ts==null ) {
tool.panic("cannot find "+tok.getText()+"in tokens {...}");
}
if ( option.getText().equals("AST") ) {
ts.setASTNodeType(value.getText());
}
else {
grammar.tool.error("invalid tokens {...} element option:"+
option.getText(),
grammar.getFilename(),
option.getLine());
}
}
public void refElementOption(Token option, Token value) {
/*
System.out.println("setting option for "+context().currentElement());
System.out.println(option.getText()+","+value.getText());
*/
AlternativeElement e = context().currentElement();
if ( e instanceof StringLiteralElement ||
e instanceof TokenRefElement ||
e instanceof WildcardElement )
{
((GrammarAtom)e).setOption(option, value);
}
else {
tool.error("cannot use element option ("+option.getText()+
") for this kind of element",
grammar.getFilename(), option.getLine());
}
}
/** Add an exception handler to an exception spec */
public void refExceptionHandler(Token exTypeAndName, Token action) {
super.refExceptionHandler(exTypeAndName, action);
if (currentExceptionSpec == null)
{
tool.panic("exception handler processing internal error");
}
currentExceptionSpec.addHandler(new ExceptionHandler(exTypeAndName, action));
}
public void refInitAction(Token action) {
super.refAction(action);
context().block.setInitAction(action.getText());
}
public void refMemberAction(Token act) {
grammar.classMemberAction = act;
}
public void refPreambleAction(Token act) {
super.refPreambleAction(act);
}
// Only called for rule blocks
public void refReturnAction(Token returnAction) {
if (grammar instanceof LexerGrammar) {
String name = CodeGenerator.lexerRuleName(((RuleBlock)context().block).getRuleName());
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(name);
if (rs.access.equals("public")) {
tool.warning("public Lexical rules cannot specify return type", grammar.getFilename(), returnAction.getLine());
return;
}
}
((RuleBlock)context().block).returnAction = returnAction.getText();
}
public void refRule(Token idAssign,
Token r,
Token label,
Token args,
int autoGenType)
{
// Disallow parser rule references in the lexer
if (grammar instanceof LexerGrammar) {
// if (!Character.isUpperCase(r.getText().charAt(0))) {
if ( r.type != ANTLRTokenTypes.TOKEN_REF ) {
tool.error("Parser rule " + r.getText() + " referenced in lexer");
return;
}
if (autoGenType == GrammarElement.AUTO_GEN_CARET) {
tool.error("AST specification ^ not allowed in lexer", grammar.getFilename(), r.getLine());
}
}
super.refRule(idAssign, r, label, args, autoGenType);
lastRuleRef = new RuleRefElement(grammar, r, autoGenType);
if (args != null)
{
lastRuleRef.setArgs(args.getText());
}
if (idAssign != null)
{
lastRuleRef.setIdAssign(idAssign.getText());
}
addElementToCurrentAlt(lastRuleRef);
String id = r.getText();
// if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
if ( r.type == ANTLRTokenTypes.TOKEN_REF ) { // lexer rule?
id = CodeGenerator.lexerRuleName(id);
}
// update symbol table so it knows what nodes reference the rule.
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(id);
rs.addReference(lastRuleRef);
labelElement(lastRuleRef, label);
}
public void refSemPred(Token pred) {
//System.out.println("refSemPred "+pred.getText());
super.refSemPred(pred);
//System.out.println("context().block: "+context().block);
if ( context().currentAlt().atStart() ) {
context().currentAlt().semPred = pred.getText();
}
else {
ActionElement a = new ActionElement(grammar,pred);
a.isSemPred = true;
addElementToCurrentAlt(a);
}
//System.out.println("DONE refSemPred "+pred.getText());
}
public void refStringLiteral(Token lit, Token label, int autoGenType, boolean lastInRule) {
super.refStringLiteral(lit, label, autoGenType, lastInRule);
if (grammar instanceof TreeWalkerGrammar && autoGenType == GrammarElement.AUTO_GEN_CARET) {
tool.error("^ not allowed in here for tree-walker", grammar.getFilename(), lit.getLine());
}
StringLiteralElement sl = new StringLiteralElement(grammar, lit, autoGenType);
// If case-insensitive, then check each char of the stirng literal
if (grammar instanceof LexerGrammar && !((LexerGrammar)grammar).caseSensitive) {
for (int i = 1; i < lit.getText().length()-1; i++) {
char c = lit.getText().charAt(i);
if (c < 128 && Character.toLowerCase(c) != c) {
tool.warning("Characters of string literal must be lowercase when caseSensitive=false", grammar.getFilename(), lit.getLine());
break;
}
}
}
addElementToCurrentAlt(sl);
labelElement(sl, label);
// if ignore option is set, must add an optional call to the specified rule.
String ignore = ruleBlock.getIgnoreRule();
if ( !lastInRule && ignore!=null ) {
addElementToCurrentAlt(createOptionalRuleRef(ignore, lit.getLine()));
}
}
public void refToken(Token idAssign, Token t, Token label, Token args,
boolean inverted, int autoGenType, boolean lastInRule) {
if (grammar instanceof LexerGrammar) {
// In lexer, token references are really rule references
if (autoGenType == GrammarElement.AUTO_GEN_CARET) {
tool.error("AST specification ^ not allowed in lexer", grammar.getFilename(), t.getLine());
}
if (inverted) {
tool.error("~TOKEN is not allowed in lexer", grammar.getFilename(), t.getLine());
}
refRule(idAssign, t, label, args, autoGenType);
// if ignore option is set, must add an optional call to the specified token rule.
String ignore = ruleBlock.getIgnoreRule();
if ( !lastInRule && ignore!=null ) {
addElementToCurrentAlt(createOptionalRuleRef(ignore, t.getLine()));
}
} else {
// Cannot have token ref args or assignment outside of lexer
if (idAssign!= null)
{
tool.error("Assignment from token reference only allowed in lexer", grammar.getFilename(), idAssign.getLine());
}
if (args != null)
{
tool.error("Token reference arguments only allowed in lexer", grammar.getFilename(), args.getLine());
}
super.refToken(idAssign, t, label, args, inverted, autoGenType, lastInRule);
TokenRefElement te = new TokenRefElement(grammar, t, inverted, autoGenType);
addElementToCurrentAlt(te);
labelElement(te, label);
}
}
public void refTokenRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule) {
if (grammar instanceof LexerGrammar) {
tool.error("Token range not allowed in lexer", grammar.getFilename(), t1.getLine());
return;
}
super.refTokenRange(t1, t2, label, autoGenType, lastInRule);
TokenRangeElement tr = new TokenRangeElement(grammar, t1, t2, autoGenType);
if (tr.end < tr.begin) {
tool.error("Malformed range.", grammar.getFilename(), t1.getLine());
return;
}
addElementToCurrentAlt(tr);
labelElement(tr, label);
}
public void refTreeSpecifier(Token treeSpec) {
context().currentAlt().treeSpecifier = treeSpec;
}
public void refWildcard(Token t, Token label, int autoGenType) {
super.refWildcard(t, label, autoGenType);
WildcardElement wc = new WildcardElement(grammar, t, autoGenType);
addElementToCurrentAlt(wc);
labelElement(wc, label);
}
/** Get ready to process a new grammar */
public void reset() {
super.reset();
blocks = new LList();
lastRuleRef = null;
ruleEnd = null;
ruleBlock = null;
nested = 0;
currentExceptionSpec = null;
grammarError = false;
}
public void setArgOfRuleRef(Token argAction) {
super.setArgOfRuleRef(argAction);
lastRuleRef.setArgs(argAction.getText());
}
public static void setBlock(AlternativeBlock b, AlternativeBlock src) {
b.setAlternatives(src.getAlternatives());
b.initAction = src.initAction;
//b.lookaheadDepth = src.lookaheadDepth;
b.label = src.label;
b.hasASynPred = src.hasASynPred;
b.hasAnAction = src.hasAnAction;
b.warnWhenFollowAmbig = src.warnWhenFollowAmbig;
b.generateAmbigWarnings = src.generateAmbigWarnings;
b.line = src.line;
b.greedy = src.greedy;
b.greedySet = src.greedySet;
}
public void setRuleOption(Token key, Token value) {
//((RuleBlock)context().block).setOption(key, value);
ruleBlock.setOption(key, value);
}
public void setSubruleOption(Token key, Token value) {
((AlternativeBlock)context().block).setOption(key, value);
}
public void synPred() {
if (context().block.not) {
tool.error("'~' cannot be applied to syntactc predicate", grammar.getFilename(), context().block.getLine());
}
// create the right kind of object now that we know what that is
// and switch the list of alternatives. Adjust the stack of blocks.
// copy any init action also.
SynPredBlock b = new SynPredBlock(grammar);
setBlock(b,context().block);
BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
blocks.push(new BlockContext());
context().block = b;
context().blockEnd = old.blockEnd;
context().blockEnd.block = b;
}
public void zeroOrMoreSubRule() {
if (context().block.not) {
tool.error("'~' cannot be applied to (...)+ subrule", grammar.getFilename(), context().block.getLine());
}
// create the right kind of object now that we know what that is
// and switch the list of alternatives. Adjust the stack of blocks.
// copy any init action also.
ZeroOrMoreBlock b = new ZeroOrMoreBlock(grammar);
setBlock(b,context().block);
BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
blocks.push(new BlockContext());
context().block = b;
context().blockEnd = old.blockEnd;
context().blockEnd.block = b;
}
}
1.1 e/src/jsrc/antlr/MismatchedCharException.java
Index: MismatchedCharException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: MismatchedCharException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
public class MismatchedCharException extends RecognitionException {
// Types of chars
public static final int CHAR = 1;
public static final int NOT_CHAR = 2;
public static final int RANGE = 3;
public static final int NOT_RANGE = 4;
public static final int SET = 5;
public static final int NOT_SET = 6;
// One of the above
public int mismatchType;
// what was found on the input stream
public char foundChar;
// For CHAR/NOT_CHAR and RANGE/NOT_RANGE
public int expecting;
// For RANGE/NOT_RANGE (expecting is lower bound of range)
public int upper;
// For SET/NOT_SET
public BitSet set;
// who knows...they may want to ask scanner questions
public CharScanner scanner;
/**
* MismatchedCharException constructor comment.
*/
public MismatchedCharException() {
super("Mismatched char");
}
// Expected range / not range
public MismatchedCharException(char c, char lower, char upper_, boolean matchNot, CharScanner scanner) {
super("Mismatched char");
foundChar = c;
expecting = lower;
upper = upper_;
// get instantaneous values of file/line/column
this.line = scanner.getLine();
this.fileName = scanner.getFilename();
this.column = scanner.getColumn();
this.scanner = scanner;
mismatchType = matchNot ? NOT_RANGE : RANGE;
}
// Expected token / not token
public MismatchedCharException(char c, char expecting_, boolean matchNot, CharScanner scanner) {
super("Mismatched char");
foundChar = c;
expecting = expecting_;
// get instantaneous values of file/line/column
this.line = scanner.getLine();
this.fileName = scanner.getFilename();
this.column = scanner.getColumn();
this.scanner = scanner;
mismatchType = matchNot ? NOT_CHAR : CHAR;
}
// Expected BitSet / not BitSet
public MismatchedCharException(char c, BitSet set_, boolean matchNot, CharScanner scanner) {
super("Mismatched char");
foundChar = c;
set = set_;
// get instantaneous values of file/line/column
this.line = scanner.getLine();
this.fileName = scanner.getFilename();
this.column = scanner.getColumn();
this.scanner = scanner;
mismatchType = matchNot ? NOT_SET : SET;
}
/**
* MismatchedCharException constructor comment.
* @param s java.lang.String
*/
public MismatchedCharException(String s, int line) {
super(s);
}
/**
* Returns the error message that happened on the line/col given.
* Copied from toString().
*/
public String getMessage() {
StringBuffer sb = new StringBuffer();
switch (mismatchType) {
case CHAR :
sb.append("expecting '" + (char)expecting + "', found '" + (char)foundChar + "'");
break;
case NOT_CHAR :
sb.append("expecting anything but '" + (char)expecting + "'; got it anyway");
break;
case RANGE :
sb.append("expecting token in range: '" + (char)expecting + "'..'" + (char)upper + "', found '" + (char)foundChar + "'");
break;
case NOT_RANGE :
sb.append("expecting token NOT in range: " + (char)expecting + "'..'" + (char)upper + "', found '" + (char)foundChar + "'");
break;
case SET :
case NOT_SET :
sb.append("expecting " + (mismatchType == NOT_SET ? "NOT " : "") + "one of (");
int[] elems = set.toArray();
for (int i = 0; i < elems.length; i++) {
sb.append(" '");
sb.append((char)elems[i]);
sb.append("'");
}
sb.append("), found '" + (char)foundChar + "'");
break;
default :
sb.append(super.getMessage());
break;
}
return sb.toString();
}
}
1.1 e/src/jsrc/antlr/MismatchedTokenException.java
Index: MismatchedTokenException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: MismatchedTokenException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
import antlr.collections.AST;
public class MismatchedTokenException extends RecognitionException {
// Token names array for formatting
String[] tokenNames;
// The token that was encountered
public Token token;
// The offending AST node if tree walking
public AST node;
String tokenText=null; // taken from node or token object
// Types of tokens
public static final int TOKEN = 1;
public static final int NOT_TOKEN = 2;
public static final int RANGE = 3;
public static final int NOT_RANGE = 4;
public static final int SET = 5;
public static final int NOT_SET = 6;
// One of the above
public int mismatchType;
// For TOKEN/NOT_TOKEN and RANGE/NOT_RANGE
public int expecting;
// For RANGE/NOT_RANGE (expecting is lower bound of range)
public int upper;
// For SET/NOT_SET
public BitSet set;
/** Looking for AST wildcard, didn't find it */
public MismatchedTokenException() {
super("Mismatched Token: expecting any AST node");
}
// Expected range / not range
public MismatchedTokenException(String[] tokenNames_, AST node, int lower, int upper_, boolean matchNot) {
super("Mismatched Token");
tokenNames = tokenNames_;
this.node = node;
if ( node==null ) {
tokenText = "<empty tree>";
}
else {
tokenText = node.toString();
}
expecting = lower;
upper = upper_;
this.fileName = "<AST>";
mismatchType = matchNot ? NOT_RANGE : RANGE;
}
// Expected token / not token
public MismatchedTokenException(String[] tokenNames_, AST node, int expecting_, boolean matchNot) {
super("Mismatched Token");
tokenNames = tokenNames_;
this.node = node;
if ( node==null ) {
tokenText = "<empty tree>";
}
else {
tokenText = node.toString();
}
expecting = expecting_;
this.fileName = "<AST>";
mismatchType = matchNot ? NOT_TOKEN : TOKEN;
}
// Expected BitSet / not BitSet
public MismatchedTokenException(String[] tokenNames_, AST node, BitSet set_, boolean matchNot) {
super("Mismatched Token");
tokenNames = tokenNames_;
this.node = node;
if ( node==null ) {
tokenText = "<empty tree>";
}
else {
tokenText = node.toString();
}
set = set_;
this.fileName = "<AST>";
mismatchType = matchNot ? NOT_SET : SET;
}
// Expected range / not range
public MismatchedTokenException(String[] tokenNames_, Token token_, int lower, int upper_, boolean matchNot, String fileName) {
super("Mismatched Token");
tokenNames = tokenNames_;
token = token_;
line = token.getLine();
column = token.getColumn();
tokenText = token.getText();
expecting = lower;
upper = upper_;
this.fileName = fileName;
mismatchType = matchNot ? NOT_RANGE : RANGE;
}
// Expected token / not token
public MismatchedTokenException(String[] tokenNames_, Token token_, int expecting_, boolean matchNot, String fileName) {
super("Mismatched Token");
tokenNames = tokenNames_;
token = token_;
line = token.getLine();
column = token.getColumn();
tokenText = token.getText();
expecting = expecting_;
this.fileName = fileName;
mismatchType = matchNot ? NOT_TOKEN : TOKEN;
}
// Expected BitSet / not BitSet
public MismatchedTokenException(String[] tokenNames_, Token token_, BitSet set_, boolean matchNot, String fileName) {
super("Mismatched Token");
tokenNames = tokenNames_;
token = token_;
line = token.getLine();
column = token.getColumn();
tokenText = token.getText();
set = set_;
this.fileName = fileName;
mismatchType = matchNot ? NOT_SET : SET;
}
/**
* @deprecated As of ANTLR 2.7.0
*/
public String getErrorMessage() {
return getMessage();
}
/**
* Returns the error message that happened on the line/col given.
* Copied from toString().
*/
public String getMessage() {
StringBuffer sb = new StringBuffer();
switch (mismatchType) {
case TOKEN :
sb.append("expecting " + tokenName(expecting) + ", found '" + tokenText + "'");
break;
case NOT_TOKEN :
sb.append("expecting anything but " + tokenName(expecting) + "; got it anyway");
break;
case RANGE :
sb.append("expecting token in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'");
break;
case NOT_RANGE :
sb.append("expecting token NOT in range: " + tokenName(expecting) + ".." + tokenName(upper) + ", found '" + tokenText + "'");
break;
case SET :
case NOT_SET :
sb.append("expecting " + (mismatchType == NOT_SET ? "NOT " : "") + "one of (");
int[] elems = set.toArray();
for (int i = 0; i < elems.length; i++) {
sb.append(" ");
sb.append(tokenName(elems[i]));
}
sb.append("), found '" + tokenText + "'");
break;
default :
sb.append(super.getMessage());
break;
}
return sb.toString();
}
private String tokenName(int tokenType)
{
if (tokenType == Token.INVALID_TYPE) {
return "<Set of tokens>";
}
else if (tokenType < 0 || tokenType >= tokenNames.length) {
return "<" + String.valueOf(tokenType) + ">";
}
else {
return tokenNames[tokenType];
}
}
/**
* @return a string representation of this exception.
*/
public String toString() {
if (token != null) { // AST or Token?
return FileLineFormatter.getFormatter().getFormatString(fileName,line)+getMessage();
}
return getMessage();
}
}
1.1 e/src/jsrc/antlr/NameSpace.java
Index: NameSpace.java
===================================================================
package antlr;
/**
* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* Container for a C++ namespace specification. Namespaces can be
* nested, so this contains a vector of all the nested names.
*
* @author David Wagner (JPL/Caltech) 8-12-00
*
* $Id: NameSpace.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Vector;
import java.util.Enumeration;
import java.io.PrintWriter;
import java.util.StringTokenizer;
public class NameSpace
{
private Vector names = new Vector();
public NameSpace(String name)
{
parse(name);
}
/**
* Parse a C++ namespace declaration into seperate names
* splitting on :: We could easily parameterize this to make
* the delimiter a language-specific parameter, or use subclasses
* to support C++ namespaces versus java packages. -DAW
*/
protected void parse(String name)
{
StringTokenizer tok = new StringTokenizer(name, "::");
while (tok.hasMoreTokens())
names.addElement(tok.nextToken());
}
/**
* Method to generate the required C++ namespace declarations
*/
void emitDeclarations(PrintWriter out)
{
for( Enumeration n = names.elements(); n.hasMoreElements(); )
{
String s = (String)n.nextElement();
out.println("ANTLR_BEGIN_NAMESPACE("+s+")");
}
}
/**
* Method to generate the required C++ namespace closures
*/
void emitClosures(PrintWriter out)
{
for(int i=0; i < names.size(); ++i)
out.println("ANTLR_END_NAMESPACE");
}
}
1.1 e/src/jsrc/antlr/NoViableAltException.java
Index: NoViableAltException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: NoViableAltException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.AST;
public class NoViableAltException extends RecognitionException {
public Token token;
public AST node; // handles parsing and treeparsing
public NoViableAltException(AST t) {
super("NoViableAlt");
node = t;
fileName = "<AST>";
}
public NoViableAltException(Token t, String fileName) {
super("NoViableAlt");
token = t;
line = t.getLine();
column = t.getColumn();
this.fileName = fileName;
}
/**
* @deprecated As of ANTLR 2.7.0
*/
public String getErrorMessage () {
return getMessage();
}
/**
* Returns a clean error message (no line number/column information)
*/
public String getMessage ()
{
if (token != null) {
return "unexpected token: "+token.getText();
}
// must a tree parser error if token==null
if ( node==TreeParser.ASTNULL ) {
return "unexpected end of subtree";
}
return "unexpected AST node: "+node.toString();
}
/**
* Returns a string representation of this exception.
*/
public String toString() {
if ( token!=null ) { // AST or Token?
return FileLineFormatter.getFormatter().getFormatString(fileName,line)+getMessage();
}
return getMessage();
}
}
1.1 e/src/jsrc/antlr/NoViableAltForCharException.java
Index: NoViableAltForCharException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: NoViableAltForCharException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class NoViableAltForCharException extends RecognitionException {
public char foundChar;
public NoViableAltForCharException(char c, CharScanner scanner) {
super("NoViableAlt");
foundChar = c;
this.line = scanner.getLine();
this.fileName = scanner.getFilename();
}
public NoViableAltForCharException(char c, String fileName, int line) {
super("NoViableAlt");
foundChar = c;
this.line = line;
this.fileName = fileName;
}
/**
* @deprecated As of ANTLR 2.7.0
*/
public String getErrorMessage()
{
return getMessage();
}
/**
* Returns a clean error message (no line number/column information)
*/
public String getMessage()
{
return "unexpected char: "+(char)foundChar;
}
}
1.1 e/src/jsrc/antlr/OneOrMoreBlock.java
Index: OneOrMoreBlock.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: OneOrMoreBlock.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class OneOrMoreBlock extends BlockWithImpliedExitPath {
public OneOrMoreBlock(Grammar g) {
super(g);
}
public OneOrMoreBlock(Grammar g, int line) {
super(g, line);
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
return super.toString() + "+";
}
}
1.1 e/src/jsrc/antlr/Parser.java
Index: Parser.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: Parser.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
import antlr.collections.AST;
import antlr.collections.impl.ASTArray;
/**A generic ANTLR parser (LL(k) for k>=1) containing a bunch of
* utility routines useful at any lookahead depth. We distinguish between
* the LL(1) and LL(k) parsers because of efficiency. This may not be
* necessary in the near future.
*
* Each parser object contains the state of the parse including a lookahead
* cache (the form of which is determined by the subclass), whether or
* not the parser is in guess mode, where tokens come from, etc...
*
* <p>
* During <b>guess</b> mode, the current lookahead token(s) and token type(s)
* cache must be saved because the token stream may not have been informed
* to save the token (via <tt>mark</tt>) before the <tt>try</tt> block.
* Guessing is started by:
* <ol>
* <li>saving the lookahead cache.
* <li>marking the current position in the TokenBuffer.
* <li>increasing the guessing level.
* </ol>
*
* After guessing, the parser state is restored by:
* <ol>
* <li>restoring the lookahead cache.
* <li>rewinding the TokenBuffer.
* <li>decreasing the guessing level.
* </ol>
*
* @see antlr.Token
* @see antlr.TokenBuffer
* @see antlr.Tokenizer
* @see antlr.LL1Parser
* @see antlr.LLkParser
*/
import java.io.IOException;
import antlr.debug.MessageListener;
import antlr.debug.ParserListener;
import antlr.debug.ParserMatchListener;
import antlr.debug.ParserTokenListener;
import antlr.debug.SemanticPredicateListener;
import antlr.debug.SyntacticPredicateListener;
import antlr.debug.TraceListener;
public abstract class Parser {
protected ParserSharedInputState inputState;
/** Nesting level of registered handlers */
// protected int exceptionLevel = 0;
/** Table of token type to token names */
protected String[] tokenNames;
/** AST return value for a rule is squirreled away here */
protected AST returnAST;
/** AST support code; parser and treeparser delegate to this object */
protected ASTFactory astFactory = new ASTFactory();
private boolean ignoreInvalidDebugCalls = false;
/** Used to keep track of indentdepth for traceIn/Out */
protected int traceDepth = 0;
public Parser() {
inputState = new ParserSharedInputState();
}
public Parser(ParserSharedInputState state) {
inputState = state;
}
public void addMessageListener(MessageListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addMessageListener() is only valid if parser built for debugging");
}
public void addParserListener(ParserListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addParserListener() is only valid if parser built for debugging");
}
public void addParserMatchListener(ParserMatchListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addParserMatchListener() is only valid if parser built for debugging");
}
public void addParserTokenListener(ParserTokenListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addParserTokenListener() is only valid if parser built for debugging");
}
public void addSemanticPredicateListener(SemanticPredicateListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addSemanticPredicateListener() is only valid if parser built for debugging");
}
public void addSyntacticPredicateListener(SyntacticPredicateListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addSyntacticPredicateListener() is only valid if parser built for debugging");
}
public void addTraceListener(TraceListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("addTraceListener() is only valid if parser built for debugging");
}
/**Get another token object from the token stream */
public abstract void consume() throws TokenStreamException;
/** Consume tokens until one matches the given token */
public void consumeUntil(int tokenType) throws TokenStreamException {
while (LA(1) != Token.EOF_TYPE && LA(1) != tokenType)
{
consume();
}
}
/** Consume tokens until one matches the given token set */
public void consumeUntil(BitSet set) throws TokenStreamException {
while (LA(1) != Token.EOF_TYPE && !set.member(LA(1))) {
consume();
}
}
protected void defaultDebuggingSetup(TokenStream lexer, TokenBuffer tokBuf) {
// by default, do nothing -- we're not debugging
}
/** Get the AST return value squirreled away in the parser */
public AST getAST() {
return returnAST;
}
public ASTFactory getASTFactory() {
return astFactory;
}
public String getFilename() {return inputState.filename;}
public ParserSharedInputState getInputState() {
return inputState;
}
public void setInputState(ParserSharedInputState state) {
inputState = state;
}
public String getTokenName(int num) {
return tokenNames[num];
}
public String[] getTokenNames() {
return tokenNames;
}
public boolean isDebugMode() {return false;}
/** Return the token type of the ith token of lookahead where i=1
* is the current token being examined by the parser (i.e., it
* has not been matched yet).
*/
public abstract int LA(int i) throws TokenStreamException;
/**Return the ith token of lookahead */
public abstract Token LT(int i) throws TokenStreamException;
// Forwarded to TokenBuffer
public int mark() {
return inputState.input.mark();
}
/**Make sure current lookahead symbol matches token type <tt>t</tt>.
* Throw an exception upon mismatch, which is catch by either the
* error handler or by the syntactic predicate.
*/
public void match(int t) throws MismatchedTokenException, TokenStreamException {
if ( LA(1)!=t )
throw new MismatchedTokenException(tokenNames, LT(1), t, false, getFilename());
else
// mark token as consumed -- fetch next token deferred until LA/LT
consume();
}
/**Make sure current lookahead symbol matches the given set
* Throw an exception upon mismatch, which is catch by either the
* error handler or by the syntactic predicate.
*/
public void match(BitSet b) throws MismatchedTokenException, TokenStreamException {
if ( !b.member(LA(1)) )
throw new MismatchedTokenException(tokenNames, LT(1), b, false, getFilename());
else
// mark token as consumed -- fetch next token deferred until LA/LT
consume();
}
public void matchNot(int t) throws MismatchedTokenException, TokenStreamException {
if ( LA(1)==t )
// Throws inverted-sense exception
throw new MismatchedTokenException(tokenNames, LT(1), t, true, getFilename());
else
// mark token as consumed -- fetch next token deferred until LA/LT
consume();
}
public static void panic() {
System.err.println("Parser: panic");
System.exit(1);
}
public void removeMessageListener(MessageListener l) {
if (!ignoreInvalidDebugCalls)
throw new RuntimeException("removeMessageListener() is only valid if parser built for debugging");
}
public void removeParserListener(ParserListener l) {
if (!ignoreInvalidDebugCalls)
throw new RuntimeException("removeParserListener() is only valid if parser built for debugging");
}
public void removeParserMatchListener(ParserMatchListener l) {
if (!ignoreInvalidDebugCalls)
throw new RuntimeException("removeParserMatchListener() is only valid if parser built for debugging");
}
public void removeParserTokenListener(ParserTokenListener l) {
if (!ignoreInvalidDebugCalls)
throw new RuntimeException("removeParserTokenListener() is only valid if parser built for debugging");
}
public void removeSemanticPredicateListener(SemanticPredicateListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("removeSemanticPredicateListener() is only valid if parser built for debugging");
}
public void removeSyntacticPredicateListener(SyntacticPredicateListener l) {
if (!ignoreInvalidDebugCalls)
throw new IllegalArgumentException("removeSyntacticPredicateListener() is only valid if parser built for debugging");
}
public void removeTraceListener(TraceListener l) {
if (!ignoreInvalidDebugCalls)
throw new RuntimeException("removeTraceListener() is only valid if parser built for debugging");
}
/** Parser error-reporting function can be overridden in subclass */
public void reportError(RecognitionException ex) {
System.err.println(ex);
}
/** Parser error-reporting function can be overridden in subclass */
public void reportError(String s) {
if ( getFilename()==null ) {
System.err.println("error: " + s);
}
else {
System.err.println(getFilename()+": error: " + s);
}
}
/** Parser warning-reporting function can be overridden in subclass */
public void reportWarning(String s) {
if ( getFilename()==null ) {
System.err.println("warning: "+s);
}
else {
System.err.println(getFilename()+": warning: " + s);
}
}
public void rewind(int pos) {
inputState.input.rewind(pos);
}
/** Specify an object with support code (shared by
* Parser and TreeParser. Normally, the programmer
* does not play with this, using setASTNodeType instead.
*/
public void setASTFactory(ASTFactory f) {
astFactory = f;
}
public void setASTNodeClass(String cl) {
astFactory.setASTNodeType(cl);
}
/** Specify the type of node to create during tree building; use setASTNodeClass now
* to be consistent with Token Object Type accessor.
*/
public void setASTNodeType (String nodeType) {
setASTNodeClass(nodeType);
}
public void setDebugMode(boolean debugMode) {
if (!ignoreInvalidDebugCalls)
throw new RuntimeException("setDebugMode() only valid if parser built for debugging");
}
public void setFilename(String f) {inputState.filename=f;}
public void setIgnoreInvalidDebugCalls(boolean value) {
ignoreInvalidDebugCalls = value;
}
/** Set or change the input token buffer */
public void setTokenBuffer(TokenBuffer t) { inputState.input = t; }
public void traceIndent() {
for( int i = 0; i < traceDepth; i++ )
System.out.print(" ");
}
public void traceIn(String rname) throws TokenStreamException {
traceDepth += 1;
traceIndent();
System.out.println("> "+rname+"; LA(1)=="+LT(1).getText()+
((inputState.guessing>0)?" [guessing]":""));
}
public void traceOut(String rname) throws TokenStreamException {
traceIndent();
System.out.println("< "+rname+"; LA(1)=="+LT(1).getText()+
((inputState.guessing>0)?" [guessing]":""));
traceDepth -= 1;
}
}
1.1 e/src/jsrc/antlr/ParserGrammar.java
Index: ParserGrammar.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ParserGrammar.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
/** Parser-specific grammar subclass */
class ParserGrammar extends Grammar {
ParserGrammar(String className_, Tool tool_, String superClass) {
super(className_, tool_, superClass);
}
/** Top-level call to generate the code for this grammar */
public void generate() throws IOException {
generator.gen(this);
}
// Get name of class from which generated parser/lexer inherits
protected String getSuperClass() {
// if debugging, choose the debugging version of the parser
if (debuggingOutput)
return "debug.LLkDebuggingParser";
return "LLkParser";
}
/**Process command line arguments.
* -trace have all rules call traceIn/traceOut
* -traceParser have parser rules call traceIn/traceOut
* -debug generate debugging output for parser debugger
*/
public void processArguments(String[] args) {
for (int i=0; i<args.length; i++) {
if ( args[i].equals("-trace") ) {
traceRules = true;
Tool.setArgOK(i);
}
else if ( args[i].equals("-traceParser") ) {
traceRules = true;
Tool.setArgOK(i);
}
else if ( args[i].equals("-debug") ) {
debuggingOutput = true;
Tool.setArgOK(i);
}
}
}
/** Set parser options -- performs action on the following options:
*/
public boolean setOption(String key, Token value) {
String s = value.getText();
if (key.equals("buildAST")) {
if (s.equals("true")) {
buildAST = true;
} else if (s.equals("false")) {
buildAST = false;
} else {
tool.error("buildAST option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("interactive")) {
if (s.equals("true")) {
interactive = true;
} else if (s.equals("false")) {
interactive = false;
} else {
tool.error("interactive option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("ASTLabelType")) {
super.setOption(key, value);
return true;
}
if (super.setOption(key, value)) {
return true;
}
tool.error("Invalid option: " + key, getFilename(), value.getLine());
return false;
}
}
1.1 e/src/jsrc/antlr/ParserSharedInputState.java
Index: ParserSharedInputState.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ParserSharedInputState.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** This object contains the data associated with an
* input stream of tokens. Multiple parsers
* share a single ParserSharedInputState to parse
* the same stream of tokens.
*/
public class ParserSharedInputState {
/** Where to get token objects */
protected TokenBuffer input;
/** Are we guessing (guessing>0)? */
public int guessing = 0;
/** What file (if known) caused the problem? */
protected String filename;
}
1.1 e/src/jsrc/antlr/RecognitionException.java
Index: RecognitionException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: RecognitionException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class RecognitionException extends ANTLRException {
public String fileName; // not used by treeparsers
public int line; // not used by treeparsers
public int column; // not used by treeparsers
public RecognitionException() {
super("parsing error");
}
/**
* RecognitionException constructor comment.
* @param s java.lang.String
*/
public RecognitionException(String s) {
super(s);
}
/**
* RecognitionException constructor comment.
* @param s java.lang.String
*/
public RecognitionException(String s, String fileName, int line) {
super(s);
this.fileName = fileName;
this.line = line;
}
public int getColumn() { return column; }
/** @deprecated As of ANTLR 2.7.0 */
public String getErrorMessage () { return getMessage(); }
public String getFilename() {
return fileName;
}
public int getLine() { return line; }
public String toString() {
return FileLineFormatter.getFormatter().
getFormatString(fileName,line)+getMessage();
}
}
1.1 e/src/jsrc/antlr/RuleBlock.java
Index: RuleBlock.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: RuleBlock.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.Vector;
import java.util.Hashtable;
/**A list of alternatives and info contained in
* the rule definition.
*/
public class RuleBlock extends AlternativeBlock {
protected String ruleName;
protected String argAction = null; // string for rule arguments [...]
protected String throwsSpec = null;
protected String returnAction = null;// string for rule return type(s) <...>
protected RuleEndElement endNode; // which node ends this rule?
// Generate literal-testing code for lexer rule?
protected boolean testLiterals=false;
Vector labeledElements; // List of labeled elements found in this rule
// This is a list of AlternativeElement (or subclass)
protected boolean[] lock; // for analysis; used to avoid infinite loops
// 1..k
protected Lookahead cache[];// Each rule can cache it's lookahead computation.
// This cache contains an epsilon
// imaginary token if the FOLLOW is required. No
// FOLLOW information is cached here.
// The FIRST(rule) is stored in this cache; 1..k
// This set includes FIRST of all alts.
Hashtable exceptionSpecs; // table of String-to-ExceptionSpec.
// grammar-settable options
protected boolean defaultErrorHandler = true;
protected String ignoreRule = null;
/** Construct a named rule. */
public RuleBlock(Grammar g, String r) {
super(g);
ruleName = r;
labeledElements = new Vector();
cache = new Lookahead[g.maxk+1];
exceptionSpecs = new Hashtable();
setAutoGen(g instanceof ParserGrammar);
}
/** Construct a named rule with line number information */
public RuleBlock(Grammar g, String r, int line, boolean doAutoGen_) {
this(g,r);
this.line = line;
setAutoGen(doAutoGen_);
}
public void addExceptionSpec(ExceptionSpec ex) {
if (findExceptionSpec(ex.label) != null) {
if (ex.label != null) {
grammar.tool.error("Rule '" + ruleName + "' already has an exception handler for label: " + ex.label);
}
else {
grammar.tool.error("Rule '" + ruleName + "' already has an exception handler");
}
}
else {
exceptionSpecs.put( (ex.label==null ? "" : ex.label.getText()), ex);
}
}
public ExceptionSpec findExceptionSpec(Token label) {
return (ExceptionSpec)exceptionSpecs.get(label==null ? "" : label.getText());
}
public ExceptionSpec findExceptionSpec(String label) {
return (ExceptionSpec)exceptionSpecs.get(label==null ? "" : label);
}
public void generate() {
grammar.generator.gen(this);
}
public boolean getDefaultErrorHandler() {
return defaultErrorHandler;
}
public RuleEndElement getEndElement() {
return endNode;
}
public String getIgnoreRule() {
return ignoreRule;
}
public String getRuleName() {
return ruleName;
}
public boolean getTestLiterals() {
return testLiterals;
}
public boolean isLexerAutoGenRule() {
return ruleName.equals("nextToken");
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public void prepareForAnalysis() {
super.prepareForAnalysis();
lock = new boolean[grammar.maxk+1];
}
// rule option values
public void setDefaultErrorHandler(boolean value) {
defaultErrorHandler = value;
}
public void setEndElement(RuleEndElement re) {
endNode = re;
}
public void setOption(Token key, Token value) {
if (key.getText().equals("defaultErrorHandler")) {
if (value.getText().equals("true")) {
defaultErrorHandler = true;
} else if (value.getText().equals("false")) {
defaultErrorHandler = false;
} else {
grammar.tool.error("Value for defaultErrorHandler must be true or false", grammar.getFilename(), key.getLine());
}
}
else if (key.getText().equals("testLiterals")) {
if (!(grammar instanceof LexerGrammar)) {
grammar.tool.error("testLiterals option only valid for lexer rules", grammar.getFilename(), key.getLine());
}
else {
if (value.getText().equals("true")) {
testLiterals = true;
} else if (value.getText().equals("false")) {
testLiterals = false;
} else {
grammar.tool.error("Value for testLiterals must be true or false", grammar.getFilename(), key.getLine());
}
}
}
else if (key.getText().equals("ignore")) {
if (!(grammar instanceof LexerGrammar)) {
grammar.tool.error("ignore option only valid for lexer rules", grammar.getFilename(), key.getLine());
}
else {
ignoreRule = value.getText();
}
}
else if (key.getText().equals("paraphrase")) {
if (!(grammar instanceof LexerGrammar)) {
grammar.tool.error("paraphrase option only valid for lexer rules", grammar.getFilename(), key.getLine());
}
else {
// find token def associated with this rule
TokenSymbol ts = grammar.tokenManager.getTokenSymbol(ruleName);
if ( ts==null ) {
antlr.Tool.panic("cannot find token associated with rule "+ruleName);
}
ts.setParaphrase(value.getText());
}
}
else if (key.equals("generateAmbigWarnings")) {
if (value.getText().equals("true")) {
generateAmbigWarnings = true;
} else if (value.getText().equals("false")) {
generateAmbigWarnings = false;
} else {
grammar.tool.error("Value for generateAmbigWarnings must be true or false", grammar.getFilename(), key.getLine());
}
}
else {
grammar.tool.error("Invalid rule option: " + key.getText(), grammar.getFilename(), key.getLine());
}
}
public String toString() {
String s = " FOLLOW={";
Lookahead cache[] = endNode.cache;
int k = grammar.maxk;
boolean allNull = true;
for (int j=1; j<=k; j++) {
if ( cache[j]==null ) continue;
s += cache[j].toString(",",grammar.tokenManager.getVocabulary());
allNull = false;
if ( j<k && cache[j+1]!=null ) s += ";";
}
s += "}";
if ( allNull ) s = "";
return ruleName + ": " + super.toString() + " ;"+s;
}
}
1.1 e/src/jsrc/antlr/RuleEndElement.java
Index: RuleEndElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: RuleEndElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**Contains a list of all places that reference
* this enclosing rule. Useful for FOLLOW computations.
*/
class RuleEndElement extends BlockEndElement {
protected Lookahead[] cache; // Each rule can cache it's lookahead computation.
// The FOLLOW(rule) is stored in this cache.
// 1..k
protected boolean noFOLLOW;
public RuleEndElement(Grammar g) {
super(g);
cache = new Lookahead[g.maxk+1];
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
//return " [RuleEnd]";
return "";
}
}
1.1 e/src/jsrc/antlr/RuleRefElement.java
Index: RuleRefElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: RuleRefElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class RuleRefElement extends AlternativeElement {
protected String targetRule; // which rule is being called?
protected String args=null; // were any args passed to rule?
protected String idAssign=null; // is the return type assigned to a variable?
protected String label;
public RuleRefElement(Grammar g, Token t, int autoGenType_) {
super(g, autoGenType_);
targetRule = t.getText();
// if ( Character.isUpperCase(targetRule.charAt(0)) ) { // lexer rule?
if ( t.type == ANTLRTokenTypes.TOKEN_REF ) { // lexer rule?
targetRule = CodeGenerator.lexerRuleName(targetRule);
}
line = t.getLine();
}
public RuleRefElement(Grammar g, String t, int line, int autoGenType_) {
super(g, autoGenType_);
targetRule = t;
if ( Character.isUpperCase(targetRule.charAt(0)) ) { // lexer rule?
targetRule = CodeGenerator.lexerRuleName(targetRule);
}
this.line = line;
}
public void generate() {
grammar.generator.gen(this);
}
public String getArgs() {
return args;
}
public String getIdAssign() {
return idAssign;
}
public String getLabel() {
return label;
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public void setArgs(String a) {
args = a;
}
public void setIdAssign(String id) {
idAssign = id;
}
public void setLabel(String label_) {
label = label_;
}
public String toString() {
if ( args!=null ) return " "+targetRule+args;
else return " "+targetRule;
}
}
1.1 e/src/jsrc/antlr/RuleSymbol.java
Index: RuleSymbol.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: RuleSymbol.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.Vector;
class RuleSymbol extends GrammarSymbol {
RuleBlock block; // list of alternatives
boolean defined; // has the rule been defined yet?
Vector references; // list of all nodes referencing this rule
// not strictly needed by generic symbol table
// but we will almost always analyze/gen code
String access; // access specifier for this rule
String comment; // A javadoc comment if any.
public RuleSymbol(String r) {
super(r);
references = new Vector();
}
public void addReference(RuleRefElement e) {
references.appendElement(e);
}
public RuleBlock getBlock() {
return block;
}
public RuleRefElement getReference(int i) {
return (RuleRefElement)references.elementAt(i);
}
public boolean isDefined() {
return defined;
}
public int numReferences() {
return references.size();
}
public void setBlock(RuleBlock rb) {
block = rb;
}
public void setDefined() {
defined = true;
}
}
1.1 e/src/jsrc/antlr/SatherBlockFinishingInfo.java
Index: SatherBlockFinishingInfo.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: SatherBlockFinishingInfo.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class SatherBlockFinishingInfo
{
String postscript; // what to generate to terminate block
boolean generatedSwitch; // did block finish with "default:" of switch?
boolean generatedAnIf;
/** When generating an if or switch, end-of-token lookahead sets
* will become the else or default clause, don't generate an
* error clause in this case.
*/
boolean needAnErrorClause;
public SatherBlockFinishingInfo()
{
postscript=null;
generatedSwitch=generatedSwitch = false;
needAnErrorClause = true;
}
public SatherBlockFinishingInfo( String ps,
boolean genS,
boolean generatedAnIf,
boolean n )
{
postscript = ps;
generatedSwitch = genS;
this.generatedAnIf = generatedAnIf;
needAnErrorClause = n;
}
}
1.1 e/src/jsrc/antlr/SatherCharFormatter.java
Index: SatherCharFormatter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: SatherCharFormatter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
class SatherCharFormatter implements CharFormatter
{
/** Given a character value, return a string representing the character
* that can be embedded inside a string literal or character literal
* This works for Java/C/C++ code-generation and languages with compatible
* special-character-escapment.
* Code-generators for languages should override this method.
* @param c The character of interest.
* @param forCharLiteral true to escape for char literal, false for string literal
*/
public String escapeChar(int c, boolean forCharLiteral)
{
switch (c) {
// case GrammarAnalyzer.EPSILON_TYPE : return "<end-of-token>";
case '\n' : return "\\n";
case '\t' : return "\\t";
case '\r' : return "\\r";
case '\\' : return "\\\\";
case '\'' : return forCharLiteral ? "\\'" : "'";
case '"' : return forCharLiteral ? "\"" : "\\\"";
default :
if ( c<' '||c>126 ) {
if (c > 255) {
System.out.println("warning: Sather does not support 16-bit characters (..yet).");
return "\\u" + Integer.toString(c,16);
}
else {
return "\\" + Integer.toString(c,8);
}
}
else {
return String.valueOf((char)c);
}
}
}
/** Converts a String into a representation that can be use as a literal
* when surrounded by double-quotes.
* @param s The String to be changed into a literal
*/
public String escapeString(String s)
{
String retval = new String();
for (int i = 0; i < s.length(); i++)
{
retval += escapeChar(s.charAt(i), false);
}
return retval;
}
/** Given a character value, return a string representing the character
* literal that can be recognized by the target language compiler.
* This works for languages that use single-quotes for character literals.
* Code-generators for languages should override this method.
* @param c The character of interest.
*/
public String literalChar(int c) {
return "'" + escapeChar(c, true) + "'";
}
/** Converts a String into a string literal
* This works for languages that use double-quotes for string literals.
* Code-generators for languages should override this method.
* @param s The String to be changed into a literal
*/
public String literalString(String s)
{
return "\"" + escapeString(s) + "\"";
}
public String BitSet2BoolList( BitSet bs, String separator )
{
String result = new String();
int bs_size = bs.size();
for ( int i = 0 ; i < bs_size ; i++ ) {
if ( bs.member(i) )
result += "true";
else
result += "false";
if ( i < bs_size - 1 )
result += separator;
}
return result;
}
public String BitSet2IntList( BitSet bs, String separator )
{
String result = new String();
boolean first = true;
for ( int i = 0 ; i < bs.size() ; i++ )
if ( bs.member(i) ) {
if ( !first )
result += separator;
else
first = false;
result += i;
}
return result;
}
}
1.1 e/src/jsrc/antlr/SatherCodeGenerator.java
Index: SatherCodeGenerator.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: SatherCodeGenerator.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Enumeration;
import java.util.Hashtable;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;
/**Generate MY_PARSER.sa, MY_LEXER.sa and MY_PARSER_TOKENTYPES.sa */
public class SatherCodeGenerator extends CodeGenerator
{
// non-zero if inside syntactic predicate generation
protected int syntacticPredLevel = 0;
// Are we generating ASTs (for parsers and tree parsers) right now?
protected boolean genAST = false;
// Are we saving the text consumed (for lexers) right now?
protected boolean saveText = false;
// Grammar parameters set up to handle different grammar classes.
// These are used to get instanceof tests out of code generation
String labeledElementType;
String labeledElementASTType;
String labeledElementInit;
String commonExtraArgs;
String commonExtraParams;
String commonLocalVars;
String lt1Value;
String exceptionThrown;
String throwNoViable;
// Tracks the rule being generated. Used for mapTreeId
RuleBlock currentRule;
// Tracks the rule or labeled subrule being generated. Used for AST generation.
String currentASTResult;
// Mapping between the ids used in the current alt, and the
// names of variables used to represent their AST values.
Hashtable treeVariableMap = new Hashtable();
// Count of unnamed generated variables
int astVarNumber = 1;
// Special value used to mark duplicate in treeVariableMap
protected static final String NONUNIQUE = new String();
public static final int caseSizeThreshold = 127; // ascii is max
private Vector semPreds;
/** Create a Java code-generator using the given Grammar.
* The caller must still call setTool, setBehavior, and setAnalyzer
* before generating code.
*/
public SatherCodeGenerator() {
super();
charFormatter = new SatherCharFormatter();
}
/** Adds a semantic predicate string to the sem pred vector
These strings will be used to build an array of sem pred names
when building a debugging parser. This method should only be
called when the debug option is specified
*/
protected int addSemPred(String predicate) {
semPreds.appendElement(predicate);
return semPreds.size()-1;
}
public void exitIfError() {
if (tool.hasError) {
System.out.println("Exiting due to errors.");
System.exit(1);
}
}
/**Generate the parser, lexer, treeparser, and token types in Java */
public void gen() {
// Do the code generation
try {
// Loop over all grammars
Enumeration grammarIter = behavior.grammars.elements();
while (grammarIter.hasMoreElements()) {
Grammar g = (Grammar)grammarIter.nextElement();
// Connect all the components to each other
g.setGrammarAnalyzer(analyzer);
g.setCodeGenerator(this);
analyzer.setGrammar(g);
// To get right overloading behavior across hetrogeneous grammars
setupGrammarParameters(g);
g.generate();
exitIfError();
}
// Loop over all token managers (some of which are lexers)
Enumeration tmIter = behavior.tokenManagers.elements();
while (tmIter.hasMoreElements()) {
TokenManager tm = (TokenManager)tmIter.nextElement();
if (!tm.isReadOnly()) {
// Write the token manager tokens as Java
// this must appear before genTokenInterchange so that
// labels are set on string literals
genTokenTypes(tm);
// Write the token manager tokens as plain text
genTokenInterchange(tm);
}
exitIfError();
}
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
/** Generate code for the given grammar element.
* @param blk The {...} action to generate
*/
public void gen(ActionElement action) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genAction("+action+")");
if ( action.isSemPred ) {
genSemPred(action.actionText, action.line);
}
else {
if ( grammar.hasSyntacticPredicate ) {
println("if ( input_state.guessing = 0 ) then");
tabs++;
}
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr = processActionForTreeSpecifiers(action.actionText, action.getLine(), currentRule, tInfo);
if ( tInfo.refRuleRoot!=null ) {
// Somebody referenced "#rule", make sure translated var is valid
// assignment to #rule is left as a ref also, meaning that assignments
// with no other refs like "#rule = foo();" still forces this code to be
// generated (unnecessarily).
println(tInfo.refRuleRoot + " := current_ast.root;");
}
// dump the translated action
printAction(actionStr);
if ( tInfo.assignToRoot ) {
// Somebody did a "#rule=", reset internal currentAST.root
println("current_ast.root := "+ tInfo.refRuleRoot + ";");
// reset the child pointer too to be last sibling in sibling list
println("if ( ~void( " + tInfo.refRuleRoot + " ) and ~void( "
+ tInfo.refRuleRoot + ".first_child ) ) then" );
tabs++;
println("current_ast.child := " + tInfo.refRuleRoot + ".first_child");
tabs--;
println("else");
tabs++;
println("current_ast.child := " + tInfo.refRuleRoot + ";");
tabs--;
println("end; -- if");
println("current_ast.advance_child_to_end;");
}
if ( grammar.hasSyntacticPredicate ) {
tabs--;
println("end; -- if");
}
}
}
/** Generate code for the given grammar element.
* @param blk The "x|y|z|..." block to generate
*/
public void gen(AlternativeBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen("+blk+")");
// println("{");
genBlockPreamble(blk);
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
genBlockFinish(howToFinish, throwNoViable);
println("");
// println("}");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate code for the given grammar element.
* @param blk The block-end element to generate. Block-end
* elements are synthesized by the grammar parser to represent
* the end of a block.
*/
public void gen(BlockEndElement end) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")");
}
/** Generate code for the given grammar element.
* @param blk The character literal reference to generate
*/
public void gen(CharLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genChar("+atom+")");
if ( atom.getLabel()!=null ) {
println(atom.getLabel() + " := " + lt1Value + ";");
}
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
genMatch(atom);
saveText = oldsaveText;
}
/** Generate code for the given grammar element.
* @param blk The character-range reference to generate
*/
public void gen(CharRangeElement r) {
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " := " + lt1Value + ";");
}
println("match_range( " + r.beginText+ ", " + r.endText+ " );");
}
/** Generate the lexer Java file */
public void gen(LexerGrammar g) throws IOException {
// If debugging, create a new sempred vector for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof LexerGrammar)) {
tool.panic("Internal error generating lexer");
}
// SAS: moved output creation to method so a subclass can change
// how the output is generated (for VAJ interface)
setupOutput(grammar.getClassName());
genAST = false; // no way to gen trees.
saveText = true; // save consumed characters.
tabs=0;
// Generate header common to all Java output files
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Generate user-defined lexer file preamble
println(grammar.preambleAction.getText());
// Generate lexer class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass;
}
else {
sup = "ANTLR_CHAR_SCANNER{TOKEN}";
}
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() +
"{TOKEN} < $ANTLR_TOKEN_STREAM{TOKEN} , $ANTLR_FILE_CURSOR is " );
tabs++;
println("include " + sup + " create -> private char_scanner_create;");
println("include " + grammar.tokenManager.getName() + "_TOKENTYPES;");
/*
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
print(", "+suffix); // must be an interface name for Java
}
}
*/
println("");
// Generate user-defined lexer class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
//
// Generate the constructor from ISTREAM, which in turn
// calls the ByteBuffer constructor
//
println("create ( istr : $ISTREAM ) : SAME is");
tabs++;
println("inp : ANTLR_BYTE_BUFFER := #ANTLR_BYTE_BUFFER( istr );");
println("res : SAME := #SAME( inp );");
println("res.EOF_CHAR := istr.eof_char;");
println("return res;");
tabs--;
println("end; -- create");
println("");
//
// Generate the constructor from Reader, which in turn
// calls the CharBuffer constructor
//
// println("public " + grammar.getClassName() + "(Reader in) {");
// tabs++;
// println("this(new CharBuffer(in));");
// tabs--;
// println("}");
println("create ( bb : ANTLR_BYTE_BUFFER ) : SAME is");
tabs++;
// if debugging, wrap the input buffer in a debugger
// if (grammar.debuggingOutput)
// println("this(new LexerSharedInputState(new antlr.debug.DebuggingInputBuffer(ib)));");
// else
println("state : ANTLR_LEXER_SHARED_INPUT_STATE := #ANTLR_LEXER_SHARED_INPUT_STATE( bb );");
println("res: SAME := #SAME( state );");
println("return res;");
tabs--;
println("end; -- create");
println("");
//
// Generate the constructor from InputBuffer (char or byte)
//
println("create ( state : ANTLR_LEXER_SHARED_INPUT_STATE ) : SAME is ");
tabs++;
println("res : SAME := char_scanner_create( state );");
// if debugging, set up array variables and call user-overridable
// debugging setup method
// if ( grammar.debuggingOutput ) {
// println("rule_names := sa_rule_names;");
// println("sem_pred_names := sa_sem_pred_names;");
// println("setup_debugging;");
// }
// Generate the initialization of a hashtable
// containing the string literals used in the lexer
// The literals variable itself is in CharScanner
println("res.literals := #MAP{STR,INT};");
Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
while ( keys.hasMoreElements() ) {
String key = (String)keys.nextElement();
if ( key.charAt(0) != '"' ) {
continue;
}
TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
if ( sym instanceof StringLiteralSymbol ) {
StringLiteralSymbol s = (StringLiteralSymbol)sym;
println("res.literals[ " + s.getId() + " ] := " + s.getTokenType() + ";");
}
}
Enumeration ids;
// Generate the setting of various generated options.
println("res.case_sensitive_literals := " + g.caseSensitiveLiterals + ";");
println("res.case_sensitive := " + g.caseSensitive + ";");
println("return res;");
tabs--;
println("end; -- create");
println("");
// generate the rule name array for debugging
if (grammar.debuggingOutput) {
println("private const sa_rule_names : ARRAY{STR} := |");
ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println(" \""+((RuleSymbol)sym).getId()+"\",");
}
println("|;");
}
// Generate nextToken() rule.
// nextToken() is a synthetic lexer rule that is the implicit OR of all
// user-defined lexer rules.
genNextToken();
// Generate code for each rule in the lexer
ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
RuleSymbol sym = (RuleSymbol) ids.nextElement();
// Don't generate the synthetic rules
if (!sym.getId().equals("mnextToken")) {
genRule(sym, false, ruleNum++);
}
exitIfError();
}
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap();
// Generate the bitsets used throughout the lexer
genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size());
println("");
tabs--;
println("end; -- class");
// Close the lexer output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The (...)+ block to generate
*/
public void gen(OneOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
String label;
String cnt;
// println("{"); // cannot nest Sather scopes within a routine
genBlockPreamble(blk);
if ( blk.getLabel() != null ) {
cnt = getNextSatherPrefix() + "_cnt_"+ blk.getLabel();
}
else {
cnt = getNextSatherPrefix() + "_cnt" + blk.ID;
}
println( cnt + " : INT := 0;");
// if ( blk.getLabel() != null ) {
// label = blk.getLabel();
// }
// else {
// label = "_loop" + blk.ID;
// }
// println(label+":");
println("loop");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)+ loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("-- nongreedy exit test");
println("if ( " + cnt + " >= 1 and " + predictExit + " ) then break! end; -- if");
}
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(
howToFinish,
"if ( " + cnt + " >= 1 ) then break! else " + throwNoViable + " end; -- if"
);
println( cnt + " := " + cnt + " + 1;" );
tabs--;
println("end; -- loop");
// println("}"); // cannot nest Sather scopes within a routine
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate the parser Java file */
public void gen(ParserGrammar g) throws IOException {
// if debugging, set up a new vector to keep track of sempred
// strings for this grammar
if (g.debuggingOutput)
semPreds = new Vector();
setGrammar(g);
if (!(grammar instanceof ParserGrammar)) {
tool.panic("Internal error generating parser");
}
// Open the output stream for the parser and set the currentOutput
// SAS: moved file setup so subclass could do it (for VAJ interface)
setupOutput(grammar.getClassName());
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Output the user-defined parser preamble
println(grammar.preambleAction.getText());
// Generate parser class definition
String sup=null;
if ( grammar.superClass != null )
sup = grammar.superClass.toUpperCase();
else
sup = "ANTLR_" + grammar.getSuperClass().toUpperCase();
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + "{ TOKEN < $ANTLR_TOKEN, AST < $ANTLR_AST{AST} } is");
tabs++;
println("include " + sup + "{ TOKEN, " + labeledElementASTType + " } create -> super_create;" );
println("include " + grammar.tokenManager.getName() + "_"
+ TokenTypesFileSuffix.toUpperCase() + ";" );
println("");
/*
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null )
print(", "+suffix); // must be an interface name for Java
}
*/
// set up an array of all the rule names so the debugger can
// keep track of them only by number -- less to store in tree...
if (grammar.debuggingOutput) {
println("const sa_rule_names : ARRAY{STR} := |");
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol)
println(" \""+((RuleSymbol)sym).getId()+"\",");
}
println("|;");
}
// Generate user-defined parser class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
// Generate parser class constructor from TokenBuffer
println("");
println( "create ( token_buf : ANTLR_TOKEN_BUFFER{TOKEN} , k : INT ) : SAME is");
tabs++;
println("res : SAME := super_create( token_buf, k );");
println("res.token_names := sa_token_names;");
// println("res.ast_factory := #ANTLR_COMMON_AST_FACTORY;");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("res.rule_names := sa_rule_names;");
println("res.sem_pred_names := sa_sem_pred_names;");
println("res.setup_debugging( token_buf );");
}
println("return res;");
tabs--;
println("end; -- create");
println("");
println( "create ( token_buf : ANTLR_TOKEN_BUFFER{TOKEN} ) : SAME is");
tabs++;
println("return #SAME( token_buf, " + grammar.maxk + ");");
tabs--;
println("end; -- create");
println("");
// Generate parser class constructor from TokenStream
println( "create ( lexer : $ANTLR_TOKEN_STREAM{TOKEN} , k : INT ) : SAME is");
tabs++;
println("res : SAME := super_create( lexer, k );");
println("res.token_names := sa_token_names;");
// println("res.ast_factory := #ANTLR_COMMON_AST_FACTORY;");
// if debugging, set up arrays and call the user-overridable
// debugging setup method
if ( grammar.debuggingOutput ) {
println("res.rule_names := sa_rule_names;");
println("res.sem_pred_names := sa_sem_pred_names;");
println("res.setup_debugging( lexer );");
}
println("return res;");
tabs--;
println("end; -- create");
println("");
println( "create( lexer : $ANTLR_TOKEN_STREAM{TOKEN} ) : SAME is");
tabs++;
println("res : SAME := #SAME( lexer, " + grammar.maxk + ");");
println("return res;");
tabs--;
println("end; -- create");
println("");
println( "create ( state : ANTLR_PARSER_SHARED_INPUT_STATE{TOKEN} ) : SAME is ");
tabs++;
println("res : SAME := super_create( state," + grammar.maxk + ");");
println("res.token_names := sa_token_names;");
// println("res.ast_factory := #ANTLR_COMMON_AST_FACTORY;");
println("return res;");
tabs--;
println("end; -- create");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++);
}
exitIfError();
}
// Generate the token names
genTokenStrings();
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Generate the semantic predicate map for debugging
if (grammar.debuggingOutput)
genSemPredMap();
// Close class definition
println("");
tabs--;
println("end; -- class");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param blk The rule-reference to generate
*/
public void gen(RuleRefElement rr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRR("+rr+")");
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rs == null || !rs.isDefined())
{
// Is this redundant???
tool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine());
return;
}
if (!(rs instanceof RuleSymbol))
{
// Is this redundant???
tool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine());
return;
}
genErrorTryForElement(rr);
// AST value for labeled rule refs in tree walker.
// This is not AST construction; it is just the input tree node value.
if ( grammar instanceof TreeWalkerGrammar &&
rr.getLabel() != null &&
syntacticPredLevel == 0 )
{
println("if ( SYS::is_eq( sa_t , " + labeledElementASTType + "::ASTNULL ) ) then");
tabs++;
println( rr.getLabel() + " := void;");
tabs--;
println("else");
println(rr.getLabel() + " := " + lt1Value + ";" );
println("end; -- if");
}
// if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("sa_save_index := text.length;");
}
// Process return value assignment if any
printTabs();
if (rr.idAssign != null)
{
// Warn if the rule has no return type
if (rs.block.returnAction == null)
{
tool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine());
}
_print(rr.idAssign + ":=");
} else {
// Warn about return value if any, but not inside syntactic predicate
if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
{
tool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine());
}
}
// Call the rule
GenRuleInvocation(rr);
// if in lexer and ! on element or alt or rule, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text := text.substring( 0, sa_save_index); -- truncate");
}
// if not in a syntactic predicate
if (syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
grammar.buildAST && rr.getLabel() != null ||
(genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
)
);
if (doNoGuessTest) {
println("if ( input_state.guessing = 0 ) then");
tabs++;
}
if (grammar.buildAST && rr.getLabel() != null) {
// always gen variable for rule return on labeled rules
println( rr.getLabel() + "_ast := return_ast;");
}
if (genAST) {
switch (rr.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
println("current_ast.add_child( return_ast );");
break;
case GrammarElement.AUTO_GEN_CARET:
tool.error("Internal: encountered ^ after rule reference");
break;
default:
break;
}
}
// if a lexer and labeled, Token label defined at rule level, just set it here
if ( grammar instanceof LexerGrammar && rr.getLabel() != null ) {
println(rr.getLabel()+" := sa_return_token;");
}
if (doNoGuessTest) {
tabs--;
println("end;");
}
}
genErrorCatchForElement(rr);
}
/** Generate code for the given grammar element.
* @param blk The string-literal reference to generate
*/
public void gen(StringLiteralElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genString("+atom+")");
// Variable declarations for labeled elements
if (atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(atom);
// is there a bang on the literal?
boolean oldsaveText = saveText;
saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
// matching
genMatch(atom);
saveText = oldsaveText;
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
}
/** Generate code for the given grammar element.
* @param blk The token-range reference to generate
*/
public void gen(TokenRangeElement r) {
genErrorTryForElement(r);
if ( r.getLabel()!=null && syntacticPredLevel == 0) {
println(r.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(r);
// match
println("match_range( " + r.beginText + ", " + r.endText + " );");
genErrorCatchForElement(r);
}
/** Generate code for the given grammar element.
* @param blk The token-reference to generate
*/
public void gen(TokenRefElement atom) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")");
if ( grammar instanceof LexerGrammar ) {
tool.panic("Token reference found in lexer");
}
genErrorTryForElement(atom);
// Assign Token value to token label variable
if ( atom.getLabel()!=null && syntacticPredLevel == 0) {
println(atom.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(atom);
// matching
genMatch(atom);
genErrorCatchForElement(atom);
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
}
public void gen(TreeElement t) {
// save AST cursor
println("sa__t" + t.ID + " : " + labeledElementASTType + " := sa_t;");
// If there is a label on the root, then assign that to the variable
if (t.root.getLabel() != null) {
println("if ( SYS::is_eq( sa_t , AST::ASTNULL ) ) then");
tabs++;
println(t.root.getLabel() + " := void;");
println("else");
println(t.root.getLabel() + " := sa_t;");
println("end; -- if");
}
// Generate AST variables
genElementAST(t.root);
if (grammar.buildAST) {
// Save the AST construction state
println("sa__current_ast" + t.ID + " : ANTLR_AST_PAIR{AST} := current_ast.copy;");
// Make the next item added a child of the TreeElement root
println("current_ast.root := current_ast.child;");
println("current_ast.child := void;");
}
// match root
genMatch(t.root);
// move to list of children
println("sa_t := sa_t.first_child;");
// walk list of children, generating code for each
for (int i=0; i<t.getAlternatives().size(); i++) {
Alternative a = t.getAlternativeAt(i);
AlternativeElement e = a.head;
while ( e != null ) {
e.generate();
e = e.next;
}
}
if (grammar.buildAST) {
// restore the AST construction state to that just after the
// tree root was added
println("current_ast := sa__current_ast" + t.ID + ";");
}
// restore AST cursor
println("sa_t := sa__t" + t.ID + ";");
// move cursor to sibling of tree just parsed
println("sa_t := sa_t.next_sibling;");
}
/** Generate the tree-parser Java file */
public void gen(TreeWalkerGrammar g) throws IOException {
// SAS: debugging stuff removed for now...
setGrammar(g);
if (!(grammar instanceof TreeWalkerGrammar)) {
tool.panic("Internal error generating tree-walker");
}
// Open the output stream for the parser and set the currentOutput
// SAS: move file open to method so subclass can override it
// (mainly for VAJ interface)
setupOutput(grammar.getClassName());
genAST = grammar.buildAST;
tabs = 0;
// Generate the header common to all output files.
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Output the user-defined parser premamble
println(grammar.preambleAction.getText());
// Generate parser class definition
String sup=null;
if ( grammar.superClass!=null ) {
sup = grammar.superClass.toUpperCase();
}
else {
sup = "ANTLR_TREE_PARSER";
}
// print javadoc comment if any
if ( grammar.comment!=null ) {
_println(grammar.comment);
}
println("class " + grammar.getClassName() + "{AST < $ANTLR_AST{AST} } is" );
println("");
tabs++;
println("include " + sup + "{" + labeledElementASTType + "} create -> tree_parser_create;" );
println("include " + grammar.tokenManager.getName() + "_"
+ TokenTypesFileSuffix.toUpperCase() + ";" );
println("");
/*
Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
print(", "+suffix); // must be an interface name for Java
}
}
*/
// Generate user-defined parser class members
print(
processActionForTreeSpecifiers(grammar.classMemberAction.getText(), 0, currentRule, null)
);
println("attr token_names : ARRAY{STR};");
println("");
// Generate default parser class constructor
println("create : SAME is" );
tabs++;
println("res : SAME := tree_parser_create;");
println("res.token_names := sa_token_names;");
println("return res;");
tabs--;
println("end; -- create");
println("");
// Generate code for each rule in the grammar
Enumeration ids = grammar.rules.elements();
int ruleNum=0;
String ruleNameInits = "";
while ( ids.hasMoreElements() ) {
GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
if ( sym instanceof RuleSymbol) {
RuleSymbol rs = (RuleSymbol)sym;
genRule(rs, rs.references.size()==0, ruleNum++);
}
exitIfError();
}
// Generate the token names
genTokenStrings();
// Generate the bitsets used throughout the grammar
genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
// Close class definition
tabs--;
println("end; -- class");
println("");
// Close the parser output stream
currentOutput.close();
currentOutput = null;
}
/** Generate code for the given grammar element.
* @param wc The wildcard element to generate
*/
public void gen(WildcardElement wc) {
// Variable assignment for labeled elements
if (wc.getLabel()!=null && syntacticPredLevel == 0) {
println(wc.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(wc);
// Match anything but EOF
if (grammar instanceof TreeWalkerGrammar) {
println("if ( void(sa_t) ) then");
tabs++;
println("raise #ANTLR_MISMATCHED_TOKEN_EXCEPTION;");
tabs--;
println("end;");
}
else if (grammar instanceof LexerGrammar) {
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("sa_save_index := text.length;");
}
println("match_not(EOF_CHAR);");
if ( grammar instanceof LexerGrammar &&
(!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
// kill text atom put in buffer
println("text := text.substring( 0 , sa_save_index);");
}
}
else {
println("match_not(" + getValueString(Token.EOF_TYPE) + ");");
}
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
}
/** Generate code for the given grammar element.
* @param blk The (...)* block to generate
*/
public void gen(ZeroOrMoreBlock blk) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen*("+blk+")");
// println("{");
genBlockPreamble(blk);
String label;
if ( blk.getLabel() != null ) {
label = blk.getLabel();
}
else {
label = "_loop" + blk.ID;
}
// println(label+":");
println("loop");
tabs++;
// Tell AST generation to build subrule result
String saveCurrentASTResult = currentASTResult;
if (blk.getLabel() != null) {
currentASTResult = blk.getLabel();
}
boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
// generate exit test if greedy set to false
// and an alt is ambiguous with exit branch
// or when lookahead derived purely from end-of-file
// Lookahead analysis stops when end-of-file is hit,
// returning set {epsilon}. Since {epsilon} is not
// ambig with any real tokens, no error is reported
// by deterministic() routines and we have to check
// for the case where the lookahead depth didn't get
// set to NONDETERMINISTIC (this only happens when the
// FOLLOW contains real atoms + epsilon).
boolean generateNonGreedyExitPath = false;
int nonGreedyExitDepth = grammar.maxk;
if ( !blk.greedy &&
blk.exitLookaheadDepth<=grammar.maxk &&
blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
{
generateNonGreedyExitPath = true;
nonGreedyExitDepth = blk.exitLookaheadDepth;
}
else if ( !blk.greedy &&
blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
{
generateNonGreedyExitPath = true;
}
if ( generateNonGreedyExitPath ) {
if ( DEBUG_CODE_GENERATOR ) {
System.out.println("nongreedy (...)* loop; exit depth is "+
blk.exitLookaheadDepth);
}
String predictExit =
getLookaheadTestExpression(blk.exitCache,
nonGreedyExitDepth);
println("-- nongreedy exit test");
println("if ( " + predictExit + " ) then break! end; -- if");
}
JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
genBlockFinish(howToFinish, "break!;" );
tabs--;
println("end; -- loop ");
// Restore previous AST generation
currentASTResult = saveCurrentASTResult;
}
/** Generate an alternative.
* @param alt The alternative to generate
* @param blk The block to which the alternative belongs
*/
protected void genAlt(Alternative alt, AlternativeBlock blk) {
// Save the AST generation state, and set it to that of the alt
boolean savegenAST = genAST;
genAST = genAST && alt.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && alt.getAutoGen();
// Reset the variable name map for the alternative
Hashtable saveMap = treeVariableMap;
treeVariableMap = new Hashtable();
// Generate try block around the alt for error handling
if (alt.exceptionSpec != null) {
println("protect -- for error handling");
tabs++;
}
AlternativeElement elem = alt.head;
while ( !(elem instanceof BlockEndElement) ) {
elem.generate(); // alt can begin with anything. Ask target to gen.
elem = elem.next;
}
if ( genAST) {
if (blk instanceof RuleBlock) {
// Set the AST return value for the rule
RuleBlock rblk = (RuleBlock)blk;
println(rblk.getRuleName() + "_ast := current_ast.root;");
}
else if (blk.getLabel() != null) {
// ### future: also set AST value for labeled subrules.
// println(blk.getLabel() + "_ast = ("+labeledElementASTType+")currentAST.root;");
}
}
if (alt.exceptionSpec != null) {
// close try block
tabs--;
genErrorHandler(alt.exceptionSpec);
}
genAST = savegenAST;
saveText = oldsaveTest;
treeVariableMap = saveMap;
}
/** Generate all the bitsets to be used in the parser or lexer
* Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
* and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
* Note that most languages do not support object initialization inside a
* class definition, so other code-generators may have to separate the
* bitset declarations from the initializations (e.g., put the initializations
* in the generated constructor instead).
* @param bitsetList The list of bitsets to generate.
* @param maxVocabulary Ensure that each generated bitset can contain at least this value.
*/
protected void genBitsets(
Vector bitsetList,
int maxVocabulary
) {
SatherCharFormatter satherCharFormatter = new SatherCharFormatter();
println("");
// here, I differ from the Java code generator. Lexer's bitsets are implemented as
// Sather sets of CHAR's, Parser bitesets as Sather sets INT's
if ( grammar instanceof LexerGrammar ) {
for ( int i = 0 ; i < bitsetList.size() ; i++) {
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
String boolList = satherCharFormatter.BitSet2BoolList( p, ", " );
String bitsetName = "sa" + getBitsetName(i);
String bitsetData = bitsetName + "_data_";
// initialization data
println(
"const " + bitsetData +
" : ARRAY{BOOL} := " +
"| " +
boolList +
" |;"
);
println( "const " + bitsetName + " : CHAR_SET := bitset( " +
bitsetData + " );" );
}
}
else {
for ( int i = 0 ; i < bitsetList.size() ; i++) {
BitSet p = (BitSet)bitsetList.elementAt(i);
// Ensure that generated BitSet is large enough for vocabulary
p.growToInclude(maxVocabulary);
String charList = satherCharFormatter.BitSet2IntList( p, ", " );
String bitsetName = "sa" + getBitsetName(i);
String bitsetData = bitsetName + "_data_";
// initialization data
println(
"const " + bitsetData +
" : ARRAY{INT} := " +
"| " +
charList +
" |;"
);
println( "const " + bitsetName + " : INT_SET := int_set( " +
bitsetData + " );" );
}
}
}
/** Generate the finish of a block, using a combination of the info
* returned from genCommonBlock() and the action to perform when
* no alts were taken
* @param howToFinish The return of genCommonBlock()
* @param noViableAction What to generate when no alt is taken
*/
private void genBlockFinish(JavaBlockFinishingInfo howToFinish, String noViableAction)
{
if (howToFinish.needAnErrorClause &&
(howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
if ( howToFinish.generatedAnIf ) {
tabs++;
println("else");
}
else {
// println("{");
}
tabs++;
println(noViableAction);
tabs--;
if ( howToFinish.generatedAnIf ) {
println("end; -- if");
tabs--;
}
if ( howToFinish.generatedSwitch )
println("end; -- case");
}
if ( !howToFinish.needAnErrorClause && howToFinish.generatedSwitch )
println("end; -- case");
if ( howToFinish.postscript!=null ) {
println(howToFinish.postscript);
}
}
/** Generate the header for a block, which may be a RuleBlock or a
* plain AlternativeBLock. This generates any variable declarations,
* init-actions, and syntactic-predicate-testing variables.
* @blk The block for which the preamble is to be generated.
*/
protected void genBlockPreamble(AlternativeBlock blk) {
// define labels for rule blocks.
if ( blk instanceof RuleBlock ) {
RuleBlock rblk = (RuleBlock)blk;
if ( rblk.labeledElements!=null ) {
for (int i=0; i<rblk.labeledElements.size(); i++) {
AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
//System.out.println("looking at labeled element: "+a);
// Variables for labeled rule refs and subrules are different than
// variables for grammar atoms. This test is a little tricky because
// we want to get all rule refs and ebnf, but not rule blocks or
// syntactic predicates
if (
a instanceof RuleRefElement ||
a instanceof AlternativeBlock &&
!(a instanceof RuleBlock) &&
!(a instanceof SynPredBlock)
) {
if (
!(a instanceof RuleRefElement) &&
((AlternativeBlock)a).not &&
analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
) {
// Special case for inverted subrules that will be inlined.
// Treat these like token or char literal references
println( a.getLabel() + " : " + labeledElementType + " := " + labeledElementInit + ";");
if (grammar.buildAST) {
println( a.getLabel() + "_ast : " + labeledElementASTType+ ";" );
}
}
else {
if (grammar.buildAST) {
// Always gen AST variables for labeled elements, even if the
// element itself is marked with !
println( a.getLabel() + "_ast : " + labeledElementASTType+ ";" );
}
if ( grammar instanceof LexerGrammar ) {
println( a.getLabel() + " : $ANTLR_TOKEN; " );
}
if (grammar instanceof TreeWalkerGrammar) {
// always generate rule-ref variables for tree walker
println( a.getLabel() + " : " + labeledElementType + " := " + labeledElementInit + ";");
}
}
}
else {
// It is a token or literal reference. Generate the
// correct variable type for this grammar
println( a.getLabel() + " : " + labeledElementType + " := " + labeledElementInit + ";");
// In addition, generate *_AST variables if building ASTs
if (grammar.buildAST) {
println( a.getLabel() + "_ast : " + labeledElementASTType + ";");
}
}
}
}
}
// dump out init action
if ( blk.initAction!=null ) {
printAction(
processActionForTreeSpecifiers(blk.initAction, 0, currentRule, null)
);
}
}
/** Generate a series of case statements that implement a BitSet test.
* @param p The Bitset for which cases are to be generated
*/
protected void genCases(BitSet p) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCases("+p+")");
int[] elems;
elems = p.toArray();
// Wrap cases four-per-line for lexer, one-per-line for parser
int wrap = (grammar instanceof LexerGrammar) ? 4 : 1;
int j=1;
boolean startOfLine = true;
for (int i = 0; i < elems.length; i++) {
if (j==1) {
print("");
} else {
_print(" ");
}
if ( i == 0 )
_print("when " + getValueString(elems[i]) );
else
_print(", " + getValueString(elems[i]) );
if (j==wrap) {
_println("");
startOfLine = true;
j=1;
}
else {
j++;
startOfLine = false;
}
}
if (!startOfLine) {
_println("");
}
}
/**Generate common code for a block of alternatives; return a postscript
* that needs to be generated at the end of the block. Other routines
* may append else-clauses and such for error checking before the postfix
* is generated.
* If the grammar is a lexer, then generate alternatives in an order where
* alternatives requiring deeper lookahead are generated first, and
* EOF in the lookahead set reduces the depth of the lookahead.
* @param blk The block to generate
* @param noTestForSingle If true, then it does not generate a test for a single alternative.
*/
public JavaBlockFinishingInfo genCommonBlock(
AlternativeBlock blk,
boolean noTestForSingle)
{
int nIF=0;
boolean createdLL1Switch = false;
int closingBracesOfIFSequence = 0;
JavaBlockFinishingInfo finishingInfo = new JavaBlockFinishingInfo();
if ( DEBUG_CODE_GENERATOR ) System.out.println("genCommonBlk("+blk+")");
// Save the AST generation state, and set it to that of the block
boolean savegenAST = genAST;
genAST = genAST && blk.getAutoGen();
boolean oldsaveTest = saveText;
saveText = saveText && blk.getAutoGen();
// Is this block inverted? If so, generate special-case code
if (
blk.not &&
analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar)
) {
Lookahead p = analyzer.look(1, blk);
// Variable assignment for labeled elements
if (blk.getLabel() != null && syntacticPredLevel == 0) {
println(blk.getLabel() + " := " + lt1Value + ";");
}
// AST
genElementAST(blk);
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
astArgs="sa_t,";
}
// match the bitset for the alternative
println("match( sa" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");
// tack on tree cursor motion if doing a tree walker
if (grammar instanceof TreeWalkerGrammar) {
println("sa_t := sa_t.next_sibling;");
}
return finishingInfo;
}
// Special handling for single alt
if (blk.getAlternatives().size() == 1) {
Alternative alt = blk.getAlternativeAt(0);
// Generate a warning if there is a synPred for single alt.
if (alt.synPred != null)
{
tool.warning(
"Syntactic predicate superfluous for single alternative",
grammar.getFilename(),
blk.getAlternativeAt(0).synPred.getLine()
);
}
if (noTestForSingle) {
if (alt.semPred != null) {
// Generate validating predicate
genSemPred(alt.semPred, blk.line);
}
genAlt(alt, blk);
return finishingInfo;
}
}
// count number of simple LL(1) cases; only do switch for
// many LL(1) cases (no preds, no end of token refs)
// We don't care about exit paths for (...)*, (...)+
// because we don't explicitly have a test for them
// as an alt in the loop.
//
// Also, we now count how many unicode lookahead sets
// there are--they must be moved to DEFAULT or ELSE
// clause.
int nLL1 = 0;
for (int i=0; i<blk.getAlternatives().size(); i++) {
Alternative a = blk.getAlternativeAt(i);
if ( suitableForCaseExpression(a) ) {
nLL1++;
}
}
// do LL(1) cases
if ( nLL1 >= makeSwitchThreshold) {
// Determine the name of the item to be compared
String testExpr = lookaheadString(1);
createdLL1Switch = true;
// when parsing trees, convert null to valid tree node with NULL lookahead
if ( grammar instanceof TreeWalkerGrammar ) {
println("if ( void(sa_t) ) then");
tabs++;
println("sa_t := AST::ASTNULL;");
tabs--;
println("end; -- if");
}
println("case ( " + testExpr + " )" );
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
// ignore any non-LL(1) alts, predicated alts,
// or end-of-token alts for case expressions
if ( !suitableForCaseExpression(alt) ) {
continue;
}
Lookahead p = alt.cache[1];
if (p.fset.degree() == 0 && !p.containsEpsilon()) {
tool.warning("Alternate omitted due to empty prediction set",
grammar.getFilename(),
alt.head.getLine());
}
else {
genCases(p.fset);
println("then");
tabs++;
genAlt(alt, blk);
// println("break;");
tabs--;
// println("}");
}
}
println("else -- default");
tabs++;
}
// do non-LL(1) and nondeterministic cases
// This is tricky in the lexer, because of cases like:
// STAR : '*' ;
// ASSIGN_STAR : "*=";
// Since nextToken is generated without a loop, then the STAR
// will have end-of-token as it's lookahead set for LA(2).
// So, we must generate the alternatives containing trailing
// end-of-token in their lookahead sets *after* the
// alternatives without end-of-token. This implements the
// usual lexer convention that longer matches come before
// shorter ones, e.g. "*=" matches ASSIGN_STAR not STAR
//
// For non-lexer grammars, this does not sort the alternates
// by depth Note that alts whose lookahead is purely
// end-of-token at k=1 end up as default or else clauses.
int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("checking depth "+altDepth);
for (int i=0; i<blk.alternatives.size(); i++) {
Alternative alt = blk.getAlternativeAt(i);
if ( DEBUG_CODE_GENERATOR )
System.out.println("genAlt: "+i);
// if we made a switch above, ignore what we already
// took care of. Specifically, LL(1) alts with no
// preds that do not have end-of-token in their
// prediction set
if ( createdLL1Switch && suitableForCaseExpression(alt) ) {
if ( DEBUG_CODE_GENERATOR )
System.out.println("ignoring alt because it was in the switch");
continue;
}
String e;
boolean unpredicted = false;
if (grammar instanceof LexerGrammar) {
// Calculate the "effective depth" of the alt,
// which is the max depth at which
// cache[depth]!=end-of-token
int effectiveDepth = alt.lookaheadDepth;
if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) {
// use maximum lookahead
effectiveDepth = grammar.maxk;
}
while ( effectiveDepth >= 1 &&
alt.cache[effectiveDepth].containsEpsilon()
)
{
effectiveDepth--;
}
// Ignore alts whose effective depth is other than
// the ones we are generating for this iteration.
if (effectiveDepth != altDepth) {
if ( DEBUG_CODE_GENERATOR )
System.out.println("ignoring alt because effectiveDepth!=altDepth;"+effectiveDepth+"/="+altDepth);
continue;
}
unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
e = getLookaheadTestExpression(alt, effectiveDepth);
} else {
unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
e = getLookaheadTestExpression(alt, grammar.maxk);
}
boolean defaultBlock = true;
// Was it a big unicode range that forced
// unsuitability for a case expression?
if ( alt.cache[1].fset.degree()>caseSizeThreshold ) {
if ( nIF==0 ) {
println("if " + e + " then");
}
else {
println("elsif " + e + " then");
}
}
else if (unpredicted &&
alt.semPred==null &&
alt.synPred==null) {
// The alt has empty prediction set and no
// predicate to help out. if we have not
// generated a previous if, just put {...} around
// the end-of-token clause
if ( nIF==0 ) {
// println("{");
}
else {
println("else ");
defaultBlock = false; // else is for an if statement, not a case statement.
}
finishingInfo.needAnErrorClause = false;
}
else { // check for sem and syn preds
// Add any semantic predicate expression to the
// lookahead test
if ( alt.semPred != null ) {
// if debugging, wrap the evaluation of the
// predicate in a method
// translate $ and # references
ActionTransInfo tInfo = new ActionTransInfo();
String actionStr = processActionForTreeSpecifiers(alt.semPred,
blk.line,
currentRule,
tInfo);
// ignore translation info...we don't need to
// do anything with it. call that will inform
// SemanticPredicateListeners of the result
if (((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar)) &&
grammar.debuggingOutput )
e = "("+e+" and fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING,"+
addSemPred(charFormatter.escapeString(actionStr))+","+actionStr+"))";
else {
e = "("+e+" and ("+actionStr +"))";
}
}
// Generate any syntactic predicates
if ( nIF>0 ) {
if ( alt.synPred != null ) {
println("else");
tabs++;
genSynPred( alt.synPred, e );
closingBracesOfIFSequence++;
}
else {
println("elsif " + e + " then" );
}
}
else {
if ( alt.synPred != null ) {
genSynPred( alt.synPred, e );
}
else {
// when parsing trees, convert null to
// valid tree node with NULL lookahead.
if ( grammar instanceof TreeWalkerGrammar ) {
println("if ( void(sa_t) ) then");
tabs++;
println("sa_t := AST::ASTNULL;");
tabs--;
println("end; -- if");
}
println("if " + e + " then");
}
}
}
nIF++;
tabs++;
genAlt(alt, blk);
tabs--;
if ( !defaultBlock )
println("end; -- if");
}
}
String ps = "";
for (int i=1; i<=closingBracesOfIFSequence; i++) {
ps+="end;";
}
// Restore the AST generation state
genAST = savegenAST;
// restore save text state
saveText=oldsaveTest;
// Return the finishing info.
if ( createdLL1Switch ) {
tabs--;
finishingInfo.postscript = ps; // + "end; -- case";
finishingInfo.generatedSwitch = true;
finishingInfo.generatedAnIf = nIF>0;
//return new JavaBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
}
else {
finishingInfo.postscript = ps;
finishingInfo.generatedSwitch = false;
finishingInfo.generatedAnIf = nIF>0;
// return new JavaBlockFinishingInfo(ps, false,nIF>0);
}
return finishingInfo;
}
private static boolean suitableForCaseExpression(Alternative a) {
return
a.lookaheadDepth == 1 &&
a.semPred == null &&
!a.cache[1].containsEpsilon() &&
a.cache[1].fset.degree()<=caseSizeThreshold;
}
/** Generate code to link an element reference into the AST */
private void genElementAST(AlternativeElement el) {
// handle case where you're not building trees, but are in tree walker.
// Just need to get labels set up.
if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST ) {
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() == null) {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_ast";
astVarNumber++;
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
// Generate an "input" AST variable also
println( astName + "_in : " + labeledElementASTType + " := " + elementRef + ";");
}
return;
}
if (grammar.buildAST && syntacticPredLevel == 0) {
boolean doNoGuessTest = (
grammar.hasSyntacticPredicate &&
(
el.getLabel() != null ||
el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG
)
);
String elementRef;
String astName;
// Generate names and declarations of the AST variable(s)
if (el.getLabel() != null) {
elementRef = el.getLabel();
astName = el.getLabel() + "_ast";
} else {
elementRef = lt1Value;
// Generate AST variables for unlabeled stuff
astName = "tmp" + astVarNumber + "_ast";
astVarNumber++;
// Generate the declaration (can only build AST's for atoms
GrammarAtom ga = (GrammarAtom)el;
if ( ga.getASTNodeType()!=null ) {
println( astName + " : " + ga.getASTNodeType() + " := void;");
}
else {
println( astName + " : " + labeledElementASTType + ";" );
}
// Map the generated AST variable in the alternate
mapTreeVariable(el, astName);
if (grammar instanceof TreeWalkerGrammar) {
// Generate an "input" AST variable also
println(astName + "_in : " + labeledElementASTType + ";" );
}
}
// Enclose actions with !guessing
if (doNoGuessTest) {
println("if ( input_state.guessing = 0 ) then");
tabs++;
}
// we need to find out the type of argument of
// toke_factory::create. Sather cannot
// overload function unless their signatures
// can clearly be disambiguated. Therefore the
// AST::create( $ANTLR_AST ) : $ANTLR_AST
// and
// AST::create( $ANTLR_TOKEN ) : $ANTLR_AST
// cannot coexist. Therefore we rename them
// create_ast_from_ast and create_ast_from_token, respectively.
String astType = labeledElementASTType;
GrammarAtom atom = (GrammarAtom)el;
if ( atom != null && atom.getASTNodeType() != null ) {
astType = atom.getASTNodeType();
// make this the current AST type, used
// for supsequent AST create's, even though
// the may be temporary AST's
labeledElementASTType = astType;
}
String astCreateString;
if ( grammar instanceof TreeWalkerGrammar )
astCreateString = astType + "::create_from_ast( " + elementRef + " )";
else
astCreateString = astType + "::create_from_token( " + elementRef + " )";
if (el.getLabel() != null) {
println(astName + " := " + astCreateString + ";" );
} else {
elementRef = lt1Value;
println(astName + " := " + astCreateString + ";" );
// Map the generated AST variable in the alternate
if (grammar instanceof TreeWalkerGrammar) {
// set "input" AST variable also
println(astName + "_in := " + elementRef + ";");
}
}
if (genAST) {
switch (el.getAutoGenType()) {
case GrammarElement.AUTO_GEN_NONE:
println("current_ast.add_child( " + astName + " );");
break;
case GrammarElement.AUTO_GEN_CARET:
println("current_ast.make_root( " + astName + " );");
break;
default:
break;
}
}
if (doNoGuessTest) {
tabs--;
println("end; -- if?");
}
}
}
/** Close the try block and generate catch phrases
* if the element has a labeled handler in the rule
*/
private void genErrorCatchForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
tabs--;
println("}*28");
genErrorHandler(ex);
}
}
/** Generate the catch phrases for a user-specified error handler */
private void genErrorHandler(ExceptionSpec ex) {
// Each ExceptionHandler in the ExceptionSpec is a separate catch
for (int i = 0; i < ex.handlers.size(); i++)
{
ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i);
// Generate catch phrase
println("when " + extractTypeOfAction(handler.exceptionTypeAndName) + " then");
tabs++;
if (grammar.hasSyntacticPredicate) {
println("if ( input_state.guessing = 0 ) then");
tabs++;
}
// When not guessing, execute user handler action
printAction(
processActionForTreeSpecifiers(handler.action.getText(), 0, currentRule, null)
);
if (grammar.hasSyntacticPredicate) {
tabs--;
println("else");
tabs++;
// When guessing, rethrow exception
println("raise exception");
// extractIdOfAction(handler.exceptionTypeAndName) + ";"
tabs--;
println("end; -- if");
}
tabs--;
}
// Close catch phrase
println("end; -- protect");
}
/** Generate a try { opening if the element has a labeled handler in the rule */
private void genErrorTryForElement(AlternativeElement el) {
if (el.getLabel() == null) return;
String r = el.enclosingRuleName;
if ( grammar instanceof LexerGrammar ) {
r = CodeGenerator.lexerRuleName(el.enclosingRuleName);
}
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
if (rs == null) {
tool.panic("Enclosing rule not found!");
}
ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
if (ex != null) {
println("try { // for error handling");
tabs++;
}
}
/** Generate a header that is common to all Sather files */
protected void genHeader() {
println("-- $ANTLR "+Tool.version+": "+
"\""+Tool.fileMinusPath(tool.grammarFile)+"\""+
" -> "+
"\""+grammar.getClassName()+".sa\"$");
}
private void genLiteralsTest() {
println("sa_ttype := test_literals_table(sa_ttype);");
}
private void genLiteralsTestForPartialToken() {
println("sa_ttype := test_literals_table( text.substring( sa_begin, text.length - sa_begin ), sa_ttype );");
}
protected void genMatch(BitSet b) {
}
protected void genMatch(GrammarAtom atom) {
if ( atom instanceof StringLiteralElement ) {
if ( grammar instanceof LexerGrammar ) {
genMatchUsingAtomText(atom);
}
else {
genMatchUsingAtomTokenType(atom);
}
}
else if ( atom instanceof CharLiteralElement ) {
if ( grammar instanceof LexerGrammar ) {
genMatchUsingAtomText(atom);
}
else {
tool.error("cannot ref character literals in grammar: "+atom);
}
}
else if ( atom instanceof TokenRefElement ) {
genMatchUsingAtomText(atom);
}
}
protected void genMatchUsingAtomText(GrammarAtom atom) {
// match() for trees needs the _t cursor
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
astArgs="sa_t,";
}
// if in lexer and ! on element, save buffer index to kill later
if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("sa_save_index := text.length;");
}
print(atom.not ? "match_not(" : "match(");
_print(astArgs);
// print out what to match
if (atom.atomText.equals("EOF")) {
// horrible hack to handle EOF case
_print("ANTLR_COMMON_TOKEN::EOF_TYPE");
}
else {
_print(atom.atomText);
}
_println(");");
if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
println("text := text.substring( 0 , sa_save_index);"); // kill text atom put in buffer
}
}
protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
// match() for trees needs the _t cursor
String astArgs="";
if (grammar instanceof TreeWalkerGrammar) {
astArgs="sa_t,";
}
// If the literal can be mangled, generate the symbolic constant instead
String mangledName = null;
String s = astArgs + getValueString(atom.getType());
// matching
println( (atom.not ? "match_not(" : "match(") + s + ");");
}
/** Generate the nextToken() rule. nextToken() is a synthetic
* lexer rule that is the implicit OR of all user-defined lexer
* rules.
*/
public void genNextToken() {
// Are there any public rules? If not, then just generate a
// fake nextToken().
boolean hasPublicRules = false;
for (int i = 0; i < grammar.rules.size(); i++) {
RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i);
if ( rs.isDefined() && rs.access.equals("public") ) {
hasPublicRules = true;
break;
}
}
if (!hasPublicRules) {
println("");
println("next_token : TOKEN is " );
tabs++;
println("protect");
tabs++;
println("upon_eof;");
tabs--;
println("when $ANTLR_CHAR_STREAM_EXCEPTION then");
tabs++;
println("raise #ANTLR_TOKEN_STREAM_EXCEPTION( exception.str );");
tabs--;
println("end; -- protect");
println("return #ANTLR_COMMON_TOKEN( ANTLR_COMMON_TOKEN::EOF_TYPE, \"\");");
tabs--;
println("end;");
println("");
return;
}
// Create the synthesized nextToken() rule
RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
// Define the nextToken rule symbol
RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
nextTokenRs.setDefined();
nextTokenRs.setBlock(nextTokenBlk);
nextTokenRs.access = "private";
grammar.define(nextTokenRs);
// Analyze the nextToken rule
boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);
// Generate the next token rule
String filterRule=null;
if ( ((LexerGrammar)grammar).filterMode ) {
filterRule = ((LexerGrammar)grammar).filterRule;
}
println("");
println("next_token : TOKEN is");
tabs++;
println("theRetToken : TOKEN;");
println("continue : BOOL := true;");
// _println("tryAgain:");
println("loop");
tabs++;
// println("Token _token = null;");
println("sa_ttype : INT := ANTLR_COMMON_TOKEN::INVALID_TYPE;");
if ( ((LexerGrammar)grammar).filterMode ) {
println("commit_to_path := false;");
println("continue := true;");
if ( filterRule!=null ) {
// Here's a good place to ensure that the filter rule actually exists
if ( !grammar.isDefined(CodeGenerator.lexerRuleName(filterRule)) ) {
grammar.tool.error("Filter rule "+filterRule+" does not exist in this lexer");
}
else {
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.lexerRuleName(filterRule));
if ( !rs.isDefined() ) {
grammar.tool.error("Filter rule "+filterRule+" does not exist in this lexer");
}
else if ( rs.access.equals("public") ) {
grammar.tool.error("Filter rule "+filterRule+" must be protected");
}
}
println("sa_m : INT := mark;");
}
}
println("reset_text;");
println("protect -- for char stream error handling");
tabs++;
// Generate try around whole thing to trap scanner errors
println("protect -- for lexical error handling");
tabs++;
// Test for public lexical rules with empty paths
for (int i=0; i<nextTokenBlk.getAlternatives().size(); i++) {
Alternative a = nextTokenBlk.getAlternativeAt(i);
if ( a.cache[1].containsEpsilon() ) {
tool.warning("found optional path in nextToken()");
}
}
// Generate the block
String newline = System.getProperty("line.separator");
JavaBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false);
String errFinish = "if ( LA(1) = EOF_CHAR ) then upon_eof; sa_return_token := make_token( ANTLR_COMMON_TOKEN::EOF_TYPE);";
errFinish += newline+"\t\t\t\t";
if ( ((LexerGrammar)grammar).filterMode ) {
if ( filterRule==null ) {
errFinish += "\telse consume; continue := false; end; -- if";
}
else {
errFinish += "\telse"+newline+
"\t\t\t\t\t\tcommit;"+newline+
"\t\t\t\t\t\tprotect" +newline+
"\t\t\t\t\t\t\tm"+filterRule+"(false);"+newline+
"\t\t\t\t\t\twhen $ANTLR_RECOGNITION_EXCEPTION then"+newline+
"\t\t\t\t\t\t\t-- catastrophic failure"+newline+
"\t\t\t\t\t\t\treport_error( exception );"+newline+
"\t\t\t\t\t\t\tconsume;"+newline+
"\t\t\t\t\t\tend; -- protect"+newline+
"\t\t\t\t\t\tcontinue := false;"+newline+
"\t\t\t\t\tend; -- if";
}
}
else {
errFinish += "\t\telse " + throwNoViable + " end; -- if";
}
genBlockFinish(howToFinish, errFinish);
// at this point a valid token has been matched, undo "mark" that was done
if ( ((LexerGrammar)grammar).filterMode && filterRule!=null ) {
println("if continue then");
tabs++;
println("commit;");
tabs--;
println("end; -- if");
}
// Generate literals test if desired
// make sure _ttype is set first; note _returnToken must be
// non-null as the rule was required to create it.
println("if ( ~void(sa_return_token) and continue ) then;");
tabs++;
println("sa_ttype := sa_return_token.ttype;");
if ( ((LexerGrammar)grammar).getTestLiterals()) {
genLiteralsTest();
}
// return token created by rule reference in switch
println("sa_return_token.ttype := sa_ttype;");
println("return sa_return_token;");
tabs--;
println("end; -- if");
// Close try block
tabs--;
println("when $ANTLR_RECOGNITION_EXCEPTION then");
tabs++;
if ( ((LexerGrammar)grammar).filterMode ) {
if ( filterRule==null ) {
println("if ( ~commit_to_path ) then");
tabs++;
println("consume;");
tabs--;
println("end; -- if");
}
else {
println("if ( ~commit_to_path ) then");
tabs++;
println("rewind( sa_m );");
println("reset_text;");
println("protect");
tabs++;
println("m" + filterRule + "(false);");
tabs--;
println("when $ANTLR_RECOGNITION_EXCEPTION then");
tabs++;
println("-- horrendous failure: error in filter rule");
println("report_error( exception );");
println("consume;");
tabs--;
println("end; -- protect");
tabs--;
println("end; -- if");
}
}
else {
if ( nextTokenBlk.getDefaultErrorHandler() ) {
println("report_error( exception );");
println("consume;");
}
else {
// pass on to invoking routine
println("raise #ANTLR_TOKEN_STREAM_RECOGNITION_EXCEPTION( exception.str );");
}
}
tabs--;
println("end; -- protect");
// close CharStreamException try
tabs--;
println("when $ANTLR_CHAR_STREAM_EXCEPTION then");
tabs++;
println("raise #ANTLR_TOKEN_STREAM_EXCEPTION( exception.message );");
tabs--;
println("end; -- protect");
// close for-loop
tabs--;
println("end; -- loop");
// close method nextToken
tabs--;
// println("}");
println("end; -- next_token");
println("");
}
/** Gen a named rule block.
* ASTs are generated for each element of an alternative unless
* the rule or the alternative have a '!' modifier.
*
* If an alternative defeats the default tree construction, it
* must set <rule>_AST to the root of the returned AST.
*
* Each alternative that does automatic tree construction, builds
* up root and child list pointers in an ASTPair structure.
*
* A rule finishes by setting the returnAST variable from the
* ASTPair.
*
* @param rule The name of the rule to generate
* @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
*/
public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum) {
tabs=1;
if ( DEBUG_CODE_GENERATOR ) System.out.println("genRule("+ s.getId() +")");
if ( !s.isDefined() ) {
tool.error("undefined rule: "+ s.getId());
return;
}
// reset the AST type to the one specified in the
// PARSER's or TREE_WALKER's class parameter list
labeledElementASTType = "AST";
// Generate rule return type, name, arguments
RuleBlock rblk = s.getBlock();
currentRule = rblk;
currentASTResult = s.getId();
// Save the AST generation state, and set it to that of the rule
boolean savegenAST = genAST;
genAST = genAST && rblk.getAutoGen();
// boolean oldsaveTest = saveText;
saveText = rblk.getAutoGen();
// print javadoc comment if any
if ( s.comment!=null ) {
_println(s.comment);
}
// Gen method name
print( s.getId() );
// sather requires enclosing parens only when the arglist is non-empty
boolean hasArgs = false;
// Additional rule parameters common to all rules for this grammar
if (commonExtraParams.length() != 0 ) {
hasArgs = true;
_print("( " + commonExtraParams);
if ( rblk.argAction != null )
_print(",");
}
if ( rblk.argAction != null )
if ( !hasArgs ) {
hasArgs = true;
_print("( ");
}
// Gen arguments
if (rblk.argAction != null)
{
// Has specified arguments
print(rblk.argAction);
}
if ( hasArgs )
_print(" )");
// Gen method return type (note lexer return action set at rule creation)
if (rblk.returnAction != null)
{
// Has specified return value
_print( " : " + extractSatherTypeOfAction(rblk.returnAction) );
}
_println(" is");
tabs++;
// Convert return action to variable declaration
if (rblk.returnAction != null)
println(rblk.returnAction + ";");
// print out definitions needed by rules for various grammar types
println(commonLocalVars);
if (grammar.traceRules) {
if ( grammar instanceof TreeWalkerGrammar ) {
println("trace_in(\""+ s.getId() +"\",sa_t);");
}
else {
println("trace_in(\""+ s.getId() +"\");");
}
}
if ( grammar instanceof LexerGrammar ) {
// lexer rule default return value is the rule's token name
// This is a horrible hack to support the built-in EOF lexer rule.
if (s.getId().equals("mEOF"))
println("sa_ttype := ANTLR_COMMON_TOKEN::EOF_TYPE;");
else
println("sa_ttype := "+ s.getId().substring(1)+";");
println("sa_save_index : INT;"); // used for element! (so we can kill text matched for element)
/*
println("boolean old_saveConsumedInput=saveConsumedInput;");
if ( !rblk.getAutoGen() ) { // turn off "save input" if ! on rule
println("saveConsumedInput=false;");
}
*/
}
// if debugging, write code to mark entry to the rule
if ( grammar.debuggingOutput)
if (grammar instanceof ParserGrammar)
println("fire_enter_rule( " + ruleNum + ", 0 );");
else if (grammar instanceof LexerGrammar)
println("fire_enter_rule( " + ruleNum + ", sa_ttype );");
// Generate trace code if desired
if ( grammar.debuggingOutput || grammar.traceRules) {
println("protect -- debugging output");
tabs++;
}
// Initialize AST variables
if (grammar instanceof TreeWalkerGrammar) {
// "Input" value for rule
println( s.getId() + "_ast_in : " + labeledElementASTType + " := sa_t;");
}
if (grammar.buildAST) {
// Parser member used to pass AST returns from rule invocations
println("return_ast := void;");
// Tracks AST construction
println("current_ast ::= #ANTLR_AST_PAIR{AST};");
// User-settable return value for rule.
println( s.getId() + "_ast : " + labeledElementASTType + ";" );
}
genBlockPreamble(rblk);
println("");
// Search for an unlabeled exception specification attached to the rule
ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
// Generate try block around the entire rule for error handling
if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
println("protect -- for error handling");
tabs++;
}
// Generate the alternatives
if ( rblk.alternatives.size()==1 ) {
// One alternative -- use simple form
Alternative alt = rblk.getAlternativeAt(0);
String pred = alt.semPred;
if ( pred!=null )
genSemPred(pred, currentRule.line);
if (alt.synPred != null) {
tool.warning(
"Syntactic predicate ignored for single alternative",
grammar.getFilename(), alt.synPred.getLine()
);
}
genAlt(alt, rblk);
}
else {
// Multiple alternatives -- generate complex form
boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
JavaBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
genBlockFinish(howToFinish, throwNoViable);
}
// Generate catch phrase for error handling
if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
// Close the try block
tabs--;
}
// Generate user-defined or default catch phrases
if (unlabeledUserSpec != null) {
genErrorHandler(unlabeledUserSpec);
}
else if (rblk.getDefaultErrorHandler()) {
// Generate default catch phrase
println("when " + exceptionThrown + " then");
tabs++;
// Generate code to handle error if not guessing
if (grammar.hasSyntacticPredicate) {
println("if ( input_state.guessing = 0 ) then");
tabs++;
}
println("report_error( exception );");
if ( !(grammar instanceof TreeWalkerGrammar) ) {
// Generate code to consume until token in k==1 follow set
Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
String followSetName = "sa" + getBitsetName(markBitsetForGen(follow.fset));
println("consume;");
println("consume_until( " + followSetName + " );");
} else {
// Just consume one token
println("if ( ~void(sa_t) ) then");
tabs++;
println("sa_t := sa_t.next_sibling;");
tabs--;
println("end; -- if");
}
if (grammar.hasSyntacticPredicate) {
tabs--;
// When guessing, rethrow exception
println("else");
tabs++;
println("raise exception;");
tabs--;
println("end; -- if");
}
// Close catch phrase
tabs--;
println("end; -- protect");
}
// Squirrel away the AST "return" value
if (grammar.buildAST) {
println("return_ast := " + s.getId() + "_ast;");
}
// Set return tree value for tree walkers
if ( grammar instanceof TreeWalkerGrammar ) {
println("sa_ret_tree := sa_t;");
}
// Generate literals test for lexer rules so marked
if (rblk.getTestLiterals()) {
if ( s.access.equals("protected") ) {
genLiteralsTestForPartialToken();
}
else {
genLiteralsTest();
}
}
// if doing a lexer rule, dump code to create token if necessary
if ( grammar instanceof LexerGrammar ) {
println("if ( sa_create_token and void(sa_token) and sa_ttype /= ANTLR_COMMON_TOKEN::SKIP ) then");
tabs++;
println("sa_token := make_token( sa_ttype );");
println("sa_token.text := text.substring( sa_begin, text.length - sa_begin );");
tabs--;
println("end; -- if");
println("sa_return_token := sa_token;");
}
// Gen the return statement if there is one (lexer has hard-wired return action)
if (rblk.returnAction != null) {
println("return " + extractSatherIdOfAction( rblk.returnAction, rblk.getLine() ) + ";");
}
if ( grammar.debuggingOutput || grammar.traceRules) {
// since Sather doesn't have anything similar to
// Java's try..finally, we use a protect..when
// instead. However, we mimic finally by printing
// debugging statements regardless of whether an
// exception is thrown
tabs--;
println("when $STR then -- assume this will catch everything");
tabs++;
// cache debugging statements since they will have
// to printed twice
String fire = null;
String trace = null;
// If debugging, generate calls to mark exit of rule
if ( grammar.debuggingOutput)
if (grammar instanceof ParserGrammar)
fire = "fire_exit_rule(" + ruleNum + ",0);";
else if (grammar instanceof LexerGrammar)
fire = "fire_exit_rule(" + ruleNum + ", sa_ttype);";
if (grammar.traceRules) {
if ( grammar instanceof TreeWalkerGrammar ) {
trace = "trace_out(\""+ s.getId() +"\", sa_t);";
}
else {
trace = "trace_out(\""+ s.getId() +"\");";
}
}
// these are printed _inside_ the when class of the
// Sather protect statement.
if ( fire != null )
println(fire);
if ( trace != null )
println(trace);
// rethrow exception
println("raise exception;");
tabs--;
println("end; -- protect");
// these are printed _outside_ the when class of the
// Sather protect statement.
if ( fire != null )
println(fire);
if ( trace != null )
println(trace);
}
tabs--;
println("end; -- rule");
println("");
// Restore the AST generation state
genAST = savegenAST;
// restore char save state
// saveText = oldsaveTest;
}
private void GenRuleInvocation(RuleRefElement rr) {
// dump rule name
_print( rr.targetRule );
boolean hasArgs = false; // flag to let us know if we need to close the arg list
// lexers must tell rule if it should set _returnToken
if ( grammar instanceof LexerGrammar ) {
// if labeled, could access Token, so tell rule to create
hasArgs = true;
if ( rr.getLabel() != null ) {
_print("( true");
}
else {
_print("( false");
}
if (commonExtraArgs.length() != 0 || rr.args!=null ) {
_print(",");
}
}
else if ( commonExtraArgs.length() != 0 || rr.args != null ) {
hasArgs = true;
_print( "( " );
}
// Extra arguments common to all rules for this grammar
_print(commonExtraArgs);
if (commonExtraArgs.length() != 0 && rr.args!=null ) {
_print(",");
}
// Process arguments to method, if any
RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
if (rr.args != null)
{
// When not guessing, execute user arg action
ActionTransInfo tInfo = new ActionTransInfo();
String args = processActionForTreeSpecifiers(rr.args, 0, currentRule, tInfo);
if ( tInfo.assignToRoot || tInfo.refRuleRoot!=null ) {
tool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #"+
currentRule.getRuleName()+" on line "+rr.getLine());
}
_print(args);
// Warn if the rule accepts no arguments
if (rs.block.argAction == null) {
tool.warning("Rule '" + rr.targetRule + "' accepts no arguments", grammar.getFilename(), rr.getLine());
}
} else {
// For C++, no warning if rule has parameters, because there may be default
// values for all of the parameters
if (rs.block.argAction != null) {
tool.warning("Missing parameters on reference to rule "+rr.targetRule, grammar.getFilename(), rr.getLine());
}
}
if ( hasArgs )
_print(" )");
_println(";");
// move down to the first child while parsing
if ( grammar instanceof TreeWalkerGrammar ) {
println("sa_t := sa_ret_tree;");
}
}
protected void genSemPred(String pred, int line) {
// translate $ and # references
ActionTransInfo tInfo = new ActionTransInfo();
pred = processActionForTreeSpecifiers(pred, line, currentRule, tInfo);
// ignore translation info...we don't need to do anything with it.
String escapedPred = charFormatter.escapeString(pred);
// if debugging, wrap the semantic predicate evaluation in a method
// that can tell SemanticPredicateListeners the result
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)))
pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING,"
+ addSemPred(escapedPred) + "," + pred + ")";
println("if (~(" + pred + ")) then");
tabs++;
println("raise #ANTLR_SEMANTIC_EXCEPTION(\"" + escapedPred + "\");");
tabs--;
println("end;");
}
/** Write an array of Strings which are the semantic predicate
* expressions. The debugger will reference them by number only
*/
protected void genSemPredMap() {
Enumeration e = semPreds.elements();
println("private String _semPredNames[] = {");
while(e.hasMoreElements())
println("\""+e.nextElement()+"\",");
println("};");
}
protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
if ( DEBUG_CODE_GENERATOR ) System.out.println("gen=>("+blk+")");
// Dump synpred result variable
println("syn_pred_matched" + blk.ID + " : BOOL := false;");
// Gen normal lookahead test
println("if (" + lookaheadExpr + ") then");
tabs++;
// Save input state
if ( grammar instanceof TreeWalkerGrammar ) {
println("sa__t" + blk.ID + " " + labeledElementASTType + " := sa_t;");
}
else {
println("sa_m" + blk.ID + " : INT := mark;");
}
// Once inside the try, assume synpred works unless exception caught
println("syn_pred_matched" + blk.ID + " := true;");
println("input_state.guessing := input_state.guessing + 1;");
// if debugging, tell listeners that a synpred has started
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar))) {
println("fireSyntacticPredicateStarted();");
}
syntacticPredLevel++;
println("protect");
tabs++;
gen((AlternativeBlock)blk); // gen code to test predicate
tabs--;
//println("System.out.println(\"pred "+blk+" succeeded\");");
println( "when " + exceptionThrown + " then" );
tabs++;
println( "syn_pred_matched" + blk.ID +" := false;");
//println("System.out.println(\"pred "+blk+" failed\");");
tabs--;
println("end; -- protect");
// Restore input state
if ( grammar instanceof TreeWalkerGrammar ) {
println("sa_t := sa__t" + blk.ID + ";");
}
else {
println("rewind( sa_m" + blk.ID + " );");
}
println("input_state.guessing := input_state.guessing - 1;");
// if debugging, tell listeners how the synpred turned out
if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
(grammar instanceof LexerGrammar))) {
println("if ( syn_pred_matched" + blk.ID + " ) then" );
tabs++;
println("fireSyntacticPredicateSucceeded();" );
tabs--;
println("else");
tabs++;
println(" fireSyntacticPredicateFailed();");
tabs--;
println("end; -- if");
}
syntacticPredLevel--;
tabs--;
// Close lookahead test
println("end; -- if");
// Test synred result
println("if ( syn_pred_matched" + blk.ID + " ) then");
}
/** Generate a static array containing the names of the tokens,
* indexed by the token type values. This static array is used
* to format error messages so that the token identifers or literal
* strings are displayed instead of the token numbers.
*
* If a lexical rule has a paraphrase, use it rather than the
* token label.
*/
public void genTokenStrings() {
// Generate a string for each token. This creates a static
// array of Strings indexed by token type.
println("");
println("const sa_token_names : ARRAY{STR} := |");
tabs++;
// Walk the token vocabulary and generate a Vector of strings
// from the tokens.
Vector v = grammar.tokenManager.getVocabulary();
for (int i = 0; i < v.size(); i++)
{
String s = (String)v.elementAt(i);
if (s == null)
{
s = "<"+String.valueOf(i)+">";
}
if ( !s.startsWith("\"") && !s.startsWith("<") ) {
TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s);
if ( ts!=null && ts.getParaphrase()!=null ) {
s = antlr.Tool.stripFrontBack(ts.getParaphrase(), "\"", "\"");
}
}
print(charFormatter.literalString(s));
if (i != v.size()-1) {
_print(",");
}
_println("");
}
// Close the string array initailizer
tabs--;
println("|;");
}
/** Generate the token types Java file */
protected void genTokenTypes(TokenManager tm) throws IOException {
// Open the token output Java file and set the currentOutput stream
// SAS: file open was moved to a method so a subclass can override
// This was mainly for the VAJ interface
setupOutput(tm.getName() + "_" + TokenTypesFileSuffix.toUpperCase() );
tabs = 0;
// Generate the header common to all Java files
genHeader();
// Do not use printAction because we assume tabs==0
println(behavior.getHeaderAction(""));
// Encapsulate the definitions in an interface. This can be done
// because they are all constants.
println("class " + tm.getName() + "_" + TokenTypesFileSuffix.toUpperCase() +" is");
tabs++;
// Generate a definition for each token type
Vector v = tm.getVocabulary();
// Do special tokens manually
println("const EOF : INT := " + Token.EOF_TYPE + ";");
println("const NULL_TREE_LOOKAHEAD : INT := " + Token.NULL_TREE_LOOKAHEAD + ";");
for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if (s != null) {
if ( s.startsWith("\"") ) {
// a string literal
StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
if ( sl==null ) {
antlr.Tool.panic("String literal "+s+" not in symbol table");
}
else if ( sl.label != null ) {
println( "const " + sl.label + " : INT" + " := " + i + ";");
}
else {
String mangledName = mangleLiteral(s);
if (mangledName != null) {
// We were able to create a meaningful mangled token name
println( "const " + mangledName + " : INT" + " := " + i + ";");
// if no label specified, make the label equal to the mangled name
sl.label = mangledName;
}
else {
println("-- " + s + " := " + i);
}
}
}
else if ( !s.startsWith("<") ) {
println( "const " + s + " : INT" + " := " + i + ";");
}
}
}
// convert the CHAR array into CHAR_SET instance
println("");
println("bitset ( bool_array : ARRAY{BOOL} ) : CHAR_SET is");
tabs++;
println( "return #CHAR_SET( bool_array );" );
tabs--;
println("end;");
// convert the INT array into INT_SET instance
println("");
println("int_set ( int_array : ARRAY{INT} ) : INT_SET is");
tabs++;
println( "return #INT_SET( int_array );" );
tabs--;
println("end;");
// Close the interface
tabs--;
println("end; -- class");
// Close the tokens output file
currentOutput.close();
currentOutput = null;
exitIfError();
}
/** Get a string for an expression to generate creation of an AST subtree.
* @param v A Vector of String, where each element is an expression in the target language yielding an AST node.
*/
public String getASTCreateString(Vector v) {
if (v.size() == 0) {
return "";
}
StringBuffer buf = new StringBuffer();
buf.append("ANTLR_AST_UTIL{AST}::make( ( #ANTLR_AST_ARRAY{AST}(" + v.size() + "))");
for (int i = 0; i < v.size(); i++) {
buf.append(".add(" + v.elementAt(i) + ")");
}
buf.append(")");
return buf.toString();
}
/** Get a string for an expression to generate creating of an AST node
* @param atom The grammar node for which you are creating the node
* @param str The arguments to the AST constructor
*/
public String getASTCreateString(GrammarAtom atom, String str) {
if ( atom!=null && atom.getASTNodeType() != null ) {
return atom.getASTNodeType() + "::create("+str + ")";
}
else {
return labeledElementASTType + "::create( " + str + " )";
}
}
protected String getLookaheadTestExpression(Lookahead[] look, int k)
{
StringBuffer e = new StringBuffer(100);
boolean first = true;
e.append("(");
for (int i = 1; i <= k; i++) {
BitSet p = look[i].fset;
if (!first) {
e.append(") and (");
}
first = false;
// Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
// There is no way to predict what that token would be. Just
// allow anything instead.
if (look[i].containsEpsilon()) {
e.append("true");
} else {
e.append(getLookaheadTestTerm(i, p));
}
}
e.append(")");
return e.toString();
}
/**Generate a lookahead test expression for an alternate. This
* will be a series of tests joined by '&&' and enclosed by '()',
* the number of such tests being determined by the depth of the lookahead.
*/
protected String getLookaheadTestExpression(Alternative alt, int maxDepth) {
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
// if the decision is nondeterministic, do the best we can: LL(k)
// any predicates that are around will be generated later.
depth = grammar.maxk;
}
if ( maxDepth==0 ) {
// empty lookahead can result from alt with sem pred
// that can see end of token. E.g., A : {pred}? ('a')? ;
return "true";
}
/*
boolean first = true;
for (int i=1; i<=depth && i<=maxDepth; i++) {
BitSet p = alt.cache[i].fset;
if (!first) {
e.append(") and (");
}
first = false;
// Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
// There is no way to predict what that token would be. Just
// allow anything instead.
if ( alt.cache[i].containsEpsilon() ) {
e.append("true");
}
else {
e.append(getLookaheadTestTerm(i, p));
}
}
e.append(")");
*/
return "(" + getLookaheadTestExpression(alt.cache,depth) + ")";
}
/**Generate a depth==1 lookahead test expression given the BitSet.
* This may be one of:
* 1) a series of 'x==X||' tests
* 2) a range test using >= && <= where possible,
* 3) a bitset membership test for complex comparisons
* @param k The lookahead level
* @param p The lookahead set for level k
*/
protected String getLookaheadTestTerm(int k, BitSet p) {
// Determine the name of the item to be compared
String ts = lookaheadString(k);
// Generate a range expression if possible
int[] elems = p.toArray();
if (elementsAreRange(elems)) {
return getRangeExpression(k, elems);
}
// Generate a bitset membership test if possible
StringBuffer e;
int degree = p.degree();
if ( degree == 0 ) {
return "true";
}
if ( degree >= bitsetTestThreshold) {
int bitsetIdx = markBitsetForGen(p);
return "sa" + getBitsetName(bitsetIdx) + ".member(" + ts + ")";
}
// Otherwise, generate the long-winded series of "x==X||" tests
e = new StringBuffer();
for (int i = 0; i < elems.length; i++) {
// Get the compared-to item (token or character value)
String cs = getValueString(elems[i]);
// Generate the element comparison
if ( i>0 ) e.append(" or ");
e.append(ts);
e.append("=");
e.append(cs);
}
return e.toString();
}
/** Return an expression for testing a contiguous renage of elements
* @param k The lookahead level
* @param elems The elements representing the set, usually from BitSet.toArray().
* @return String containing test expression.
*/
public String getRangeExpression(int k, int[] elems) {
if (!elementsAreRange(elems)) {
tool.panic("getRangeExpression called with non-range");
}
int begin = elems[0];
int end = elems[elems.length-1];
return
"(" + lookaheadString(k) + " >= " + getValueString(begin) + " and " +
lookaheadString(k) + " <= " + getValueString(end) + ")";
}
/** getValueString: get a string representation of a token or char value
* @param value The token or char value
*/
private String getValueString(int value) {
String cs;
if ( grammar instanceof LexerGrammar ) {
cs = charFormatter.literalChar(value);
}
else {
TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value);
if ( ts == null ) {
return ""+value; // return token type as string
// tool.panic("vocabulary for token type " + value + " is null");
}
String tId = ts.getId();
if ( ts instanceof StringLiteralSymbol ) {
// if string literal, use predefined label if any
// if no predefined, try to mangle into LITERAL_xxx.
// if can't mangle, use int value as last resort
StringLiteralSymbol sl = (StringLiteralSymbol)ts;
String label = sl.getLabel();
if ( label!=null ) {
cs = label;
}
else {
cs = mangleLiteral(tId);
if (cs == null) {
cs = String.valueOf(value);
}
}
}
else {
cs = tId;
}
}
return cs;
}
/**Is the lookahead for this alt empty? */
protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
int depth = alt.lookaheadDepth;
if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
depth = grammar.maxk;
}
for (int i=1; i<=depth && i<=maxDepth; i++) {
BitSet p = alt.cache[i].fset;
if (p.degree() != 0) {
return false;
}
}
return true;
}
private String lookaheadString(int k) {
if (grammar instanceof TreeWalkerGrammar) {
return "sa_t.ttype";
}
return "LA(" + k + ")";
}
/** Mangle a string literal into a meaningful token name. This is
* only possible for literals that are all characters. The resulting
* mangled literal name is literalsPrefix with the text of the literal
* appended.
* @return A string representing the mangled literal, or null if not possible.
*/
private String mangleLiteral(String s) {
String mangled = antlr.Tool.literalsPrefix;
for (int i = 1; i < s.length()-1; i++) {
if (!Character.isLetter(s.charAt(i)) &&
s.charAt(i) != '_') {
return null;
}
mangled += s.charAt(i);
}
if ( antlr.Tool.upperCaseMangledLiterals ) {
mangled = mangled.toUpperCase();
}
return mangled;
}
/** Map an identifier to it's corresponding tree-node variable.
* This is context-sensitive, depending on the rule and alternative
* being generated
* @param idParam The identifier name to map
* @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
*/
public String mapTreeId(String idParam, ActionTransInfo transInfo) {
// if not in an action of a rule, nothing to map.
if ( currentRule==null ) return idParam;
boolean in_var = false;
String id = idParam;
if (grammar instanceof TreeWalkerGrammar) {
if ( !grammar.buildAST ) {
in_var = true;
}
// If the id ends with "_in", then map it to the input variable
else if (id.length() > 3 && id.lastIndexOf("_in") == id.length()-3) {
// Strip off the "_in"
id = id.substring(0, id.length()-3);
in_var = true;
}
}
// Check the rule labels. If id is a label, then the output
// variable is label_AST, and the input variable is plain label.
for (int i = 0; i < currentRule.labeledElements.size(); i++) {
AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i);
if (elt.getLabel().equals(id)) {
return in_var ? id : id + "_ast";
}
}
// Failing that, check the id-to-variable map for the alternative.
// If the id is in the map, then output variable is the name in the
// map, and input variable is name_in
String s = (String)treeVariableMap.get(id);
if (s != null) {
if (s == NONUNIQUE) {
// There is more than one element with this id
return null;
} else if (s.equals(currentRule.getRuleName())) {
// a recursive call to the enclosing rule is
// ambiguous with the rule itself.
return null;
} else {
return in_var ? s + "_in" : s;
}
}
// Failing that, check the rule name itself. Output variable
// is rule_AST; input variable is rule_AST_in (treeparsers).
if (id.equals(currentRule.getRuleName())) {
String r = in_var ? id + "_ast_in" : id + "_ast";
if ( transInfo!=null ) {
if ( !in_var ) {
transInfo.refRuleRoot = r;
}
}
return r;
} else {
// id does not map to anything -- return itself.
return id;
}
}
/** Given an element and the name of an associated AST variable,
* create a mapping between the element "name" and the variable name.
*/
private void mapTreeVariable(AlternativeElement e, String name)
{
// For tree elements, defer to the root
if (e instanceof TreeElement) {
mapTreeVariable( ((TreeElement)e).root, name);
return;
}
// Determine the name of the element, if any, for mapping purposes
String elName = null;
// Don't map labeled items
if (e.getLabel() == null) {
if (e instanceof TokenRefElement) {
// use the token id
elName = ((TokenRefElement)e).atomText;
}
else if (e instanceof RuleRefElement) {
// use the rule name
elName = ((RuleRefElement)e).targetRule;
}
}
// Add the element to the tree variable map if it has a name
if (elName != null) {
if (treeVariableMap.get(elName) != null) {
// Name is already in the map -- mark it as duplicate
treeVariableMap.remove(elName);
treeVariableMap.put(elName, NONUNIQUE);
}
else {
treeVariableMap.put(elName, name);
}
}
}
private void setupGrammarParameters(Grammar g) {
if (g instanceof ParserGrammar) {
labeledElementASTType = "AST";
/*
if ( g.hasOption("ASTLabelType") ) {
Token tsuffix = g.getOption("ASTLabelType");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
labeledElementASTType = suffix;
}
}
}
*/
labeledElementType = "$ANTLR_TOKEN";
labeledElementInit = "void";
commonExtraArgs = "";
commonExtraParams = "";
commonLocalVars = "";
lt1Value = "LT(1)";
exceptionThrown = "$ANTLR_RECOGNITION_EXCEPTION";
throwNoViable = "raise ANTLR_NO_VIABLE_ALT_EXCEPTION{AST}::create_from_token(LT(1), file_name );";
}
else if (g instanceof LexerGrammar) {
labeledElementType = "CHAR ";
labeledElementInit = "'\\0'";
commonExtraArgs = "";
commonExtraParams = "sa_create_token : BOOL";
commonLocalVars = "sa_ttype : INT; sa_token : TOKEN; sa_begin : INT := text.length;";
lt1Value = "LA(1)";
exceptionThrown = "$ANTLR_RECOGNITION_EXCEPTION";
throwNoViable = "raise #ANTLR_NO_VIABLE_ALT_FOR_CHAR_EXCEPTION( LA(1), file_name, line );";
}
else if (g instanceof TreeWalkerGrammar) {
labeledElementASTType = "AST";
labeledElementType = labeledElementASTType;
/*
if ( g.hasOption("ASTLabelType") ) {
Token tsuffix = g.getOption("ASTLabelType");
if ( tsuffix != null ) {
String suffix = Tool.stripFrontBack(tsuffix.getText(),"\"","\"");
if ( suffix != null ) {
labeledElementASTType = suffix;
labeledElementType = suffix;
}
}
}
*/
if ( !g.hasOption("ASTLabelType") ) {
g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL,"AST"));
}
labeledElementInit = "void";
commonExtraArgs = "sa_t";
commonExtraParams = "sa_t : " + labeledElementASTType;
commonLocalVars = "";
lt1Value = "sa_t";
exceptionThrown = "$ANTLR_RECOGNITION_EXCEPTION";
throwNoViable = "raise #ANTLR_NO_VIABLE_ALT_EXCEPTION{AST}(sa_t);";
}
else {
tool.panic("Unknown grammar type");
}
}
/** This method exists so a subclass, namely VAJCodeGenerator,
* can open the file in its own evil way. JavaCodeGenerator
* simply opens a text file...
*/
public void setupOutput(String className) throws IOException {
currentOutput = antlr.Tool.openOutputFile(className + ".sa");
}
private static int satherBlockId = 0;
private static synchronized String getNextSatherPrefix() {
// This method is required to overcome Sather's lack of
// multiple/nested scopes within a method. It is used as a
// prefix to newly declared variables. The prefix disambiguates
// varaible names that in the Java/Cpp code generators would have
// resided in their own scope.
String label = "sa" + satherBlockId;
satherBlockId++;
return label;
}
protected String extractSatherTypeOfAction(String s) {
int s_length = s.length();
for (int i = s_length - 1 ; i >=0 ; i-- ) {
if ( s.charAt(i) == ':' ) {
return s.substring( i+1 , s_length );
}
}
tool.warning("Unable to determine Sather type" );
return "";
}
protected String extractSatherIdOfAction(String s, int line) {
int s_length = s.length();
for (int i = s_length - 1 ; i >=0 ; i-- ) {
if ( s.charAt(i) == ':' ) {
return s.substring( 0 , i );
}
}
tool.warning("Unable to determine Sather return identifier");
return "";
}
/** Lexically process tree-specifiers in the action.
* This will replace @id and @(...) with the appropriate
* function calls and/or variables.
*
* Override the default implementation inherited from CodeGenerator
* in order to instantiate the Sather's ActionLexer rather than Java's
*/
protected String processActionForTreeSpecifiers( String actionStr,
int line,
RuleBlock currentRule,
ActionTransInfo tInfo )
{
if ( actionStr==null || actionStr.length() == 0 ) return null;
// The action trans info tells us (at the moment) whether an
// assignment was done to the rule's tree root.
if (grammar==null) return actionStr;
if ( (grammar.buildAST && actionStr.indexOf('@') != -1) ||
grammar instanceof TreeWalkerGrammar ||
(grammar instanceof LexerGrammar && actionStr.indexOf('%') != -1) ) {
// Create a lexer to read an action and return the translated version
antlr.actions.sather.ActionLexer lexer =
new antlr.actions.sather.ActionLexer(actionStr, currentRule, this, tInfo);
lexer.setLineOffset(line);
lexer.setTool(tool);
try {
lexer.mACTION(true);
actionStr = lexer.getTokenObject().getText();
// System.out.println("action translated: "+actionStr);
// System.out.println("trans info is "+tInfo);
}
catch (RecognitionException ex) {
lexer.reportError(ex);
return actionStr;
}
catch (TokenStreamException tex) {
antlr.Tool.panic("Error reading action:"+actionStr);
return actionStr;
}
catch (CharStreamException io) {
antlr.Tool.panic("Error reading action:"+actionStr);
return actionStr;
}
}
return actionStr;
}
}
1.1 e/src/jsrc/antlr/SemanticException.java
Index: SemanticException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: SemanticException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public class SemanticException extends RecognitionException {
public SemanticException(String s) {
super(s);
}
public SemanticException(String s, String fileName, int line) {
super(s, fileName, line);
}
}
1.1 e/src/jsrc/antlr/SimpleTokenManager.java
Index: SimpleTokenManager.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: SimpleTokenManager.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.*;
import java.util.Hashtable;
import java.util.Enumeration;
import antlr.collections.impl.Vector;
class SimpleTokenManager implements TokenManager, Cloneable {
protected int maxToken = Token.MIN_USER_TYPE;
// Token vocabulary is Vector of String's
protected Vector vocabulary;
// Hash table is a mapping from Strings to TokenSymbol
private Hashtable table;
// the ANTLR tool
protected Tool tool;
// Name of the token manager
protected String name;
protected boolean readOnly = false;
SimpleTokenManager(String name_, Tool tool_) {
tool = tool_;
name = name_;
// Don't make a bigger vector than we need, because it will show up in output sets.
vocabulary = new Vector(1);
table = new Hashtable();
// define EOF symbol
TokenSymbol ts = new TokenSymbol("EOF");
ts.setTokenType(Token.EOF_TYPE);
define(ts);
// define <null-tree-lookahead> but only in the vocabulary vector
vocabulary.ensureCapacity(Token.NULL_TREE_LOOKAHEAD);
vocabulary.setElementAt("NULL_TREE_LOOKAHEAD", Token.NULL_TREE_LOOKAHEAD);
}
public Object clone() {
SimpleTokenManager tm;
try {
tm = (SimpleTokenManager) super.clone();
tm.vocabulary = (Vector) this.vocabulary.clone();
tm.table = (Hashtable) this.table.clone();
tm.maxToken = this.maxToken;
tm.tool = this.tool;
tm.name = this.name;
} catch (CloneNotSupportedException e) {
tool.panic("cannot clone token manager");
return null;
}
return tm;
}
/** define a token */
public void define(TokenSymbol ts) {
// Add the symbol to the vocabulary vector
vocabulary.ensureCapacity(ts.getTokenType());
vocabulary.setElementAt(ts.getId(), ts.getTokenType());
// add the symbol to the hash table
mapToTokenSymbol(ts.getId(), ts);
}
/** Simple token manager doesn't have a name -- must be set externally */
public String getName() { return name; }
/** Get a token symbol by index */
public String getTokenStringAt(int idx) {
return (String)vocabulary.elementAt(idx);
}
/** Get the TokenSymbol for a string */
public TokenSymbol getTokenSymbol(String sym) {
return (TokenSymbol)table.get(sym);
}
/** Get a token symbol by index */
public TokenSymbol getTokenSymbolAt(int idx) {
return getTokenSymbol(getTokenStringAt(idx));
}
/** Get an enumerator over the symbol table */
public Enumeration getTokenSymbolElements() {
return table.elements();
}
public Enumeration getTokenSymbolKeys() {
return table.keys();
}
/** Get the token vocabulary (read-only).
* @return A Vector of TokenSymbol
*/
public Vector getVocabulary() {
return vocabulary;
}
/** Simple token manager is not read-only */
public boolean isReadOnly() { return false; }
/** Map a label or string to an existing token symbol */
public void mapToTokenSymbol(String name, TokenSymbol sym) {
table.put(name, sym);
}
/** Get the highest token type in use */
public int maxTokenType() {
return maxToken-1;
}
/** Get the next unused token type */
public int nextTokenType() {
return maxToken++;
}
/** Set the name of the token manager */
public void setName(String name_) { name = name_; }
public void setReadOnly(boolean ro) {
readOnly = ro;
}
/** Is a token symbol defined? */
public boolean tokenDefined(String symbol) {
return table.containsKey(symbol);
}
}
1.1 e/src/jsrc/antlr/StringLiteralElement.java
Index: StringLiteralElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: StringLiteralElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class StringLiteralElement extends GrammarAtom {
// atomText with quotes stripped and escape codes processed
protected String processedAtomText;
public StringLiteralElement(Grammar g, Token t, int autoGenType) {
super(g, t, autoGenType);
if (!(g instanceof LexerGrammar)) {
// lexer does not have token types for string literals
TokenSymbol ts = grammar.tokenManager.getTokenSymbol(atomText);
if (ts == null) {
g.tool.error("Undefined literal: " + atomText, grammar.getFilename(), t.getLine());
} else {
tokenType = ts.getTokenType();
}
}
line = t.getLine();
// process the string literal text by removing quotes and escaping chars
// If a lexical grammar, add the characters to the char vocabulary
processedAtomText = new String();
for (int i = 1; i < atomText.length()-1; i++)
{
char c = atomText.charAt(i);
if (c == '\\') {
if (i+1 < atomText.length()-1) {
i++;
c = atomText.charAt(i);
switch (c) {
case 'n' : c = '\n'; break;
case 'r' : c = '\r'; break;
case 't' : c = '\t'; break;
}
}
}
if (g instanceof LexerGrammar) {
((LexerGrammar)g).charVocabulary.add(c);
}
processedAtomText += c;
}
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
}
1.1 e/src/jsrc/antlr/StringLiteralSymbol.java
Index: StringLiteralSymbol.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: StringLiteralSymbol.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class StringLiteralSymbol extends TokenSymbol {
protected String label; // was this string literal labeled?
public StringLiteralSymbol(String r) {
super(r);
}
public String getLabel() { return label; }
public void setLabel(String label) {this.label = label;}
}
1.1 e/src/jsrc/antlr/SynPredBlock.java
Index: SynPredBlock.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: SynPredBlock.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class SynPredBlock extends AlternativeBlock {
public SynPredBlock(Grammar g) {
super(g);
}
public SynPredBlock(Grammar g, int line) {
super(g, line, false);
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
return super.toString() + "=>";
}
}
1.1 e/src/jsrc/antlr/Token.java
Index: Token.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: Token.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** A token is minimally a token type. Subclasses can add the text matched
* for the token and line info.
*/
public class Token implements Cloneable {
// constants
public static final int MIN_USER_TYPE = 4;
public static final int NULL_TREE_LOOKAHEAD = 3;
public static final int INVALID_TYPE = 0;
public static final int EOF_TYPE = 1;
public static final int SKIP = -1;
// each Token has at least a token type
int type=INVALID_TYPE;
// the illegal token object
public static Token badToken = new Token(INVALID_TYPE, "<no text>");
public Token() {;}
public Token(int t) { type = t; }
public Token(int t, String txt) { type = t; setText(txt); }
public int getColumn() { return 0; }
public int getLine() { return 0; }
public String getText() { return "<no text>"; }
public int getType() { return type; }
public void setColumn(int c) {;}
public void setLine(int l) {;}
public void setText(String t) {;}
public void setType(int t) { type = t; }
public String toString() {
return "[\""+getText()+"\",<"+type+">]";
}
}
1.1 e/src/jsrc/antlr/TokenBuffer.java
Index: TokenBuffer.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenBuffer.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**A Stream of Token objects fed to the parser from a Tokenizer that can
* be rewound via mark()/rewind() methods.
* <p>
* A dynamic array is used to buffer up all the input tokens. Normally,
* "k" tokens are stored in the buffer. More tokens may be stored during
* guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
* Consumption of tokens is deferred. In other words, reading the next
* token is not done by conume(), but deferred until needed by LA or LT.
* <p>
*
* @see antlr.Token
* @see antlr.Tokenizer
* @see antlr.TokenQueue
*/
import java.io.IOException;
public class TokenBuffer {
// Token source
protected TokenStream input;
// Number of active markers
int nMarkers = 0;
// Additional offset used when markers are active
int markerOffset = 0;
// Number of calls to consume() since last LA() or LT() call
int numToConsume = 0;
// Circular queue
TokenQueue queue;
/** Create a token buffer */
public TokenBuffer(TokenStream input_) {
input = input_;
queue = new TokenQueue(1);
}
/** Mark another token for deferred consumption */
public final void consume() {
numToConsume++;
}
/** Ensure that the token buffer is sufficiently full */
private final void fill(int amount) throws TokenStreamException
{
syncConsume();
// Fill the buffer sufficiently to hold needed tokens
while (queue.nbrEntries < amount + markerOffset) {
// Append the next token
queue.append(input.nextToken());
}
}
/** return the Tokenizer (needed by ParseView) */
public TokenStream getInput() {
return input;
}
/** Get a lookahead token value */
public final int LA(int i) throws TokenStreamException {
fill(i);
return queue.elementAt(markerOffset + i - 1).type;
}
/** Get a lookahead token */
public final Token LT(int i) throws TokenStreamException {
fill(i);
return queue.elementAt(markerOffset + i - 1);
}
/**Return an integer marker that can be used to rewind the buffer to
* its current state.
*/
public final int mark() {
syncConsume();
//System.out.println("Marking at " + markerOffset);
//try { for (int i = 1; i <= 2; i++) { System.out.println("LA("+i+")=="+LT(i).getText()); } } catch (ScannerException e) {}
nMarkers++;
return markerOffset;
}
/**Rewind the token buffer to a marker.
* @param mark Marker returned previously from mark()
*/
public final void rewind(int mark) {
syncConsume();
markerOffset = mark;
nMarkers--;
//System.out.println("Rewinding to " + mark);
//try { for (int i = 1; i <= 2; i++) { System.out.println("LA("+i+")=="+LT(i).getText()); } } catch (ScannerException e) {}
}
/** Sync up deferred consumption */
private final void syncConsume() {
while (numToConsume > 0) {
if (nMarkers > 0)
{
// guess mode -- leave leading tokens and bump offset.
markerOffset++;
} else {
// normal mode -- remove first token
queue.removeFirst();
}
numToConsume--;
}
}
}
1.1 e/src/jsrc/antlr/TokenManager.java
Index: TokenManager.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenManager.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import java.util.Enumeration;
import antlr.collections.impl.Vector;
/** Interface that describes the set of defined tokens */
interface TokenManager {
public Object clone();
/** define a token symbol */
public void define(TokenSymbol ts);
/** Get the name of the token manager */
public String getName();
/** Get a token string by index */
public String getTokenStringAt(int idx);
/** Get the TokenSymbol for a string */
public TokenSymbol getTokenSymbol(String sym);
public TokenSymbol getTokenSymbolAt(int idx);
/** Get an enumerator over the symbol table */
public Enumeration getTokenSymbolElements();
public Enumeration getTokenSymbolKeys();
/** Get the token vocabulary (read-only).
* @return A Vector of Strings indexed by token type */
public Vector getVocabulary();
/** Is this token manager read-only? */
public boolean isReadOnly();
public void mapToTokenSymbol(String name, TokenSymbol sym);
/** Get the highest token type in use */
public int maxTokenType();
/** Get the next unused token type */
public int nextTokenType();
public void setName(String n);
public void setReadOnly(boolean ro);
/** Is a token symbol defined? */
public boolean tokenDefined(String symbol);
}
1.1 e/src/jsrc/antlr/TokenQueue.java
Index: TokenQueue.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenQueue.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** A private circular buffer object used by the token buffer */
class TokenQueue {
// Physical circular buffer of tokens
private Token[] buffer;
// buffer.length-1 for quick modulous
private int sizeLessOne;
// physical index of front token
private int offset;
// number of tokens in the queue
protected int nbrEntries;
public TokenQueue(int minSize) {
// Find first power of 2 >= to requested size
int size;
for (size = 2; size < minSize; size *= 2) {;}
init(size);
}
/** Add token to end of the queue
* @param tok The token to add
*/
public final void append(Token tok)
{
if (nbrEntries == buffer.length)
{
expand();
}
buffer[(offset + nbrEntries) & sizeLessOne] = tok;
nbrEntries++;
}
/** Fetch a token from the queue by index
* @param idx The index of the token to fetch, where zero is the token at the front of the queue
*/
public final Token elementAt(int idx) {
return buffer[(offset + idx) & sizeLessOne];
}
/** Expand the token buffer by doubling its capacity */
private final void expand()
{
Token[] newBuffer = new Token[buffer.length * 2];
// Copy the contents to the new buffer
// Note that this will store the first logical item in the
// first physical array element.
for (int i = 0; i < buffer.length; i++)
{
newBuffer[i] = elementAt(i);
}
// Re-initialize with new contents, keep old nbrEntries
buffer = newBuffer;
sizeLessOne = buffer.length - 1;
offset = 0;
}
/** Initialize the queue.
* @param size The initial size of the queue
*/
private final void init(int size) {
// Allocate buffer
buffer = new Token[size];
// Other initialization
sizeLessOne = size - 1;
offset = 0;
nbrEntries = 0;
}
/** Remove token from front of queue */
public final void removeFirst() {
offset = (offset+1) & sizeLessOne;
nbrEntries--;
}
}
1.1 e/src/jsrc/antlr/TokenRangeElement.java
Index: TokenRangeElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenRangeElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class TokenRangeElement extends AlternativeElement {
String label;
protected int begin=Token.INVALID_TYPE;
protected int end =Token.INVALID_TYPE;
protected String beginText;
protected String endText;
public TokenRangeElement(Grammar g, Token t1, Token t2, int autoGenType) {
super(g, autoGenType);
begin = grammar.tokenManager.getTokenSymbol(t1.getText()).getTokenType();
beginText = t1.getText();
end = grammar.tokenManager.getTokenSymbol(t2.getText()).getTokenType();
endText = t2.getText();
line = t1.getLine();
}
public void generate() {
grammar.generator.gen(this);
}
public String getLabel() {
return label;
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public void setLabel(String label_) {
label = label_;
}
public String toString() {
if ( label!=null ) {
return " "+label+":"+beginText+".."+endText;
}
else {
return " "+beginText+".."+endText;
}
}
}
1.1 e/src/jsrc/antlr/TokenRefElement.java
Index: TokenRefElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenRefElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class TokenRefElement extends GrammarAtom {
public TokenRefElement(Grammar g,
Token t,
boolean inverted,
int autoGenType)
{
super(g, t, autoGenType);
not = inverted;
TokenSymbol ts = grammar.tokenManager.getTokenSymbol(atomText);
if (ts == null) {
g.tool.error("Undefined token symbol: " +
atomText, grammar.getFilename(), t.getLine());
} else {
tokenType = ts.getTokenType();
// set the AST node type to whatever was set in tokens {...}
// section (if anything);
// Lafter, after this is created, the element option can set this.
setASTNodeType(ts.getASTNodeType());
}
line = t.getLine();
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
}
1.1 e/src/jsrc/antlr/TokenStream.java
Index: TokenStream.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStream.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
public interface TokenStream {
public Token nextToken() throws TokenStreamException;
}
1.1 e/src/jsrc/antlr/TokenStreamBasicFilter.java
Index: TokenStreamBasicFilter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamBasicFilter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
/** This object is a TokenStream that passes through all
* tokens except for those that you tell it to discard.
* There is no buffering of the tokens.
*/
public class TokenStreamBasicFilter implements TokenStream {
/** The set of token types to discard */
protected BitSet discardMask;
/** The input stream */
protected TokenStream input;
public TokenStreamBasicFilter(TokenStream input) {
this.input = input;
discardMask = new BitSet();
}
public void discard(int ttype) {
discardMask.add(ttype);
}
public void discard(BitSet mask) {
discardMask = mask;
}
public Token nextToken() throws TokenStreamException {
Token tok = input.nextToken();
while ( tok!=null && discardMask.member(tok.getType()) ) {
tok = input.nextToken();
}
return tok;
}
}
1.1 e/src/jsrc/antlr/TokenStreamException.java
Index: TokenStreamException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**
* Anything that goes wrong while generating a stream of tokens.
*/
public class TokenStreamException extends ANTLRException {
public TokenStreamException() {
}
public TokenStreamException(String s) {
super(s);
}
}
1.1 e/src/jsrc/antlr/TokenStreamHiddenTokenFilter.java
Index: TokenStreamHiddenTokenFilter.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamHiddenTokenFilter.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
/**This object filters a token stream coming from a lexer
* or another TokenStream so that only certain token channels
* get transmitted to the parser.
*
* Any of the channels can be filtered off as "hidden" channels whose
* tokens can be accessed from the parser.
*/
public class TokenStreamHiddenTokenFilter extends TokenStreamBasicFilter implements TokenStream {
// protected BitSet discardMask;
protected BitSet hideMask;
private CommonHiddenStreamToken nextMonitoredToken;
/** track tail of hidden list emanating from previous
* monitored token
*/
protected CommonHiddenStreamToken lastHiddenToken;
protected CommonHiddenStreamToken firstHidden = null;
public TokenStreamHiddenTokenFilter(TokenStream input) {
super(input);
hideMask = new BitSet();
}
protected void consume() throws TokenStreamException {
nextMonitoredToken = (CommonHiddenStreamToken)input.nextToken();
}
private void consumeFirst() throws TokenStreamException {
consume(); // get first token of input stream
// Handle situation where hidden or discarded tokens
// appear first in input stream
CommonHiddenStreamToken p=null;
// while hidden or discarded scarf tokens
while ( hideMask.member(LA(1).getType()) || discardMask.member(LA(1).getType()) ) {
if ( hideMask.member(LA(1).getType()) ) {
if ( p==null ) {
p = LA(1);
}
else {
p.setHiddenAfter(LA(1));
LA(1).setHiddenBefore(p); // double-link
p = LA(1);
}
lastHiddenToken = p;
if (firstHidden==null) {
firstHidden = p; // record hidden token if first
}
}
consume();
}
}
public BitSet getDiscardMask() {return discardMask;}
/** Return a ptr to the hidden token appearing immediately after
* token t in the input stream.
*/
public CommonHiddenStreamToken getHiddenAfter(CommonHiddenStreamToken t) {
return t.getHiddenAfter();
}
/** Return a ptr to the hidden token appearing immediately before
* token t in the input stream.
*/
public CommonHiddenStreamToken getHiddenBefore(CommonHiddenStreamToken t) {
return t.getHiddenBefore();
}
public BitSet getHideMask() {return hideMask;}
/** Return the first hidden token if one appears
* before any monitored token.
*/
public CommonHiddenStreamToken getInitialHiddenToken() {
return firstHidden;
}
public void hide(int m) {
hideMask.add(m);
}
public void hide(BitSet mask) {
hideMask = mask;
}
protected CommonHiddenStreamToken LA(int i) {
return nextMonitoredToken;
}
/** Return the next monitored token.
* Test the token following the monitored token.
* If following is another monitored token, save it
* for the next invocation of nextToken (like a single
* lookahead token) and return it then.
* If following is unmonitored, nondiscarded (hidden)
* channel token, add it to the monitored token.
*
* Note: EOF must be a monitored Token.
*/
public Token nextToken() throws TokenStreamException {
// handle an initial condition; don't want to get lookahead
// token of this splitter until first call to nextToken
if ( LA(1)==null ) {
consumeFirst();
}
// we always consume hidden tokens after monitored, thus,
// upon entry LA(1) is a monitored token.
CommonHiddenStreamToken monitored = LA(1);
// point to hidden tokens found during last invocation
monitored.setHiddenBefore(lastHiddenToken);
lastHiddenToken = null;
// Look for hidden tokens, hook them into list emanating
// from the monitored tokens.
consume();
CommonHiddenStreamToken p = monitored;
// while hidden or discarded scarf tokens
while ( hideMask.member(LA(1).getType()) || discardMask.member(LA(1).getType()) ) {
if ( hideMask.member(LA(1).getType()) ) {
// attach the hidden token to the monitored in a chain
// link forwards
p.setHiddenAfter(LA(1));
// link backwards
if (p != monitored) { //hidden cannot point to monitored tokens
LA(1).setHiddenBefore(p);
}
p = lastHiddenToken = LA(1);
}
consume();
}
return monitored;
}
}
1.1 e/src/jsrc/antlr/TokenStreamIOException.java
Index: TokenStreamIOException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamIOException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.IOException;
/**
* Wraps an IOException in a TokenStreamException
*/
public class TokenStreamIOException extends TokenStreamException {
public IOException io;
/**
* TokenStreamIOException constructor comment.
* @param s java.lang.String
*/
public TokenStreamIOException(IOException io) {
super(io.getMessage());
this.io = io;
}
}
1.1 e/src/jsrc/antlr/TokenStreamRecognitionException.java
Index: TokenStreamRecognitionException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamRecognitionException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**
* Wraps a RecognitionException in a TokenStreamException so you
* can pass it along.
*/
public class TokenStreamRecognitionException extends TokenStreamException {
public RecognitionException recog;
public TokenStreamRecognitionException(RecognitionException re) {
super(re.getMessage());
this.recog = re;
}
}
1.1 e/src/jsrc/antlr/TokenStreamRetryException.java
Index: TokenStreamRetryException.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamRetryException.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**
* Aborted recognition of current token. Try to get one again.
* Used by TokenStreamSelector.retry() to force nextToken()
* of stream to re-enter and retry.
*/
public class TokenStreamRetryException extends TokenStreamException {
public TokenStreamRetryException() {
}
}
1.1 e/src/jsrc/antlr/TokenStreamSelector.java
Index: TokenStreamSelector.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenStreamSelector.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.util.Hashtable;
import antlr.collections.impl.LList;
import antlr.collections.Stack;
import java.io.IOException;
/** A token stream MUX (multiplexor) knows about n token streams
* and can multiplex them onto the same channel for use by token
* stream consumer like a parser. This is a way to have multiple
* lexers break up the same input stream for a single parser.
* Or, you can have multiple instances of the same lexer handle
* multiple input streams; this works great for includes.
*/
public class TokenStreamSelector implements TokenStream {
/** The set of inputs to the MUX */
protected Hashtable inputStreamNames;
/** The currently-selected token stream input */
protected TokenStream input;
/** Used to track stack of input streams */
protected Stack streamStack = new LList();
public TokenStreamSelector() {
super();
inputStreamNames = new Hashtable();
}
public void addInputStream(TokenStream stream, String key) {
inputStreamNames.put(key, stream);
}
/** Return the stream from tokens are being pulled at
* the moment.
*/
public TokenStream getCurrentStream() {
return input;
}
public TokenStream getStream(String sname) {
TokenStream stream = (TokenStream)inputStreamNames.get(sname);
if ( stream==null ) {
throw new IllegalArgumentException("TokenStream "+sname+" not found");
}
return stream;
}
public Token nextToken() throws TokenStreamException {
// return input.nextToken();
// keep looking for a token until you don't
// get a retry exception.
for (;;) {
try {
return input.nextToken();
}
catch (TokenStreamRetryException r) {
// just retry "forever"
}
}
}
public TokenStream pop() {
TokenStream stream = (TokenStream) streamStack.pop();
select(stream);
return stream;
}
public void push(TokenStream stream) {
streamStack.push(input); // save current stream
select(stream);
}
public void push(String sname) {
streamStack.push(input);
select(sname);
}
/** Abort recognition of current Token and try again.
* A stream can push a new stream (for include files
* for example, and then retry(), which will cause
* the current stream to abort back to this.nextToken().
* this.nextToken() then asks for a token from the
* current stream, which is the new "substream."
*/
public void retry() throws TokenStreamRetryException {
throw new TokenStreamRetryException();
}
/** Set the stream without pushing old stream */
public void select(TokenStream stream) {
input = stream;
}
public void select(String sname) throws IllegalArgumentException {
input = getStream(sname);
}
}
1.1 e/src/jsrc/antlr/TokenSymbol.java
Index: TokenSymbol.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TokenSymbol.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
class TokenSymbol extends GrammarSymbol {
protected int ttype;
/** describes what token matches in "human terms" */
protected String paraphrase = null;
/** Set to a value in the tokens {...} section */
protected String ASTNodeType;
public TokenSymbol(String r) {
super(r);
ttype = Token.INVALID_TYPE;
}
public String getASTNodeType() {
return ASTNodeType;
}
public void setASTNodeType(String type) {
ASTNodeType = type;
}
public String getParaphrase() {return paraphrase;}
public int getTokenType() {
return ttype;
}
public void setParaphrase(String p) {paraphrase = p;}
public void setTokenType(int t) {
ttype = t;
}
}
1.1 e/src/jsrc/antlr/Tool.java
Index: Tool.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: Tool.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import java.io.*;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
public class Tool {
public static final String version = "2.7.1";
/** Object that handles analysis errors */
ToolErrorHandler errorHandler;
/** Was there an error during parsing or analysis? */
protected boolean hasError = false;
/** Generate diagnostics? (vs code) */
boolean genDiagnostics = false;
/** Generate HTML vs code? */
boolean genHTML = false;
/** Current output directory for generated files */
protected static String outputDir = ".";
// Grammar input
String grammarFile;
transient Reader f = new InputStreamReader(System.in);
// SAS: changed for proper text io
// transient DataInputStream in = null;
protected static String literalsPrefix = "LITERAL_";
protected static boolean upperCaseMangledLiterals = false;
/** C++ file level options */
protected static NameSpace nameSpace = null;
protected static String namespaceAntlr = null;
protected static String namespaceStd = null;
protected static boolean genHashLines = true;
private static BitSet cmdLineArgValid = new BitSet();
/** Construct a new Tool. */
public Tool() {
errorHandler = new DefaultToolErrorHandler();
}
public static void setFileLineFormatter(FileLineFormatter formatter) {
FileLineFormatter.setFormatter(formatter);
}
private static void checkForInvalidArguments(String[] args, BitSet cmdLineArgValid) {
// check for invalid command line args
for (int a = 0; a < args.length; a++) {
if (!cmdLineArgValid.member(a)) {
warning("invalid command-line argument: " + args[a] + "; ignored");
}
}
}
/** This example is from the book _Java in a Nutshell_ by David
* Flanagan. Written by David Flanagan. Copyright (c) 1996
* O'Reilly & Associates. You may study, use, modify, and
* distribute this example for any purpose. This example is
* provided WITHOUT WARRANTY either expressed or implied. */
public static void copyFile(String source_name, String dest_name)
throws IOException
{
File source_file = new File(source_name);
File destination_file = new File(dest_name);
FileReader source = null; // SAS: changed for proper text io
FileWriter destination = null;
char[] buffer;
int bytes_read;
try {
// First make sure the specified source file
// exists, is a file, and is readable.
if (!source_file.exists() || !source_file.isFile())
throw new FileCopyException("FileCopy: no such source file: " +
source_name);
if (!source_file.canRead())
throw new FileCopyException("FileCopy: source file " +
"is unreadable: " + source_name);
// If the destination exists, make sure it is a writeable file
// and ask before overwriting it. If the destination doesn't
// exist, make sure the directory exists and is writeable.
if (destination_file.exists()) {
if (destination_file.isFile()) {
DataInputStream in = new DataInputStream(System.in);
String response;
if (!destination_file.canWrite())
throw new FileCopyException("FileCopy: destination " +
"file is unwriteable: " + dest_name);
/*
System.out.print("File " + dest_name +
" already exists. Overwrite? (Y/N): ");
System.out.flush();
response = in.readLine();
if (!response.equals("Y") && !response.equals("y"))
throw new FileCopyException("FileCopy: copy cancelled.");
*/
}
else{
throw new FileCopyException("FileCopy: destination "
+ "is not a file: " + dest_name);
}
}
else {
File parentdir = parent(destination_file);
if (!parentdir.exists())
throw new FileCopyException("FileCopy: destination "
+ "directory doesn't exist: " + dest_name);
if (!parentdir.canWrite())
throw new FileCopyException("FileCopy: destination "
+ "directory is unwriteable: " + dest_name);
}
// If we've gotten this far, then everything is okay; we can
// copy the file.
source = new FileReader(source_file);
destination = new FileWriter(destination_file);
buffer = new char[1024];
while(true) {
bytes_read = source.read(buffer,0,1024);
if (bytes_read == -1) break;
destination.write(buffer, 0, bytes_read);
}
}
// No matter what happens, always close any streams we've opened.
finally {
if (source != null)
try { source.close(); } catch (IOException e) { ; }
if (destination != null)
try { destination.close(); } catch (IOException e) { ; }
}
}
/** Perform processing on the grammar file. Can only be called
* from main() @param args The command-line arguments passed to
* main()
*/
protected void doEverything(String[] args) {
// SAS: removed "private" so subclass can call
// (The subclass is for the VAJ interface)
// run the preprocessor to handle inheritance first.
antlr.preprocessor.Tool preTool = new antlr.preprocessor.Tool(this, args);
if ( !preTool.preprocess() ) {
System.exit(1);
}
String[] modifiedArgs = preTool.preprocessedArgList();
// process arguments for the Tool
processArguments(modifiedArgs);
f = getGrammarReader();
TokenBuffer tokenBuf = new TokenBuffer(new ANTLRLexer(f));
LLkAnalyzer analyzer = new LLkAnalyzer(this);
MakeGrammar behavior = new MakeGrammar(this, args, analyzer);
try {
ANTLRParser p = new ANTLRParser(tokenBuf, behavior, this);
p.setFilename(grammarFile);
p.grammar();
if (hasError) {
System.err.println("Exiting due to errors.");
System.exit(1);
}
checkForInvalidArguments(modifiedArgs, cmdLineArgValid);
// Create the right code generator according to the "language" option
CodeGenerator codeGen;
// SAS: created getLanguage() method so subclass can override
// (necessary for VAJ interface)
String codeGenClassName = "antlr." + getLanguage(behavior) + "CodeGenerator";
try {
Class codeGenClass = Class.forName(codeGenClassName);
codeGen = (CodeGenerator)codeGenClass.newInstance();
codeGen.setBehavior(behavior);
codeGen.setAnalyzer(analyzer);
codeGen.setTool(this);
codeGen.gen();
}
catch (ClassNotFoundException cnfe) {
panic("Cannot instantiate code-generator: " + codeGenClassName);
}
catch (InstantiationException ie) {
panic("Cannot instantiate code-generator: " + codeGenClassName);
}
catch (IllegalArgumentException ie) {
panic("Cannot instantiate code-generator: " + codeGenClassName);
}
catch (IllegalAccessException iae) {
panic("code-generator class '" + codeGenClassName + "' is not accessible");
}
}
catch (RecognitionException pe) {
System.err.println("Unhandled parser error: " + pe.getMessage());
System.exit(1);
}
catch (TokenStreamException io) {
System.err.println("TokenStreamException: " + io.getMessage());
System.exit(1);
}
System.exit(0);
}
/** Issue an error
* @param s The message
*/
public void error(String s) {
hasError = true;
System.err.println("error: "+s);
}
/** Issue an error with line number information
* @param s The message
* @param file The file that has the error
* @param line The grammar file line number on which the error occured
*/
public void error(String s, String file, int line) {
hasError = true;
if ( file!=null ) {
System.err.println(FileLineFormatter.getFormatter().getFormatString(file,line)+s);
}
else {
System.err.println("line "+line+": "+s);
}
}
/** When we are 1.1 compatible...
public static Object factory2 (String p, Object[] initargs) {
Class c;
Object o = null;
try {
int argslen = initargs.length;
Class cl[] = new Class[argslen];
for (int i=0;i<argslen;i++) {
cl[i] = Class.forName(initargs[i].getClass().getName());
}
c = Class.forName (p);
Constructor con = c.getConstructor (cl);
o = con.newInstance (initargs);
} catch (Exception e) {
System.err.println ("Can't make a " + p);
}
return o;
}
*/
public static Object factory(String p) {
Class c;
Object o=null;
try {
c = Class.forName(p);// get class def
o = c.newInstance(); // make a new one
}
catch (Exception e) {
// either class not found,
// class is interface/abstract, or
// class or initializer is not accessible.
warning("Can't create an object of type " + p);
return null;
}
return o;
}
public static String fileMinusPath(String f) {
String separator = System.getProperty("file.separator");
int endOfPath = f.lastIndexOf(separator);
if ( endOfPath == -1 ) {
return f; // no path found
}
return f.substring(endOfPath+1);
}
/** Determine the language used for this run of ANTLR
* This was made a method so the subclass can override it
*/
public String getLanguage(MakeGrammar behavior) {
if (genDiagnostics) {
return "Diagnostic";
}
if (genHTML) {
return "HTML";
}
return behavior.language;
}
public static String getOutputDirectory() { return outputDir; }
private static void help() {
System.err.println("usage: java antlr.Tool [args] file.g");
System.err.println(" -o outputDir specify output directory where all output generated.");
System.err.println(" -glib superGrammar specify location of supergrammar file.");
System.err.println(" -debug launch the ParseView debugger upon parser invocation.");
System.err.println(" -html generate an html file from your grammar (minus actions).");
System.err.println(" -diagnostic generate a textfile with diagnostics.");
System.err.println(" -trace have all rules call traceIn/traceOut.");
System.err.println(" -traceParser have parser rules call traceIn/traceOut.");
System.err.println(" -traceLexer have lexer rules call traceIn/traceOut.");
System.err.println(" -traceTreeParser have tree parser rules call traceIn/traceOut.");
}
public static void main(String[] args) {
System.err.println("ANTLR Parser Generator Version "+
Tool.version+" 1989-2000 jGuru.com");
try {
if ( args.length==0 ) {
help();
}
Tool theTool = new Tool();
theTool.doEverything(args);
theTool = null;
}
catch (Exception e) {
System.err.println(System.getProperty("line.separator")+
System.getProperty("line.separator"));
System.err.println("#$%%*&@# internal error: "+e.toString());
System.err.println("[complain to nearest government official");
System.err.println(" or send hate-mail to parrt@jguru.com;");
System.err.println(" please send stack trace with report.]"+
System.getProperty("line.separator"));
e.printStackTrace();
}
System.exit(0);
}
public static PrintWriter openOutputFile(String f) throws IOException {
return new PrintWriter(new FileWriter(outputDir+System.getProperty("file.separator")+f));
}
public Reader getGrammarReader() {
try {
if (grammarFile != null) {
f = new FileReader(grammarFile);
}
}
catch (IOException e) {
panic("Error: cannot open grammar file " + grammarFile);
help();
System.exit(1);
}
return f;
}
/** Issue an unknown fatal error */
public static void panic() {
System.err.println("panic");
System.exit(1);
}
/** Issue a fatal error message
* @param s The message
*/
public static void panic(String s) {
System.err.println("panic: "+s);
System.exit(1);
}
// File.getParent() can return null when the file is specified without
// a directory or is in the root directory.
// This method handles those cases.
public static File parent(File f) {
String dirname = f.getParent();
if (dirname == null) {
if (f.isAbsolute()) return new File(File.separator);
else return new File(System.getProperty("user.dir"));
}
return new File(dirname);
}
/** Parse a list such as "f1.g;f2.g;..." and return a Vector
* of the elements.
*/
public static Vector parseSeparatedList(String list, char separator) {
Vector v = new Vector(10);
StringBuffer buf = new StringBuffer(100);
int i=0;
while ( i<list.length() ) {
while ( i<list.length() && list.charAt(i)!=separator ) {
buf.append(list.charAt(i));
i++;
}
// add element to vector
v.appendElement(buf.toString());
buf.setLength(0);
// must be a separator or finished.
if ( i<list.length() ) { // not done?
i++; // skip separator
}
}
if ( v.size()==0 ) return null;
return v;
}
/** given a filename, strip off the directory prefix (if any)
* and return it. Return "./" if f has no dir prefix.
*/
public static String pathToFile(String f) {
String separator = System.getProperty("file.separator");
int endOfPath = f.lastIndexOf(separator);
if ( endOfPath == -1 ) {
// no path, use current directory
return "."+System.getProperty("file.separator");
}
return f.substring(0, endOfPath+1);
}
/** Process the command-line arguments. Can only be called by Tool.
* @param args The command-line arguments passed to main()
*/
private void processArguments(String[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-diagnostic")) {
genDiagnostics = true;
genHTML = false;
Tool.setArgOK(i);
} else {
if (args[i].equals("-o")) {
Tool.setArgOK(i);
if (i + 1 >= args.length) {
error("missing output directory with -o option; ignoring");
} else {
i++;
setOutputDirectory(args[i]);
Tool.setArgOK(i);
}
} else
if (args[i].equals("-html")) {
genHTML = true;
genDiagnostics = false;
Tool.setArgOK(i);
} else {
if (args[i].charAt(0) != '-') {
// Must be the grammar file
grammarFile = args[i];
Tool.setArgOK(i);
}
}
}
}
}
public static void setArgOK(int i) {
cmdLineArgValid.add(i);
}
public static void setOutputDirectory(String o) { outputDir = o; }
/** General-purpose utility function for removing
* characters from back of string
* @param s The string to process
* @param c The character to remove
* @return The resulting string
*/
static public String stripBack(String s, char c) {
while (s.length() > 0 && s.charAt(s.length()-1) == c)
{
s = s.substring(0, s.length()-1);
}
return s;
}
/** General-purpose utility function for removing
* characters from back of string
* @param s The string to process
* @param remove A string containing the set of characters to remove
* @return The resulting string
*/
static public String stripBack(String s, String remove) {
boolean changed;
do {
changed = false;
for (int i = 0; i < remove.length(); i++) {
char c = remove.charAt(i);
while (s.length() > 0 && s.charAt(s.length()-1) == c)
{
changed = true;
s = s.substring(0, s.length()-1);
}
}
} while (changed);
return s;
}
/** General-purpose utility function for removing
* characters from front of string
* @param s The string to process
* @param c The character to remove
* @return The resulting string
*/
static public String stripFront(String s, char c) {
while (s.length() > 0 && s.charAt(0) == c) {
s = s.substring(1);
}
return s;
}
/** General-purpose utility function for removing
* characters from front of string
* @param s The string to process
* @param remove A string containing the set of characters to remove
* @return The resulting string
*/
static public String stripFront(String s, String remove) {
boolean changed;
do {
changed = false;
for (int i = 0; i < remove.length(); i++) {
char c = remove.charAt(i);
while (s.length() > 0 && s.charAt(0) == c) {
changed = true;
s = s.substring(1);
}
}
} while (changed);
return s;
}
/** General-purpose utility function for removing
* characters from the front and back of string
* @param s The string to process
* @param head exact string to strip from head
* @param tail exact string to strip from tail
* @return The resulting string
*/
public static String stripFrontBack(String src, String head, String tail) {
int h = src.indexOf(head);
int t = src.lastIndexOf(tail);
if ( h==-1 || t==-1 ) return src;
return src.substring(h+1,t);
}
/** Issue an error; used for general tool errors not for grammar stuff
* @param s The message
*/
public static void toolError(String s) {
System.err.println("error: "+s);
}
/** Issue a warning
* @param s the message
*/
public static void warning(String s) {
System.err.println("warning: "+s);
}
/** Issue a warning with line number information
* @param s The message
* @param file The file that has the warning
* @param line The grammar file line number on which the warning occured
*/
public static void warning(String s, String file, int line) {
if ( file!=null ) {
System.err.println(FileLineFormatter.getFormatter().getFormatString(file,line)+"warning:"+s);
}
else {
System.err.println("warning; line "+line+": "+s);
}
}
/** Issue a warning with line number information
* @param s The lines of the message
* @param file The file that has the warning
* @param line The grammar file line number on which the warning occured
*/
public static void warning(String[] s, String file, int line) {
if ( s==null || s.length==0 ) {
panic("bad multi-line message to Tool.warning");
}
if ( file!=null ) {
System.err.println(FileLineFormatter.getFormatter().getFormatString(file,line)+"warning:"+s[0]);
for (int i=1; i<s.length; i++) {
System.err.println(FileLineFormatter.getFormatter().getFormatString(file,line)+s[i]);
}
}
else {
System.err.println("warning: line "+line+": "+s[0]);
for (int i=1; i<s.length; i++) {
System.err.println("warning: line "+line+": "+s[i]);
}
}
}
/**
* Support C++ namespaces (for now). Add a nested namespace name to the
* current namespace.
* DAW: David Wagner
*/
public void setNameSpace(String name) {
if ( null == nameSpace )
nameSpace = new NameSpace(stripFrontBack(name,"\"", "\""));
}
}
1.1 e/src/jsrc/antlr/ToolErrorHandler.java
Index: ToolErrorHandler.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ToolErrorHandler.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
import antlr.collections.impl.BitSet;
interface ToolErrorHandler {
/** Issue a warning about ambiguity between a alternates
* @param blk The block being analyzed
* @param lexicalAnalysis true for lexical rule
* @param depth The depth of the ambiguity
* @param sets An array of bitsets containing the ambiguities
* @param altIdx1 The zero-based index of the first ambiguous alternative
* @param altIdx2 The zero-based index of the second ambiguous alternative
*/
public void warnAltAmbiguity(
Grammar grammar,
AlternativeBlock blk,
boolean lexicalAnalysis,
int depth,
Lookahead[] sets,
int altIdx1,
int altIdx2
);
/** Issue a warning about ambiguity between an alternate and exit path.
* @param blk The block being analyzed
* @param lexicalAnalysis true for lexical rule
* @param depth The depth of the ambiguity
* @param sets An array of bitsets containing the ambiguities
* @param altIdx The zero-based index of the ambiguous alternative
*/
public void warnAltExitAmbiguity(
Grammar grammar,
BlockWithImpliedExitPath blk,
boolean lexicalAnalysis,
int depth,
Lookahead[] sets,
int altIdx
);
}
1.1 e/src/jsrc/antlr/TreeBlockContext.java
Index: TreeBlockContext.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TreeBlockContext.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/**The context needed to add root,child elements to a Tree. There
* is only one alternative (i.e., a list of children). We subclass to
* specialize. MakeGrammar.addElementToCurrentAlt will work correctly
* now for either a block of alts or a Tree child list.
*
* The first time addAlternativeElement is called, it sets the root element
* rather than adding it to one of the alternative lists. Rather than have
* the grammar duplicate the rules for grammar atoms etc... we use the same
* grammar and same refToken behavior etc... We have to special case somewhere
* and here is where we do it.
*/
class TreeBlockContext extends BlockContext {
protected boolean nextElementIsRoot = true;
public void addAlternativeElement(AlternativeElement e) {
TreeElement tree = (TreeElement)block;
if ( nextElementIsRoot ) {
tree.root = (GrammarAtom)e;
nextElementIsRoot = false;
}
else {
super.addAlternativeElement(e);
}
}
}
1.1 e/src/jsrc/antlr/TreeElement.java
Index: TreeElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TreeElement.java,v 1.1 2001/10/03 21:04:13 markm Exp $
*/
/** A TreeElement is a block with one alternative and a root node */
class TreeElement extends AlternativeBlock {
GrammarAtom root;
public TreeElement(Grammar g, int line) {
super(g, line, false);
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
String s = " #(" + root;
Alternative a = (Alternative)alternatives.elementAt(0);
AlternativeElement p = a.head;
while ( p!=null ) {
s += p;
p = p.next;
}
return s + " )";
}
}
1.1 e/src/jsrc/antlr/TreeParser.java
Index: TreeParser.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TreeParser.java,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
import java.util.NoSuchElementException;
import antlr.collections.AST;
import antlr.collections.impl.BitSet;
public class TreeParser {
/** The AST Null object; the parsing cursor is set to this when
* it is found to be null. This way, we can test the
* token type of a node without having to have tests for null
* everywhere.
*/
public static ASTNULLType ASTNULL = new ASTNULLType();
/** Where did this rule leave off parsing; avoids a return parameter */
protected AST _retTree;
/** guessing nesting level; guessing==0 implies not guessing */
// protected int guessing = 0;
/** Nesting level of registered handlers */
// protected int exceptionLevel = 0;
protected TreeParserSharedInputState inputState;
/** Table of token type to token names */
protected String[] tokenNames;
/** AST return value for a rule is squirreled away here */
protected AST returnAST;
/** AST support code; parser and treeparser delegate to this object */
protected ASTFactory astFactory = new ASTFactory();
/** Used to keep track of indentdepth for traceIn/Out */
protected int traceDepth = 0;
public TreeParser() {
inputState = new TreeParserSharedInputState();
}
/** Get the AST return value squirreled away in the parser */
public AST getAST() {
return returnAST;
}
public ASTFactory getASTFactory() {
return astFactory;
}
public String getTokenName(int num) {
return tokenNames[num];
}
public String[] getTokenNames() {
return tokenNames;
}
protected void match(AST t, int ttype) throws MismatchedTokenException {
//System.out.println("match("+ttype+"); cursor is "+t);
if ( t==null || t==ASTNULL || t.getType() != ttype ) {
throw new MismatchedTokenException(getTokenNames(), t, ttype, false);
}
}
/**Make sure current lookahead symbol matches the given set
* Throw an exception upon mismatch, which is catch by either the
* error handler or by the syntactic predicate.
*/
public void match(AST t, BitSet b) throws MismatchedTokenException {
if ( t==null || t==ASTNULL || !b.member(t.getType()) ) {
throw new MismatchedTokenException(getTokenNames(), t, b, false);
}
}
protected void matchNot(AST t, int ttype) throws MismatchedTokenException {
//System.out.println("match("+ttype+"); cursor is "+t);
if ( t==null || t==ASTNULL || t.getType() == ttype ) {
throw new MismatchedTokenException(getTokenNames(), t, ttype, true);
}
}
public static void panic() {
System.err.println("TreeWalker: panic");
System.exit(1);
}
/** Parser error-reporting function can be overridden in subclass */
public void reportError(RecognitionException ex) {
System.err.println(ex.toString());
}
/** Parser error-reporting function can be overridden in subclass */
public void reportError(String s) {
System.err.println("error: " + s);
}
/** Parser warning-reporting function can be overridden in subclass */
public void reportWarning(String s) {
System.err.println("warning: " + s);
}
/** Specify an object with support code (shared by
* Parser and TreeParser. Normally, the programmer
* does not play with this, using setASTNodeType instead.
*/
public void setASTFactory(ASTFactory f) {
astFactory = f;
}
/** Specify the type of node to create during tree building */
public void setASTNodeType(String nodeType) {
setASTNodeClass(nodeType);
}
/** Specify the type of node to create during tree building */
public void setASTNodeClass(String nodeType) {
astFactory.setASTNodeType(nodeType);
}
public void traceIndent() {
for( int i = 0; i < traceDepth; i++ )
System.out.print(" ");
}
public void traceIn(String rname, AST t) {
traceDepth += 1;
traceIndent();
System.out.println("> "+rname+
"("+(t!=null?t.toString():"null")+")"+
((inputState.guessing>0)?" [guessing]":""));
}
public void traceOut(String rname, AST t) {
traceIndent();
System.out.println("< "+rname+
"("+(t!=null?t.toString():"null")+")"+
((inputState.guessing>0)?" [guessing]":""));
traceDepth--;
}
}
1.1 e/src/jsrc/antlr/TreeParserSharedInputState.java
Index: TreeParserSharedInputState.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TreeParserSharedInputState.java,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
/** This object contains the data associated with an
* input AST. Multiple parsers
* share a single TreeParserSharedInputState to parse
* the same tree or to have the parser walk multiple
* trees.
*/
public class TreeParserSharedInputState {
/** Are we guessing (guessing>0)? */
public int guessing = 0;
}
1.1 e/src/jsrc/antlr/TreeSpecifierNode.java
Index: TreeSpecifierNode.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TreeSpecifierNode.java,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
class TreeSpecifierNode {
private TreeSpecifierNode parent = null;
private TreeSpecifierNode firstChild = null;
private TreeSpecifierNode nextSibling = null;
private Token tok;
TreeSpecifierNode(Token tok_)
{
tok = tok_;
}
public TreeSpecifierNode getFirstChild() { return firstChild; }
public TreeSpecifierNode getNextSibling() { return nextSibling; }
// Accessors
public TreeSpecifierNode getParent() { return parent; }
public Token getToken() { return tok; }
public void setFirstChild(TreeSpecifierNode child) {
firstChild = child;
child.parent = this;
}
// Structure-building
public void setNextSibling(TreeSpecifierNode sibling) {
nextSibling = sibling;
sibling.parent = parent;
}
}
1.1 e/src/jsrc/antlr/TreeWalkerGrammar.java
Index: TreeWalkerGrammar.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: TreeWalkerGrammar.java,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
/** Parser-specific grammar subclass */
class TreeWalkerGrammar extends Grammar {
// true for transform mode
protected boolean transform = false;
TreeWalkerGrammar(String className_, Tool tool_, String superClass) {
super(className_, tool_, superClass);
}
/** Top-level call to generate the code for this grammar */
public void generate() throws IOException {
generator.gen(this);
}
// Get name of class from which generated parser/lexer inherits
protected String getSuperClass() { return "TreeParser"; }
/**Process command line arguments.
* -trace have all rules call traceIn/traceOut
* -traceParser have parser rules call traceIn/traceOut
* -debug generate debugging output for parser debugger
*/
public void processArguments(String[] args) {
for (int i=0; i<args.length; i++) {
if ( args[i].equals("-trace") ) {
traceRules = true;
Tool.setArgOK(i);
}
else if ( args[i].equals("-traceTreeParser") ) {
traceRules = true;
Tool.setArgOK(i);
}
// else if ( args[i].equals("-debug") ) {
// debuggingOutput = true;
// superClass = "parseview.DebuggingTreeWalker";
// Tool.setArgOK(i);
// }
}
}
/** Set tree parser options */
public boolean setOption(String key, Token value) {
if (key.equals("buildAST")) {
if (value.getText().equals("true")) {
buildAST = true;
} else if (value.getText().equals("false")) {
buildAST = false;
} else {
tool.error("buildAST option must be true or false", getFilename(), value.getLine());
}
return true;
}
if (key.equals("ASTLabelType")) {
super.setOption(key, value);
return true;
}
if (super.setOption(key, value)) {
return true;
}
tool.error("Invalid option: " + key, getFilename(), value.getLine());
return false;
}
}
1.1 e/src/jsrc/antlr/WildcardElement.java
Index: WildcardElement.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: WildcardElement.java,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
class WildcardElement extends GrammarAtom {
protected String label;
public WildcardElement(Grammar g, Token t, int autoGenType) {
super(g, t, autoGenType);
line = t.getLine();
}
public void generate() {
grammar.generator.gen(this);
}
public String getLabel() {
return label;
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public void setLabel(String label_) {
label = label_;
}
public String toString() {
String s = " ";
if ( label!=null ) s += label+":";
return s + ".";
}
}
1.1 e/src/jsrc/antlr/ZeroOrMoreBlock.java
Index: ZeroOrMoreBlock.java
===================================================================
package antlr;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: ZeroOrMoreBlock.java,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
class ZeroOrMoreBlock extends BlockWithImpliedExitPath {
public ZeroOrMoreBlock(Grammar g) {
super(g);
}
public ZeroOrMoreBlock(Grammar g, int line) {
super(g, line);
}
public void generate() {
grammar.generator.gen(this);
}
public Lookahead look(int k) {
return grammar.theLLkAnalyzer.look(k, this);
}
public String toString() {
return super.toString() + "*";
}
}
1.1 e/src/jsrc/antlr/antlr.g
Index: antlr.g
===================================================================
header {
package antlr;
}
{
import java.util.Enumeration;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;
}
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: antlr.g,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
class ANTLRParser extends Parser;
options {
exportVocab=ANTLR;
defaultErrorHandler=false;
k=2;
}
tokens {
"tokens";
}
{
private static final boolean DEBUG_PARSER = false;
ANTLRGrammarParseBehavior behavior;
Tool tool;
protected int blockNesting= -1;
public ANTLRParser(
TokenBuffer tokenBuf,
ANTLRGrammarParseBehavior behavior_,
Tool tool_
) {
super(tokenBuf, 1);
tokenNames = _tokenNames;
behavior = behavior_;
tool = tool_;
}
private boolean lastInRule() throws TokenStreamException {
if ( blockNesting==0 && (LA(1)==SEMI || LA(1)==LITERAL_exception || LA(1)==OR) ) {
return true;
}
return false;
}
private void checkForMissingEndRule(Token label) {
if ( label.getColumn()==1 ) {
Tool.warning("did you forget to terminate previous rule?", getFilename(), label.getLine());
}
}
}
grammar
:
( "header" (n:STRING_LITERAL)? h:ACTION {behavior.refHeaderAction(n,h);} )*
( fileOptionsSpec )?
( classDef )*
EOF
;
exception catch [RecognitionException ex] {
reportError("rule grammar trapped: "+ex.toString());
consumeUntil(EOF);
}
classDef
{String doc=null;}
:
( a:ACTION { behavior.refPreambleAction(a);} )?
( d:DOC_COMMENT {doc=d.getText();} )?
( ("lexclass" | "class" id "extends" "Lexer" ) => lexerSpec[doc]
| ( "class" id "extends" "TreeParser" ) => treeParserSpec[doc]
| parserSpec[doc]
)
rules
{ behavior.endGrammar(); }
;
exception catch [RecognitionException ex] {
if ( ex instanceof NoViableAltException ) {
NoViableAltException e = (NoViableAltException)ex;
if ( e.token.getType()==DOC_COMMENT ) {
reportError("line "+ex.line+": JAVADOC comments may only prefix rules and grammars");
}
else {
reportError("rule classDef trapped: "+ex.toString());
}
}
else {
reportError("rule classDef trapped: "+ex.toString());
}
behavior.abortGrammar();
boolean consuming = true;
// consume everything until the next class definition or EOF
while (consuming) {
consume();
switch(LA(1)) {
case LITERAL_class:
case LITERAL_lexclass:
case EOF:
consuming = false;
break;
}
}
}
fileOptionsSpec
{ Token idTok; Token value; }
: OPTIONS
(
idTok = id
ASSIGN
value = optionValue
{ behavior.setFileOption(idTok, value,getInputState().filename); }
SEMI
)*
RCURLY
;
parserOptionsSpec
{ Token idTok; Token value; }
: OPTIONS
(
idTok = id
ASSIGN
value = optionValue
{ behavior.setGrammarOption(idTok, value); }
SEMI
)*
RCURLY
;
treeParserOptionsSpec
{ Token idTok; Token value; }
: OPTIONS
(
idTok = id
ASSIGN
value = optionValue
{ behavior.setGrammarOption(idTok, value); }
SEMI
)*
RCURLY
;
lexerOptionsSpec
{ Token idTok; Token value; BitSet b; }
:
OPTIONS
( // Special case for vocabulary option because it has a bit-set
"charVocabulary"
ASSIGN
b = charSet
SEMI
{ behavior.setCharVocabulary(b); }
| idTok = id
ASSIGN
value = optionValue
{ behavior.setGrammarOption(idTok, value); }
SEMI
)*
RCURLY
;
subruleOptionsSpec
{ Token idTok; Token value; }
: OPTIONS
( idTok = id
ASSIGN
value = optionValue
{ behavior.setSubruleOption(idTok, value); }
SEMI
)*
RCURLY
;
// optionValue returns a Token which may be one of several things:
// STRING_LITERAL -- a quoted string
// CHAR_LITERAL -- a single quoted character
// INT -- an integer
// RULE_REF or TOKEN_REF -- an identifier
optionValue
returns [ Token retval ]
{ retval = null; }
: retval = qualifiedID
| sl:STRING_LITERAL { retval = sl; }
| cl:CHAR_LITERAL { retval = cl; }
| il:INT { retval = il; }
;
charSet
returns [ BitSet b ]
{
b = null;
BitSet tmpSet = null;
}
:
// TODO: generate a bit set
b = setBlockElement
(
OR
tmpSet = setBlockElement
{ b.orInPlace(tmpSet); }
)*
;
setBlockElement
returns [ BitSet b ]
{
b = null;
int rangeMin = 0;
}
:
c1:CHAR_LITERAL
{
rangeMin = ANTLRLexer.tokenTypeForCharLiteral(c1.getText());
b = BitSet.of(rangeMin);
}
(
RANGE c2:CHAR_LITERAL
{
int rangeMax = ANTLRLexer.tokenTypeForCharLiteral(c2.getText());
if (rangeMax < rangeMin) {
tool.error("Malformed range line "+c1.getLine());
}
for (int i = rangeMin+1; i <= rangeMax; i++) {
b.add(i);
}
}
)?
;
tokensSpec
: TOKENS
( ( {s1=null;}
t1:TOKEN_REF
( ASSIGN s1:STRING_LITERAL )?
{behavior.defineToken(t1, s1);}
(tokensSpecOptions[t1])?
| s3:STRING_LITERAL
{behavior.defineToken(null, s3);}
(tokensSpecOptions[s3])?
)
SEMI
)+
RCURLY
;
tokensSpecOptions[Token t]
{
Token o=null, v=null;
}
: OPEN_ELEMENT_OPTION
o=id ASSIGN v=optionValue
{behavior.refTokensSpecElementOption(t,o,v);}
(
SEMI
o=id ASSIGN v=optionValue
{behavior.refTokensSpecElementOption(t,o,v);}
)*
CLOSE_ELEMENT_OPTION
;
superClass returns [String sup]
{sup=null;}
: LPAREN
{sup = LT(1).getText();}
(TOKEN_REF|RULE_REF)
RPAREN
;
parserSpec[String doc]
{
Token idTok;
String sup=null;
}
: "class"
idTok = id
( "extends" "Parser"
(sup=superClass)?
| {
System.out.println("warning: line " +
idTok.getLine() + ": use 'class X extends Parser'");
}
)
{behavior.startParser(getFilename(), idTok, sup, doc);}
SEMI
(parserOptionsSpec)?
{ behavior.endOptions(); }
(tokensSpec)?
( a:ACTION {behavior.refMemberAction(a);} )?
;
lexerSpec[String doc]
{
Token idTok;
String sup=null;
}
: ( lc:"lexclass"
idTok = id
{ System.out.println("warning: line " + lc.getLine() + ": 'lexclass' is deprecated; use 'class X extends Lexer'"); }
| "class"
idTok = id
"extends"
"Lexer"
(sup=superClass)?
)
{behavior.startLexer(getFilename(), idTok,sup,doc);}
SEMI
(lexerOptionsSpec)?
{ behavior.endOptions(); }
(tokensSpec)?
( a:ACTION {behavior.refMemberAction(a);} )?
;
treeParserSpec[String doc]
{
Token idTok;
String sup=null;
}
: "class"
idTok = id
"extends"
"TreeParser"
(sup=superClass)?
{behavior.startTreeWalker(getFilename(), idTok,sup,doc);}
SEMI
(treeParserOptionsSpec)?
{ behavior.endOptions(); }
(tokensSpec)?
( a:ACTION {behavior.refMemberAction(a);} )?
;
rules
: (
options {
// limitation of appox LL(k) says ambig upon
// DOC_COMMENT TOKEN_REF, but that's an impossible sequence
warnWhenFollowAmbig=false;
}
: rule
)+
;
rule
{
String access="public";
Token idTok;
String doc=null;
boolean ruleAutoGen = true;
blockNesting = -1; // block increments, so -1 to make rule at level 0
}
:
( d:DOC_COMMENT {doc=d.getText();}
)?
( p1:"protected" {access=p1.getText();}
| p2:"public" {access=p2.getText();}
| p3:"private" {access=p3.getText();}
)?
idTok = id
( BANG { ruleAutoGen = false; } )?
{
behavior.defineRuleName(idTok, access, ruleAutoGen, doc);
}
( aa:ARG_ACTION { behavior.refArgAction(aa); } )?
( "returns" rt:ARG_ACTION { behavior.refReturnAction(rt); } )?
( throwsSpec )?
( ruleOptionsSpec )?
(a:ACTION {behavior.refInitAction(a);})?
COLON block SEMI
( exceptionGroup )?
{behavior.endRule(idTok.getText());}
;
/*
//
// for now, syntax error in rule aborts the whole grammar
//
exception catch [ParserException ex] {
behavior.abortRule(idTok);
behavior.hasError();
// Consume until something that looks like end of a rule
consume();
while (LA(1) != SEMI && LA(1) != EOF) {
consume();
}
consume();
}
*/
ruleOptionsSpec
{ Token idTok; Token value; }
: OPTIONS
(
idTok = id
ASSIGN
value = optionValue
{ behavior.setRuleOption(idTok, value); }
SEMI
)*
RCURLY
;
throwsSpec
{
String t=null;
Token a,b;
}
: "throws" a=id {t=a.getText();}
( COMMA b=id {t+=","+b.getText();} )*
{ behavior.setUserExceptions(t); }
;
block
: {blockNesting++;}
alternative ( OR alternative )*
{blockNesting--;}
;
alternative
{ boolean altAutoGen = true; }
:
(BANG { altAutoGen=false;} )?
{behavior.beginAlt(altAutoGen);}
( element )* ( exceptionSpecNoLabel )?
{behavior.endAlt();}
;
exceptionGroup
: { behavior.beginExceptionGroup(); }
( exceptionSpec )+
{ behavior.endExceptionGroup(); }
;
exceptionSpec
{ Token labelAction = null; }
:
"exception"
( aa:ARG_ACTION { labelAction = aa; } )?
{ behavior.beginExceptionSpec(labelAction); }
( exceptionHandler )*
{ behavior.endExceptionSpec(); }
;
exceptionSpecNoLabel
:
"exception"
{ behavior.beginExceptionSpec(null); }
( exceptionHandler )*
{ behavior.endExceptionSpec(); }
;
exceptionHandler
{ Token exType; Token exName; }
:
"catch"
a1:ARG_ACTION
a2:ACTION
{ behavior.refExceptionHandler(a1, a2); }
;
element
: elementNoOptionSpec (elementOptionSpec)?
;
elementOptionSpec
{
Token o=null, v=null;
}
: OPEN_ELEMENT_OPTION
o=id ASSIGN v=optionValue
{behavior.refElementOption(o,v);}
(
SEMI
o=id ASSIGN v=optionValue
{behavior.refElementOption(o,v);}
)*
CLOSE_ELEMENT_OPTION
;
elementNoOptionSpec
{
Token label = null;
Token assignId = null;
Token args = null;
int autoGen = GrammarElement.AUTO_GEN_NONE;
}
: assignId=id
ASSIGN
( label=id COLON {checkForMissingEndRule(label);} )?
( rr:RULE_REF
( aa:ARG_ACTION { args=aa; } )?
( BANG { autoGen = GrammarElement.AUTO_GEN_BANG; } )?
{ behavior.refRule(assignId, rr, label, args, autoGen); }
| // this syntax only valid for lexer
tr:TOKEN_REF
( aa2:ARG_ACTION { args=aa2; } )?
{ behavior.refToken(assignId, tr, label, args, false, autoGen, lastInRule()); }
)
|
(label=id COLON {checkForMissingEndRule(label);} )?
( r2:RULE_REF
( aa3:ARG_ACTION { args=aa3; } )?
( BANG { autoGen = GrammarElement.AUTO_GEN_BANG; } )?
{ behavior.refRule(assignId, r2, label, args, autoGen); }
|
range [label]
|
terminal [label]
|
NOT_OP
( notTerminal[label]
| ebnf[label,true]
)
|
ebnf[label,false]
)
|
a:ACTION { behavior.refAction(a);}
|
p:SEMPRED { behavior.refSemPred(p);}
|
tree
;
tree :
lp:TREE_BEGIN
{ behavior.beginTree(lp.getLine()); }
rootNode
{behavior.beginChildList();}
( element )+
{behavior.endChildList();}
RPAREN
{ behavior.endTree(); }
;
rootNode
{ Token label = null; }
:
(label=id COLON {checkForMissingEndRule(label);} )?
terminal[label]
// | range[null]
;
ebnf
[ Token label, boolean not ]
: lp:LPAREN
{behavior.beginSubRule(label, lp.getLine(), not);}
(
// 2nd alt and optional branch ambig due to
// linear approx LL(2) issue. COLON ACTION
// matched correctly in 2nd alt.
options {
warnWhenFollowAmbig = false;
}
:
subruleOptionsSpec
( aa:ACTION {behavior.refInitAction(aa);} )?
COLON
| ab:ACTION {behavior.refInitAction(ab);}
COLON
)?
block
RPAREN
( ( QUESTION{behavior.optionalSubRule();}
| STAR {behavior.zeroOrMoreSubRule();;}
| PLUS {behavior.oneOrMoreSubRule();}
)?
( BANG {behavior.noASTSubRule(); } )?
|
IMPLIES {behavior.synPred();}
)
{behavior.endSubRule();}
;
ast_type_spec
returns [ int autoGen ]
{ autoGen = GrammarElement.AUTO_GEN_NONE; }
: ( CARET { autoGen = GrammarElement.AUTO_GEN_CARET; }
| BANG { autoGen = GrammarElement.AUTO_GEN_BANG; }
)?
;
range
[ Token label ]
{
Token trLeft=null;
Token trRight=null;
int autoGen=GrammarElement.AUTO_GEN_NONE;
}
: crLeft:CHAR_LITERAL RANGE crRight:CHAR_LITERAL
( BANG { autoGen = GrammarElement.AUTO_GEN_BANG; } )?
{ behavior.refCharRange(crLeft, crRight, label, autoGen, lastInRule()); }
|
(t:TOKEN_REF{trLeft=t;}|u:STRING_LITERAL{trLeft=u;})
RANGE
(v:TOKEN_REF{trRight=v;}|w:STRING_LITERAL{trRight=w;})
autoGen = ast_type_spec
{ behavior.refTokenRange(trLeft, trRight, label, autoGen, lastInRule()); }
;
terminal
[ Token label ]
{
int autoGen=GrammarElement.AUTO_GEN_NONE;
Token args=null;
}
:
cl:CHAR_LITERAL
( BANG { autoGen = GrammarElement.AUTO_GEN_BANG; } )?
{behavior.refCharLiteral(cl, label, false, autoGen, lastInRule());}
|
tr:TOKEN_REF
autoGen = ast_type_spec
// Args are only valid for lexer
( aa:ARG_ACTION { args=aa; } )?
{ behavior.refToken(null, tr, label, args, false, autoGen, lastInRule()); }
|
sl:STRING_LITERAL
autoGen = ast_type_spec
{behavior.refStringLiteral(sl, label, autoGen, lastInRule());}
|
wi:WILDCARD
autoGen = ast_type_spec
{behavior.refWildcard(wi, label, autoGen);}
;
notTerminal
[ Token label ]
{ int autoGen=GrammarElement.AUTO_GEN_NONE; }
:
cl:CHAR_LITERAL
( BANG { autoGen = GrammarElement.AUTO_GEN_BANG; } )?
{behavior.refCharLiteral(cl, label, true, autoGen, lastInRule());}
|
tr:TOKEN_REF
autoGen = ast_type_spec
{behavior.refToken(null, tr, label, null, true, autoGen, lastInRule());}
;
/** Match a.b.c.d qualified ids; WILDCARD here is overloaded as
* id separator; that is, I need a reference to the '.' token.
*/
qualifiedID returns [Token qidTok=null]
{
StringBuffer buf = new StringBuffer(30);
Token a;
}
: a=id {buf.append(a.getText());}
( WILDCARD a=id
{buf.append('.'); buf.append(a.getText());}
)*
{
// can use either TOKEN_REF or RULE_REF; should
// really create a QID or something instead.
qidTok = new CommonToken(TOKEN_REF, buf.toString());
qidTok.setLine(a.getLine());
}
;
id
returns [ Token idTok ]
{ idTok = null; }
: a:TOKEN_REF {idTok = a;}
| b:RULE_REF {idTok = b;}
;
class ANTLRLexer extends Lexer;
options {
k=2;
exportVocab=ANTLR;
testLiterals=false;
interactive=true;
}
tokens {
"options";
}
{
/**Convert 'c' to an integer char value. */
public static int escapeCharValue(String cs) {
//System.out.println("escapeCharValue("+cs+")");
if ( cs.charAt(1)!='\\' ) return 0;
switch ( cs.charAt(2) ) {
case 'b' : return '\b';
case 'r' : return '\r';
case 't' : return '\t';
case 'n' : return '\n';
case 'f' : return '\f';
case '"' : return '\"';
case '\'' :return '\'';
case '\\' :return '\\';
case 'u' :
// Unicode char
if (cs.length() != 8) {
return 0;
}
else {
return
Character.digit(cs.charAt(3), 16) * 16 * 16 * 16 +
Character.digit(cs.charAt(4), 16) * 16 * 16 +
Character.digit(cs.charAt(5), 16) * 16 +
Character.digit(cs.charAt(6), 16);
}
case '0' :
case '1' :
case '2' :
case '3' :
if ( cs.length()>5 && Character.isDigit(cs.charAt(4)) ) {
return (cs.charAt(2)-'0')*8*8 + (cs.charAt(3)-'0')*8 + (cs.charAt(4)-'0');
}
if ( cs.length()>4 && Character.isDigit(cs.charAt(3)) ) {
return (cs.charAt(2)-'0')*8 + (cs.charAt(3)-'0');
}
return cs.charAt(2)-'0';
case '4' :
case '5' :
case '6' :
case '7' :
if ( cs.length()>4 && Character.isDigit(cs.charAt(3)) ) {
return (cs.charAt(2)-'0')*8 + (cs.charAt(3)-'0');
}
return cs.charAt(2)-'0';
default :
return 0;
}
}
public static int tokenTypeForCharLiteral(String lit) {
if ( lit.length()>3 ) { // does char contain escape?
return escapeCharValue(lit);
}
else {
return lit.charAt(1);
}
}
}
WS : ( /* '\r' '\n' can be matched in one alternative or by matching
'\r' in one iteration and '\n' in another. I am trying to
handle any flavor of newline that comes in, but the language
that allows both "\r\n" and "\r" and "\n" to all be valid
newline is ambiguous. Consequently, the resulting grammar
must be ambiguous. I'm shutting this warning off.
*/
options {
generateAmbigWarnings=false;
}
: ' '
| '\t'
| '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
)
{ $setType(Token.SKIP); }
;
COMMENT :
( SL_COMMENT | t:ML_COMMENT {$setType(t.getType());} )
{if ( _ttype != DOC_COMMENT ) $setType(Token.SKIP);}
;
protected
SL_COMMENT :
"//"
( ~('\n'|'\r') )*
(
/* '\r' '\n' can be matched in one alternative or by matching
'\r' and then in the next token. The language
that allows both "\r\n" and "\r" and "\n" to all be valid
newline is ambiguous. Consequently, the resulting grammar
must be ambiguous. I'm shutting this warning off.
*/
options {
generateAmbigWarnings=false;
}
: '\r' '\n'
| '\r'
| '\n'
)
{ newline(); }
;
protected
ML_COMMENT :
"/*"
( { LA(2)!='/' }? '*' {$setType(DOC_COMMENT);}
|
)
(
/* '\r' '\n' can be matched in one alternative or by matching
'\r' and then in the next token. The language
that allows both "\r\n" and "\r" and "\n" to all be valid
newline is ambiguous. Consequently, the resulting grammar
must be ambiguous. I'm shutting this warning off.
*/
options {
greedy=false; // make it exit upon "*/"
generateAmbigWarnings=false; // shut off newline errors
}
: '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
| ~('\n'|'\r')
)*
"*/"
;
OPEN_ELEMENT_OPTION
: '<'
;
CLOSE_ELEMENT_OPTION
: '>'
;
COMMA : ',';
QUESTION : '?' ;
TREE_BEGIN : "#(" ;
LPAREN: '(' ;
RPAREN: ')' ;
COLON : ':' ;
STAR: '*' ;
PLUS: '+' ;
ASSIGN : '=' ;
IMPLIES : "=>" ;
SEMI: ';' ;
CARET : '^' ;
BANG : '!' ;
OR : '|' ;
WILDCARD : '.' ;
RANGE : ".." ;
NOT_OP : '~' ;
RCURLY: '}' ;
CHAR_LITERAL
: '\'' (ESC|~'\'') '\''
;
STRING_LITERAL
: '"' (ESC|~'"')* '"'
;
protected
ESC : '\\'
( 'n'
| 'r'
| 't'
| 'b'
| 'f'
| 'w'
| 'a'
| '"'
| '\''
| '\\'
| ('0'..'3')
(
options {
warnWhenFollowAmbig = false;
}
:
('0'..'9')
(
options {
warnWhenFollowAmbig = false;
}
:
'0'..'9'
)?
)?
| ('4'..'7')
(
options {
warnWhenFollowAmbig = false;
}
:
('0'..'9')
)?
| 'u' XDIGIT XDIGIT XDIGIT XDIGIT
)
;
protected
DIGIT
: '0'..'9'
;
protected
XDIGIT :
'0' .. '9'
| 'a' .. 'f'
| 'A' .. 'F'
;
protected
VOCAB
: '\3'..'\176' // common ASCII
;
INT : ('0'..'9')+
;
ARG_ACTION
:
NESTED_ARG_ACTION
{ setText(Tool.stripFrontBack(getText(), "[", "]")); }
;
protected
NESTED_ARG_ACTION :
'['
(
/* '\r' '\n' can be matched in one alternative or by matching
'\r' and then '\n' in the next iteration.
*/
options {
generateAmbigWarnings=false; // shut off newline errors
}
: NESTED_ARG_ACTION
| '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
| CHAR_LITERAL
| STRING_LITERAL
| ~']'
)*
']'
;
ACTION
{int actionLine=getLine();}
: NESTED_ACTION
( '?' {_ttype = SEMPRED;} )?
{
if ( _ttype==ACTION ) {
setText(Tool.stripFrontBack(getText(), "{", "}"));
}
else {
setText(Tool.stripFrontBack(getText(), "{", "}?"));
}
CommonToken t = new CommonToken(_ttype,$getText);
t.setLine(actionLine); // set action line to start
$setToken(t);
}
;
protected
NESTED_ACTION :
'{'
(
options {
greedy = false; // exit upon '}'
}
:
(
options {
generateAmbigWarnings = false; // shut off newline warning
}
: '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
)
| NESTED_ACTION
| CHAR_LITERAL
| COMMENT
| STRING_LITERAL
| .
)*
'}'
;
TOKEN_REF
options { testLiterals = true; }
: 'A'..'Z'
( // scarf as many letters/numbers as you can
options {
warnWhenFollowAmbig=false;
}
:
'a'..'z'|'A'..'Z'|'_'|'0'..'9'
)*
;
// we get a warning here when looking for options '{', but it works right
RULE_REF
{
int t=0;
}
: t=INTERNAL_RULE_REF {_ttype=t;}
( {t==LITERAL_options}? WS_LOOP ('{' {_ttype = OPTIONS;})?
| {t==LITERAL_tokens}? WS_LOOP ('{' {_ttype = TOKENS;})?
|
)
;
protected
WS_LOOP
: ( // grab as much WS as you can
options {
greedy=true;
}
:
WS
| COMMENT
)*
;
protected
INTERNAL_RULE_REF returns [int t]
{
t = RULE_REF;
}
: 'a'..'z'
( // scarf as many letters/numbers as you can
options {
warnWhenFollowAmbig=false;
}
:
'a'..'z'|'A'..'Z'|'_'|'0'..'9'
)*
{t = testLiteralsTable(t);}
;
protected
WS_OPT :
(WS)?
;
// remove after the class variants of the scanners/parsers go
// away. this rule, just forces the lexer to use the most
// complicated class so I can get rid of the others.
protected
NOT_USEFUL
: ('a')=>'a'
| 'a'
;
1.1 e/src/jsrc/antlr/tokdef.g
Index: tokdef.g
===================================================================
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: tokdef.g,v 1.1 2001/10/03 21:04:14 markm Exp $
*/
header { package antlr; }
/** Simple lexer/parser for reading token definition files
in support of the import/export vocab option for grammars.
*/
class ANTLRTokdefParser extends Parser;
options {
k=3;
interactive=true;
}
file [ImportVocabTokenManager tm] :
name:ID
(line[tm])*;
line [ImportVocabTokenManager tm]
{ Token t=null; Token s=null; }
: ( s1:STRING {s = s1;}
| lab:ID {t = lab;} ASSIGN s2:STRING {s = s2;}
| id:ID {t=id;} LPAREN para:STRING RPAREN
| id2:ID {t=id2;}
)
ASSIGN
i:INT
{
Integer value = Integer.valueOf(i.getText());
// if literal found, define as a string literal
if ( s!=null ) {
tm.define(s.getText(), value.intValue());
// if label, then label the string and map label to token symbol also
if ( t!=null ) {
StringLiteralSymbol sl =
(StringLiteralSymbol) tm.getTokenSymbol(s.getText());
sl.setLabel(t.getText());
tm.mapToTokenSymbol(t.getText(), sl);
}
}
// define token (not a literal)
else if ( t!=null ) {
tm.define(t.getText(), value.intValue());
if ( para!=null ) {
TokenSymbol ts = tm.getTokenSymbol(t.getText());
ts.setParaphrase(
para.getText()
);
}
}
}
;
class ANTLRTokdefLexer extends Lexer;
options {
k=2;
testLiterals=false;
interactive=true;
}
WS : ( ' '
| '\t'
| '\r' ('\n')? {newline();}
| '\n' {newline();}
)
{ _ttype = Token.SKIP; }
;
SL_COMMENT :
"//"
(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
{ _ttype = Token.SKIP; newline(); }
;
ML_COMMENT :
"/*"
(
'\n' { newline(); }
| '*' ~'/'
| ~'*'
)*
"*/"
{ _ttype = Token.SKIP; }
;
LPAREN : '(' ;
RPAREN : ')' ;
ASSIGN : '=' ;
STRING
: '"' (ESC|~'"')* '"'
;
protected
ESC : '\\'
( 'n'
| 'r'
| 't'
| 'b'
| 'f'
| '"'
| '\''
| '\\'
| ('0'..'3') ( DIGIT (DIGIT)? )?
| ('4'..'7') (DIGIT)?
| 'u' XDIGIT XDIGIT XDIGIT XDIGIT
)
;
protected
DIGIT
: '0'..'9'
;
protected
XDIGIT :
'0' .. '9'
| 'a' .. 'f'
| 'A' .. 'F'
;
protected
VOCAB
: '\3'..'\176' // common ASCII
;
ID :
('a'..'z'|'A'..'Z')
('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
;
INT : (DIGIT)+
;
1.1 e/src/jsrc/antlr/actions/cpp/ActionLexer.java
Index: ActionLexer.java
===================================================================
// $ANTLR 2.7.1: "action.g" -> "ActionLexer.java"$
package antlr.actions.cpp;
import java.io.InputStream;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.TokenStreamRecognitionException;
import antlr.CharStreamException;
import antlr.CharStreamIOException;
import antlr.ANTLRException;
import java.io.Reader;
import java.util.Hashtable;
import antlr.CharScanner;
import antlr.InputBuffer;
import antlr.ByteBuffer;
import antlr.CharBuffer;
import antlr.Token;
import antlr.CommonToken;
import antlr.RecognitionException;
import antlr.NoViableAltForCharException;
import antlr.MismatchedCharException;
import antlr.TokenStream;
import antlr.ANTLRHashString;
import antlr.LexerSharedInputState;
import antlr.collections.impl.BitSet;
import antlr.SemanticException;
import java.io.StringReader;
import antlr.collections.impl.Vector;
import antlr.*;
/** Perform the following translations:
AST related translations
## -> currentRule_AST
#(x,y,z) -> codeGenerator.getASTCreateString(vector-of(x,y,z))
#[x] -> codeGenerator.getASTCreateString(x)
#x -> codeGenerator.mapTreeId(x)
Inside context of #(...), you can ref (x,y,z), [x], and x as shortcuts.
Text related translations
$append(x) -> text.append(x)
$setText(x) -> text.setLength(_begin); text.append(x)
$getText -> new String(text.getBuffer(),_begin,text.length()-_begin)
$setToken(x) -> _token = x
$setType(x) -> _ttype = x
*/
public class ActionLexer extends antlr.CharScanner implements ActionLexerTokenTypes, TokenStream
{
protected RuleBlock currentRule;
protected CodeGenerator generator;
protected int lineOffset = 0;
private Tool tool; // The ANTLR tool
ActionTransInfo transInfo;
public ActionLexer( String s,
RuleBlock currentRule,
CodeGenerator generator,
ActionTransInfo transInfo) {
this(new StringReader(s));
this.currentRule = currentRule;
this.generator = generator;
this.transInfo = transInfo;
}
public void setLineOffset(int lineOffset) {
// this.lineOffset = lineOffset;
setLine(lineOffset);
}
public void setTool(Tool tool) {
this.tool = tool;
}
// Override of error-reporting for syntax
public void reportError(RecognitionException e) {
System.err.print("Syntax error in action: ");
super.reportError(e);
}
public ActionLexer(InputStream in) {
this(new ByteBuffer(in));
}
public ActionLexer(Reader in) {
this(new CharBuffer(in));
}
public ActionLexer(InputBuffer ib) {
this(new LexerSharedInputState(ib));
}
public ActionLexer(LexerSharedInputState state) {
super(state);
literals = new Hashtable();
caseSensitiveLiterals = true;
setCaseSensitive(true);
}
public Token nextToken() throws TokenStreamException {
Token theRetToken=null;
tryAgain:
for (;;) {
Token _token = null;
int _ttype = Token.INVALID_TYPE;
resetText();
try { // for char stream error handling
try { // for lexical error handling
if (((LA(1) >= '\u0003' && LA(1) <= '~'))) {
mACTION(true);
theRetToken=_returnToken;
}
else {
if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}
else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
if ( _returnToken==null ) continue tryAgain; // found SKIP token
_ttype = _returnToken.getType();
_returnToken.setType(_ttype);
return _returnToken;
}
catch (RecognitionException e) {
throw new TokenStreamRecognitionException(e);
}
}
catch (CharStreamException cse) {
if ( cse instanceof CharStreamIOException ) {
throw new TokenStreamIOException(((CharStreamIOException)cse).io);
}
else {
throw new TokenStreamException(cse.getMessage());
}
}
}
}
public final void mACTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ACTION;
int _saveIndex;
{
int _cnt3=0;
_loop3:
do {
switch ( LA(1)) {
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '"':
case '%': case '&': case '\'': case '(':
case ')': case '*': case '+': case ',':
case '-': case '.': case '/': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case ':': case ';': case '<':
case '=': case '>': case '?': case '@':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '[': case '\\':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
mSTUFF(false);
break;
}
case '#':
{
mAST_ITEM(false);
break;
}
case '$':
{
mTEXT_ITEM(false);
break;
}
default:
{
if ( _cnt3>=1 ) { break _loop3; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
}
_cnt3++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mSTUFF(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STUFF;
int _saveIndex;
switch ( LA(1)) {
case '"':
{
mSTRING(false);
break;
}
case '\'':
{
mCHAR(false);
break;
}
case '\n':
{
match('\n');
newline();
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\u000b':
case '\u000c': case '\u000e': case '\u000f': case '\u0010':
case '\u0011': case '\u0012': case '\u0013': case '\u0014':
case '\u0015': case '\u0016': case '\u0017': case '\u0018':
case '\u0019': case '\u001a': case '\u001b': case '\u001c':
case '\u001d': case '\u001e': case '\u001f': case ' ':
case '!': case '%': case '&': case '(':
case ')': case '*': case '+': case ',':
case '-': case '.': case '0': case '1':
case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case ':': case ';': case '<': case '=':
case '>': case '?': case '@': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '\\': case ']':
case '^': case '_': case '`': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z': case '{': case '|': case '}':
case '~':
{
{
match(_tokenSet_0);
}
break;
}
default:
if ((LA(1)=='/') && (LA(2)=='*'||LA(2)=='/')) {
mCOMMENT(false);
}
else if ((LA(1)=='\r') && (LA(2)=='\n')) {
match("\r\n");
newline();
}
else if ((LA(1)=='/') && (_tokenSet_1.member(LA(2)))) {
match('/');
{
match(_tokenSet_1);
}
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
newline();
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mAST_ITEM(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = AST_ITEM;
int _saveIndex;
Token t=null;
Token id=null;
Token ctor=null;
if ((LA(1)=='#') && (LA(2)=='(')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mTREE(true);
t=_returnToken;
}
else if ((LA(1)=='#') && (_tokenSet_2.member(LA(2)))) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mID(true);
id=_returnToken;
String idt = id.getText();
text.setLength(_begin); text.append(generator.mapTreeId(idt,transInfo));
{
if ((_tokenSet_3.member(LA(1))) && (true)) {
mWS(false);
}
else {
}
}
{
if ((LA(1)=='=') && (true)) {
mVAR_ASSIGN(false);
}
else {
}
}
}
else if ((LA(1)=='#') && (LA(2)=='[')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mAST_CONSTRUCTOR(true);
ctor=_returnToken;
}
else if ((LA(1)=='#') && (LA(2)=='#')) {
match("##");
String r=currentRule.getRuleName()+"_AST"; text.setLength(_begin); text.append(r);
if ( transInfo!=null ) {
transInfo.refRuleRoot=r; // we ref root of tree
}
{
if ((_tokenSet_3.member(LA(1))) && (true)) {
mWS(false);
}
else {
}
}
{
if ((LA(1)=='=') && (true)) {
mVAR_ASSIGN(false);
}
else {
}
}
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTEXT_ITEM(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TEXT_ITEM;
int _saveIndex;
Token a1=null;
Token a2=null;
Token a3=null;
Token a4=null;
if ((LA(1)=='$') && (LA(2)=='a')) {
match("$append(");
mTEXT_ARG(true);
a1=_returnToken;
match(')');
String t = "text += "+a1.getText();
text.setLength(_begin); text.append(t);
}
else if ((LA(1)=='$') && (LA(2)=='s')) {
match("$set");
{
if ((LA(1)=='T') && (LA(2)=='e')) {
match("Text(");
mTEXT_ARG(true);
a2=_returnToken;
match(')');
String t;
t = "text.erase(_begin); text += "+a2.getText();
text.setLength(_begin); text.append(t);
}
else if ((LA(1)=='T') && (LA(2)=='o')) {
match("Token(");
mTEXT_ARG(true);
a3=_returnToken;
match(')');
String t="_token = "+a3.getText();
text.setLength(_begin); text.append(t);
}
else if ((LA(1)=='T') && (LA(2)=='y')) {
match("Type(");
mTEXT_ARG(true);
a4=_returnToken;
match(')');
String t="_ttype = "+a4.getText();
text.setLength(_begin); text.append(t);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else if ((LA(1)=='$') && (LA(2)=='g')) {
match("$getText");
text.setLength(_begin); text.append("text.substr(_begin,text.length()-_begin)");
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mCOMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = COMMENT;
int _saveIndex;
if ((LA(1)=='/') && (LA(2)=='/')) {
mSL_COMMENT(false);
}
else if ((LA(1)=='/') && (LA(2)=='*')) {
mML_COMMENT(false);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mSTRING(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STRING;
int _saveIndex;
match('"');
{
_loop91:
do {
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '#':
case '$': case '%': case '&': case '\'':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('"');
break;
}
default:
{
break _loop91;
}
}
} while (true);
}
match('"');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mCHAR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = CHAR;
int _saveIndex;
match('\'');
{
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '"':
case '#': case '$': case '%': case '&':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('\'');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match('\'');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTREE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TREE;
int _saveIndex;
Token t=null;
Token t2=null;
StringBuffer buf = new StringBuffer();
int n=0;
Vector terms = new Vector(10);
_saveIndex=text.length();
match('(');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case ':':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '[': case '_':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mTREE_ELEMENT(true);
text.setLength(_saveIndex);
t=_returnToken;
terms.appendElement(
generator.processStringForASTConstructor(t.getText())
);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ')': case ',':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
_loop20:
do {
if ((LA(1)==',')) {
_saveIndex=text.length();
match(',');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case ':':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '[': case '_':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mTREE_ELEMENT(true);
text.setLength(_saveIndex);
t2=_returnToken;
terms.appendElement(
generator.processStringForASTConstructor(t2.getText())
);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ')': case ',':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
}
else {
break _loop20;
}
} while (true);
}
text.setLength(_begin); text.append(generator.getASTCreateString(terms));
_saveIndex=text.length();
match(')');
text.setLength(_saveIndex);
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mID(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ID;
int _saveIndex;
{
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '_':
{
match('_');
break;
}
case ':':
{
match("::");
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
_loop77:
do {
if ((_tokenSet_4.member(LA(1))) && (true)) {
{
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
case '_':
{
match('_');
break;
}
case ':':
{
match("::");
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
}
else {
break _loop77;
}
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mWS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WS;
int _saveIndex;
{
int _cnt111=0;
_loop111:
do {
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
newline();
}
else if ((LA(1)==' ') && (true)) {
match(' ');
}
else if ((LA(1)=='\t') && (true)) {
match('\t');
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
newline();
}
else if ((LA(1)=='\n') && (true)) {
match('\n');
newline();
}
else {
if ( _cnt111>=1 ) { break _loop111; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt111++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mVAR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = VAR_ASSIGN;
int _saveIndex;
match('=');
// inform the code generator that an assignment was done to
// AST root for the rule if invoker set refRuleRoot.
if ( LA(1)!='=' && transInfo!=null && transInfo.refRuleRoot!=null ) {
transInfo.assignToRoot=true;
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mAST_CONSTRUCTOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = AST_CONSTRUCTOR;
int _saveIndex;
Token x=null;
Token y=null;
_saveIndex=text.length();
match('[');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case ':': case 'A': case 'B':
case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V':
case 'W': case 'X': case 'Y': case 'Z':
case '[': case '_': case 'a': case 'b':
case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v':
case 'w': case 'x': case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mAST_CTOR_ELEMENT(true);
text.setLength(_saveIndex);
x=_returnToken;
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ',': case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
switch ( LA(1)) {
case ',':
{
_saveIndex=text.length();
match(',');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case ':': case 'A': case 'B':
case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V':
case 'W': case 'X': case 'Y': case 'Z':
case '[': case '_': case 'a': case 'b':
case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v':
case 'w': case 'x': case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mAST_CTOR_ELEMENT(true);
text.setLength(_saveIndex);
y=_returnToken;
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
break;
}
case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
match(']');
text.setLength(_saveIndex);
// System.out.println("AST_CONSTRUCTOR: "+((x==null)?"null":x.getText())+
// ", "+((y==null)?"null":y.getText()));
String ys = generator.processStringForASTConstructor(x.getText());
// the second does not need processing coz it's a string
// (eg second param of astFactory.create(x,y)
if ( y!=null )
ys += ","+y.getText();
text.setLength(_begin); text.append( generator.getASTCreateString(null,ys) );
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTEXT_ARG(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TEXT_ARG;
int _saveIndex;
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(false);
break;
}
case '"': case '$': case '\'': case '+':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '_': case 'a': case 'b':
case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v':
case 'w': case 'x': case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
int _cnt51=0;
_loop51:
do {
if ((_tokenSet_5.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mTEXT_ARG_ELEMENT(false);
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_6.member(LA(2)))) {
mWS(false);
}
else if ((_tokenSet_6.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else {
if ( _cnt51>=1 ) { break _loop51; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt51++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTREE_ELEMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TREE_ELEMENT;
int _saveIndex;
Token id=null;
boolean was_mapped;
switch ( LA(1)) {
case '(':
{
mTREE(false);
break;
}
case '[':
{
mAST_CONSTRUCTOR(false);
break;
}
case ':': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '_':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
mID_ELEMENT(false);
break;
}
case '"':
{
mSTRING(false);
break;
}
default:
if ((LA(1)=='#') && (LA(2)=='(')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mTREE(false);
}
else if ((LA(1)=='#') && (LA(2)=='[')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mAST_CONSTRUCTOR(false);
}
else if ((LA(1)=='#') && (_tokenSet_2.member(LA(2)))) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
was_mapped=mID_ELEMENT(true);
id=_returnToken;
// RK: I have a queer feeling that this maptreeid is redundant..
if ( ! was_mapped )
{
String t = generator.mapTreeId(id.getText(), null);
text.setLength(_begin); text.append(t);
}
}
else if ((LA(1)=='#') && (LA(2)=='#')) {
match("##");
String t = currentRule.getRuleName()+"_AST"; text.setLength(_begin); text.append(t);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
/** An ID_ELEMENT can be a func call, array ref, simple var,
* or AST label ref.
*/
protected final boolean mID_ELEMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
boolean mapped=false;
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ID_ELEMENT;
int _saveIndex;
Token id=null;
mID(true);
id=_returnToken;
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_7.member(LA(2)))) {
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
}
else if ((_tokenSet_7.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
{
switch ( LA(1)) {
case '(': case '<':
{
{
switch ( LA(1)) {
case '<':
{
match('<');
{
_loop34:
do {
if ((_tokenSet_8.member(LA(1)))) {
matchNot('>');
}
else {
break _loop34;
}
} while (true);
}
match('>');
break;
}
case '(':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match('(');
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_9.member(LA(2)))) {
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
}
else if ((_tokenSet_9.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
{
switch ( LA(1)) {
case '"': case '#': case '\'': case '(':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
mARG(false);
{
_loop39:
do {
if ((LA(1)==',')) {
match(',');
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '\'': case '(':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
mARG(false);
}
else {
break _loop39;
}
} while (true);
}
break;
}
case '\t': case '\n': case '\r': case ' ':
case ')':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ')':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match(')');
break;
}
case '[':
{
{
int _cnt44=0;
_loop44:
do {
if ((LA(1)=='[')) {
match('[');
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '\'': case '(':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
mARG(false);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match(']');
}
else {
if ( _cnt44>=1 ) { break _loop44; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt44++;
} while (true);
}
break;
}
case '.':
{
match('.');
mID_ELEMENT(false);
break;
}
case ':':
{
match("::");
mID_ELEMENT(false);
break;
}
default:
if ((LA(1)=='-') && (LA(2)=='>')) {
match("->");
mID_ELEMENT(false);
}
else if ((_tokenSet_10.member(LA(1))) && (true)) {
mapped = true;
String t = generator.mapTreeId(id.getText(), transInfo);
text.setLength(_begin); text.append(t);
{
if (((_tokenSet_11.member(LA(1))) && (_tokenSet_10.member(LA(2))))&&(transInfo!=null && transInfo.refRuleRoot!=null)) {
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(false);
break;
}
case '=':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
mVAR_ASSIGN(false);
}
else if ((_tokenSet_12.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
return mapped;
}
/** The arguments of a #[...] constructor are text, token type,
* or a tree.
*/
protected final void mAST_CTOR_ELEMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = AST_CTOR_ELEMENT;
int _saveIndex;
if ((LA(1)=='"') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mSTRING(false);
}
else if ((_tokenSet_13.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mTREE_ELEMENT(false);
}
else if (((LA(1) >= '0' && LA(1) <= '9'))) {
mINT(false);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mINT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = INT;
int _saveIndex;
{
int _cnt102=0;
_loop102:
do {
if (((LA(1) >= '0' && LA(1) <= '9'))) {
mDIGIT(false);
}
else {
if ( _cnt102>=1 ) { break _loop102; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt102++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mARG(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ARG;
int _saveIndex;
{
switch ( LA(1)) {
case '\'':
{
mCHAR(false);
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
mINT_OR_FLOAT(false);
break;
}
default:
if ((_tokenSet_13.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mTREE_ELEMENT(false);
}
else if ((LA(1)=='"') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mSTRING(false);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
_loop72:
do {
if ((_tokenSet_14.member(LA(1))) && (_tokenSet_15.member(LA(2)))) {
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(false);
break;
}
case '*': case '+': case '-': case '/':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
switch ( LA(1)) {
case '+':
{
match('+');
break;
}
case '-':
{
match('-');
break;
}
case '*':
{
match('*');
break;
}
case '/':
{
match('/');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(false);
break;
}
case '"': case '#': case '\'': case '(':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
mARG(false);
}
else {
break _loop72;
}
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTEXT_ARG_ELEMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TEXT_ARG_ELEMENT;
int _saveIndex;
switch ( LA(1)) {
case ':': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '_':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
mTEXT_ARG_ID_ELEMENT(false);
break;
}
case '"':
{
mSTRING(false);
break;
}
case '\'':
{
mCHAR(false);
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
mINT_OR_FLOAT(false);
break;
}
case '$':
{
mTEXT_ITEM(false);
break;
}
case '+':
{
match('+');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTEXT_ARG_ID_ELEMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TEXT_ARG_ID_ELEMENT;
int _saveIndex;
Token id=null;
mID(true);
id=_returnToken;
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_16.member(LA(2)))) {
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
}
else if ((_tokenSet_16.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
{
switch ( LA(1)) {
case '(':
{
match('(');
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_17.member(LA(2)))) {
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
}
else if ((_tokenSet_17.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
{
_loop60:
do {
if ((_tokenSet_18.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mTEXT_ARG(false);
{
_loop59:
do {
if ((LA(1)==',')) {
match(',');
mTEXT_ARG(false);
}
else {
break _loop59;
}
} while (true);
}
}
else {
break _loop60;
}
} while (true);
}
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ')':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match(')');
break;
}
case '[':
{
{
int _cnt65=0;
_loop65:
do {
if ((LA(1)=='[')) {
match('[');
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_18.member(LA(2)))) {
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
}
else if ((_tokenSet_18.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
mTEXT_ARG(false);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match(']');
}
else {
if ( _cnt65>=1 ) { break _loop65; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt65++;
} while (true);
}
break;
}
case '.':
{
match('.');
mTEXT_ARG_ID_ELEMENT(false);
break;
}
case '-':
{
match("->");
mTEXT_ARG_ID_ELEMENT(false);
break;
}
default:
if ((LA(1)==':') && (LA(2)==':')) {
match("::");
mTEXT_ARG_ID_ELEMENT(false);
}
else if ((_tokenSet_6.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mINT_OR_FLOAT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = INT_OR_FLOAT;
int _saveIndex;
{
int _cnt105=0;
_loop105:
do {
if (((LA(1) >= '0' && LA(1) <= '9')) && (_tokenSet_19.member(LA(2)))) {
mDIGIT(false);
}
else {
if ( _cnt105>=1 ) { break _loop105; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt105++;
} while (true);
}
{
if ((LA(1)=='L') && (_tokenSet_20.member(LA(2)))) {
match('L');
}
else if ((LA(1)=='l') && (_tokenSet_20.member(LA(2)))) {
match('l');
}
else if ((LA(1)=='.')) {
match('.');
{
_loop108:
do {
if (((LA(1) >= '0' && LA(1) <= '9')) && (_tokenSet_20.member(LA(2)))) {
mDIGIT(false);
}
else {
break _loop108;
}
} while (true);
}
}
else if ((_tokenSet_20.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mSL_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = SL_COMMENT;
int _saveIndex;
match("//");
{
_loop82:
do {
// nongreedy exit test
if ((LA(1)=='\n'||LA(1)=='\r') && (true)) break _loop82;
if (((LA(1) >= '\u0003' && LA(1) <= '~')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
matchNot(EOF_CHAR);
}
else {
break _loop82;
}
} while (true);
}
{
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match("\r\n");
}
else if ((LA(1)=='\n')) {
match('\n');
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
newline();
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mML_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ML_COMMENT;
int _saveIndex;
match("/*");
{
_loop86:
do {
// nongreedy exit test
if ((LA(1)=='*') && (LA(2)=='/')) break _loop86;
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
newline();
}
else if ((LA(1)=='\r') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
match('\r');
newline();
}
else if ((LA(1)=='\n') && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
match('\n');
newline();
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
matchNot(EOF_CHAR);
}
else {
break _loop86;
}
} while (true);
}
match("*/");
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mESC(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ESC;
int _saveIndex;
match('\\');
{
switch ( LA(1)) {
case 'n':
{
match('n');
break;
}
case 'r':
{
match('r');
break;
}
case 't':
{
match('t');
break;
}
case 'b':
{
match('b');
break;
}
case 'f':
{
match('f');
break;
}
case '"':
{
match('"');
break;
}
case '\'':
{
match('\'');
break;
}
case '\\':
{
match('\\');
break;
}
case '0': case '1': case '2': case '3':
{
{
matchRange('0','3');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mDIGIT(false);
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mDIGIT(false);
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
break;
}
case '4': case '5': case '6': case '7':
{
{
matchRange('4','7');
}
{
if (((LA(1) >= '0' && LA(1) <= '9')) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mDIGIT(false);
}
else if (((LA(1) >= '\u0003' && LA(1) <= '~')) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mDIGIT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = DIGIT;
int _saveIndex;
matchRange('0','9');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
private static final long _tokenSet_0_data_[] = { -141407503262728L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_0 = new BitSet(_tokenSet_0_data_);
private static final long _tokenSet_1_data_[] = { -145135534866440L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_1 = new BitSet(_tokenSet_1_data_);
private static final long _tokenSet_2_data_[] = { 288230376151711744L, 576460745995190270L, 0L, 0L };
public static final BitSet _tokenSet_2 = new BitSet(_tokenSet_2_data_);
private static final long _tokenSet_3_data_[] = { 4294977024L, 0L, 0L };
public static final BitSet _tokenSet_3 = new BitSet(_tokenSet_3_data_);
private static final long _tokenSet_4_data_[] = { 576179277326712832L, 576460745995190270L, 0L, 0L };
public static final BitSet _tokenSet_4 = new BitSet(_tokenSet_4_data_);
private static final long _tokenSet_5_data_[] = { 576188709074894848L, 576460745995190270L, 0L, 0L };
public static final BitSet _tokenSet_5 = new BitSet(_tokenSet_5_data_);
private static final long _tokenSet_6_data_[] = { 576208504579171840L, 576460746532061182L, 0L, 0L };
public static final BitSet _tokenSet_6 = new BitSet(_tokenSet_6_data_);
private static final long _tokenSet_7_data_[] = { 3747275269732312576L, 671088640L, 0L, 0L };
public static final BitSet _tokenSet_7 = new BitSet(_tokenSet_7_data_);
private static final long _tokenSet_8_data_[] = { -4611686018427387912L, 9223372036854775807L, 0L, 0L };
public static final BitSet _tokenSet_8 = new BitSet(_tokenSet_8_data_);
private static final long _tokenSet_9_data_[] = { 576183181451994624L, 576460746129407998L, 0L, 0L };
public static final BitSet _tokenSet_9 = new BitSet(_tokenSet_9_data_);
private static final long _tokenSet_10_data_[] = { 2306051920717948416L, 536870912L, 0L, 0L };
public static final BitSet _tokenSet_10 = new BitSet(_tokenSet_10_data_);
private static final long _tokenSet_11_data_[] = { 2305843013508670976L, 0L, 0L };
public static final BitSet _tokenSet_11 = new BitSet(_tokenSet_11_data_);
private static final long _tokenSet_12_data_[] = { 208911504254464L, 536870912L, 0L, 0L };
public static final BitSet _tokenSet_12 = new BitSet(_tokenSet_12_data_);
private static final long _tokenSet_13_data_[] = { 288231527202947072L, 576460746129407998L, 0L, 0L };
public static final BitSet _tokenSet_13 = new BitSet(_tokenSet_13_data_);
private static final long _tokenSet_14_data_[] = { 189120294954496L, 0L, 0L };
public static final BitSet _tokenSet_14 = new BitSet(_tokenSet_14_data_);
private static final long _tokenSet_15_data_[] = { 576370098428716544L, 576460746129407998L, 0L, 0L };
public static final BitSet _tokenSet_15 = new BitSet(_tokenSet_15_data_);
private static final long _tokenSet_16_data_[] = { 576315157207066112L, 576460746666278910L, 0L, 0L };
public static final BitSet _tokenSet_16 = new BitSet(_tokenSet_16_data_);
private static final long _tokenSet_17_data_[] = { 576190912393127424L, 576460745995190270L, 0L, 0L };
public static final BitSet _tokenSet_17 = new BitSet(_tokenSet_17_data_);
private static final long _tokenSet_18_data_[] = { 576188713369871872L, 576460745995190270L, 0L, 0L };
public static final BitSet _tokenSet_18 = new BitSet(_tokenSet_18_data_);
private static final long _tokenSet_19_data_[] = { 576459193230304768L, 576460746532061182L, 0L, 0L };
public static final BitSet _tokenSet_19 = new BitSet(_tokenSet_19_data_);
private static final long _tokenSet_20_data_[] = { 576388824486127104L, 576460746532061182L, 0L, 0L };
public static final BitSet _tokenSet_20 = new BitSet(_tokenSet_20_data_);
}
1.1 e/src/jsrc/antlr/actions/cpp/ActionLexerTokenTypes.java
Index: ActionLexerTokenTypes.java
===================================================================
// $ANTLR 2.7.1: "action.g" -> "ActionLexer.java"$
package antlr.actions.cpp;
public interface ActionLexerTokenTypes {
int EOF = 1;
int NULL_TREE_LOOKAHEAD = 3;
int ACTION = 4;
int STUFF = 5;
int AST_ITEM = 6;
int TEXT_ITEM = 7;
int TREE = 8;
int TREE_ELEMENT = 9;
int AST_CONSTRUCTOR = 10;
int AST_CTOR_ELEMENT = 11;
int ID_ELEMENT = 12;
int TEXT_ARG = 13;
int TEXT_ARG_ELEMENT = 14;
int TEXT_ARG_ID_ELEMENT = 15;
int ARG = 16;
int ID = 17;
int VAR_ASSIGN = 18;
int COMMENT = 19;
int SL_COMMENT = 20;
int ML_COMMENT = 21;
int CHAR = 22;
int STRING = 23;
int ESC = 24;
int DIGIT = 25;
int INT = 26;
int INT_OR_FLOAT = 27;
int WS = 28;
}
1.1 e/src/jsrc/antlr/actions/cpp/ActionLexerTokenTypes.txt
Index: ActionLexerTokenTypes.txt
===================================================================
// $ANTLR 2.7.1: action.g -> ActionLexerTokenTypes.txt$
ActionLexer // output token vocab name
ACTION=4
STUFF=5
AST_ITEM=6
TEXT_ITEM=7
TREE=8
TREE_ELEMENT=9
AST_CONSTRUCTOR=10
AST_CTOR_ELEMENT=11
ID_ELEMENT=12
TEXT_ARG=13
TEXT_ARG_ELEMENT=14
TEXT_ARG_ID_ELEMENT=15
ARG=16
ID=17
VAR_ASSIGN=18
COMMENT=19
SL_COMMENT=20
ML_COMMENT=21
CHAR=22
STRING=23
ESC=24
DIGIT=25
INT=26
INT_OR_FLOAT=27
WS=28
1.1 e/src/jsrc/antlr/actions/cpp/action.g
Index: action.g
===================================================================
header {
package antlr.actions.cpp;
}
{
import java.io.StringReader;
import antlr.collections.impl.Vector;
import antlr.*;
}
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/RIGHTS.html
*
* $Id: action.g,v 1.1 2001/10/03 21:04:18 markm Exp $
*/
/** Perform the following translations:
AST related translations
## -> currentRule_AST
#(x,y,z) -> codeGenerator.getASTCreateString(vector-of(x,y,z))
#[x] -> codeGenerator.getASTCreateString(x)
#x -> codeGenerator.mapTreeId(x)
Inside context of #(...), you can ref (x,y,z), [x], and x as shortcuts.
Text related translations
$append(x) -> text.append(x)
$setText(x) -> text.setLength(_begin); text.append(x)
$getText -> new String(text.getBuffer(),_begin,text.length()-_begin)
$setToken(x) -> _token = x
$setType(x) -> _ttype = x
*/
class ActionLexer extends Lexer;
options {
k = 2;
charVocabulary = '\3'..'\176';
testLiterals=false;
interactive=true;
}
{
protected RuleBlock currentRule;
protected CodeGenerator generator;
protected int lineOffset = 0;
private Tool tool; // The ANTLR tool
ActionTransInfo transInfo;
public ActionLexer( String s,
RuleBlock currentRule,
CodeGenerator generator,
ActionTransInfo transInfo) {
this(new StringReader(s));
this.currentRule = currentRule;
this.generator = generator;
this.transInfo = transInfo;
}
public void setLineOffset(int lineOffset) {
// this.lineOffset = lineOffset;
setLine(lineOffset);
}
public void setTool(Tool tool) {
this.tool = tool;
}
// Override of error-reporting for syntax
public void reportError(RecognitionException e) {
System.err.print("Syntax error in action: ");
super.reportError(e);
}
}
// rules are protected because we don't care about nextToken().
public
ACTION
: ( STUFF
| AST_ITEM
| TEXT_ITEM
)+
;
// stuff in between #(...) and #id items
protected
STUFF
: COMMENT
| STRING
| CHAR
| "\r\n" {newline();}
| '\r' {newline();}
| '\n' {newline();}
| '/' ~('/'|'*') // non-comment start '/'
// | ( ~('/'|'\n'|'\r'|'$'|'#'|'"'|'\'') )+
| ~('/'|'\n'|'\r'|'$'|'#'|'"'|'\'')
;
protected
AST_ITEM
: '#'! t:TREE // #( )
| '#'! id:ID // #a_name (=)?
{
String idt = id.getText();
$setText(generator.mapTreeId(idt,transInfo));
}
(WS)?
( options {greedy=true;} : VAR_ASSIGN )?
| '#'! ctor:AST_CONSTRUCTOR // #[ ]
| "##"
{
String r=currentRule.getRuleName()+"_AST"; $setText(r);
if ( transInfo!=null ) {
transInfo.refRuleRoot=r; // we ref root of tree
}
}
(WS)?
( options {greedy=true;} : VAR_ASSIGN )?
;
protected
TEXT_ITEM
: "$append(" a1:TEXT_ARG ')'
{
String t = "text += "+a1.getText();
$setText(t);
}
| "$set"
( "Text(" a2:TEXT_ARG ')'
{
String t;
t = "text.erase(_begin); text += "+a2.getText();
$setText(t);
}
| "Token(" a3:TEXT_ARG ')'
{
String t="_token = "+a3.getText();
$setText(t);
}
| "Type(" a4:TEXT_ARG ')'
{
String t="_ttype = "+a4.getText();
$setText(t);
}
)
| "$getText"
{
$setText("text.substr(_begin,text.length()-_begin)");
}
;
protected
TREE!
{
StringBuffer buf = new StringBuffer();
int n=0;
Vector terms = new Vector(10);
}
: '('
(WS)?
t:TREE_ELEMENT
{
terms.appendElement(
generator.processStringForASTConstructor(t.getText())
);
}
(WS)?
( ',' (WS)?
t2:TREE_ELEMENT
{
terms.appendElement(
generator.processStringForASTConstructor(t2.getText())
);
}
(WS)?
)*
{$setText(generator.getASTCreateString(terms));}
')'
;
protected
TREE_ELEMENT { boolean was_mapped; }
: '#'! TREE
| '#'! AST_CONSTRUCTOR
| '#'! was_mapped=id:ID_ELEMENT
{ // RK: I have a queer feeling that this maptreeid is redundant..
if ( ! was_mapped )
{
String t = generator.mapTreeId(id.getText(), null);
$setText(t);
}
}
| "##"
{String t = currentRule.getRuleName()+"_AST"; $setText(t);}
| TREE
| AST_CONSTRUCTOR
| ID_ELEMENT
| STRING
;
protected
AST_CONSTRUCTOR!
: '[' (WS)? x:AST_CTOR_ELEMENT (WS)?
(',' (WS)? y:AST_CTOR_ELEMENT (WS)? )? ']'
{
// System.out.println("AST_CONSTRUCTOR: "+((x==null)?"null":x.getText())+
// ", "+((y==null)?"null":y.getText()));
String ys = generator.processStringForASTConstructor(x.getText());
// the second does not need processing coz it's a string
// (eg second param of astFactory.create(x,y)
if ( y!=null )
ys += ","+y.getText();
$setText( generator.getASTCreateString(null,ys) );
}
;
/** The arguments of a #[...] constructor are text, token type,
* or a tree.
*/
protected
AST_CTOR_ELEMENT
: STRING
| INT
| TREE_ELEMENT
;
/** An ID_ELEMENT can be a func call, array ref, simple var,
* or AST label ref.
*/
protected
ID_ELEMENT returns [boolean mapped=false]
: id:ID (options {greedy=true;}:WS!)?
( ('<' (~'>')* '>')? // allow typecast
'(' (options {greedy=true;}:WS!)? ( ARG (',' (WS!)? ARG)* )? (WS!)? ')' // method call
| ( '[' (WS!)? ARG (WS!)? ']' )+ // array reference
| '.' ID_ELEMENT
| "->" ID_ELEMENT
| "::" ID_ELEMENT
| /* could be a token reference or just a user var */
{
mapped = true;
String t = generator.mapTreeId(id.getText(), transInfo);
$setText(t);
}
// if #rule referenced, check for assignment
( options {greedy=true;}
: {transInfo!=null && transInfo.refRuleRoot!=null}?
(WS)? VAR_ASSIGN
)?
)
;
protected
TEXT_ARG
: (WS)? ( TEXT_ARG_ELEMENT (options {greedy=true;}:WS)? )+
;
protected
TEXT_ARG_ELEMENT
: TEXT_ARG_ID_ELEMENT
| STRING
| CHAR
| INT_OR_FLOAT
| TEXT_ITEM
| '+'
;
protected
TEXT_ARG_ID_ELEMENT
: id:ID (options {greedy=true;}:WS!)?
( '(' (options {greedy=true;}:WS!)? ( TEXT_ARG (',' TEXT_ARG)* )* (WS!)? ')' // method call
| ( '[' (WS!)? TEXT_ARG (WS!)? ']' )+ // array reference
| '.' TEXT_ARG_ID_ELEMENT
| "->" TEXT_ARG_ID_ELEMENT
| "::" TEXT_ARG_ID_ELEMENT
|
)
;
protected
ARG : ( TREE_ELEMENT
| STRING
| CHAR
| INT_OR_FLOAT
)
(options {greedy=true;} : (WS)? ( '+'| '-' | '*' | '/' ) (WS)? ARG )*
;
protected
ID : ('a'..'z'|'A'..'Z'|'_'|"::")
(options {greedy=true;} : ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|"::"))*
;
protected
VAR_ASSIGN
: '='
{
// inform the code generator that an assignment was done to
// AST root for the rule if invoker set refRuleRoot.
if ( LA(1)!='=' && transInfo!=null && transInfo.refRuleRoot!=null ) {
transInfo.assignToRoot=true;
}
}
;
protected
COMMENT
: SL_COMMENT
| ML_COMMENT
;
protected
SL_COMMENT
: "//" (options {greedy=false;}:.)* ('\n'|"\r\n"|'\r')
{newline();}
;
protected
ML_COMMENT :
"/*"
( options {greedy=false;}
: '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
| .
)*
"*/"
;
protected
CHAR :
'\''
( ESC | ~'\'' )
'\''
;
protected
STRING :
'"'
(ESC|~'"')*
'"'
;
protected
ESC : '\\'
( 'n'
| 'r'
| 't'
| 'b'
| 'f'
| '"'
| '\''
| '\\'
| ('0'..'3')
( options {greedy=true;}
: DIGIT
( options {greedy=true;}
: DIGIT
)?
)?
| ('4'..'7') (options {greedy=true;}:DIGIT)?
)
;
protected
DIGIT
: '0'..'9'
;
protected
INT : (DIGIT)+
;
protected
INT_OR_FLOAT
: (options {greedy=true;}:DIGIT)+
( options {greedy=true;}
: '.' (options {greedy=true;}:DIGIT)*
| 'L'
| 'l'
)?
;
protected
WS : ( options {greedy=true;}
: ' '
| '\t'
| '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
)+
;
1.1 e/src/jsrc/antlr/actions/java/ActionLexer.java
Index: ActionLexer.java
===================================================================
// $ANTLR 2.7.1: "action.g" -> "ActionLexer.java"$
package antlr.actions.java;
import java.io.InputStream;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.TokenStreamRecognitionException;
import antlr.CharStreamException;
import antlr.CharStreamIOException;
import antlr.ANTLRException;
import java.io.Reader;
import java.util.Hashtable;
import antlr.CharScanner;
import antlr.InputBuffer;
import antlr.ByteBuffer;
import antlr.CharBuffer;
import antlr.Token;
import antlr.CommonToken;
import antlr.RecognitionException;
import antlr.NoViableAltForCharException;
import antlr.MismatchedCharException;
import antlr.TokenStream;
import antlr.ANTLRHashString;
import antlr.LexerSharedInputState;
import antlr.collections.impl.BitSet;
import antlr.SemanticException;
import java.io.StringReader;
import antlr.collections.impl.Vector;
import antlr.*;
/** Perform the following translations:
AST related translations
## -> currentRule_AST
#(x,y,z) -> codeGenerator.getASTCreateString(vector-of(x,y,z))
#[x] -> codeGenerator.getASTCreateString(x)
#x -> codeGenerator.mapTreeId(x)
Inside context of #(...), you can ref (x,y,z), [x], and x as shortcuts.
Text related translations
$append(x) -> text.append(x)
$setText(x) -> text.setLength(_begin); text.append(x)
$getText -> new String(text.getBuffer(),_begin,text.length()-_begin)
$setToken(x) -> _token = x
$setType(x) -> _ttype = x
*/
public class ActionLexer extends antlr.CharScanner implements ActionLexerTokenTypes, TokenStream
{
protected RuleBlock currentRule;
protected CodeGenerator generator;
protected int lineOffset = 0;
private Tool tool; // The ANTLR tool
ActionTransInfo transInfo;
public ActionLexer( String s,
RuleBlock currentRule,
CodeGenerator generator,
ActionTransInfo transInfo) {
this(new StringReader(s));
this.currentRule = currentRule;
this.generator = generator;
this.transInfo = transInfo;
}
public void setLineOffset(int lineOffset) {
// this.lineOffset = lineOffset;
setLine(lineOffset);
}
public void setTool(Tool tool) {
this.tool = tool;
}
// Override of error-reporting for syntax
public void reportError(RecognitionException e) {
System.err.print("Syntax error in action: ");
super.reportError(e);
}
public ActionLexer(InputStream in) {
this(new ByteBuffer(in));
}
public ActionLexer(Reader in) {
this(new CharBuffer(in));
}
public ActionLexer(InputBuffer ib) {
this(new LexerSharedInputState(ib));
}
public ActionLexer(LexerSharedInputState state) {
super(state);
literals = new Hashtable();
caseSensitiveLiterals = true;
setCaseSensitive(true);
}
public Token nextToken() throws TokenStreamException {
Token theRetToken=null;
tryAgain:
for (;;) {
Token _token = null;
int _ttype = Token.INVALID_TYPE;
resetText();
try { // for char stream error handling
try { // for lexical error handling
if (((LA(1) >= '\u0003' && LA(1) <= '~'))) {
mACTION(true);
theRetToken=_returnToken;
}
else {
if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}
else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
if ( _returnToken==null ) continue tryAgain; // found SKIP token
_ttype = _returnToken.getType();
_returnToken.setType(_ttype);
return _returnToken;
}
catch (RecognitionException e) {
throw new TokenStreamRecognitionException(e);
}
}
catch (CharStreamException cse) {
if ( cse instanceof CharStreamIOException ) {
throw new TokenStreamIOException(((CharStreamIOException)cse).io);
}
else {
throw new TokenStreamException(cse.getMessage());
}
}
}
}
public final void mACTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ACTION;
int _saveIndex;
{
int _cnt3=0;
_loop3:
do {
switch ( LA(1)) {
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '"':
case '%': case '&': case '\'': case '(':
case ')': case '*': case '+': case ',':
case '-': case '.': case '/': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case ':': case ';': case '<':
case '=': case '>': case '?': case '@':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '[': case '\\':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
mSTUFF(false);
break;
}
case '#':
{
mAST_ITEM(false);
break;
}
case '$':
{
mTEXT_ITEM(false);
break;
}
default:
{
if ( _cnt3>=1 ) { break _loop3; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
}
_cnt3++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mSTUFF(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STUFF;
int _saveIndex;
switch ( LA(1)) {
case '"':
{
mSTRING(false);
break;
}
case '\'':
{
mCHAR(false);
break;
}
case '\n':
{
match('\n');
newline();
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\u000b':
case '\u000c': case '\u000e': case '\u000f': case '\u0010':
case '\u0011': case '\u0012': case '\u0013': case '\u0014':
case '\u0015': case '\u0016': case '\u0017': case '\u0018':
case '\u0019': case '\u001a': case '\u001b': case '\u001c':
case '\u001d': case '\u001e': case '\u001f': case ' ':
case '!': case '%': case '&': case '(':
case ')': case '*': case '+': case ',':
case '-': case '.': case '0': case '1':
case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case ':': case ';': case '<': case '=':
case '>': case '?': case '@': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '\\': case ']':
case '^': case '_': case '`': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z': case '{': case '|': case '}':
case '~':
{
{
match(_tokenSet_0);
}
break;
}
default:
if ((LA(1)=='/') && (LA(2)=='*'||LA(2)=='/')) {
mCOMMENT(false);
}
else if ((LA(1)=='\r') && (LA(2)=='\n')) {
match("\r\n");
newline();
}
else if ((LA(1)=='/') && (_tokenSet_1.member(LA(2)))) {
match('/');
{
match(_tokenSet_1);
}
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
newline();
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mAST_ITEM(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = AST_ITEM;
int _saveIndex;
Token t=null;
Token id=null;
Token ctor=null;
if ((LA(1)=='#') && (LA(2)=='(')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mTREE(true);
t=_returnToken;
}
else if ((LA(1)=='#') && (_tokenSet_2.member(LA(2)))) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mID(true);
id=_returnToken;
String idt = id.getText();
text.setLength(_begin); text.append(generator.mapTreeId(idt,transInfo));
{
if ((_tokenSet_3.member(LA(1))) && (true)) {
mWS(false);
}
else {
}
}
{
if ((LA(1)=='=') && (true)) {
mVAR_ASSIGN(false);
}
else {
}
}
}
else if ((LA(1)=='#') && (LA(2)=='[')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mAST_CONSTRUCTOR(true);
ctor=_returnToken;
}
else if ((LA(1)=='#') && (LA(2)=='#')) {
match("##");
String r=currentRule.getRuleName()+"_AST"; text.setLength(_begin); text.append(r);
if ( transInfo!=null ) {
transInfo.refRuleRoot=r; // we ref root of tree
}
{
if ((_tokenSet_3.member(LA(1))) && (true)) {
mWS(false);
}
else {
}
}
{
if ((LA(1)=='=') && (true)) {
mVAR_ASSIGN(false);
}
else {
}
}
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTEXT_ITEM(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TEXT_ITEM;
int _saveIndex;
Token a1=null;
Token a2=null;
Token a3=null;
Token a4=null;
if ((LA(1)=='$') && (LA(2)=='a')) {
match("$append(");
mTEXT_ARG(true);
a1=_returnToken;
match(')');
String t = "text.append("+a1.getText()+")";
text.setLength(_begin); text.append(t);
}
else if ((LA(1)=='$') && (LA(2)=='s')) {
match("$set");
{
if ((LA(1)=='T') && (LA(2)=='e')) {
match("Text(");
mTEXT_ARG(true);
a2=_returnToken;
match(')');
String t;
t = "text.setLength(_begin); text.append("+a2.getText()+")";
text.setLength(_begin); text.append(t);
}
else if ((LA(1)=='T') && (LA(2)=='o')) {
match("Token(");
mTEXT_ARG(true);
a3=_returnToken;
match(')');
String t="_token = "+a3.getText();
text.setLength(_begin); text.append(t);
}
else if ((LA(1)=='T') && (LA(2)=='y')) {
match("Type(");
mTEXT_ARG(true);
a4=_returnToken;
match(')');
String t="_ttype = "+a4.getText();
text.setLength(_begin); text.append(t);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else if ((LA(1)=='$') && (LA(2)=='g')) {
match("$getText");
text.setLength(_begin); text.append("new String(text.getBuffer(),_begin,text.length()-_begin)");
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mCOMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = COMMENT;
int _saveIndex;
if ((LA(1)=='/') && (LA(2)=='/')) {
mSL_COMMENT(false);
}
else if ((LA(1)=='/') && (LA(2)=='*')) {
mML_COMMENT(false);
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mSTRING(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = STRING;
int _saveIndex;
match('"');
{
_loop88:
do {
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '#':
case '$': case '%': case '&': case '\'':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('"');
break;
}
default:
{
break _loop88;
}
}
} while (true);
}
match('"');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mCHAR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = CHAR;
int _saveIndex;
match('\'');
{
switch ( LA(1)) {
case '\\':
{
mESC(false);
break;
}
case '\u0003': case '\u0004': case '\u0005': case '\u0006':
case '\u0007': case '\u0008': case '\t': case '\n':
case '\u000b': case '\u000c': case '\r': case '\u000e':
case '\u000f': case '\u0010': case '\u0011': case '\u0012':
case '\u0013': case '\u0014': case '\u0015': case '\u0016':
case '\u0017': case '\u0018': case '\u0019': case '\u001a':
case '\u001b': case '\u001c': case '\u001d': case '\u001e':
case '\u001f': case ' ': case '!': case '"':
case '#': case '$': case '%': case '&':
case '(': case ')': case '*': case '+':
case ',': case '-': case '.': case '/':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case ':': case ';':
case '<': case '=': case '>': case '?':
case '@': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case ']': case '^': case '_': case '`':
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z': case '{': case '|':
case '}': case '~':
{
matchNot('\'');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
match('\'');
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTREE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TREE;
int _saveIndex;
Token t=null;
Token t2=null;
StringBuffer buf = new StringBuffer();
int n=0;
Vector terms = new Vector(10);
_saveIndex=text.length();
match('(');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mTREE_ELEMENT(true);
text.setLength(_saveIndex);
t=_returnToken;
terms.appendElement(t.getText());
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ')': case ',':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
_loop20:
do {
if ((LA(1)==',')) {
_saveIndex=text.length();
match(',');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case 'A':
case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q':
case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y':
case 'Z': case '[': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mTREE_ELEMENT(true);
text.setLength(_saveIndex);
t2=_returnToken;
terms.appendElement(t2.getText());
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ')': case ',':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
}
else {
break _loop20;
}
} while (true);
}
text.setLength(_begin); text.append(generator.getASTCreateString(terms));
_saveIndex=text.length();
match(')');
text.setLength(_saveIndex);
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mID(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = ID;
int _saveIndex;
{
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '_':
{
match('_');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
_loop74:
do {
if ((_tokenSet_4.member(LA(1))) && (true)) {
{
switch ( LA(1)) {
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
{
matchRange('a','z');
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
{
matchRange('A','Z');
break;
}
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
{
matchRange('0','9');
break;
}
case '_':
{
match('_');
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
}
else {
break _loop74;
}
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mWS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = WS;
int _saveIndex;
{
int _cnt108=0;
_loop108:
do {
if ((LA(1)=='\r') && (LA(2)=='\n')) {
match('\r');
match('\n');
newline();
}
else if ((LA(1)==' ') && (true)) {
match(' ');
}
else if ((LA(1)=='\t') && (true)) {
match('\t');
}
else if ((LA(1)=='\r') && (true)) {
match('\r');
newline();
}
else if ((LA(1)=='\n') && (true)) {
match('\n');
newline();
}
else {
if ( _cnt108>=1 ) { break _loop108; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt108++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mVAR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = VAR_ASSIGN;
int _saveIndex;
match('=');
// inform the code generator that an assignment was done to
// AST root for the rule if invoker set refRuleRoot.
if ( LA(1)!='=' && transInfo!=null && transInfo.refRuleRoot!=null ) {
transInfo.assignToRoot=true;
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mAST_CONSTRUCTOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = AST_CONSTRUCTOR;
int _saveIndex;
Token x=null;
Token y=null;
_saveIndex=text.length();
match('[');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case '_': case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k':
case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's':
case 't': case 'u': case 'v': case 'w':
case 'x': case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mAST_CTOR_ELEMENT(true);
text.setLength(_saveIndex);
x=_returnToken;
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ',': case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
switch ( LA(1)) {
case ',':
{
_saveIndex=text.length();
match(',');
text.setLength(_saveIndex);
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case '"': case '#': case '(': case '0':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9': case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K':
case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S':
case 'T': case 'U': case 'V': case 'W':
case 'X': case 'Y': case 'Z': case '[':
case '_': case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k':
case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's':
case 't': case 'u': case 'v': case 'w':
case 'x': case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
mAST_CTOR_ELEMENT(true);
text.setLength(_saveIndex);
y=_returnToken;
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
_saveIndex=text.length();
mWS(false);
text.setLength(_saveIndex);
break;
}
case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
break;
}
case ']':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
_saveIndex=text.length();
match(']');
text.setLength(_saveIndex);
String ys = "";
if ( y!=null ) {
ys = ","+y.getText();
}
text.setLength(_begin); text.append(generator.getASTCreateString(null,x.getText()+ys));
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTEXT_ARG(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TEXT_ARG;
int _saveIndex;
{
switch ( LA(1)) {
case '\t': case '\n': case '\r': case ' ':
{
mWS(false);
break;
}
case '"': case '$': case '\'': case '+':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9': case 'A': case 'B':
case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V':
case 'W': case 'X': case 'Y': case 'Z':
case '_': case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k':
case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's':
case 't': case 'u': case 'v': case 'w':
case 'x': case 'y': case 'z':
{
break;
}
default:
{
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
{
int _cnt48=0;
_loop48:
do {
if ((_tokenSet_5.member(LA(1))) && ((LA(2) >= '\u0003' && LA(2) <= '~'))) {
mTEXT_ARG_ELEMENT(false);
{
if ((_tokenSet_3.member(LA(1))) && (_tokenSet_6.member(LA(2)))) {
mWS(false);
}
else if ((_tokenSet_6.member(LA(1))) && (true)) {
}
else {
throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());
}
}
}
else {
if ( _cnt48>=1 ) { break _loop48; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine());}
}
_cnt48++;
} while (true);
}
if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
_token = makeToken(_ttype);
_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
}
_returnToken = _token;
}
protected final void mTREE_ELEMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
int _ttype; Token _token=null; int _begin=text.length();
_ttype = TREE_ELEMENT;
int _saveIndex;
Token id=null;
boolean was_mapped;
switch ( LA(1)) {
case '(':
{
mTREE(false);
break;
}
case '[':
{
mAST_CONSTRUCTOR(false);
break;
}
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '_': case 'a':
case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm':
case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y':
case 'z':
{
mID_ELEMENT(false);
break;
}
case '"':
{
mSTRING(false);
break;
}
default:
if ((LA(1)=='#') && (LA(2)=='(')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mTREE(false);
}
else if ((LA(1)=='#') && (LA(2)=='[')) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
mAST_CONSTRUCTOR(false);
}
else if ((LA(1)=='#') && (_tokenSet_2.member(LA(2)))) {
_saveIndex=text.length();
match('#');
text.setLength(_saveIndex);
was_mapped=mID_ELEMENT(true);
id=_returnToken;
// RK: I have a queer feeling that this maptreeid is redundant
if( ! was_mapped )
{
Strin