From 4ae23f4a644842a727dcbafd046b75f8cc2eab3b Mon Sep 17 00:00:00 2001 From: parrt Date: Thu, 5 Jan 2012 12:27:14 -0800 Subject: [PATCH] * 1+2*3 now gives new parse tree: (e (e 1) + (e (e 2) * (e 3))) See CHANGES.txt now too [git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9833] --- CHANGES.txt | 8 +- .../Java/src/org/antlr/v4/runtime/Parser.java | 57 +++-- .../v4/tool/templates/LeftRecursiveRules.stg | 4 +- .../v4/tool/templates/codegen/Java/Java.stg | 48 +++- .../org/antlr/v4/codegen/ParserFactory.java | 8 +- .../codegen/model/LRecursiveRuleFunction.java | 39 ++++ .../org/antlr/v4/codegen/model/StarBlock.java | 5 + .../v4/codegen/model/decl/StructDecl.java | 1 + .../v4/parse/LeftRecursiveRuleAnalyzer.java | 8 +- .../v4/semantics/BasicSemanticChecks.java | 10 +- .../org/antlr/v4/test/TestLeftRecursion.java | 208 +++++------------- 11 files changed, 216 insertions(+), 180 deletions(-) create mode 100644 tool/src/org/antlr/v4/codegen/model/LRecursiveRuleFunction.java diff --git a/CHANGES.txt b/CHANGES.txt index abda2a014..fc71dc839 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,9 +1,15 @@ ANTLR v4 Honey Badger early access +Jan 5, 2012 + +* Deleted code to call specific listeners by mistake. added back. + Jan 4, 2012 * '_' was allowed first in symbol names in grammar * fix unit tests * Allow labels in left-recursive rules * lr rules now gen only 1 rule e->e not e->e_ etc... altered tests to build parse trees. -* no more -trace, use Parser.setTrace(true) \ No newline at end of file +* no more -trace, use Parser.setTrace(true) +* add context rule option; not hooked up +* 1+2*3 now gives new parse tree: (e (e 1) + (e (e 2) * (e 3))) diff --git a/runtime/Java/src/org/antlr/v4/runtime/Parser.java b/runtime/Java/src/org/antlr/v4/runtime/Parser.java index 22b581aa0..6f0580b12 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/Parser.java +++ b/runtime/Java/src/org/antlr/v4/runtime/Parser.java @@ -173,6 +173,22 @@ public abstract class Parser extends Recognizer l : _parseListeners) { + l.enterEveryRule(_ctx); + _ctx.enterRule(l); + } + } + + public void triggerExitRuleEvent() { + // reverse order walk of listeners + for (int i = _parseListeners.size()-1; i >= 0; i--) { + ParseTreeListener l = _parseListeners.get(i); + _ctx.exitRule(l); + l.exitEveryRule(_ctx); + } + } + /** Get number of recognition errors (lexer, parser, tree parser). Each * recognizer tracks its own number. So parser and lexer each have * separate count. Does not count the spurious errors found between @@ -302,22 +318,12 @@ public abstract class Parser extends Recognizer l : _parseListeners) { - _ctx.enterRule(l); - l.enterEveryRule(_ctx); - } - } + if ( _parseListeners != null) triggerEnterRuleEvent(); } - public void exitRule(int ruleIndex) { + public void exitRule() { // trigger event on _ctx, before it reverts to parent - if ( _parseListeners != null) { - for (ParseTreeListener l : _parseListeners) { - _ctx.exitRule(l); - l.exitEveryRule(_ctx); - } - } + if ( _parseListeners != null) triggerExitRuleEvent(); _ctx = (ParserRuleContext)_ctx.parent; } @@ -333,6 +339,31 @@ public abstract class Parser extends Recognizer localctx, int ruleIndex) { + _ctx = localctx; + _ctx.start = _input.LT(1); + _ctx.ruleIndex = ruleIndex; + } + + public void unrollRecursionContexts(ParserRuleContext _parentctx) { + ParserRuleContext retctx = _ctx; // save current ctx (return value) + + // unroll so _ctx is as it was before call to recursive method + if ( _parseListeners != null ) { + while ( _ctx != _parentctx ) { + triggerExitRuleEvent(); + _ctx = (ParserRuleContext)_ctx.parent; + } + } + else { + _ctx = _parentctx; + } + // hook into tree + retctx.parent = _parentctx; + if (_buildParseTrees) _parentctx.addChild(retctx); // add return ctx into invoking rule's tree + } + public ParserRuleContext getInvokingContext(int ruleIndex) { ParserRuleContext p = _ctx; while ( p!=null ) { diff --git a/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg b/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg index d885d3e3d..10c0852f6 100644 --- a/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg +++ b/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg @@ -37,6 +37,7 @@ recRule(ruleName, precArgDef, argName, primaryAlts, opAlts, setResultAction, userRetvals, userRetvalAssignments) ::= << [] returns [] +options {simrecursion_=true;} : ( ) @@ -44,7 +45,8 @@ recRule(ruleName, precArgDef, argName, primaryAlts, opAlts, setResultAction, } - ( + ( options {simrecursion_=true;} + : )* ; >> diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg index 399fe599f..74cc6b09f 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg @@ -175,7 +175,36 @@ RuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAc } finally { - exitRule(RULE_); + exitRule(); + } + return _localctx; +} +>> + +LRecursiveRuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble) ::= << + + + + + }>public final () throws RecognitionException { + ParserRuleContext\ _parentctx = _ctx; + _localctx = new (_ctx, }>); + pushNewRecursionContext(_localctx, RULE_); + + + try { + + _localctx.stop = _input.LT(-1); + + + } + catch (RecognitionException re) { + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + + unrollRecursionContexts(_parentctx); } return _localctx; } @@ -322,12 +351,15 @@ setState(); _errHandler.sync(this); int _alt = getInterpreter().adaptivePredict(_input,,_ctx); while ( _alt!= && _alt!=-1 ) { - switch ( _alt ) { - : - - break;}; separator="\n"> - } + if ( _alt==1 ) { + + if ( _parseListeners!=null ) triggerExitRuleEvent(); + _localctx = new Context(_parentctx, , _p); + _localctx.addChild(_ctx); + pushNewRecursionContext(_localctx, RULE_); + + + } setState(); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,,_ctx); @@ -512,7 +544,7 @@ labelref(x) ::= "_localctx." recRuleDefArg() ::= "int _p" recRuleArg() ::= "$_p" recRuleAltPredicate(ruleName,opPrec) ::= " >= " -recRuleSetResultAction() ::= "$tree=$_primary.tree;" +recRuleSetResultAction() ::= "$tree=$.tree;" recRuleSetReturnAction(src,name) ::= "$=$.;" LexerFile(lexerFile, lexer, namedActions) ::= << diff --git a/tool/src/org/antlr/v4/codegen/ParserFactory.java b/tool/src/org/antlr/v4/codegen/ParserFactory.java index fd2cdcbfc..f0aa08bde 100644 --- a/tool/src/org/antlr/v4/codegen/ParserFactory.java +++ b/tool/src/org/antlr/v4/codegen/ParserFactory.java @@ -61,7 +61,13 @@ public class ParserFactory extends DefaultOutputModelFactory { } public RuleFunction rule(Rule r) { - return new RuleFunction(this, r); + GrammarAST optionNode = r.ast.getOption("simrecursion_"); + if ( optionNode!=null && optionNode.getText().equals("true") ) { + return new LRecursiveRuleFunction(this, r); + } + else { + return new RuleFunction(this, r); + } } public CodeBlockForAlt epsilon() { return new CodeBlockForAlt(this); } diff --git a/tool/src/org/antlr/v4/codegen/model/LRecursiveRuleFunction.java b/tool/src/org/antlr/v4/codegen/model/LRecursiveRuleFunction.java new file mode 100644 index 000000000..128fcbd36 --- /dev/null +++ b/tool/src/org/antlr/v4/codegen/model/LRecursiveRuleFunction.java @@ -0,0 +1,39 @@ +/* + [The "BSD license"] + Copyright (c) 2012 Terence Parr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.antlr.v4.codegen.model; + +import org.antlr.v4.codegen.OutputModelFactory; +import org.antlr.v4.tool.Rule; + +public class LRecursiveRuleFunction extends RuleFunction { + public LRecursiveRuleFunction(OutputModelFactory factory, Rule r) { + super(factory, r); + } +} diff --git a/tool/src/org/antlr/v4/codegen/model/StarBlock.java b/tool/src/org/antlr/v4/codegen/model/StarBlock.java index a7408afd7..19bb81fe8 100644 --- a/tool/src/org/antlr/v4/codegen/model/StarBlock.java +++ b/tool/src/org/antlr/v4/codegen/model/StarBlock.java @@ -31,18 +31,23 @@ package org.antlr.v4.codegen.model; import org.antlr.v4.codegen.OutputModelFactory; import org.antlr.v4.runtime.atn.StarLoopEntryState; +import org.antlr.v4.tool.ast.BlockAST; import org.antlr.v4.tool.ast.GrammarAST; import java.util.List; public class StarBlock extends Loop { public String loopLabel; + public boolean isForRecursiveRule; public StarBlock(OutputModelFactory factory, GrammarAST blkOrEbnfRootAST, List alts) { super(factory, blkOrEbnfRootAST, alts); + BlockAST blk = (BlockAST)ast.getChild(0); + GrammarAST optionNode = blk.getOption("simrecursion_"); + isForRecursiveRule = optionNode!=null && optionNode.getText().equals("true"); loopLabel = factory.getGenerator().target.getLoopLabel(blkOrEbnfRootAST); StarLoopEntryState star = (StarLoopEntryState)blkOrEbnfRootAST.atnState; loopBackStateNumber = star.loopBackState.stateNumber; diff --git a/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java index fb30715b6..01deaf537 100644 --- a/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java +++ b/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java @@ -54,6 +54,7 @@ public class StructDecl extends Decl { public StructDecl(OutputModelFactory factory, Rule r) { super(factory, factory.getGenerator().target.getRuleFunctionContextStructName(r)); + addVisitorDispatchMethods(r); } public void addVisitorDispatchMethods(Rule r) { diff --git a/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java b/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java index 4181433c3..3d39b0d17 100644 --- a/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java +++ b/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java @@ -233,7 +233,7 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker { ST setResultST = codegenTemplates.getInstanceOf("recRuleSetResultAction"); ruleST.add("setResultAction", setResultST); ruleST.add("userRetvals", retvals); - fillRetValAssignments(ruleST, "recPrimaryName"); + fillRetValAssignments(ruleST); LinkedHashMap opPrecRuleAlts = new LinkedHashMap(); opPrecRuleAlts.putAll(binaryAlts); @@ -354,7 +354,7 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker { return p; } - public void fillRetValAssignments(ST ruleST, String srcName) { + public void fillRetValAssignments(ST ruleST) { if ( retvals==null ) return; // complicated since we must be target-independent @@ -363,9 +363,7 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker { for (String name : args.attributes.keySet()) { ST setRetValST = codegenTemplates.getInstanceOf("recRuleSetReturnAction"); - ST ruleNameST = recRuleTemplates.getInstanceOf(srcName); - ruleNameST.add("ruleName", ruleName); - setRetValST.add("src", ruleNameST); + setRetValST.add("src", ruleName); setRetValST.add("name", name); ruleST.add("userRetvalAssignments",setRetValST); } diff --git a/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java b/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java index 277d399b6..04f2465cf 100644 --- a/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java +++ b/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java @@ -95,12 +95,18 @@ public class BasicSemanticChecks extends GrammarTreeVisitor { public static final Set legalRuleOptions = new HashSet() { { - + add("context"); + add("simrecursion_"); } }; public static final Set legalBlockOptions = - new HashSet() {{add("greedy");}}; + new HashSet() { + { + add("greedy"); + add("simrecursion_"); + } + }; /** Legal options for terminal refs like ID */ public static final Set legalTokenOptions = diff --git a/tool/test/org/antlr/v4/test/TestLeftRecursion.java b/tool/test/org/antlr/v4/test/TestLeftRecursion.java index 2741d65a3..cc68db8d5 100644 --- a/tool/test/org/antlr/v4/test/TestLeftRecursion.java +++ b/tool/test/org/antlr/v4/test/TestLeftRecursion.java @@ -17,7 +17,7 @@ public class TestLeftRecursion extends BaseTest { "WS : (' '|'\\n') {skip();} ;\n"; String found = execParser("T.g", grammar, "TParser", "TLexer", "s", "x y z", debug); - String expecting = "(s (a x y z))\n"; + String expecting = "(s (a (a (a x) y) z))\n"; assertEquals(expecting, found); } @@ -32,7 +32,7 @@ public class TestLeftRecursion extends BaseTest { "WS : (' '|'\\n') {skip();} ;\n"; String found = execParser("T.g", grammar, "TParser", "TLexer", "s", "x y z", debug); - String expecting = "(s (a x y z))\n"; + String expecting = "(s (a (a (a x) y) z))\n"; assertEquals(expecting, found); } @@ -50,81 +50,20 @@ public class TestLeftRecursion extends BaseTest { "WS : (' '|'\\n') {skip();} ;\n"; String[] tests = { "a", "(s (e a) )", - "a+b", "(s (e a + (e b)) )", - "a*b", "(* a b)", - "a?b:c", "(? a b c)", - "a=b=c", "(= a (= b c))", - "a?b+c:d", "(? a (+ b c) d)", - "a?b=c:d", "(? a (= b c) d)", - "a? b?c:d : e", "(? a (? b c d) e)", - "a?b: c?d:e", "(? a b (? c d e))", + "a+b", "(s (e (e a) + (e b)) )", + "a*b", "(s (e (e a) * (e b)) )", + "a?b:c", "(s (e (e a) ? (e b) : (e c)) )", + "a=b=c", "(s (e (e a) = (e (e b) = (e c))) )", + "a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) )", + "a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) )", + "a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) )", + "a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) )", }; runTests(grammar, tests, "s"); } - @Test public void testDeclarationsUsingASTOperators() throws Exception { - String grammar = - "grammar T;\n" + - "s @after {System.out.println($ctx.toStringTree(this));} : declarator EOF ;\n" + // must indicate EOF can follow - "declarator\n" + - " : declarator '[' e ']'\n" + - " | declarator '[' ']'\n" + - " | declarator '(' ')'\n" + - " | '*' declarator\n" + // binds less tight than suffixes - " | '(' declarator ')'\n" + - " | ID\n" + - " ;\n" + - "e : INT ;\n" + - "ID : 'a'..'z'+ ;\n" + - "INT : '0'..'9'+ ;\n" + - "WS : (' '|'\\n') {skip();} ;\n"; - String[] tests = { - "a", "a", - "*a", "(* a)", - "**a", "(* (* a))", - "a[3]", "([ a 3)", - "b[]", "([ b)", - "(a)", "a", - "a[]()", "(( ([ a))", - "a[][]", "([ ([ a))", - "*a[]", "(* ([ a))", - "(*a)[]", "([ (* a))", - }; - runTests(grammar, tests, "s"); - } - @Test public void testDeclarationsUsingRewriteOperators() throws Exception { - String grammar = - "grammar T;\n" + - "s @after {System.out.println($ctx.toStringTree(this));} : declarator EOF ;\n" + // must indicate EOF can follow - "declarator\n" + - " : declarator '[' e ']'" + - " | declarator '[' ']'" + - " | declarator '(' ')'" + - " | '*' declarator" + // binds less tight than suffixes - " | '(' declarator ')'" + - " | ID" + - " ;\n" + - "e : INT ;\n" + - "ID : 'a'..'z'+ ;\n" + - "INT : '0'..'9'+ ;\n" + - "WS : (' '|'\\n') {skip();} ;\n"; - String[] tests = { - "a", "a", - "*a", "(* a)", - "**a", "(* (* a))", - "a[3]", "([ a 3)", - "b[]", "([ b)", - "(a)", "a", - "a[]()", "(( ([ a))", - "a[][]", "([ ([ a))", - "*a[]", "(* ([ a))", - "(*a)[]", "([ (* a))", - }; - runTests(grammar, tests, "s"); - } - - @Test public void testExpressionsUsingASTOperators() throws Exception { + @Test public void testExpressions() throws Exception { String grammar = "grammar T;\n" + "s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow @@ -140,59 +79,17 @@ public class TestLeftRecursion extends BaseTest { "INT : '0'..'9'+ ;\n" + "WS : (' '|'\\n') {skip();} ;\n"; String[] tests = { - "a", "a", - "1", "1", - "a+1", "(+ a 1)", - "a*1", "(* a 1)", - "a.b", "(. a b)", - "a.this", "(. a this)", - "a-b+c", "(+ (- a b) c)", - "a+b*c", "(+ a (* b c))", - "a.b+1", "(+ (. a b) 1)", - "-a", "(- a)", - "-a+b", "(+ (- a) b)", - "-a.b", "(- (. a b))", + "a", "(s (e a) )", + "1", "(s (e 1) )", + "a-1", "(s (e (e a) - (e 1)) )", + "a.b", "(s (e (e a) . b) )", + "a.this", "(s (e (e a) . this) )", + "-a", "(s (e - (e a)) )", + "-a+b", "(s (e (e - (e a)) + (e b)) )", }; runTests(grammar, tests, "s"); } - @Test public void testExpressionAssociativity() throws Exception { - String grammar = - "grammar T;\n" + - "s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow - "e\n" + - " : e '.' ID\n" + - " | '-' e\n" + - " | e '' e\n" + - " | e '*' e\n" + - " | e ('+'|'-') e\n" + - " | e ('=' |'+=') e\n" + - " | INT\n" + - " | ID\n" + - " ;\n" + - "ID : 'a'..'z'+ ;\n" + - "INT : '0'..'9'+ ;\n" + - "WS : (' '|'\\n') {skip();} ;\n"; - String[] tests = { - "a", "a", - "1", "1", - "a+1", "(+ a 1)", - "a*1", "(* a 1)", - "a.b", "(. a b)", - "a-b+c", "(+ (- a b) c)", - - "a+b*c", "(+ a (* b c))", - "a.b+1", "(+ (. a b) 1)", - "-a", "(- a)", - "-a+b", "(+ (- a) b)", - "-a.b", "(- (. a b))", - "a^b^c", "(^ a (^ b c))", - "a=b=c", "(= a (= b c))", - "a=b=c+d.e","(= a (= b (+ c (. d e))))", - }; - runTests(grammar, tests, "e"); - } - @Test public void testJavaExpressions() throws Exception { // Generates about 7k in bytecodes for generated e_ rule; // Well within the 64k method limit. e_primary compiles @@ -255,34 +152,47 @@ public class TestLeftRecursion extends BaseTest { "INT : '0'..'9'+ ;\n" + "WS : (' '|'\\n') {skip();} ;\n"; String[] tests = { - "a", "a", - "1", "1", - "a+1", "(+ a 1)", - "a*1", "(* a 1)", - "a.b", "(. a b)", - "a-b+c", "(+ (- a b) c)", + "a|b&c", "(s (e (e a) | (e (e b) & (e c))) )", + "(a|b)&c", "(s (e (e ( (e (e a) | (e b)) )) & (e c)) )", + "a > b", "(s (e (e a) > (e b)) )", + "a >> b", "(s (e (e a) >> (e b)) )", + "(T)x", "(s (e ( (type T) ) (e x)) )", + "new A().b", "(s (e (e new (type A) ( )) . b) )", + "(T)t.f()", "(s (e (e ( (type T) ) (e (e t) . f)) ( )) )", + "a.f(x)==T.c", "(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) )", + "a.f().g(x,1)", "(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) )", + "new T[((n-1) * x) + 1]", "(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) )", + }; + runTests(grammar, tests, "s"); + } - "a+b*c", "(+ a (* b c))", - "a.b+1", "(+ (. a b) 1)", - "-a", "(- a)", - "-a+b", "(+ (- a) b)", - "-a.b", "(- (. a b))", - "a^b^c", "(^ a (^ b c))", - "a=b=c", "(= a (= b c))", - "a=b=c+d.e","(= a (= b (+ c (. d e))))", - "a|b&c", "(| a (& b c))", - "(a|b)&c", "(& (| a b) c)", - "a > b", "(> a b)", - "a > 0", "(> a 0)", - "a >> b", "(>> a b)", // text is from one token - "a < b", "(< a b)", - - "(T)x", "(( T x)", - "new A().b", "(. (new A () b)", - "(T)t.f()", "(( (( T (. t f)))", - "a.f(x)==T.c", "(== (( (. a f) x) (. T c))", - "a.f().g(x,1)", "(( (. (( (. a f)) g) x 1)", - "new T[((n-1) * x) + 1]", "(new T [ (+ (* (- n 1) x) 1))", + @Test public void testDeclarations() throws Exception { + String grammar = + "grammar T;\n" + + "s @after {System.out.println($ctx.toStringTree(this));} : declarator EOF ;\n" + // must indicate EOF can follow + "declarator\n" + + " : declarator '[' e ']'\n" + + " | declarator '[' ']'\n" + + " | declarator '(' ')'\n" + + " | '*' declarator\n" + // binds less tight than suffixes + " | '(' declarator ')'\n" + + " | ID\n" + + " ;\n" + + "e : INT ;\n" + + "ID : 'a'..'z'+ ;\n" + + "INT : '0'..'9'+ ;\n" + + "WS : (' '|'\\n') {skip();} ;\n"; + String[] tests = { + "a", "(s (declarator a) )", + "*a", "(s (declarator * (declarator a)) )", + "**a", "(s (declarator * (declarator * (declarator a))) )", + "a[3]", "(s (declarator (declarator a) [ (e 3) ]) )", + "b[]", "(s (declarator (declarator b) [ ]) )", + "(a)", "(s (declarator ( (declarator a) )) )", + "a[]()", "(s (declarator (declarator (declarator a) [ ]) ( )) )", + "a[][]", "(s (declarator (declarator (declarator a) [ ]) [ ]) )", + "*a[]", "(s (declarator * (declarator (declarator a) [ ])) )", + "(*a)[]", "(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) )", }; runTests(grammar, tests, "s"); } @@ -290,7 +200,7 @@ public class TestLeftRecursion extends BaseTest { @Test public void testReturnValueAndActions() throws Exception { String grammar = "grammar T;\n" + - "s @after {System.out.println($ctx.toStringTree(this));} : e {System.out.println($e.v);} ;\n" + + "s : e {System.out.println($e.v);} ;\n" + "e returns [int v, List ignored]\n" + " : e '*' b=e {$v *= $b.v;}\n" + " | e '+' b=e {$v += $b.v;}\n" +