[antlr-interest] antlr should throw NoViableAltException

femto gary femtowin at gmail.com
Sun Apr 15 03:05:32 PDT 2007


Hi all, for following grammar,

grammar Rubyv3;

options {
        output=AST;
}
tokens {
	// 'imaginary' tokens
	STATEMENT_LIST;
	STATEMENT;
	RPAREN_IN_METHOD_DEFINATION;
	BODY;
	CALL;
	ARG;
	//COMPSTMT;
	SYMBOL;
	BLOCK;
	MULTIPLE_ASSIGN;
	MULTIPLE_ASSIGN_WITH_EXTRA_COMMA;
	BLOCK_ARG;
	BLOCK_ARG_WITH_EXTRA_COMMA;
	MRHS;
	NESTED_LHS;
	SINGLETON_METHOD;
	STRING;
}

/*@rulecatch {
catch (RecognitionException e) {
throw e;
}
}*/

@header {
package com.xruby.compiler.parser;
}
@lexer::header {
package com.xruby.compiler.parser;
}

@members{
	private int can_be_command_ = 0;

	protected void enterScope()	{assert(false);}
	protected void enterBlockScope()	{assert(false);}
	protected void leaveScope()	{assert(false);}
	protected void addVariable(Token id)	{assert(false);}
	protected void setIsInNestedMultipleAssign(boolean v)	{assert(false);}
	protected void
tellLexerWeHaveFinishedParsingMethodparameters()	{assert(false);}
	protected void tellLexerWeHaveFinishedParsingSymbol()	{assert(false);}
	protected void
tellLexerWeHaveFinishedParsingStringExpressionSubstituation()	{assert(false);}
	protected void
tellLexerWeHaveFinishedParsingRegexExpressionSubstituation()	{assert(false);}
	protected void
tellLexerWeHaveFinishedParsingHeredocExpressionSubstituation()	{assert(false);}

	
}

@lexer::members
{
	//The following methods are to be implemented in the subclass.
	//In fact they should be 'abstract', but antlr refuses to generate
	//abstract class. We can either insert 'abstract' keyword manually
	//after the lexer is generated, or simply use assert() to prevent
	//these function to run (so you have to overide them). I choosed
	//the later approach.
	protected boolean expectOperator(int k) throws
Exception		{assert(false);return false;}
	protected boolean expectUnary()	 throws
Exception			{assert(false);return false;}
	protected boolean expectHash()					{assert(false);return false;}
	protected boolean expectHeredoc()				{assert(false);return false;}
	protected boolean expectLeadingColon2()		{assert(false);return false;}
	protected boolean expectArrayAccess()				{assert(false);return false;}
	protected boolean lastTokenIsDotOrColon2()		{assert(false);return false;}
	protected boolean lastTokenIsSemi()				{assert(false);return false;}
	protected boolean
lastTokenIsKeywordDefOrColonWithNoFollowingSpace()			{assert(false);return
false;}
	protected boolean
lastTokenIsColonWithNoFollowingSpace()			{assert(false);return false;}
	protected boolean shouldIgnoreLinebreak()			{assert(false);return false;}
	protected int trackDelimiterCount(char next_char, char delimeter, int
delimeter_count)	{assert(false);return 0;}
	protected boolean isDelimiter(String next_line, String
delimiter)	{assert(false);return false;}
	protected boolean isAsciiValueTerminator(char
value)	{assert(false);return false;}
	protected boolean justSeenWhitespace()	{assert(false);return false;}
	protected void setSeenWhitespace()			{assert(false);}
	protected boolean expressionSubstitutionIsNext()	throws
Exception	{assert(false);return false;}
	protected boolean spaceIsNext()	throws Exception	{assert(false);return false;}
	protected void setCurrentSpecialStringDelimiter(char delimiter, int
delimiter_count)	{assert(false);}
	protected void updateCurrentSpecialStringDelimiterCount(int
delimiter_count)	{assert(false);}
}

program
		:	statement_list
		;

statement_list
		:	statement* -> ^(STATEMENT_LIST statement*)
			;

/*terminal
		:	SEMI!
		|	LINE_BREAK!
		;*/
statement
	:	expression (modifier_line)* SEMI? -> ^(STATEMENT expression
(modifier_line)*)
	|       SEMI!
	;

modifier_line
	:(IF_MODIFIER|UNLESS_MODIFIER|WHILE_MODIFIER|UNTIL_MODIFIER|RESCUE_MODIFIER)^
