forked from jasder/antlr
* 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]
This commit is contained in:
parent
2e8a5f391a
commit
4ae23f4a64
|
@ -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 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)))
|
||||
|
|
|
@ -173,6 +173,22 @@ public abstract class Parser extends Recognizer<Token, v2ParserATNSimulator<Toke
|
|||
|
||||
public void removeParseListeners() { if ( _parseListeners!=null ) _parseListeners.clear(); }
|
||||
|
||||
public void triggerEnterRuleEvent() {
|
||||
for (ParseTreeListener<Token> 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<Token> 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<Token, v2ParserATNSimulator<Toke
|
|||
_ctx.start = _input.LT(1);
|
||||
_ctx.ruleIndex = ruleIndex;
|
||||
if (_buildParseTrees) addContextToParseTree();
|
||||
if ( _parseListeners != null) {
|
||||
for (ParseTreeListener<Token> 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<Token> l : _parseListeners) {
|
||||
_ctx.exitRule(l);
|
||||
l.exitEveryRule(_ctx);
|
||||
}
|
||||
}
|
||||
if ( _parseListeners != null) triggerExitRuleEvent();
|
||||
_ctx = (ParserRuleContext<Token>)_ctx.parent;
|
||||
}
|
||||
|
||||
|
@ -333,6 +339,31 @@ public abstract class Parser extends Recognizer<Token, v2ParserATNSimulator<Toke
|
|||
_ctx.altNum = altNum;
|
||||
}
|
||||
|
||||
/* like enterRule but for recursive rules; no enter events for recursive rules. */
|
||||
public void pushNewRecursionContext(ParserRuleContext<Token> localctx, int ruleIndex) {
|
||||
_ctx = localctx;
|
||||
_ctx.start = _input.LT(1);
|
||||
_ctx.ruleIndex = ruleIndex;
|
||||
}
|
||||
|
||||
public void unrollRecursionContexts(ParserRuleContext<Token> _parentctx) {
|
||||
ParserRuleContext<Token> 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<Token>)_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<Token> getInvokingContext(int ruleIndex) {
|
||||
ParserRuleContext<Token> p = _ctx;
|
||||
while ( p!=null ) {
|
||||
|
|
|
@ -37,6 +37,7 @@ recRule(ruleName, precArgDef, argName, primaryAlts, opAlts, setResultAction,
|
|||
userRetvals, userRetvalAssignments) ::=
|
||||
<<
|
||||
<ruleName>[<precArgDef>]<if(userRetvals)> returns [<userRetvals>]<endif>
|
||||
options {simrecursion_=true;}
|
||||
: ( <primaryAlts; separator="\n | ">
|
||||
)
|
||||
<if(userRetvals)>
|
||||
|
@ -44,7 +45,8 @@ recRule(ruleName, precArgDef, argName, primaryAlts, opAlts, setResultAction,
|
|||
<userRetvalAssignments; separator="\n">
|
||||
}
|
||||
<endif>
|
||||
( <opAlts; separator="\n | ">
|
||||
( options {simrecursion_=true;}
|
||||
: <opAlts; separator="\n | ">
|
||||
)*
|
||||
;
|
||||
>>
|
||||
|
|
|
@ -175,7 +175,36 @@ RuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAc
|
|||
}
|
||||
finally {
|
||||
<finallyAction>
|
||||
exitRule(RULE_<currentRule.name>);
|
||||
exitRule();
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
>>
|
||||
|
||||
LRecursiveRuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble) ::= <<
|
||||
|
||||
<ruleCtx>
|
||||
<altLabelCtxs; separator="\n">
|
||||
|
||||
<if(currentRule.modifiers)><currentRule.modifiers:{f | <f> }><else>public final <endif><currentRule.ctxType> <currentRule.name>(<currentRule.args; separator=",">) throws RecognitionException {
|
||||
ParserRuleContext\<Token> _parentctx = _ctx;
|
||||
<currentRule.ctxType> _localctx = new <currentRule.ctxType>(_ctx, <currentRule.startState><currentRule.args:{a | , <a.name>}>);
|
||||
pushNewRecursionContext(_localctx, RULE_<currentRule.name>);
|
||||
<namedActions.init>
|
||||
<locals; separator="\n">
|
||||
try {
|
||||
<code>
|
||||
_localctx.stop = _input.LT(-1);
|
||||
<postamble; separator="\n">
|
||||
<namedActions.after>
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
_errHandler.reportError(this, re);
|
||||
_errHandler.recover(this, re);
|
||||
}
|
||||
finally {
|
||||
<finallyAction>
|
||||
unrollRecursionContexts(_parentctx);
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
|
@ -322,12 +351,15 @@ setState(<choice.stateNumber>);
|
|||
_errHandler.sync(this);
|
||||
int _alt<choice.uniqueID> = getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx);
|
||||
while ( _alt<choice.uniqueID>!=<choice.exitAlt> && _alt<choice.uniqueID>!=-1 ) {
|
||||
switch ( _alt<choice.uniqueID> ) {
|
||||
<alts:{alt|
|
||||
case <i>:
|
||||
<alt>
|
||||
break;}; separator="\n">
|
||||
}
|
||||
if ( _alt<choice.uniqueID>==1 ) {
|
||||
<if(choice.isForRecursiveRule)>
|
||||
if ( _parseListeners!=null ) triggerExitRuleEvent();
|
||||
_localctx = new <currentRule.name>Context(_parentctx, <currentRule.startState>, _p);
|
||||
_localctx.addChild(_ctx);
|
||||
pushNewRecursionContext(_localctx, RULE_<currentRule.name>);
|
||||
<endif>
|
||||
<alts> <! should only be one !>
|
||||
}
|
||||
setState(<choice.loopBackStateNumber>);
|
||||
_errHandler.sync(this);
|
||||
_alt<choice.uniqueID> = getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx);
|
||||
|
@ -512,7 +544,7 @@ labelref(x) ::= "<if(!x.isLocal)>_localctx.<endif><x.name>"
|
|||
recRuleDefArg() ::= "int _p"
|
||||
recRuleArg() ::= "$_p"
|
||||
recRuleAltPredicate(ruleName,opPrec) ::= "<opPrec> >= <recRuleArg()>"
|
||||
recRuleSetResultAction() ::= "$tree=$<ruleName>_primary.tree;"
|
||||
recRuleSetResultAction() ::= "$tree=$<ruleName>.tree;"
|
||||
recRuleSetReturnAction(src,name) ::= "$<name>=$<src>.<name>;"
|
||||
|
||||
LexerFile(lexerFile, lexer, namedActions) ::= <<
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<CodeBlockForAlt> 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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<Integer, String> opPrecRuleAlts = new LinkedHashMap<Integer, String>();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -95,12 +95,18 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
|
|||
public static final Set<String> legalRuleOptions =
|
||||
new HashSet<String>() {
|
||||
{
|
||||
|
||||
add("context");
|
||||
add("simrecursion_");
|
||||
}
|
||||
};
|
||||
|
||||
public static final Set<String> legalBlockOptions =
|
||||
new HashSet<String>() {{add("greedy");}};
|
||||
new HashSet<String>() {
|
||||
{
|
||||
add("greedy");
|
||||
add("simrecursion_");
|
||||
}
|
||||
};
|
||||
|
||||
/** Legal options for terminal refs like ID<node=MyVarNode> */
|
||||
public static final Set<String> legalTokenOptions =
|
||||
|
|
|
@ -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) <EOF>)",
|
||||
"a+b", "(s (e a + (e b)) <EOF>)",
|
||||
"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)) <EOF>)",
|
||||
"a*b", "(s (e (e a) * (e b)) <EOF>)",
|
||||
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)",
|
||||
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
|
||||
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)",
|
||||
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)",
|
||||
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)",
|
||||
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)",
|
||||
};
|
||||
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) <EOF>)",
|
||||
"1", "(s (e 1) <EOF>)",
|
||||
"a-1", "(s (e (e a) - (e 1)) <EOF>)",
|
||||
"a.b", "(s (e (e a) . b) <EOF>)",
|
||||
"a.this", "(s (e (e a) . this) <EOF>)",
|
||||
"-a", "(s (e - (e a)) <EOF>)",
|
||||
"-a+b", "(s (e (e - (e a)) + (e b)) <EOF>)",
|
||||
};
|
||||
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 ''<assoc=right> e\n" +
|
||||
" | e '*' e\n" +
|
||||
" | e ('+'|'-') e\n" +
|
||||
" | e ('='<assoc=right> |'+='<assoc=right>) 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))) <EOF>)",
|
||||
"(a|b)&c", "(s (e (e ( (e (e a) | (e b)) )) & (e c)) <EOF>)",
|
||||
"a > b", "(s (e (e a) > (e b)) <EOF>)",
|
||||
"a >> b", "(s (e (e a) >> (e b)) <EOF>)",
|
||||
"(T)x", "(s (e ( (type T) ) (e x)) <EOF>)",
|
||||
"new A().b", "(s (e (e new (type A) ( )) . b) <EOF>)",
|
||||
"(T)t.f()", "(s (e (e ( (type T) ) (e (e t) . f)) ( )) <EOF>)",
|
||||
"a.f(x)==T.c", "(s (e (e (e (e a) . f) ( (expressionList (e x)) )) == (e (e T) . c)) <EOF>)",
|
||||
"a.f().g(x,1)", "(s (e (e (e (e (e a) . f) ( )) . g) ( (expressionList (e x) , (e 1)) )) <EOF>)",
|
||||
"new T[((n-1) * x) + 1]", "(s (e new (type T) [ (e (e ( (e (e ( (e (e n) - (e 1)) )) * (e x)) )) + (e 1)) ]) <EOF>)",
|
||||
};
|
||||
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) <EOF>)",
|
||||
"*a", "(s (declarator * (declarator a)) <EOF>)",
|
||||
"**a", "(s (declarator * (declarator * (declarator a))) <EOF>)",
|
||||
"a[3]", "(s (declarator (declarator a) [ (e 3) ]) <EOF>)",
|
||||
"b[]", "(s (declarator (declarator b) [ ]) <EOF>)",
|
||||
"(a)", "(s (declarator ( (declarator a) )) <EOF>)",
|
||||
"a[]()", "(s (declarator (declarator (declarator a) [ ]) ( )) <EOF>)",
|
||||
"a[][]", "(s (declarator (declarator (declarator a) [ ]) [ ]) <EOF>)",
|
||||
"*a[]", "(s (declarator * (declarator (declarator a) [ ])) <EOF>)",
|
||||
"(*a)[]", "(s (declarator (declarator ( (declarator * (declarator a)) )) [ ]) <EOF>)",
|
||||
};
|
||||
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<String> ignored]\n" +
|
||||
" : e '*' b=e {$v *= $b.v;}\n" +
|
||||
" | e '+' b=e {$v += $b.v;}\n" +
|
||||
|
|
Loading…
Reference in New Issue