expression
/*statement
		:	body=statementWithoutModifier
									(IF_MODIFIER^		if_condition=expression	{#statement =
#(#[LITERAL_if, 'if'], if_condition, #(#[COMPSTMT, 'COMPSTMT'],
#body));}
									|UNLESS_MODIFIER^	unless_condition=expression	{#statement =
#(#[LITERAL_unless, 'unless'], unless_condition, #(#[COMPSTMT,
'COMPSTMT'], #body));}
									|WHILE_MODIFIER^	while_condition=expression	{#statement =
#(#[LITERAL_while, 'while'], while_condition, #(#[COMPSTMT,
'COMPSTMT'], #body));}
									|UNTIL_MODIFIER^	until_condition=expression	{#statement =
#(#[LITERAL_until, 'until'], until_condition, #(#[COMPSTMT,
'COMPSTMT'], #body));}
									|RESCUE_MODIFIER^	rescue_condition=expression	{#statement =
#(#[LITERAL_rescue, 'rescue'], rescue_condition, #(#[COMPSTMT,
'COMPSTMT'], #body));}
									)**/
		;
IF_MODIFIER     :  'if';
UNLESS_MODIFIER :  'unless';
WHILE_MODIFIER  :  'while';
UNTIL_MODIFIER  :  'until';
RESCUE_MODIFIER :  'resuce';

SEMI	:';'
	;

LINE_BREAK
	:'\r'? '\n'{skip();}
	;
//OMIT_LINE_BREAK
//	:	LINE_BREAK* {skip();}
//	;
//emptyable_expression
//	:	expression|;
expression
	:	'expression0' | 'expression1' | 'expression2';
	
WS	:	(' ' | '\t') { skip(); }
	;
ID	:	('a'..'z' | 'A'..'Z') (('a'..'z' | 'A'..'Z') | ('0'..'9'))*
	;
----------------------------------------------------------------------------
ruby should throw NoViableAltException when meeting input
"if expression1; ",
this is the test drive:

package com.xruby.compiler.parser;

import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonTree;

import java.io.StringReader;
import java.io.StringBufferInputStream;
import java.io.IOException;

import junit.framework.TestCase;

/**
 * Copyright 2005-2007 femto
 * Distributed under the GNU General Public License 2.0
 */
public class Rubyv3Test extends TestCase {
    public void test_parse() throws Exception {
        assert_parse("", "STATEMENT_LIST");
        assert_parse(";", "STATEMENT_LIST");
        assert_parse("  ", "STATEMENT_LIST");
        assert_parse(";\n;\n;\n;\n", "STATEMENT_LIST");
        assert_parse("expression0 \tif expression1 if expression2; ",
"(STATEMENT_LIST (STATEMENT expression0 (if expression1) (if
expression2)))");
        assert_parse("expression0 \tif\nexpression1 if expression2;",
"(STATEMENT_LIST (STATEMENT expression0 (if expression1) (if
expression2)))");
        assert_parse("expression0 \tif\nexpression1 if expression2",
"(STATEMENT_LIST (STATEMENT expression0 (if expression1) (if
expression2)))");
        assert_parse("expression0 \tif expression1 if expression2\n
expression0", "(STATEMENT_LIST (STATEMENT expression0 (if expression1)
(if expression2)) (STATEMENT expression0))");
        assert_parse("expression0 \tif expression1 if expression2;
expression0", "(STATEMENT_LIST (STATEMENT expression0 (if expression1)
(if expression2)) (STATEMENT expression0))");
        assert_parse("expression0 \tif expression1 if expression2;;
expression0", "(STATEMENT_LIST (STATEMENT expression0 (if expression1)
(if expression2)) (STATEMENT expression0))");
        assert_parse("if expression1; ", "");
    }
    public void assert_parse(String text, String expectedTree) throws
IOException

    {
        ANTLRInputStream input =
                new ANTLRInputStream(new StringBufferInputStream(text));

        Rubyv3Lexer lexer = new Rubyv3Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        Rubyv3Parser parser = new Rubyv3Parser(tokens);
        Rubyv3Parser.program_return result = null;
        try {
            result = parser.program();
        } catch (NoViableAltException e) {
            e.printStackTrace();
        }
        catch (RecognitionException e) {
            e.printStackTrace();
        }
        assertEquals(expectedTree, ((CommonTree)result.tree).toStringTree());
        //System.out.println("tree:" +
((CommonTree)result.tree).toStringTree());
    }

}
//besides, in Antlrworks interpreter mode, it will produce NoViableAltException,
so I think it is a bug in main program.(antlr should throw Exception,
but instead
nothing happened).


More information about the antlr-interest mailing list