Merge remote-tracking branch 'parrt/master'

This commit is contained in:
Sam Harwell 2012-02-15 14:58:16 -06:00
commit 27806dc490
104 changed files with 1511 additions and 694 deletions

View File

@ -1,5 +1,9 @@
ANTLR v4 Honey Badger early access
Feb 14, 2012
* Fixed https://github.com/antlr/antlr4/issues/8 and lots of other little things.
Jan 30, 2012
* Moving to github.

View File

@ -64,8 +64,10 @@ public class CommonToken implements WritableToken, Serializable {
this.channel = channel;
this.start = start;
this.stop = stop;
this.line = source.getLine();
this.charPositionInLine = source.getCharPositionInLine();
if (source != null) {
this.line = source.getLine();
this.charPositionInLine = source.getCharPositionInLine();
}
}
public CommonToken(int type, String text) {
@ -190,7 +192,7 @@ public class CommonToken implements WritableToken, Serializable {
}
public CharStream getInputStream() {
return source.getInputStream();
return source != null ? source.getInputStream() : null;
}
public String toString() {

View File

@ -88,7 +88,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
/** The token type for the current token */
public int _type;
public ArrayDeque<Integer> _modeStack;
public ArrayDeque<Integer> _modeStack = new ArrayDeque<Integer>();
public int _mode = Lexer.DEFAULT_MODE;
/** You can set the text for the current token to override what is in
@ -115,9 +115,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
_hitEOF = false;
_mode = Lexer.DEFAULT_MODE;
if (_modeStack != null) {
_modeStack.clear();
}
_modeStack.clear();
getInterpreter().reset();
}
@ -184,14 +182,13 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
public void pushMode(int m) {
if ( LexerATNSimulator.debug ) System.out.println("pushMode "+m);
if ( _modeStack ==null ) _modeStack = new ArrayDeque<Integer>();
getInterpreter().tracePushMode(m);
_modeStack.push(_mode);
mode(m);
}
public int popMode() {
if ( _modeStack ==null ) throw new EmptyStackException();
if ( _modeStack.isEmpty() ) throw new EmptyStackException();
if ( LexerATNSimulator.debug ) System.out.println("popMode back to "+ _modeStack.peek());
getInterpreter().tracePopMode();
mode( _modeStack.pop() );

View File

@ -30,6 +30,7 @@
package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.misc.Utils;
public class LexerNoViableAltException extends RecognitionException {
/** Matching attempted at what input index? */
@ -47,7 +48,19 @@ public class LexerNoViableAltException extends RecognitionException {
this.deadEndConfigs = deadEndConfigs;
}
@Override
public CharStream getInputStream() {
return (CharStream)super.getInputStream();
}
@Override
public String toString() {
return "NoViableAltException('')";
String symbol = "";
if (startIndex >= 0 && startIndex < input.size()) {
symbol = getInputStream().substring(startIndex, startIndex);
symbol = Utils.escapeWhitespace(symbol, false);
}
return "NoViableAltException('" + symbol + "')";
}
}

View File

@ -1,65 +0,0 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.runtime;
// TODO: del or rename LexerNoViableAlt?
public class LexerRecognitionExeption extends RuntimeException {
/** Who threw the exception? */
public Lexer lexer;
/** What is index of token/char were we looking at when the error occurred? */
public int index;
/** The current char when an error occurred. For lexers. */
public int c;
/** Track the line at which the error occurred in case this is
* generated from a lexer. We need to track this since the
* unexpected char doesn't carry the line info.
*/
public int line;
public int charPositionInLine;
/** Used for remote debugger deserialization */
public LexerRecognitionExeption() {
}
public LexerRecognitionExeption(Lexer lexer, CharStream input) {
this.lexer = lexer;
this.index = input.index();
this.c = input.LA(1);
if ( lexer!=null ) {
this.line = lexer.getLine();
this.charPositionInLine = lexer.getCharPositionInLine();
}
}
}

View File

@ -63,7 +63,7 @@ import java.util.List;
* satisfy the superclass interface.
*/
public class ParserRuleContext<Symbol> extends RuleContext {
public static final ParserRuleContext EMPTY = new ParserRuleContext();
public static final ParserRuleContext<?> EMPTY = new ParserRuleContext<Object>();
/** If we are debugging or building a parse tree for a visitor,
* we need to track all of the tokens and rule invocations associated
@ -131,17 +131,6 @@ public class ParserRuleContext<Symbol> extends RuleContext {
this(parent, parent!=null ? parent.s : -1 /* invoking state */, stateNumber);
}
// @Override
// public int hashCode() {
// return super.hashCode() + s;
// }
//
// @Override
// public boolean equals(Object o) {
// if ( !super.equals(o) ) return false;
// return s != ((RuleContext)o).s; // must be parsing the same location in the ATN
// }
// Double dispatch methods
public void enterRule(ParseTreeListener<Symbol> listener) { }
@ -187,7 +176,101 @@ public class ParserRuleContext<Symbol> extends RuleContext {
@Override
public ParseTree getChild(int i) {
return children!=null ? children.get(i) : null;
return children!=null && i>=0 && i<children.size() ? children.get(i) : null;
}
public <T extends ParseTree> T getChild(Class<? extends T> ctxType, int i) {
if ( children==null || i < 0 || i >= children.size() ) {
return null;
}
int j = -1; // what element have we found with ctxType?
for (ParseTree o : children) {
if ( ctxType.isInstance(o) ) {
j++;
if ( j == i ) {
return ctxType.cast(o);
}
}
}
return null;
}
public Token getToken(int ttype, int i) {
if ( children==null || i < 0 || i >= children.size() ) {
return null;
}
int j = -1; // what token with ttype have we found?
for (ParseTree o : children) {
if ( o instanceof TerminalNode<?> ) {
TerminalNode<?> tnode = (TerminalNode<?>)o;
if ( tnode.getSymbol() instanceof Token ) {
Token symbol = (Token)tnode.getSymbol();
if ( symbol.getType()==ttype ) {
j++;
if ( j == i ) {
return symbol;
}
}
}
}
}
return null;
}
public List<? extends Token> getTokens(int ttype) {
if ( children==null ) {
return Collections.emptyList();
}
List<Token> tokens = null;
for (ParseTree o : children) {
if ( o instanceof TerminalNode<?> ) {
TerminalNode<?> tnode = (TerminalNode<?>)o;
if ( tnode.getSymbol() instanceof Token ) {
Token symbol = (Token)tnode.getSymbol();
if ( tokens==null ) {
tokens = new ArrayList<Token>();
}
tokens.add(symbol);
}
}
}
if ( tokens==null ) {
return Collections.emptyList();
}
return tokens;
}
public <T extends ParserRuleContext<?>> T getRuleContext(Class<? extends T> ctxType, int i) {
return getChild(ctxType, i);
}
public <T extends ParserRuleContext<?>> List<? extends T> getRuleContexts(Class<? extends T> ctxType) {
if ( children==null ) {
return Collections.emptyList();
}
List<T> contexts = null;
for (ParseTree o : children) {
if ( ctxType.isInstance(o) ) {
if ( contexts==null ) {
contexts = new ArrayList<T>();
}
contexts.add(ctxType.cast(o));
}
}
if ( contexts==null ) {
return Collections.emptyList();
}
return contexts;
}
@Override
@ -203,7 +286,7 @@ public class ParserRuleContext<Symbol> extends RuleContext {
public String toString(@NotNull Recognizer<?,?> recog, RuleContext stop) {
if ( recog==null ) return super.toString(recog, stop);
StringBuilder buf = new StringBuilder();
ParserRuleContext p = this;
ParserRuleContext<?> p = this;
buf.append("[");
while ( p != null && p != stop ) {
ATN atn = recog.getATN();
@ -214,7 +297,7 @@ public class ParserRuleContext<Symbol> extends RuleContext {
// ATNState invoker = atn.states.get(ctx.invokingState);
// RuleTransition rt = (RuleTransition)invoker.transition(0);
// buf.append(recog.getRuleNames()[rt.target.ruleIndex]);
p = (ParserRuleContext)p.parent;
p = (ParserRuleContext<?>)p.parent;
}
buf.append("]");
return buf.toString();

View File

@ -80,16 +80,6 @@ public class RuleContext implements ParseTree.RuleNode {
public RuleContext() {}
// public RuleContext(RuleContext parent) {
// this(parent, -1);
// }
//
// public RuleContext(RuleContext parent, int stateNumber) {
// // capture state that called us as we create this context; use later for
// // return state in closure
// this(parent, parent != null ? parent.s : -1, stateNumber);
// }
public RuleContext(RuleContext parent, int invokingState) {
this.parent = parent;
//if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent);
@ -103,13 +93,6 @@ public class RuleContext implements ParseTree.RuleNode {
@Override
public int hashCode() {
// int h = 0;
// RuleContext p = this;
// while ( p!=null ) {
// h += p.stateNumber;
// p = p.parent;
// }
// return h;
return cachedHashCode; // works with tests; don't recompute.
}

View File

@ -363,6 +363,10 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
// TODO: v3 dfa don't do this.
break;
}
// t is not updated if one of these states is reached
assert !s.isCtxSensitive && !s.isAcceptState;
// if no edge, pop over to ATN interpreter, update DFA and return
if ( s.edges == null || t >= s.edges.length || t < -1 || s.edges[t+1] == null ) {
if ( dfa_debug && t>=0 ) System.out.println("no edge for "+parser.getTokenNames()[t]);
@ -398,8 +402,10 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
throw noViableAlt(input, outerContext, s.configset, startIndex);
}
s = target;
input.consume();
t = input.LA(1);
if (!s.isCtxSensitive && !s.isAcceptState) {
input.consume();
t = input.LA(1);
}
}
// if ( acceptState==null ) {
// if ( debug ) System.out.println("!!! no viable alt in dfa");

View File

@ -28,8 +28,7 @@
*/
package org.antlr.v4.runtime.misc;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.*;
import java.util.*;
@ -56,11 +55,6 @@ public class IntervalSet implements IntSet {
protected boolean readonly;
/** Create a set with no elements */
public IntervalSet() {
intervals = new ArrayList<Interval>(2); // most sets are 1 or 2 elements
}
public IntervalSet(List<Interval> intervals) {
this.intervals = intervals;
}
@ -70,6 +64,16 @@ public class IntervalSet implements IntSet {
addAll(set);
}
public IntervalSet(int... els) {
if ( els==null ) {
intervals = new ArrayList<Interval>(2); // most sets are 1 or 2 elements
}
else {
intervals = new ArrayList<Interval>(els.length);
for (int e : els) add(e);
}
}
/** Create a set with a single element, el. */
@NotNull
public static IntervalSet of(int a) {

View File

@ -1,16 +1,12 @@
grammar A;
s : q=e {System.out.println("result = "+$e.v);} ;
s : e ;
e returns [int v]
: a=e op='*' b=e {$v = $a.v * $b.v;} -> mult
| a=e '+' b=e {$v = $a.v + $b.v;} -> add
| INT {$v = $INT.int;}
| '(' x=e ')' {$v = $x.v;}
| e '++' -> inc
| e '--'
| ID -> anID
e : e '*' e -> Mult
| e '+' e -> Add
| INT -> Int
| '(' e ')' -> Parens
;
INT : '0'..'9'+ ;
WS : (' '|'\n')+ {skip();} ;
INT : [0-9]+ ;
WS : [ \t\n]+ -> skip ;

13
tool/playground/A2.g4 Normal file
View File

@ -0,0 +1,13 @@
grammar A2;
s : e {System.out.println($e.v);} ;
e returns [int v]
: a=e '*' b=e {$v = $a.v * $b.v;} -> Mult
| a=e '+' b=e {$v = $a.v + $b.v;} -> Add
| INT {$v = $INT.int;} -> Int
| '(' x=e ')' {$v = $x.v;} -> Parens
;
INT : [0-9]+ ;
WS : [ \t\n]+ -> skip ;

View File

@ -77,6 +77,7 @@ prog : expr_or_assign* ;
//prog : expr_or_assign prog | ;
expr_or_assign
@after {System.out.println(getRuleInvocationStack());}
: expr '++'
| expr // match ID a, fall out, reenter, match "(i)<-x" via alt 1
// it thinks it's same context from prog, but it's not; it's

View File

@ -27,41 +27,70 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.Stack;
public class TestA {
public static class Do extends BlankAListener {
Parser p;
public Do(Parser p ) { this.p = p; }
/** An example listener that uses a stack to store return values
* so that exit methods executed on notes further up the parse tree
* can see the results of these computations.
*
* Because we are using only the exit routines, the same listener works
* as a parse listener and is a parse tree listener. It generates
* the following output from input 3+4*5:
Int: 3
Int: 4
Int: 5
Mult: 20
Add: 23
tree = (s (e (e 3) + (e (e 4) * (e 5))))
Int: 3
Int: 4
Int: 5
Mult: 20
Add: 23
result from tree walk = 23
* The key things to notice are that there are no actions
* and the labels in the grammar--it is completely language neutral.
* Also, I have labeled each alternative so that we get a different
* context object. That way we get a listener method for each
* alternative.
*
* Compare this to A2.g4, which adds a field to the context objects
* by using a "returns [int v]" on the expression rule.
*/
public static class Do extends ABaseListener {
Stack<Integer> results = new Stack<Integer>();
@Override
public void exitEveryRule(ParserRuleContext<Token> ctx) {
System.out.println("exit "+ctx.toStringTree(p));
public void exit(AParser.AddContext ctx) {
results.push( results.pop() + results.pop() );
System.out.println("Add: " + results.peek());
}
@Override
public void enterRule(AParser.eContext ctx) {
System.out.println("enter alt w/o -> label: "+ctx.toInfoString(p));
public void exit(AParser.IntContext ctx) {
results.push( Integer.valueOf(ctx.INT().getText()) );
System.out.println("Int: "+results.peek());
}
@Override
public void visitTerminal(ParserRuleContext<Token> ctx, Token symbol) {
if ( ctx instanceof AParser.eContext && symbol.getType()==AParser.INT ) {
AParser.eContext ectx = (AParser.eContext)ctx;
ectx.v = Integer.valueOf(symbol.getText());
}
public void exit(AParser.MultContext ctx) {
results.push( results.pop() * results.pop() );
System.out.println("Mult: " + results.peek());
}
@Override
public void exitRule(AParser.multContext ctx) {
System.out.println("mult "+ctx.a.v+" * "+ctx.b.v);
ctx.v = ctx.a.v * ctx.b.v; // repeat of what parser did--set return value
}
@Override
public void exitRule(AParser.addContext ctx) {
System.out.println("add "+ctx.a.v+" + "+ctx.b.v);
ctx.v = ctx.a.v + ctx.b.v;
public void exit(AParser.ParensContext ctx) {
// result already on stack
System.out.println("Parens: "+results.peek());
}
}
public static void main(String[] args) throws Exception {
@ -69,14 +98,13 @@ public class TestA {
CommonTokenStream tokens = new CommonTokenStream(lexer);
AParser p = new AParser(tokens);
p.setBuildParseTree(true);
// p.addParseListener(new Do(p));
p.addParseListener(new Do());
ParserRuleContext<Token> t = p.s();
System.out.println("tree = "+t.toStringTree(p));
ParseTreeWalker walker = new ParseTreeWalker();
Do doer = new Do(p);
Do doer = new Do();
walker.walk(doer, t);
AParser.eContext ectx = (AParser.eContext)t.getChild(0);
System.out.println("result from tree walk = "+ ectx.v);
System.out.println("result from tree walk = "+ doer.results.pop());
}
}

View File

@ -0,0 +1,84 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.
*/
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class TestA2 {
/** An example listener that squirrels away a return value in a field
* called v that we get added to the expression context objects
* by adding a return value to rule e. This is a version of A.g4
* that performs actions during the parse with user-defined actions.
* AND, we pass in a listener that gets executed during the parse
* and we use a listener on a tree walk that executes after the parse.
* So, it affect, we compute the result of the expression 3 times.
*/
public static class Do extends A2BaseListener {
A2Parser p;
public Do(A2Parser p) { this.p = p; }
@Override
public void exit(A2Parser.AddContext ctx) {
ctx.v = ctx.e(0).v + ctx.e(1).v;
System.out.println("Add: " + ctx.v);
}
@Override
public void exit(A2Parser.IntContext ctx) {
ctx.v = Integer.valueOf(ctx.INT().getText());
System.out.println("Int: "+ctx.v);
}
@Override
public void exit(A2Parser.MultContext ctx) {
ctx.v = ctx.e(0).v * ctx.e(1).v;
System.out.println("Mult: " + ctx.v);
}
@Override
public void exit(A2Parser.ParensContext ctx) {
ctx.v = ctx.e().v;
System.out.println("Parens: "+ctx.v);
}
}
public static void main(String[] args) throws Exception {
A2Lexer lexer = new A2Lexer(new ANTLRFileStream(args[0]));
CommonTokenStream tokens = new CommonTokenStream(lexer);
A2Parser p = new A2Parser(tokens);
p.setBuildParseTree(true);
p.addParseListener(new Do(p));
ParserRuleContext<Token> t = p.s();
System.out.println("tree = "+t.toStringTree(p));
ParseTreeWalker walker = new ParseTreeWalker();
Do doer = new Do(p);
walker.walk(doer, t);
A2Parser.eContext ectx = (A2Parser.eContext)t.getChild(0);
System.out.println("result from tree walk = "+ ectx.v);
}
}

View File

@ -81,6 +81,11 @@
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
</plugin>
</plugins>
</build>

View File

@ -34,21 +34,21 @@ import org.antlr.v4.runtime.Token;
public interface <file.grammarName>Listener extends ParseTreeListener\<<InputSymbolType()>\> {
<file.listenerNames:{lname |
void enterRule(<file.parserName>.<lname>Context ctx);
void exitRule(<file.parserName>.<lname>Context ctx);}; separator="\n">
void enter(<file.parserName>.<lname>Context ctx);
void exit(<file.parserName>.<lname>Context ctx);}; separator="\n">
}
>>
BlankListenerFile(file, header) ::= <<
BaseListenerFile(file, header) ::= <<
<header>
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
public class Blank<file.grammarName>Listener implements <file.grammarName>Listener {
public class <file.grammarName>BaseListener implements <file.grammarName>Listener {
<file.listenerNames:{lname |
@Override public void enterRule(<file.parserName>.<lname>Context ctx) { \}
@Override public void exitRule(<file.parserName>.<lname>Context ctx) { \}}; separator="\n">
@Override public void enter(<file.parserName>.<lname>Context ctx) { \}
@Override public void exit(<file.parserName>.<lname>Context ctx) { \}}; separator="\n">
@Override public void enterEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
@Override public void exitEveryRule(ParserRuleContext\<<InputSymbolType()>\> ctx) { }
@ -156,7 +156,7 @@ case <index> : return <actions.(index)>;}; separator="\n">
RuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble) ::= <<
<ruleCtx>
<altLabelCtxs; separator="\n">
<altLabelCtxs:{l | <altLabelCtxs.(l)>}; separator="\n">
<if(currentRule.modifiers)><currentRule.modifiers:{f | <f> }><else>public final <endif><currentRule.ctxType> <currentRule.name>(<currentRule.args; separator=",">) throws RecognitionException {
<currentRule.ctxType> _localctx = new <currentRule.ctxType>(_ctx, <currentRule.startState><currentRule.args:{a | , <a.name>}>);
@ -186,7 +186,7 @@ LeftRecursiveRuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,
<<
<ruleCtx>
<altLabelCtxs; separator="\n">
<altLabelCtxs:{l | <altLabelCtxs.(l)>}; 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;
@ -214,13 +214,13 @@ LeftRecursiveRuleFunction(currentRule,code,locals,ruleCtx,altLabelCtxs,
}
>>
CodeBlockForOuterMostAlt(c, locals, preamble, ops) ::= <<
<if(c.altLabel)>_localctx = new <c.altLabel>Context(_localctx);<endif>
enterOuterAlt(_localctx, <c.alt.altNum>);
<CodeBlockForAlt(...)>
CodeBlockForOuterMostAlt(currentOuterMostAltCodeBlock, locals, preamble, ops) ::= <<
<if(currentOuterMostAltCodeBlock.altLabel)>_localctx = new <currentOuterMostAltCodeBlock.altLabel>Context(_localctx);<endif>
enterOuterAlt(_localctx, <currentOuterMostAltCodeBlock.alt.altNum>);
<CodeBlockForAlt(currentAltCodeBlock=currentOuterMostAltCodeBlock, ...)>
>>
CodeBlockForAlt(c, locals, preamble, ops) ::= <<
CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= <<
{
<locals; separator="\n">
<preamble; separator="\n">
@ -425,7 +425,7 @@ setState(<w.stateNumber>);
// ACTION STUFF
Action(a, chunks) ::= "<chunks>"
Action(a, foo, chunks) ::= "<chunks>"
ArgAction(a, chunks) ::= "<chunks>"
@ -448,32 +448,33 @@ LexerPushModeCommand(arg) ::= "pushMode(<arg>);"
DefaultParserSuperClass(s) ::= "Parser"
ActionText(t) ::= "<t.text>"
ActionTemplate(t) ::= "<t.st>"
ArgRef(a) ::= "_localctx.<a.name>"
LocalRef(a) ::= "_localctx.<a.name>"
RetValueRef(a) ::= "_localctx.<a.name>"
QRetValueRef(a) ::= "_localctx.<a.dict>.<a.name>"
QRetValueRef(a) ::= "<ctx(a)>.<a.dict>.<a.name>"
/** How to translate $tokenLabel */
TokenRef(t) ::= "_localctx.<t.name>"
LabelRef(t) ::= "_localctx.<t.name>"
ListLabelRef(t) ::= "_localctx.<ListLabelName(t.name)>"
SetAttr(s,rhsChunks) ::= "_localctx.<s.name> = <rhsChunks>;"
TokenRef(t) ::= "<ctx(t)>.<t.name>"
LabelRef(t) ::= "<ctx(t)>.<t.name>"
ListLabelRef(t) ::= "<ctx(t)>.<ListLabelName(t.name)>"
SetAttr(s,rhsChunks) ::= "<ctx(s)>.<s.name> = <rhsChunks>;"
LexerSetAttr(s,rhsChunks) ::= "_<s.name> = <rhsChunks>;" // _type etc...
TokenLabelType() ::= "<file.TokenLabelType; null={Token}>"
InputSymbolType() ::= "<file.InputSymbolType; null={Token}>"
TokenPropertyRef_text(t) ::= "(_localctx.<t.label>!=null?_localctx.<t.label>.getText():null)"
TokenPropertyRef_type(t) ::= "(_localctx.<t.label>!=null?_localctx.<t.label>.getType():0)"
TokenPropertyRef_line(t) ::= "(_localctx.<t.label>!=null?_localctx.<t.label>.getLine():0)"
TokenPropertyRef_pos(t) ::= "(_localctx.<t.label>!=null?_localctx.<t.label>.getCharPositionInLine():0)"
TokenPropertyRef_channel(t) ::= "(_localctx.<t.label>!=null?_localctx.<t.label>.getChannel():0)"
TokenPropertyRef_index(t) ::= "(_localctx.<t.label>!=null?_localctx.<t.label>.getTokenIndex():0)"
TokenPropertyRef_int(t) ::= "(_localctx.<t.label>!=null?Integer.valueOf(_localctx.<t.label>.getText()):0)"
TokenPropertyRef_text(t) ::= "(<ctx(t)>.<t.label>!=null?<ctx(t)>.<t.label>.getText():null)"
TokenPropertyRef_type(t) ::= "(<ctx(t)>.<t.label>!=null?<ctx(t)>.<t.label>.getType():0)"
TokenPropertyRef_line(t) ::= "(<ctx(t)>.<t.label>!=null?<ctx(t)>.<t.label>.getLine():0)"
TokenPropertyRef_pos(t) ::= "(<ctx(t)>.<t.label>!=null?<ctx(t)>.<t.label>.getCharPositionInLine():0)"
TokenPropertyRef_channel(t) ::= "(<ctx(t)>.<t.label>!=null?<ctx(t)>.<t.label>.getChannel():0)"
TokenPropertyRef_index(t) ::= "(<ctx(t)>.<t.label>!=null?<ctx(t)>.<t.label>.getTokenIndex():0)"
TokenPropertyRef_int(t) ::= "(<ctx(t)>.<t.label>!=null?Integer.valueOf(<ctx(t)>.<t.label>.getText()):0)"
RulePropertyRef_start(r) ::= "(_localctx.<r.label>!=null?(_localctx.<r.label>.start):null)"
RulePropertyRef_stop(r) ::= "(_localctx.<r.label>!=null?(_localctx.<r.label>.stop):null)"
RulePropertyRef_text(r) ::= "(_localctx.<r.label>!=null?_input.toString(_localctx.<r.label>.start,_localctx.<r.label>.stop):null)"
RulePropertyRef_ctx(r) ::= "_localctx.<r.label>"
RulePropertyRef_start(r) ::= "(<ctx(r)>.<r.label>!=null?(<ctx(r)>.<r.label>.start):null)"
RulePropertyRef_stop(r) ::= "(<ctx(r)>.<r.label>!=null?(<ctx(r)>.<r.label>.stop):null)"
RulePropertyRef_text(r) ::= "(<ctx(r)>.<r.label>!=null?_input.toString(<ctx(r)>.<r.label>.start,<ctx(r)>.<r.label>.stop):null)"
RulePropertyRef_ctx(r) ::= "<ctx(r)>.<r.label>"
ThisRulePropertyRef_start(r) ::= "_localctx.start"
ThisRulePropertyRef_stop(r) ::= "_localctx.stop"
@ -484,13 +485,38 @@ NonLocalAttrRef(s) ::= "((<s.ruleName>Context)getInvokingContext(<s.ruleIndex>
SetNonLocalAttr(s, rhsChunks) ::=
"((<s.ruleName>Context)getInvokingContext(<s.ruleIndex>)).<s.name> = <rhsChunks>;"
AddToLabelList(a) ::= "_localctx.<a.listName>.add(<labelref(a.label)>);"
AddToLabelList(a) ::= "<ctx(a.label)>.<a.listName>.add(<labelref(a.label)>);"
TokenDecl(t) ::= "Token <t.name>;"
TokenDecl(t) ::= "public Token <t.name>;"
TokenTypeDecl(t) ::= "int <t.name>;"
TokenListDecl(t) ::= "List\<Token> <t.name> = new ArrayList\<Token>();"
RuleContextDecl(r) ::= "<r.ctxName> <r.name>;"
RuleContextListDecl(rdecl) ::= "List\<<rdecl.ctxName>> <rdecl.name> = new ArrayList\<<rdecl.ctxName>>();"
TokenListDecl(t) ::= "public List\<Token> <t.name> = new ArrayList\<Token>();"
RuleContextDecl(r) ::= "public <r.ctxName> <r.name>;"
RuleContextListDecl(rdecl) ::= "public List\<<rdecl.ctxName>> <rdecl.name> = new ArrayList\<<rdecl.ctxName>>();"
ContextTokenGetterDecl(t) ::=
"public Token <t.name>() { return getToken(<parser.name>.<t.name>, 0); }"
ContextTokenListGetterDecl(t) ::=
"public List\<? extends Token> <t.name>() { return getTokens(<parser.name>.<t.name>); }"
ContextTokenListIndexedGetterDecl(t) ::= <<
public Token <t.name>(int i) {
return getToken(<parser.name>.<t.name>, i);
}
>>
ContextRuleGetterDecl(r) ::= <<
public <r.ctxName> <r.name>() {
return (<r.ctxName>)getRuleContext(<r.ctxName>.class,0);
}
>>
ContextRuleListGetterDecl(r) ::= <<
public List\<? extends <r.ctxName>\> <r.name>() {
return (List\<<r.ctxName>\>)getRuleContexts(<r.ctxName>.class);
}
>>
ContextRuleListIndexedGetterDecl(r) ::= <<
public <r.ctxName> <r.name>(int i) {
return (<r.ctxName>)getRuleContext(<r.ctxName>.class,i);
}
>>
LexerRuleContext() ::= "RuleContext"
@ -499,18 +525,19 @@ LexerRuleContext() ::= "RuleContext"
*/
RuleContextNameSuffix() ::= "Context"
ImplicitTokenLabel(tokenName) ::= "_t<tokenName>"
ImplicitRuleLabel(ruleName) ::= "_r<ruleName>"
ImplicitTokenLabel(tokenName) ::= "<tokenName>"
ImplicitRuleLabel(ruleName) ::= "<ruleName>"
ImplicitSetLabel(id) ::= "_tset<id>"
ListLabelName(label) ::= "<label>_list"
ListLabelName(label) ::= "<label>"
CaptureNextToken(d) ::= "<d.varName> = _input.LT(1);"
CaptureNextTokenType(d) ::= "<d.varName> = _input.LA(1);"
StructDecl(s,attrs,visitorDispatchMethods,interfaces,extensionMembers,
StructDecl(s,attrs,getters,visitorDispatchMethods,interfaces,extensionMembers,
superClass={ParserRuleContext\<<InputSymbolType()>>}) ::= <<
public static class <s.name> extends <superClass><if(interfaces)> implements <interfaces; separator=", "><endif> {
<attrs:{a | public <a>;}; separator="\n">
<attrs:{a | <a>}; separator="\n">
<getters:{g | <g>}; separator="\n">
<if(s.ctorAttrs)>public <s.name>(ParserRuleContext\<<InputSymbolType()>\> parent, int state) { super(parent, state); }<endif>
public <s.name>(ParserRuleContext\<<InputSymbolType()>\> parent, int state<s.ctorAttrs:{a | , <a>}>) {
super(parent, state);
@ -528,9 +555,11 @@ public static class <s.name> extends <superClass><if(interfaces)> implements <in
}
>>
AltLabelStructDecl(s,attrs,visitorDispatchMethods) ::= <<
public static class <s.label>Context extends <currentRule.name>Context {
public <s.label>Context(<currentRule.name>Context ctx) { copyFrom(ctx); }
AltLabelStructDecl(s,attrs,getters,visitorDispatchMethods) ::= <<
public static class <s.name> extends <currentRule.name>Context {
<attrs:{a | <a>}; separator="\n">
<getters:{g | <g>}; separator="\n">
public <s.name>(<currentRule.name>Context ctx) { copyFrom(ctx); }
<visitorDispatchMethods; separator="\n">
}
>>
@ -538,14 +567,17 @@ public static class <s.label>Context extends <currentRule.name>Context {
VisitorDispatchMethod(method) ::= <<
@Override
public void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener\<<InputSymbolType()>\> listener) {
if ( listener!=null && listener instanceof <parser.grammarName>Listener ) ((<parser.grammarName>Listener)listener).<if(method.isEnter)>enter<else>exit<endif>Rule(this);
if ( listener instanceof <parser.grammarName>Listener ) ((<parser.grammarName>Listener)listener).<if(method.isEnter)>enter<else>exit<endif>(this);
}
>>
AttributeDecl(d) ::= "<d.decl>"
AttributeDecl(d) ::= "public <d.decl>;"
/** If we don't know location of label def x, use this template */
labelref(x) ::= "<if(!x.isLocal)>_localctx.<endif><x.name>"
labelref(x) ::= "<if(!x.isLocal)>((<x.ctx.name>)_localctx).<endif><x.name>"
/** For any action chunk, what is correctly-typed context struct ptr? */
ctx(actionChunk) ::= "((<actionChunk.ctx.name>)_localctx)"
// used for left-recursive rules
recRuleDefArg() ::= "int _p"
@ -563,10 +595,10 @@ pushNewRecursionContext(_localctx, RULE_<ruleName>);
_localctx.start = _prevctx.start;
>>
recRuleLabeledAltStartAction(ruleName, ctxName, label) ::= <<
_localctx = new <ctxName>Context(new <ruleName>Context(_parentctx, _startState, _p));
recRuleLabeledAltStartAction(ruleName, currentAltLabel, label) ::= <<
_localctx = new <currentAltLabel>Context(new <ruleName>Context(_parentctx, _startState, _p));
_localctx.addChild(_prevctx);
<if(label)>_localctx.<label> = _prevctx;<endif>
<if(label)>((<currentAltLabel>Context)_localctx).<label> = _prevctx;<endif>
pushNewRecursionContext(_localctx, RULE_<ruleName>);
_localctx.start = _prevctx.start;
>>

View File

@ -58,7 +58,7 @@ import java.util.List;
public class Tool {
public String VERSION = "4.0-"+new Date();
public static enum OptionArgType { NONE, STRING }
public static enum OptionArgType { NONE, STRING } // NONE implies boolean
public static class Option {
String fieldName;
String name;
@ -90,11 +90,13 @@ public class Tool {
public String grammarEncoding = null; // use default locale's encoding
public String msgFormat = "antlr";
public boolean saveLexer = false;
public boolean genListener = true;
public boolean launch_ST_inspector = false;
public boolean force_atn = false;
public boolean log = false;
public boolean verbose_dfa = false;
public boolean no_auto_element_labels = false;
public boolean gen_listener = true;
public boolean gen_visitor = false;
public static Option[] optionDefs = {
new Option("outputDirectory", "-o", OptionArgType.STRING, "specify output directory where all output is generated"),
@ -103,10 +105,14 @@ public class Tool {
new Option("printGrammar", "-print", "print out the grammar without actions"),
new Option("debug", "-debug", "generate a parser that emits debugging events"),
new Option("profile", "-profile", "generate a parser that computes profiling information"),
new Option("generate_ATN_dot", "-atn", "generate rule augmented transition networks"),
new Option("generate_ATN_dot", "-atn", "generate rule augmented transition network diagrams"),
new Option("grammarEncoding", "-encoding", OptionArgType.STRING, "specify grammar file encoding; e.g., euc-jp"),
new Option("msgFormat", "-message-format", OptionArgType.STRING, "specify output style for messages"),
new Option("genListener", "-walker", "generate parse tree walker and listener"),
new Option("gen_listener", "-listener", "generate parse tree listener (default)"),
new Option("gen_listener", "-no-listener", "don't generate parse tree listener"),
new Option("gen_visitor", "-visitor", "generate parse tree visitor"),
new Option("gen_visitor", "-no-visitor", "don't generate parse tree visitor (default)"),
new Option("saveLexer", "-Xsave-lexer", "save temp lexer file created for combined grammars"),
new Option("launch_ST_inspector", "-XdbgST", "launch StringTemplate visualizer on generated code"),
new Option("force_atn", "-Xforce-atn", "use the ATN simulator for all predictions"),
@ -182,17 +188,20 @@ public class Tool {
}
for (Option o : optionDefs) {
if ( arg.equals(o.name) ) {
String value = null;
String argValue = null;
if ( o.argType==OptionArgType.STRING ) {
value = args[i];
argValue = args[i];
i++;
}
// use reflection to set field
Class c = this.getClass();
try {
Field f = c.getField(o.fieldName);
if ( value==null ) f.setBoolean(this, true);
else f.set(this, value);
if ( argValue==null ) {
if ( o.fieldName.startsWith("-no-") ) f.setBoolean(this, false);
else f.setBoolean(this, true);
}
else f.set(this, argValue);
}
catch (Exception e) {
errMgr.toolError(ErrorType.INTERNAL_ERROR, "can't access field "+o.fieldName);

View File

@ -32,19 +32,19 @@ package org.antlr.v4.analysis;
import org.antlr.v4.tool.ast.AltAST;
public class LeftRecursiveRuleAltInfo {
public int alt;
public int altNum; // original alt index (from 1)
public String leftRecursiveRuleRefLabel;
public String altLabel;
public String altText;
public AltAST altAST;
public int nextPrec;
public LeftRecursiveRuleAltInfo(int alt, String altText) {
this(alt, altText, null, null);
public LeftRecursiveRuleAltInfo(int altNum, String altText) {
this(altNum, altText, null, null);
}
public LeftRecursiveRuleAltInfo(int alt, String altText, String leftRecursiveRuleRefLabel, String altLabel) {
this.alt = alt;
public LeftRecursiveRuleAltInfo(int altNum, String altText, String leftRecursiveRuleRefLabel, String altLabel) {
this.altNum = altNum;
this.altText = altText;
this.leftRecursiveRuleRefLabel = leftRecursiveRuleRefLabel;
this.altLabel = altLabel;

View File

@ -29,21 +29,15 @@
package org.antlr.v4.analysis;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.tree.Tree;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.v4.Tool;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.parse.LeftRecursiveRuleWalker;
import org.antlr.v4.misc.Pair;
import org.antlr.v4.parse.*;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.GrammarASTWithOptions;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;
import org.antlr.v4.tool.ast.*;
import org.stringtemplate.v4.*;
import java.util.*;
@ -62,7 +56,8 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
public List<LeftRecursiveRuleAltInfo> otherAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
/** Pointer to ID node of ^(= ID element) */
public List<GrammarAST> leftRecursiveRuleRefLabels = new ArrayList<GrammarAST>();
public List<Pair<GrammarAST,String>> leftRecursiveRuleRefLabels =
new ArrayList<Pair<GrammarAST,String>>();
public GrammarAST retvals;
@ -131,10 +126,13 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
@Override
public void binaryAlt(AltAST altTree, int alt) {
altTree = (AltAST)altTree.dupTree();
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
GrammarAST lrlabel = stripLeftRecursion(altTree);
String label = lrlabel != null ? lrlabel.getText() : null;
if ( lrlabel!=null ) leftRecursiveRuleRefLabels.add(lrlabel);
if ( lrlabel!=null ) {
leftRecursiveRuleRefLabels.add(new Pair<GrammarAST,String>(lrlabel,altLabel));
}
stripAssocOptions(altTree);
stripAltLabel(altTree);
@ -145,7 +143,6 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
stripAltLabel(altTree);
String altText = text(altTree);
altText = altText.trim();
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
LeftRecursiveRuleAltInfo a = new LeftRecursiveRuleAltInfo(alt, altText, label, altLabel);
a.nextPrec = nextPrec;
binaryAlts.put(alt, a);
@ -156,10 +153,13 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
@Override
public void ternaryAlt(AltAST altTree, int alt) {
altTree = (AltAST)altTree.dupTree();
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
GrammarAST lrlabel = stripLeftRecursion(altTree);
String label = lrlabel != null ? lrlabel.getText() : null;
if ( lrlabel!=null ) leftRecursiveRuleRefLabels.add(lrlabel);
if ( lrlabel!=null ) {
leftRecursiveRuleRefLabels.add(new Pair<GrammarAST,String>(lrlabel,altLabel));
}
stripAssocOptions(altTree);
stripAltLabel(altTree);
@ -168,7 +168,6 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
String altText = text(altTree);
altText = altText.trim();
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
LeftRecursiveRuleAltInfo a = new LeftRecursiveRuleAltInfo(alt, altText, label, altLabel);
a.nextPrec = nextPrec;
ternaryAlts.put(alt, a);
@ -195,13 +194,16 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
@Override
public void suffixAlt(AltAST altTree, int alt) {
altTree = (AltAST)altTree.dupTree();
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
GrammarAST lrlabel = stripLeftRecursion(altTree);
String label = lrlabel != null ? lrlabel.getText() : null;
if ( lrlabel!=null ) {
leftRecursiveRuleRefLabels.add(new Pair<GrammarAST,String>(lrlabel,altLabel));
}
stripAltLabel(altTree);
if ( lrlabel!=null ) leftRecursiveRuleRefLabels.add(lrlabel);
String altText = text(altTree);
altText = altText.trim();
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
LeftRecursiveRuleAltInfo a = new LeftRecursiveRuleAltInfo(alt, altText, label, altLabel);
suffixAlts.put(alt, a);
// System.out.println("suffixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
@ -210,17 +212,10 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
@Override
public void otherAlt(AltAST altTree, int alt) {
altTree = (AltAST)altTree.dupTree();
GrammarAST lrlabel = stripLeftRecursion(altTree);
String label = lrlabel != null ? lrlabel.getText() : null;
stripAltLabel(altTree);
if ( lrlabel!=null ) leftRecursiveRuleRefLabels.add(lrlabel);
String altText = text(altTree);
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
LeftRecursiveRuleAltInfo a = new LeftRecursiveRuleAltInfo(alt, altText, label, altLabel);
// if ( altLabel!=null ) {
// a.startAction = codegenTemplates.getInstanceOf("recRuleReplaceContext");
// a.startAction.add("ctxName", altLabel);
// }
LeftRecursiveRuleAltInfo a = new LeftRecursiveRuleAltInfo(alt, altText, null, altLabel);
otherAlts.add(a);
// System.out.println("otherAlt " + alt + ": " + altText);
}
@ -256,8 +251,6 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
ruleST.add("primaryAlts", prefixAlts);
ruleST.add("primaryAlts", otherAlts);
ruleST.add("leftRecursiveRuleRefLabels", leftRecursiveRuleRefLabels);
tool.log("left-recursion", ruleST.render());
return ruleST.render();

View File

@ -32,6 +32,7 @@ package org.antlr.v4.analysis;
import org.antlr.runtime.*;
import org.antlr.v4.Tool;
import org.antlr.v4.misc.OrderedHashMap;
import org.antlr.v4.misc.Pair;
import org.antlr.v4.parse.*;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
@ -142,12 +143,16 @@ public class LeftRecursiveRuleTransformer {
}
// define labels on recursive rule refs we delete; they don't point to nodes of course
for (GrammarAST labelNode : leftRecursiveRuleWalker.leftRecursiveRuleRefLabels) {
// these are so $label in action translation works
for (Pair<GrammarAST,String> pair : leftRecursiveRuleWalker.leftRecursiveRuleRefLabels) {
GrammarAST labelNode = pair.a;
GrammarAST labelOpNode = (GrammarAST)labelNode.getParent();
GrammarAST elementNode = (GrammarAST)labelOpNode.getChild(1);
LabelElementPair lp = new LabelElementPair(g, labelNode, elementNode, labelOpNode.getType());
r.alt[1].labelDefs.map(labelNode.getText(), lp);
}
// copy to rule from walker
r.leftRecursiveRuleRefLabels = leftRecursiveRuleWalker.leftRecursiveRuleRefLabels;
tool.log("grammar", "added: "+t.toStringTree());
return true;
@ -189,6 +194,7 @@ public class LeftRecursiveRuleTransformer {
*/
public void setAltASTPointers(LeftRecursiveRule r, RuleAST t) {
// System.out.println("RULE: "+t.toStringTree());
BlockAST ruleBlk = (BlockAST)t.getFirstChildWithType(ANTLRParser.BLOCK);
AltAST mainAlt = (AltAST)ruleBlk.getChild(0);
BlockAST primaryBlk = (BlockAST)mainAlt.getChild(0);
@ -196,11 +202,13 @@ public class LeftRecursiveRuleTransformer {
for (int i = 0; i < r.recPrimaryAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i);
altInfo.altAST = (AltAST)primaryBlk.getChild(i);
altInfo.altAST.leftRecursiveAltInfo = altInfo;
// System.out.println(altInfo.altAST.toStringTree());
}
for (int i = 0; i < r.recOpAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
altInfo.altAST = (AltAST)opsBlk.getChild(i);
altInfo.altAST.leftRecursiveAltInfo = altInfo;
// System.out.println(altInfo.altAST.toStringTree());
}
}

View File

@ -33,6 +33,7 @@ import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.Token;
import org.antlr.v4.codegen.model.RuleFunction;
import org.antlr.v4.codegen.model.chunk.*;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.parse.ActionSplitter;
import org.antlr.v4.parse.ActionSplitterListener;
import org.antlr.v4.tool.Attribute;
@ -78,6 +79,7 @@ public class ActionTranslator implements ActionSplitterListener {
RuleFunction rf;
List<ActionChunk> chunks = new ArrayList<ActionChunk>();
OutputModelFactory factory;
StructDecl nodeContext;
public ActionTranslator(OutputModelFactory factory, ActionAST node) {
this.factory = factory;
@ -116,6 +118,9 @@ public class ActionTranslator implements ActionSplitterListener {
ActionTranslator translator = new ActionTranslator(factory, node);
translator.rf = rf;
factory.getGrammar().tool.log("action-translator", "translate " + action);
String altLabel = node.getAltLabel();
if ( rf!=null ) translator.nodeContext = rf.ruleCtx;
if ( altLabel!=null ) translator.nodeContext = rf.altLabelCtxs.get(altLabel);
ANTLRStringStream in = new ANTLRStringStream(action);
in.setLine(tokenWithinAction.getLine());
in.setCharPositionInLine(tokenWithinAction.getCharPositionInLine());
@ -130,27 +135,27 @@ public class ActionTranslator implements ActionSplitterListener {
Attribute a = node.resolver.resolveToAttribute(x.getText(), node);
if ( a!=null ) {
switch ( a.dict.type ) {
case ARG: chunks.add(new ArgRef(x.getText())); break;
case RET: chunks.add(new RetValueRef(x.getText())); break;
case LOCAL: chunks.add(new LocalRef(x.getText())); break;
case ARG: chunks.add(new ArgRef(nodeContext,x.getText())); break;
case RET: chunks.add(new RetValueRef(rf.ruleCtx, x.getText())); break;
case LOCAL: chunks.add(new LocalRef(nodeContext,x.getText())); break;
case PREDEFINED_RULE: chunks.add(getRulePropertyRef(x)); break;
}
}
if ( node.resolver.resolvesToToken(x.getText(), node) ) {
chunks.add(new TokenRef(getTokenLabel(x.getText()))); // $label
chunks.add(new TokenRef(nodeContext,getTokenLabel(x.getText()))); // $label
return;
}
if ( node.resolver.resolvesToLabel(x.getText(), node) ) {
chunks.add(new LabelRef(getTokenLabel(x.getText()))); // $x for x=ID etc...
chunks.add(new LabelRef(nodeContext,getTokenLabel(x.getText()))); // $x for x=ID etc...
return;
}
if ( node.resolver.resolvesToListLabel(x.getText(), node) ) {
chunks.add(new ListLabelRef(x.getText())); // $ids for ids+=ID etc...
chunks.add(new ListLabelRef(nodeContext,x.getText())); // $ids for ids+=ID etc...
return;
}
Rule r = factory.getGrammar().getRule(x.getText());
if ( r!=null ) {
chunks.add(new LabelRef(getRuleLabel(x.getText()))); // $r for r rule ref
chunks.add(new LabelRef(nodeContext,getRuleLabel(x.getText()))); // $r for r rule ref
}
}
@ -159,22 +164,22 @@ public class ActionTranslator implements ActionSplitterListener {
gen.g.tool.log("action-translator", "setQAttr "+x+"."+y+"="+rhs);
// x has to be current rule; just set y attr
List<ActionChunk> rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
chunks.add(new SetAttr(y.getText(), rhsChunks));
chunks.add(new SetAttr(nodeContext,y.getText(), rhsChunks));
}
public void qualifiedAttr(String expr, Token x, Token y) {
gen.g.tool.log("action-translator", "qattr "+x+"."+y);
Attribute a = node.resolver.resolveToAttribute(x.getText(), y.getText(), node);
switch ( a.dict.type ) {
case ARG: chunks.add(new ArgRef(y.getText())); break; // has to be current rule
case ARG: chunks.add(new ArgRef(nodeContext,y.getText())); break; // has to be current rule
case RET:
if ( factory.getCurrentRuleFunction()!=null &&
factory.getCurrentRuleFunction().name.equals(x.getText()) )
{
chunks.add(new RetValueRef(y.getText())); break;
chunks.add(new RetValueRef(rf.ruleCtx, y.getText())); break;
}
else {
chunks.add(new QRetValueRef(getRuleLabel(x.getText()), y.getText())); break;
chunks.add(new QRetValueRef(nodeContext, getRuleLabel(x.getText()), y.getText())); break;
}
case PREDEFINED_RULE:
if ( factory.getCurrentRuleFunction()!=null &&
@ -195,22 +200,22 @@ public class ActionTranslator implements ActionSplitterListener {
public void setAttr(String expr, Token x, Token rhs) {
gen.g.tool.log("action-translator", "setAttr "+x+" "+rhs);
List<ActionChunk> rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
SetAttr s = new SetAttr(x.getText(), rhsChunks);
if ( factory.getGrammar().isLexer() ) s = new LexerSetAttr(x.getText(), rhsChunks);
SetAttr s = new SetAttr(nodeContext, x.getText(), rhsChunks);
if ( factory.getGrammar().isLexer() ) s = new LexerSetAttr(nodeContext, x.getText(), rhsChunks);
chunks.add(s);
}
public void nonLocalAttr(String expr, Token x, Token y) {
gen.g.tool.log("action-translator", "nonLocalAttr "+x+"::"+y);
Rule r = factory.getGrammar().getRule(x.getText());
chunks.add(new NonLocalAttrRef(x.getText(), y.getText(), r.index));
chunks.add(new NonLocalAttrRef(nodeContext, x.getText(), y.getText(), r.index));
}
public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) {
gen.g.tool.log("action-translator", "setNonLocalAttr "+x+"::"+y+"="+rhs);
Rule r = factory.getGrammar().getRule(x.getText());
List<ActionChunk> rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
SetNonLocalAttr s = new SetNonLocalAttr(x.getText(), y.getText(), r.index, rhsChunks);
SetNonLocalAttr s = new SetNonLocalAttr(nodeContext, x.getText(), y.getText(), r.index, rhsChunks);
chunks.add(s);
}
@ -218,15 +223,15 @@ public class ActionTranslator implements ActionSplitterListener {
}
public void text(String text) {
chunks.add(new ActionText(text));
chunks.add(new ActionText(nodeContext,text));
}
TokenPropertyRef getTokenPropertyRef(Token x, Token y) {
try {
Class c = tokenPropToModelMap.get(y.getText());
Constructor ctor = c.getConstructor(new Class[] {String.class});
Constructor ctor = c.getConstructor(new Class[] {StructDecl.class, String.class});
TokenPropertyRef ref =
(TokenPropertyRef)ctor.newInstance(getTokenLabel(x.getText()));
(TokenPropertyRef)ctor.newInstance(nodeContext, getTokenLabel(x.getText()));
return ref;
}
catch (Exception e) {
@ -239,9 +244,9 @@ public class ActionTranslator implements ActionSplitterListener {
RulePropertyRef getRulePropertyRef(Token prop) {
try {
Class c = thisRulePropToModelMap.get(prop.getText());
Constructor ctor = c.getConstructor(new Class[] {String.class});
Constructor ctor = c.getConstructor(new Class[] {StructDecl.class, String.class});
RulePropertyRef ref =
(RulePropertyRef)ctor.newInstance(getRuleLabel(prop.getText()));
(RulePropertyRef)ctor.newInstance(nodeContext, getRuleLabel(prop.getText()));
return ref;
}
catch (Exception e) {
@ -254,9 +259,9 @@ public class ActionTranslator implements ActionSplitterListener {
Grammar g = factory.getGrammar();
try {
Class c = rulePropToModelMap.get(prop.getText());
Constructor ctor = c.getConstructor(new Class[] {String.class});
Constructor ctor = c.getConstructor(new Class[] {StructDecl.class, String.class});
RulePropertyRef ref =
(RulePropertyRef)ctor.newInstance(getRuleLabel(x.getText()));
(RulePropertyRef)ctor.newInstance(nodeContext, getRuleLabel(x.getText()));
return ref;
}
catch (Exception e) {

View File

@ -46,7 +46,7 @@ public class CodeGenPipeline {
}
else {
gen.writeRecognizer(gen.generateParser());
if ( g.tool.genListener) {
if ( g.tool.gen_listener) {
gen.writeListener(gen.generateListener());
gen.writeBlankListener(gen.generateBlankListener());
}

View File

@ -303,6 +303,7 @@ public class CodeGenerator {
* TListener.java, if we're using the Java target.
*/
public String getListenerFileName() {
assert g.name != null;
ST extST = templates.getInstanceOf("codeFileExtension");
String listenerName = g.name + "Listener";
return listenerName+extST.render();
@ -312,8 +313,9 @@ public class CodeGenerator {
* such as BlankTListener.java, if we're using the Java target.
*/
public String getBlankListenerFileName() {
assert g.name != null;
ST extST = templates.getInstanceOf("codeFileExtension");
String listenerName = "Blank" + g.name + "Listener";
String listenerName = g.name + "BaseListener";
return listenerName+extST.render();
}

View File

@ -29,18 +29,12 @@
package org.antlr.v4.codegen;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.codegen.model.RuleFunction;
import org.antlr.v4.codegen.model.SrcOp;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.tool.Alternative;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.tool.*;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
/** Create output objects for elements *within* rule functions except
* buildOutputModel() which builds outer/root model object and any
@ -66,6 +60,11 @@ public abstract class DefaultOutputModelFactory extends BlankOutputModelFactory
this.controller = controller;
}
@Override
public OutputModelController getController() {
return controller;
}
// Convenience methods
@NotNull
@ -87,7 +86,7 @@ public abstract class DefaultOutputModelFactory extends BlankOutputModelFactory
public CodeBlock getCurrentBlock() { return controller.getCurrentBlock(); }
@Override
public CodeBlock getCurrentOuterMostAlternativeBlock() { return controller.getCurrentOuterMostAlternativeBlock(); }
public CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock() { return controller.getCurrentOuterMostAlternativeBlock(); }
@Override
public int getCodeBlockLevel() { return controller.codeBlockLevel; }

View File

@ -72,8 +72,7 @@ public class OutputModelController {
public Stack<RuleFunction> currentRule = new Stack<RuleFunction>();
public Alternative currentOuterMostAlt;
public CodeBlock currentBlock;
public CodeBlock currentOuterMostAlternativeBlock;
public CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock;
public OutputModelController(OutputModelFactory factory) {
this.delegate = factory;
@ -121,7 +120,7 @@ public class OutputModelController {
public OutputModelObject buildBlankListenerOutputModel() {
CodeGenerator gen = delegate.getGenerator();
return new BlankListenerFile(delegate, gen.getBlankListenerFileName());
return new BaseListenerFile(delegate, gen.getBlankListenerFileName());
}
public ParserFile parserFile(String fileName) {
@ -151,6 +150,7 @@ public class OutputModelController {
RuleFunction function = rule(r);
parser.funcs.add(function);
pushCurrentRule(function);
function.fillNamedActions(delegate, r);
if ( r instanceof LeftRecursiveRule ) {
buildLeftRecursiveRuleFunction((LeftRecursiveRule)r,
@ -214,36 +214,39 @@ public class OutputModelController {
if ( altInfo.altLabel==null ) continue;
ST altActionST = codegenTemplates.getInstanceOf("recRuleReplaceContext");
altActionST.add("ctxName", altInfo.altLabel);
Action altAction = new Action(delegate, altActionST.render());
Action altAction =
new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
CodeBlockForAlt alt = primaryAltsCode.get(i);
alt.insertOp(0, altAction);
}
// Insert code to set ctx.stop after primary block and before op * loop
ST setStopTokenAST = codegenTemplates.getInstanceOf("recRuleSetStopToken");
Action setStopTokenAction = new Action(delegate, setStopTokenAST.render());
Action setStopTokenAction = new Action(delegate, function.ruleCtx, setStopTokenAST);
outerAlt.insertOp(1, setStopTokenAction);
// Insert code to set _prevctx at start of * loop
ST setPrevCtx = codegenTemplates.getInstanceOf("recRuleSetPrevCtx");
Action setPrevCtxAction = new Action(delegate, setPrevCtx.render());
Action setPrevCtxAction = new Action(delegate, function.ruleCtx, setPrevCtx);
opAltStarBlock.addIterationOp(setPrevCtxAction);
// Insert code in front of each op alt to create specialized ctx if there was a label
// Insert code in front of each op alt to create specialized ctx if there was an alt label
for (int i = 0; i < opAltsCode.size(); i++) {
ST altActionST;
LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
if ( altInfo.altLabel!=null ) {
altActionST = codegenTemplates.getInstanceOf("recRuleLabeledAltStartAction");
altActionST.add("ctxName", altInfo.altLabel);
altActionST.add("currentAltLabel", altInfo.altLabel);
}
else {
altActionST = codegenTemplates.getInstanceOf("recRuleAltStartAction");
altActionST.add("ctxName", r.name);
}
altActionST.add("ruleName", r.name);
// add label of any lr ref we deleted
altActionST.add("label", altInfo.leftRecursiveRuleRefLabel);
Action altAction = new Action(delegate, altActionST.render());
Action altAction =
new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
CodeBlockForAlt alt = opAltsCode.get(i);
alt.insertOp(0, altAction);
}
@ -312,7 +315,9 @@ public class OutputModelController {
public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) {
CodeBlockForAlt blk = delegate.alternative(alt, outerMost);
if ( outerMost ) currentOuterMostAlternativeBlock = blk;
if ( outerMost ) {
currentOuterMostAlternativeBlock = (CodeBlockForOuterMostAlt)blk;
}
for (CodeGeneratorExtension ext : extensions) blk = ext.alternative(blk, outerMost);
return blk;
}
@ -431,15 +436,13 @@ public class OutputModelController {
return currentBlock;
}
public void setCurrentOuterMostAlternativeBlock(CodeBlock currentOuterMostAlternativeBlock) {
public void setCurrentOuterMostAlternativeBlock(CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock) {
this.currentOuterMostAlternativeBlock = currentOuterMostAlternativeBlock;
}
public CodeBlock getCurrentOuterMostAlternativeBlock() {
public CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock() {
return currentOuterMostAlternativeBlock;
}
public int getCodeBlockLevel() { return codeBlockLevel; }
public int getTreeLevel() { return treeLevel; }
}

View File

@ -32,11 +32,8 @@ package org.antlr.v4.codegen;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.Alternative;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.BlockAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import java.util.List;
@ -47,6 +44,8 @@ public interface OutputModelFactory {
void setController(OutputModelController controller);
OutputModelController getController();
ParserFile parserFile(String fileName);
Parser parser(ParserFile file);
@ -109,7 +108,7 @@ public interface OutputModelFactory {
CodeBlock getCurrentBlock();
CodeBlock getCurrentOuterMostAlternativeBlock();
CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock();
int getCodeBlockLevel();

View File

@ -66,7 +66,8 @@ public class ParserFactory extends DefaultOutputModelFactory {
return new LeftRecursiveRuleFunction(this, (LeftRecursiveRule)r);
}
else {
return new RuleFunction(this, r);
RuleFunction rf = new RuleFunction(this, r);
return rf;
}
}
@ -91,7 +92,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
InvokeRule invokeOp = new InvokeRule(this, ID, label);
// If no manual label and action refs as token/rule not label, we need to define implicit label
if ( controller.needsImplicitLabel(ID, invokeOp) ) defineImplicitLabel(ID, invokeOp);
AddToLabelList listLabelOp = getListLabelIfPresent(invokeOp, label);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(invokeOp, label);
return list(invokeOp, listLabelOp);
}
@ -99,16 +100,29 @@ public class ParserFactory extends DefaultOutputModelFactory {
LabeledOp matchOp = new MatchToken(this, (TerminalAST) ID);
if ( labelAST!=null ) {
String label = labelAST.getText();
Decl d = getTokenLabelDecl(label);
((MatchToken)matchOp).labels.add(d);
getCurrentRuleFunction().addContextDecl(d);
RuleFunction rf = getCurrentRuleFunction();
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
// add Token _X and List<Token> X decls
defineImplicitLabel(ID, matchOp); // adds _X
TokenListDecl l = getTokenListLabelDecl(label);
getCurrentRuleFunction().addContextDecl(l);
rf.addContextDecl(ID.getAltLabel(), l);
}
else {
Decl d = getTokenLabelDecl(label);
((MatchToken) matchOp).labels.add(d);
rf.addContextDecl(ID.getAltLabel(), d);
}
// Decl d = getTokenLabelDecl(label);
// ((MatchToken)matchOp).labels.add(d);
// getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), d);
// if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
// TokenListDecl l = getTokenListLabelDecl(label);
// getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), l);
// }
}
if ( controller.needsImplicitLabel(ID, matchOp) ) defineImplicitLabel(ID, matchOp);
AddToLabelList listLabelOp = getListLabelIfPresent(matchOp, labelAST);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(matchOp, labelAST);
return list(matchOp, listLabelOp);
}
@ -129,14 +143,14 @@ public class ParserFactory extends DefaultOutputModelFactory {
String label = labelAST.getText();
Decl d = getTokenLabelDecl(label);
((MatchSet)matchOp).labels.add(d);
getCurrentRuleFunction().addContextDecl(d);
getCurrentRuleFunction().addContextDecl(setAST.getAltLabel(), d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
TokenListDecl l = getTokenListLabelDecl(label);
getCurrentRuleFunction().addContextDecl(l);
getCurrentRuleFunction().addContextDecl(setAST.getAltLabel(), l);
}
}
if ( controller.needsImplicitLabel(setAST, matchOp) ) defineImplicitLabel(setAST, matchOp);
AddToLabelList listLabelOp = getListLabelIfPresent(matchOp, labelAST);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(matchOp, labelAST);
return list(matchOp, listLabelOp);
}
@ -148,14 +162,14 @@ public class ParserFactory extends DefaultOutputModelFactory {
String label = labelAST.getText();
Decl d = getTokenLabelDecl(label);
wild.labels.add(d);
getCurrentRuleFunction().addContextDecl(d);
getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
TokenListDecl l = getTokenListLabelDecl(label);
getCurrentRuleFunction().addContextDecl(l);
getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), l);
}
}
if ( controller.needsImplicitLabel(ast, wild) ) defineImplicitLabel(ast, wild);
AddToLabelList listLabelOp = getListLabelIfPresent(wild, labelAST);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(wild, labelAST);
return list(wild, listLabelOp);
}
@ -173,11 +187,11 @@ public class ParserFactory extends DefaultOutputModelFactory {
String label = labelAST.getText();
Decl d = getTokenLabelDecl(label);
c.label = d;
getCurrentRuleFunction().addContextDecl(d);
getCurrentRuleFunction().addContextDecl(labelAST.getAltLabel(), d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
String listLabel = gen.target.getListLabel(label);
TokenListDecl l = new TokenListDecl(this, listLabel);
getCurrentRuleFunction().addContextDecl(l);
getCurrentRuleFunction().addContextDecl(labelAST.getAltLabel(), l);
}
}
@ -288,10 +302,10 @@ public class ParserFactory extends DefaultOutputModelFactory {
}
op.getLabels().add(d);
// all labels must be in scope struct in case we exec action out of context
getCurrentRuleFunction().addContextDecl(d);
getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), d);
}
public AddToLabelList getListLabelIfPresent(LabeledOp op, GrammarAST label) {
public AddToLabelList getAddToListOpIfListLabelPresent(LabeledOp op, GrammarAST label) {
AddToLabelList labelOp = null;
if ( label!=null && label.parent.getType()==ANTLRParser.PLUS_ASSIGN ) {
String listLabel = gen.target.getListLabel(label.getText());

View File

@ -84,8 +84,10 @@ alternative returns [CodeBlockForAlt altCodeBlock, List<SrcOp> ops]
alt[boolean outerMost] returns [CodeBlockForAlt altCodeBlock, List<SrcOp> ops]
: {
// set alt if outer ALT only (the only ones with alt field set to Alternative object)
if ( outerMost ) controller.setCurrentOuterMostAlt(((AltAST)$start).alt);
List<SrcOp> elems = new ArrayList<SrcOp>();
AltAST altAST = (AltAST)retval.start;
if ( outerMost ) controller.setCurrentOuterMostAlt(altAST.alt);
List<SrcOp> elems = new ArrayList<SrcOp>();
// TODO: shouldn't we pass $start to controller.alternative()?
$altCodeBlock = controller.alternative(controller.getCurrentOuterMostAlt(), outerMost);
$altCodeBlock.ops = $ops = elems;
controller.setCurrentBlock($altCodeBlock);

View File

@ -30,16 +30,14 @@
package org.antlr.v4.codegen.model;
import org.antlr.runtime.CommonToken;
import org.antlr.v4.codegen.ActionTranslator;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.chunk.ActionChunk;
import org.antlr.v4.codegen.model.chunk.ActionText;
import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.model.chunk.*;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.*;
import org.stringtemplate.v4.ST;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
/** */
public class Action extends RuleElement {
@ -57,7 +55,7 @@ public class Action extends RuleElement {
//System.out.println("actions="+chunks);
}
public Action(OutputModelFactory factory, String action) {
public Action(OutputModelFactory factory, StructDecl ctx, String action) {
super(factory,null);
ActionAST ast = new ActionAST(new CommonToken(ANTLRParser.ACTION, action));
RuleFunction rf = factory.getCurrentRuleFunction();
@ -67,7 +65,14 @@ public class Action extends RuleElement {
}
else {
chunks = new ArrayList<ActionChunk>();
chunks.add(new ActionText(action));
chunks.add(new ActionText(ctx, action));
}
}
public Action(OutputModelFactory factory, StructDecl ctx, ST actionST) {
super(factory, null);
chunks = new ArrayList<ActionChunk>();
chunks.add(new ActionTemplate(ctx, actionST));
}
}

View File

@ -0,0 +1,9 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
public class BaseListenerFile extends ListenerFile {
public BaseListenerFile(OutputModelFactory factory, String fileName) {
super(factory, fileName);
}
}

View File

@ -1,9 +0,0 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
public class BlankListenerFile extends ListenerFile {
public BlankListenerFile(OutputModelFactory factory, String fileName) {
super(factory, fileName);
}
}

View File

@ -34,5 +34,8 @@ import org.antlr.v4.codegen.model.decl.CodeBlock;
/** Contains Rewrite block (usually as last op) */
public class CodeBlockForAlt extends CodeBlock {
public CodeBlockForAlt(OutputModelFactory factory) { super(factory); }
public CodeBlockForAlt(OutputModelFactory factory) {
super(factory);
}
}

View File

@ -29,19 +29,14 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.ActionTranslator;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.model.chunk.ActionChunk;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.RuleContextDecl;
import org.antlr.v4.codegen.model.decl.RuleContextListDecl;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.*;
import java.util.List;
@ -72,11 +67,11 @@ public class InvokeRule extends RuleElement implements LabeledOp {
String label = labelAST.getText();
RuleContextDecl d = new RuleContextDecl(factory,label,ctxName);
labels.add(d);
rf.addContextDecl(d);
rf.addContextDecl(ast.getAltLabel(), d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
String listLabel = gen.target.getListLabel(label);
RuleContextListDecl l = new RuleContextListDecl(factory, listLabel, ctxName);
rf.addContextDecl(l);
rf.addContextDecl(ast.getAltLabel(), l);
}
}
if ( ast.getChildCount()>0 ) {
@ -89,15 +84,8 @@ public class InvokeRule extends RuleElement implements LabeledOp {
String label = gen.target.getImplicitRuleLabel(ast.getText());
RuleContextDecl d = new RuleContextDecl(factory,label,ctxName);
labels.add(d);
rf.addContextDecl(d);
rf.addContextDecl(ast.getAltLabel(), d);
}
// LinearApproximator approx = new LinearApproximator(factory.g, ATN.INVALID_DECISION_NUMBER);
// RuleTransition call = (RuleTransition)ast.atnState.transition(0);
// IntervalSet fset = approx.FIRST(call.followState);
// System.out.println("follow rule ref "+name+"="+fset);
// follow = factory.createFollowBitSet(ast, fset);
// factory.defineBitSet(follow);
}
public List<Decl> getLabels() {

View File

@ -33,7 +33,7 @@ import org.antlr.v4.codegen.model.decl.Decl;
import java.util.List;
/** */
/** All the rule elements we can label like tokens, rules, sets, wildcard. */
public interface LabeledOp {
public List<Decl> getLabels();
}

View File

@ -29,34 +29,35 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.RuleContextDecl;
import org.antlr.v4.tool.LabelElementPair;
import org.antlr.v4.tool.LabelType;
import org.antlr.v4.tool.LeftRecursiveRule;
import org.antlr.v4.tool.Rule;
import org.stringtemplate.v4.misc.MultiMap;
import java.util.Iterator;
import java.util.Set;
import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.misc.Pair;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.GrammarAST;
public class LeftRecursiveRuleFunction extends RuleFunction {
public LeftRecursiveRuleFunction(OutputModelFactory factory, LeftRecursiveRule r) {
super(factory, r);
// Since we delete x=lr, we have to manually add decls for all labels on left-recur refs
CodeGenerator gen = factory.getGenerator();
MultiMap<String,LabelElementPair> labelDefs = r.alt[1].labelDefs;
Set<String> labels = labelDefs.keySet();
for (Iterator<String> iterator = labels.iterator(); iterator.hasNext(); ) {
String label = iterator.next();
LabelElementPair l = r.getAnyLabelDef(label);
Rule targetRule = factory.getGrammar().getRule(l.element.getText());
if ( l.type == LabelType.RULE_LABEL ) {
// Since we delete x=lr, we have to manually add decls for all labels
// on left-recur refs to proper structs
for (Pair<GrammarAST,String> pair : r.leftRecursiveRuleRefLabels) {
GrammarAST idAST = pair.a;
String altLabel = pair.b;
String label = idAST.getText();
GrammarAST rrefAST = (GrammarAST)idAST.getParent().getChild(1);
if ( rrefAST.getType() == ANTLRParser.RULE_REF ) {
Rule targetRule = factory.getGrammar().getRule(rrefAST.getText());
String ctxName = gen.target.getRuleFunctionContextStructName(targetRule);
RuleContextDecl d = new RuleContextDecl(factory,label,ctxName);
addContextDecl(d);
StructDecl struct = ruleCtx;
if ( altLabelCtxs!=null ) {
StructDecl s = altLabelCtxs.get(altLabel);
if ( s!=null ) struct = s; // if alt label, use subctx
}
struct.addDecl(d); // stick in overall rule's ctx
}
}
}

View File

@ -1,13 +1,11 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/** A model object representing a parse tree listener file.
* These are the rules specific events triggered by a parse tree visitor.
@ -26,11 +24,11 @@ public class ListenerFile extends OutputFile {
parserName = g.getRecognizerName();
grammarName = g.name;
for (Rule r : g.rules.values()) {
List<String> labels = r.getAltLabels();
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
listenerNames.add(r.name);
if ( labels!=null ) {
for (String label : labels) {
listenerNames.add(label);
for (Triple<Integer,AltAST,String> pair : labels) {
listenerNames.add(pair.c);
}
}
}

View File

@ -29,13 +29,9 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.chunk.ActionChunk;
import org.antlr.v4.codegen.model.chunk.ActionText;
import org.antlr.v4.codegen.model.chunk.DefaultParserSuperClass;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.model.chunk.*;
import org.antlr.v4.tool.*;
import java.util.*;
@ -86,7 +82,7 @@ public class Parser extends OutputModelObject {
rules = g.rules.values();
atn = new SerializedATN(factory, g.atn);
if (g.getOptionString("superClass") != null) {
superclass = new ActionText(g.getOptionString("superClass"));
superclass = new ActionText(null, g.getOptionString("superClass"));
} else {
superclass = new DefaultParserSuperClass();
}

View File

@ -30,18 +30,22 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.AltLabelStructDecl;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.misc.FrequencySet;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.misc.Utils;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import java.util.*;
import static org.antlr.v4.parse.ANTLRParser.*;
/** */
public class RuleFunction extends OutputModelObject {
public String name;
@ -54,12 +58,13 @@ public class RuleFunction extends OutputModelObject {
public int index;
public Collection<Attribute> args = null;
public Rule rule;
public AltLabelStructDecl[] altToContext;
@ModelElement public List<SrcOp> code;
@ModelElement public OrderedHashSet<Decl> locals; // TODO: move into ctx?
@ModelElement public StructDecl ruleCtx;
@ModelElement public Set<AltLabelStructDecl> altLabelCtxs;
@ModelElement public Map<String, Action> namedActions;
@ModelElement public Map<String,AltLabelStructDecl> altLabelCtxs;
@ModelElement public Map<String,Action> namedActions;
@ModelElement public Action finallyAction;
@ModelElement public List<SrcOp> postamble;
@ -76,12 +81,33 @@ public class RuleFunction extends OutputModelObject {
index = r.index;
ruleCtx = new StructDecl(factory, r);
altToContext = new AltLabelStructDecl[r.getOriginalNumberOfAlts()+1];
List<String> labels = r.getAltLabels();
// Add ctx labels for elements in alts with no -> label
if ( !factory.getGrammar().tool.no_auto_element_labels ) {
List<AltAST> altsNoLabels = r.getUnlabeledAltASTs();
if ( altsNoLabels!=null ) {
Set<Decl> decls = getDeclsForAllElements(altsNoLabels);
// we know to put in rule ctx, so do it directly
for (Decl d : decls) ruleCtx.addDecl(d);
}
}
// make structs for -> labeled alts, define ctx labels for elements
altLabelCtxs = new HashMap<String,AltLabelStructDecl>();
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
if ( labels!=null ) {
altLabelCtxs = new HashSet<AltLabelStructDecl>();
for (String label : labels) {
altLabelCtxs.add(new AltLabelStructDecl(factory, r, label));
for (Triple<Integer,AltAST,String> pair : labels) {
Integer altNum = pair.a;
AltAST altAST = pair.b;
String label = pair.c;
altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
altLabelCtxs.put(label, altToContext[altNum]);
if ( !factory.getGrammar().tool.no_auto_element_labels ) {
Set<Decl> decls = getDeclsForAltElements(altAST);
// we know which ctx to put in, so do it directly
for (Decl d : decls) altToContext[altNum].addDecl(d);
}
}
}
@ -102,13 +128,100 @@ public class RuleFunction extends OutputModelObject {
exceptions = Utils.nodesToStrings(r.exceptionActions);
if ( r.finallyAction!=null ) finallyAction = new Action(factory, r.finallyAction);
startState = factory.getGrammar().atn.ruleToStartState[r.index];
}
public void fillNamedActions(OutputModelFactory factory, Rule r) {
namedActions = new HashMap<String, Action>();
for (String name : r.namedActions.keySet()) {
GrammarAST ast = r.namedActions.get(name);
namedActions.put(name, new Action(factory, ast));
}
}
startState = factory.getGrammar().atn.ruleToStartState[r.index];
/** for all alts, find which ref X or r in way which needs List
Must see across alts. If any alt needs X or r as list, then
define as list.
*/
public Set<Decl> getDeclsForAllElements(List<AltAST> altASTs) {
Set<String> needsList = new HashSet<String>();
List<GrammarAST> allRefs = new ArrayList<GrammarAST>();
// for (Alternative a :alts) {
for (AltAST ast : altASTs) {
IntervalSet reftypes = new IntervalSet(RULE_REF, TOKEN_REF);
List<GrammarAST> refs = ast.getNodesWithType(reftypes);
FrequencySet<String> altFreq = new FrequencySet<String>();
for (GrammarAST t : refs) {
String refLabelName = t.getText();
altFreq.add(refLabelName);
allRefs.add(t);
}
for (GrammarAST t : refs) {
String refLabelName = t.getText();
if ( altFreq.count(t.getText())>1 ) needsList.add(refLabelName);
}
}
Set<Decl> decls = new HashSet<Decl>();
for (GrammarAST t : allRefs) {
String refLabelName = t.getText();
List<Decl> d = getDeclForAltElement(t,
refLabelName,
needsList.contains(refLabelName));
decls.addAll(d);
}
return decls;
}
/** Get list of decls for token/rule refs.
* Single ref X becomes X() getter
* Multiple refs to X becomes List X() method, X(int i) method.
* Ref X in a loop then we get List X(), X(int i)
*
* Does not gen labels for literals like '+', 'begin', ';', ...
*/
public Set<Decl> getDeclsForAltElements(AltAST altAST) {
IntervalSet reftypes = new IntervalSet(RULE_REF,
TOKEN_REF);
List<GrammarAST> refs = altAST.getNodesWithType(reftypes);
Set<Decl> decls = new HashSet<Decl>();
FrequencySet<String> freq = new FrequencySet<String>();
for (GrammarAST t : refs) freq.add(t.getText());
for (GrammarAST t : refs) {
String refLabelName = t.getText();
boolean inLoop = t.hasAncestor(CLOSURE) || t.hasAncestor(POSITIVE_CLOSURE);
boolean multipleRefs = freq.count(refLabelName)>1;
boolean needList = inLoop || multipleRefs;
// System.out.println(altAST.toStringTree()+" "+t+" inLoop? "+inLoop);
List<Decl> d = getDeclForAltElement(t, refLabelName, needList);
decls.addAll(d);
}
return decls;
}
public List<Decl> getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList) {
List<Decl> decls = new ArrayList<Decl>();
if ( t.getType()==RULE_REF ) {
Rule rref = factory.getGrammar().getRule(t.getText());
String ctxName = factory.getGenerator().target
.getRuleFunctionContextStructName(rref);
if ( needList ) {
decls.add( new ContextRuleListGetterDecl(factory, refLabelName, ctxName) );
decls.add( new ContextRuleListIndexedGetterDecl(factory, refLabelName, ctxName) );
}
else {
decls.add( new ContextRuleGetterDecl(factory, refLabelName, ctxName) );
}
}
else {
if ( needList ) {
decls.add( new ContextTokenListGetterDecl(factory, refLabelName) );
decls.add( new ContextTokenListIndexedGetterDecl(factory, refLabelName) );
}
else {
decls.add( new ContextTokenGetterDecl(factory, refLabelName) );
}
}
return decls;
}
/** Add local var decl */
@ -118,8 +231,19 @@ public class RuleFunction extends OutputModelObject {
d.isLocal = true;
}
/** Add decl to struct ctx */
public void addContextDecl(Decl d) {
ruleCtx.addDecl(d);
/** Add decl to struct ctx for rule or alt if labeled */
public void addContextDecl(String altLabel, Decl d) {
CodeBlockForOuterMostAlt alt = d.getOuterMostAltCodeBlock();
// if we found code blk and might be alt label, try to add to that label ctx
if ( alt!=null && altLabelCtxs!=null ) {
// System.out.println(d.name+" lives in alt "+alt.alt.altNum);
AltLabelStructDecl altCtx = altLabelCtxs.get(altLabel);
if ( altCtx!=null ) { // we have an alt ctx
// System.out.println("ctx is "+ altCtx.name);
altCtx.addDecl(d);
return;
}
}
ruleCtx.addDecl(d); // stick in overall rule's ctx
}
}

View File

@ -30,6 +30,7 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.tool.ast.GrammarAST;
/** */
@ -39,17 +40,42 @@ public abstract class SrcOp extends OutputModelObject {
/** All operations know in which block they live:
*
* CodeBlockForAlt, TreeRewrite, STRewrite
* CodeBlock, CodeBlockForAlt
*
* Templates might need to know block nesting level or find
* a specific declaration, etc...
*/
public SrcOp enclosingBlock;
public CodeBlock enclosingBlock;
public RuleFunction enclosingRuleRunction;
public SrcOp(OutputModelFactory factory) { this(factory,null); }
public SrcOp(OutputModelFactory factory, GrammarAST ast) {
super(factory,ast);
if ( ast!=null ) uniqueID = ast.token.getTokenIndex();
enclosingBlock = factory.getCurrentBlock();
enclosingRuleRunction = factory.getCurrentRuleFunction();
}
/** Walk upwards in model tree, looking for outer alt's code block */
public CodeBlockForOuterMostAlt getOuterMostAltCodeBlock() {
if ( this instanceof CodeBlockForOuterMostAlt ) {
return (CodeBlockForOuterMostAlt)this;
}
CodeBlock p = enclosingBlock;
while ( p!=null ) {
if ( p instanceof CodeBlockForOuterMostAlt ) {
return (CodeBlockForOuterMostAlt)p;
}
p = p.enclosingBlock;
}
return null;
}
/** Return label alt or return name of rule */
public String getContextName() {
CodeBlockForOuterMostAlt alt = getOuterMostAltCodeBlock();
if ( alt!=null && alt.altLabel!=null ) return alt.altLabel;
return enclosingRuleRunction.name;
}
}

View File

@ -1,7 +1,9 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.AltAST;
import java.util.List;
@ -12,7 +14,7 @@ public class VisitorDispatchMethod extends OutputModelObject {
public VisitorDispatchMethod(OutputModelFactory factory, Rule r, boolean isEnter) {
super(factory);
this.isEnter = isEnter;
List<String> label = r.getAltLabels();
if ( label!=null ) listenerName = label.get(0);
List<Triple<Integer,AltAST,String>> label = r.getAltLabels();
if ( label!=null ) listenerName = label.get(0).c;
}
}

View File

@ -30,7 +30,14 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class ActionChunk extends OutputModelObject {
/** Where is the ctx that defines attrs,labels etc... for this action? */
public StructDecl ctx;
public ActionChunk(StructDecl ctx) {
this.ctx = ctx;
}
}

View File

@ -0,0 +1,13 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.stringtemplate.v4.ST;
public class ActionTemplate extends ActionChunk {
public ST st;
public ActionTemplate(StructDecl ctx, ST st) {
super(ctx);
this.st = st;
}
}

View File

@ -29,11 +29,14 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class ActionText extends ActionChunk {
public String text;
public ActionText(String text) {
public ActionText(StructDecl ctx, String text) {
super(ctx);
this.text = text;
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class ArgRef extends LocalRef {
public ArgRef(String name) {
super(name);
public ArgRef(StructDecl ctx, String name) {
super(ctx, name);
}
}

View File

@ -30,4 +30,5 @@
package org.antlr.v4.codegen.model.chunk;
public class DefaultParserSuperClass extends ActionChunk {
public DefaultParserSuperClass() { super(null); }
}

View File

@ -29,10 +29,13 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
public class LabelRef extends ActionChunk {
public String name;
public LabelRef(String name) {
public LabelRef(StructDecl ctx, String name) {
super(ctx);
this.name = name;
}
}

View File

@ -29,10 +29,12 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
import java.util.List;
public class LexerSetAttr extends SetAttr {
public LexerSetAttr(String name, List<ActionChunk> rhsChunks) {
super(name, rhsChunks);
public LexerSetAttr(StructDecl ctx, String name, List<ActionChunk> rhsChunks) {
super(ctx, name, rhsChunks);
}
}

View File

@ -29,6 +29,8 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
public class ListLabelRef extends LabelRef {
public ListLabelRef(String name) { super(name); }
public ListLabelRef(StructDecl ctx, String name) { super(ctx, name); }
}

View File

@ -29,10 +29,13 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
public class LocalRef extends ActionChunk {
public String name;
public LocalRef(String name) {
public LocalRef(StructDecl ctx, String name) {
super(ctx);
this.name = name;
}
}

View File

@ -29,12 +29,15 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
public class NonLocalAttrRef extends ActionChunk {
public String ruleName;
public String name;
public int ruleIndex;
public NonLocalAttrRef(String ruleName, String name, int ruleIndex) {
public NonLocalAttrRef(StructDecl ctx, String ruleName, String name, int ruleIndex) {
super(ctx);
this.name = name;
this.ruleName = ruleName;
this.ruleIndex = ruleIndex;

View File

@ -29,11 +29,13 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class QRetValueRef extends RetValueRef {
public String dict;
public QRetValueRef(String dict, String name) {
super(name);
public QRetValueRef(StructDecl ctx, String dict, String name) {
super(ctx,name);
this.dict = dict;
}
}

View File

@ -29,11 +29,14 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class RetValueRef extends ActionChunk {
public String name;
public RetValueRef(String name) {
public RetValueRef(StructDecl ctx, String name) {
super(ctx);
this.name = name;
}

View File

@ -29,11 +29,14 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class RulePropertyRef extends ActionChunk {
public String label;
public RulePropertyRef(String label) {
public RulePropertyRef(StructDecl ctx, String label) {
super(ctx);
this.label = label;
}
}

View File

@ -29,8 +29,10 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
public class RulePropertyRef_ctx extends RulePropertyRef {
public RulePropertyRef_ctx(String label) {
super(label);
public RulePropertyRef_ctx(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class RulePropertyRef_start extends RulePropertyRef {
public RulePropertyRef_start(String label) {
super(label);
public RulePropertyRef_start(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class RulePropertyRef_stop extends RulePropertyRef {
public RulePropertyRef_stop(String label) {
super(label);
public RulePropertyRef_stop(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class RulePropertyRef_text extends RulePropertyRef {
public RulePropertyRef_text(String label) {
super(label);
public RulePropertyRef_text(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -30,6 +30,7 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.ModelElement;
import org.antlr.v4.codegen.model.decl.StructDecl;
import java.util.List;
@ -38,17 +39,9 @@ public class SetAttr extends ActionChunk {
public String name;
@ModelElement public List<ActionChunk> rhsChunks;
public SetAttr(String name, List<ActionChunk> rhsChunks) {
public SetAttr(StructDecl ctx, String name, List<ActionChunk> rhsChunks) {
super(ctx);
this.name = name;
this.rhsChunks = rhsChunks;
}
// @Override
// public List<String> getChildren() {
// final List<String> sup = super.getChildren();
// return new ArrayList<String>() {{
// if ( sup!=null ) addAll(sup);
// add("rhsChunks");
// }};
// }
}

View File

@ -29,16 +29,19 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
import java.util.List;
public class SetNonLocalAttr extends SetAttr {
public String ruleName;
public int ruleIndex;
public SetNonLocalAttr(String ruleName, String name, int ruleIndex,
public SetNonLocalAttr(StructDecl ctx,
String ruleName, String name, int ruleIndex,
List<ActionChunk> rhsChunks)
{
super(name, rhsChunks);
super(ctx, name, rhsChunks);
this.ruleName = ruleName;
this.ruleIndex = ruleIndex;
}

View File

@ -29,8 +29,10 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
public class ThisRulePropertyRef_ctx extends RulePropertyRef {
public ThisRulePropertyRef_ctx(String label) {
super(label);
public ThisRulePropertyRef_ctx(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class ThisRulePropertyRef_start extends RulePropertyRef {
public ThisRulePropertyRef_start(String label) {
super(label);
public ThisRulePropertyRef_start(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class ThisRulePropertyRef_stop extends RulePropertyRef {
public ThisRulePropertyRef_stop(String label) {
super(label);
public ThisRulePropertyRef_stop(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class ThisRulePropertyRef_text extends RulePropertyRef {
public ThisRulePropertyRef_text(String label) {
super(label);
public ThisRulePropertyRef_text(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,11 +29,14 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef extends ActionChunk {
public String label;
public TokenPropertyRef(String label) {
public TokenPropertyRef(StructDecl ctx, String label) {
super(ctx);
this.label = label;
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_channel extends TokenPropertyRef {
public TokenPropertyRef_channel(String label) {
super(label);
public TokenPropertyRef_channel(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_index extends TokenPropertyRef {
public TokenPropertyRef_index(String label) {
super(label);
public TokenPropertyRef_index(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_int extends TokenPropertyRef {
public TokenPropertyRef_int(String label) {
super(label);
public TokenPropertyRef_int(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_line extends TokenPropertyRef {
public TokenPropertyRef_line(String label) {
super(label);
public TokenPropertyRef_line(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_pos extends TokenPropertyRef {
public TokenPropertyRef_pos(String label) {
super(label);
public TokenPropertyRef_pos(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_text extends TokenPropertyRef {
public TokenPropertyRef_text(String label) {
super(label);
public TokenPropertyRef_text(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,9 +29,11 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenPropertyRef_type extends TokenPropertyRef {
public TokenPropertyRef_type(String label) {
super(label);
public TokenPropertyRef_type(StructDecl ctx, String label) {
super(ctx, label);
}
}

View File

@ -29,11 +29,14 @@
package org.antlr.v4.codegen.model.chunk;
import org.antlr.v4.codegen.model.decl.StructDecl;
/** */
public class TokenRef extends ActionChunk {
public String name;
public TokenRef(String name) {
public TokenRef(StructDecl ctx, String name) {
super(ctx);
this.name = name;
}
}

View File

@ -34,15 +34,21 @@ import org.antlr.v4.tool.Rule;
/** A StructDecl to handle a -> label on alt */
public class AltLabelStructDecl extends StructDecl {
public String label;
public AltLabelStructDecl(OutputModelFactory factory, Rule r, String label) {
public int altNum;
public AltLabelStructDecl(OutputModelFactory factory, Rule r,
int altNum, String label)
{
super(factory, r);
this.label = label;
this.altNum = altNum;
this.name = // override name set in super to the label ctx
label+
factory.getGenerator().templates
.getInstanceOf("RuleContextNameSuffix").render();
}
@Override
public int hashCode() {
return label.hashCode();
return name.hashCode();
}
@Override
@ -50,7 +56,7 @@ public class AltLabelStructDecl extends StructDecl {
if ( obj == this ) return true;
if ( obj.hashCode() != this.hashCode() ) return false;
if ( obj instanceof AltLabelStructDecl ) {
return label.equals(((AltLabelStructDecl)obj).label);
return name.equals(((AltLabelStructDecl)obj).name);
}
return false;
}

View File

@ -0,0 +1,35 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
public abstract class ContextGetterDecl extends Decl {
public ContextGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
/** Not used for output; just used to distinguish between decl types
* to avoid dups.
*/
public String getArgType() { return ""; }; // assume no args
@Override
public int hashCode() {
return name.hashCode() + getArgType().hashCode();
}
/** Make sure that a getter does not equal a label. X() and X are ok.
* OTOH, treat X() with two diff return values as the same. Treat
* two X() with diff args as different.
*/
@Override
public boolean equals(Object obj) {
if ( obj==null ) return false;
// A() and label A are different
if ( !(obj instanceof ContextGetterDecl) ) return false;
if ( this==obj ) return true;
if ( this.hashCode() != obj.hashCode() ) return false;
return
name.equals(((Decl) obj).name) &&
getArgType().equals(((ContextGetterDecl) obj).getArgType());
}
}

View File

@ -0,0 +1,12 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public XContext X() { } */
public class ContextRuleGetterDecl extends ContextGetterDecl {
public String ctxName;
public ContextRuleGetterDecl(OutputModelFactory factory, String name, String ctxName) {
super(factory, name);
this.ctxName = ctxName;
}
}

View File

@ -0,0 +1,14 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public List<XContext> X() { }
* public XContext X(int i) { }
*/
public class ContextRuleListGetterDecl extends ContextGetterDecl {
public String ctxName;
public ContextRuleListGetterDecl(OutputModelFactory factory, String name, String ctxName) {
super(factory, name);
this.ctxName = ctxName;
}
}

View File

@ -0,0 +1,14 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
public class ContextRuleListIndexedGetterDecl extends ContextRuleListGetterDecl {
public ContextRuleListIndexedGetterDecl(OutputModelFactory factory, String name, String ctxName) {
super(factory, name, ctxName);
}
@Override
public String getArgType() {
return "int";
}
}

View File

@ -0,0 +1,10 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public Token X() { } */
public class ContextTokenGetterDecl extends ContextGetterDecl {
public ContextTokenGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
}

View File

@ -0,0 +1,12 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public List<Token> X() { }
* public Token X(int i) { }
*/
public class ContextTokenListGetterDecl extends ContextGetterDecl {
public ContextTokenListGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
}

View File

@ -0,0 +1,14 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
public class ContextTokenListIndexedGetterDecl extends ContextTokenListGetterDecl {
public ContextTokenListIndexedGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
@Override
public String getArgType() {
return "int";
}
}

View File

@ -37,6 +37,7 @@ public class Decl extends SrcOp {
public String name;
public String decl; // whole thing if copied from action
public boolean isLocal; // if local var (not in RuleContext struct)
public StructDecl ctx; // which context contains us? set by addDecl
public Decl(OutputModelFactory factory, String name, String decl) {
this(factory, name);
@ -53,8 +54,14 @@ public class Decl extends SrcOp {
return name.hashCode();
}
/** If same name, can't redefine, unless it's a getter */
@Override
public boolean equals(Object obj) {
return name.equals(((Decl)obj).name);
if ( obj==null ) return false;
// A() and label A are different
if ( obj instanceof ContextGetterDecl ) return false;
if ( this==obj ) return true;
if ( this.hashCode() != obj.hashCode() ) return false;
return name.equals(((Decl) obj).name);
}
}

View File

@ -48,6 +48,7 @@ public class StructDecl extends Decl {
public String superClass;
public boolean provideCopyFrom;
@ModelElement public OrderedHashSet<Decl> attrs = new OrderedHashSet<Decl>();
@ModelElement public OrderedHashSet<Decl> getters = new OrderedHashSet<Decl>();
@ModelElement public Collection<Attribute> ctorAttrs;
@ModelElement public List<VisitorDispatchMethod> visitorDispatchMethods;
@ModelElement public List<OutputModelObject> interfaces;
@ -65,7 +66,11 @@ public class StructDecl extends Decl {
visitorDispatchMethods.add(new VisitorDispatchMethod(factory, r, false));
}
public void addDecl(Decl d) { attrs.add(d); }
public void addDecl(Decl d) {
d.ctx = this;
if ( d instanceof ContextGetterDecl ) getters.add(d);
else attrs.add(d);
}
public void addDecl(Attribute a) {
addDecl(new AttributeDecl(factory, a.name, a.decl));

View File

@ -0,0 +1,22 @@
package org.antlr.v4.misc;
import java.util.Hashtable;
/** Count how many of each key we have; not thread safe */
public class FrequencySet<T> extends Hashtable<T, MutableInt> {
public int count(T key) {
MutableInt value = get(key);
if (value == null) return 0;
return value.v;
}
public void add(T key) {
MutableInt value = get(key);
if (value == null) {
value = new MutableInt(1);
put(key, value);
}
else {
value.v++;
}
}
}

View File

@ -0,0 +1,17 @@
package org.antlr.v4.misc;
public class MutableInt extends Number implements Comparable<Number> {
public int v;
public MutableInt(int v) { this.v = v; }
@Override public int compareTo(Number o) { return v; }
@Override public int intValue() { return v; }
@Override public long longValue() { return v; }
@Override public float floatValue() { return v; }
@Override public double doubleValue() { return v; }
@Override
public String toString() {
return String.valueOf(v);
}
}

View File

@ -0,0 +1,11 @@
package org.antlr.v4.misc;
public class Pair<A,B> {
public A a;
public B b;
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
}

View File

@ -0,0 +1,10 @@
package org.antlr.v4.misc;
public class Triple<A,B,C> extends Pair<A,B> {
public C c;
public Triple(A a, B b, C c) {
super(a,b);
this.c = c;
}
}

View File

@ -642,8 +642,8 @@ lexerCommands
;
lexerCommand
: id LPAREN lexerCommandExpr RPAREN -> ^(LEXER_ACTION_CALL id lexerCommandExpr)
| id
: lexerCommandName LPAREN lexerCommandExpr RPAREN -> ^(LEXER_ACTION_CALL lexerCommandName lexerCommandExpr)
| lexerCommandName
;
lexerCommandExpr
@ -651,6 +651,11 @@ lexerCommandExpr
| INT
;
lexerCommandName
: id
| MODE ->ID[$MODE]
;
altList
: alternative (OR alternative)* -> alternative+
;

View File

@ -31,6 +31,10 @@ package org.antlr.v4.tool;
import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
import org.antlr.v4.misc.OrderedHashMap;
import org.antlr.v4.misc.Pair;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.RuleAST;
import java.util.ArrayList;
@ -40,6 +44,10 @@ public class LeftRecursiveRule extends Rule {
public List<LeftRecursiveRuleAltInfo> recPrimaryAlts;
public OrderedHashMap<Integer, LeftRecursiveRuleAltInfo> recOpAlts;
/** Did we delete any labels on direct left-recur refs? Points at ID of ^(= ID el) */
public List<Pair<GrammarAST,String>> leftRecursiveRuleRefLabels =
new ArrayList<Pair<GrammarAST,String>>();
public LeftRecursiveRule(Grammar g, String name, RuleAST ast) {
super(g, name, ast, 1);
alt = new Alternative[numberOfAlts+1]; // always just one
@ -51,19 +59,46 @@ public class LeftRecursiveRule extends Rule {
return super.hasAltSpecificContexts() || getAltLabels()!=null;
}
/** Get -> labels and also those we deleted for left-recursive rules. */
@Override
public List<String> getAltLabels() {
List<String> labels = new ArrayList<String>();
List<String> normalAltLabels = super.getAltLabels();
if ( normalAltLabels!=null ) labels.addAll(normalAltLabels);
public int getOriginalNumberOfAlts() {
int n = 0;
if ( recPrimaryAlts!=null ) n += recPrimaryAlts.size();
if ( recOpAlts!=null ) n += recOpAlts.size();
return n;
}
@Override
public List<AltAST> getUnlabeledAltASTs() {
List<AltAST> alts = new ArrayList<AltAST>();
for (int i = 0; i < recPrimaryAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = recPrimaryAlts.get(i);
if ( altInfo.altLabel!=null ) labels.add(altInfo.altLabel);
if ( altInfo.altLabel==null ) alts.add(altInfo.altAST);
}
for (int i = 0; i < recOpAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = recOpAlts.getElement(i);
if ( altInfo.altLabel!=null ) labels.add(altInfo.altLabel);
if ( altInfo.altLabel==null ) alts.add(altInfo.altAST);
}
if ( alts.size()==0 ) return null;
return alts;
}
/** Get -> labels from those alts we deleted for left-recursive rules. */
@Override
public List<Triple<Integer,AltAST,String>> getAltLabels() {
List<Triple<Integer,AltAST,String>> labels = new ArrayList<Triple<Integer,AltAST,String>>();
List<Triple<Integer,AltAST,String>> normalAltLabels = super.getAltLabels();
if ( normalAltLabels!=null ) labels.addAll(normalAltLabels);
for (int i = 0; i < recPrimaryAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = recPrimaryAlts.get(i);
if ( altInfo.altLabel!=null ) {
labels.add(new Triple<Integer,AltAST,String>(altInfo.altNum,altInfo.altAST,altInfo.altLabel));
}
}
for (int i = 0; i < recOpAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = recOpAlts.getElement(i);
if ( altInfo.altLabel!=null ) {
labels.add(new Triple<Integer,AltAST,String>(altInfo.altNum,altInfo.altAST,altInfo.altLabel));
}
}
if ( labels.size()==0 ) return null;
return labels;

View File

@ -29,10 +29,8 @@
package org.antlr.v4.tool;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.PredAST;
import org.antlr.v4.tool.ast.RuleAST;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.ast.*;
import org.stringtemplate.v4.misc.MultiMap;
import java.util.*;
@ -205,18 +203,34 @@ public class Rule implements AttributeResolver {
return getAltLabels()!=null;
}
/** Used for recursive rules (subclass), which have 1 alt, but many original alts */
public int getOriginalNumberOfAlts() {
return numberOfAlts;
}
/** Get -> labels. */
public List<String> getAltLabels() {
List<String> labels = new ArrayList<String>();
public List<Triple<Integer,AltAST,String>> getAltLabels() {
List<Triple<Integer,AltAST,String>> labels = new ArrayList<Triple<Integer,AltAST,String>>();
for (int i=1; i<=numberOfAlts; i++) {
GrammarAST altLabel = alt[i].ast.altLabel;
if ( altLabel==null ) break; // all or none
labels.add(altLabel.getText());
if ( altLabel!=null ) {
labels.add(new Triple<Integer,AltAST,String>(i,alt[i].ast,altLabel.getText()));
}
}
if ( labels.size()==0 ) return null;
return labels;
}
public List<AltAST> getUnlabeledAltASTs() {
List<AltAST> alts = new ArrayList<AltAST>();
for (int i=1; i<=numberOfAlts; i++) {
GrammarAST altLabel = alt[i].ast.altLabel;
if ( altLabel==null ) alts.add(alt[i].ast);
}
if ( alts.size()==0 ) return null;
return alts;
}
/** $x Attribute: rule arguments, return values, predefined rule prop.
*/
public Attribute resolveToAttribute(String x, ActionAST node) {

View File

@ -31,13 +31,17 @@ package org.antlr.v4.tool.ast;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.Tree;
import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
import org.antlr.v4.tool.Alternative;
/** Any ALT (which can be child of ALT_REWRITE node) */
public class AltAST extends GrammarAST {
public Alternative alt;
/** If someone specified an outermost alternative label with #foo.
/** If we transformed this alt from a left-recursive one, need info on it */
public LeftRecursiveRuleAltInfo leftRecursiveAltInfo;
/** If someone specified an outermost alternative label with -> foo.
* Token type will be ID.
*/
public GrammarAST altLabel;

View File

@ -1,52 +0,0 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.tool.ast;
import org.antlr.runtime.Token;
public class DownAST extends TerminalAST {
public DownAST(int type, Token t) {
super(type, t);
}
@Override
public String getText() {
return "DOWN";
}
@Override
public String toString() {
return getText();
}
@Override
public Object visit(GrammarASTVisitor v) { return v.visit(this); }
}

View File

@ -29,14 +29,22 @@
package org.antlr.v4.tool.ast;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.v4.parse.*;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.tree.Tree;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.Grammar;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public class GrammarAST extends CommonTree {
/** For error msgs, nice to know which grammar this AST lives in */
@ -108,6 +116,26 @@ public class GrammarAST extends CommonTree {
return null;
}
/** Walk ancestors of this node until we find ALT with
* alt!=null or leftRecursiveAltInfo!=null. Then grab label if any.
* If not a rule element, just returns null.
*/
public String getAltLabel() {
List ancestors = this.getAncestors();
if ( ancestors==null ) return null;
for (int i=ancestors.size()-1; i>=0; i--) {
GrammarAST p = (GrammarAST)ancestors.get(i);
if ( p.getType()== ANTLRParser.ALT ) {
AltAST a = (AltAST)p;
if ( a.altLabel!=null ) return a.altLabel.getText();
if ( a.leftRecursiveAltInfo!=null ) {
return a.leftRecursiveAltInfo.altLabel;
}
}
}
return null;
}
public boolean deleteChild(org.antlr.runtime.tree.Tree t) {
for (int i=0; i<children.size(); i++) {
Object c = children.get(i);

View File

@ -35,7 +35,4 @@ public interface GrammarASTVisitor {
Object visit(SetAST node);
Object visit(RuleRefAST node);
Object visit(TerminalAST node);
Object visit(TreePatternAST node);
Object visit(UpAST node);
Object visit(DownAST node);
}

View File

@ -1,46 +0,0 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.tool.ast;
import org.antlr.runtime.Token;
import org.antlr.v4.runtime.atn.ATNState;
public class TreePatternAST extends GrammarAST implements RuleElementAST {
/** Record ATN DN, UP nodes so we can find easily later */
public ATNState downState;
public ATNState upState;
public TreePatternAST(Token t) {
super(t);
}
@Override
public Object visit(GrammarASTVisitor v) { return v.visit(this); }
}

View File

@ -1,51 +0,0 @@
/*
[The "BSD license"]
Copyright (c) 2011 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.tool.ast;
import org.antlr.runtime.Token;
public class UpAST extends TerminalAST {
public UpAST(int type, Token t) {
super(type, t);
}
@Override
public String getText() {
return "UP";
}
@Override
public String toString() {
return getText();
}
@Override
public Object visit(GrammarASTVisitor v) { return v.visit(this); }
}

View File

@ -71,7 +71,7 @@ public abstract class BaseTest {
public static final String newline = System.getProperty("line.separator");
public static final String pathSep = System.getProperty("path.separator");
public static final boolean TEST_IN_SAME_PROCESS = false;
public static final boolean TEST_IN_SAME_PROCESS = Boolean.parseBoolean(System.getProperty("antlr.testinprocess"));
/**
* Build up the full classpath we need, including the surefire path (if present)
@ -510,7 +510,7 @@ public abstract class BaseTest {
}
if ( parserName!=null ) {
files.add(parserName+".java");
files.add("Blank"+grammarFileName.substring(0, grammarFileName.lastIndexOf('.'))+"Listener.java");
files.add(grammarFileName.substring(0, grammarFileName.lastIndexOf('.'))+"BaseListener.java");
}
ok = compile(files.toArray(new String[files.size()]));
if ( !ok ) { allIsWell = false; }

View File

@ -926,13 +926,13 @@ JavaIDDigit
'\u1040'..'\u1049'
;
WS : (' '|'\r'|'\t'|'\u000C'|'\n')+ {$channel=HIDDEN;}//-> channel(HIDDEN)
WS : (' '|'\r'|'\t'|'\u000C'|'\n')+ -> channel(HIDDEN)
;
COMMENT
: '/*' .* '*/' {$channel=HIDDEN;}//-> channel(HIDDEN)
: '/*' .* '*/' -> channel(HIDDEN)
;
LINE_COMMENT
: '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}//-> channel(HIDDEN)
: '//' ~('\n'|'\r')* '\r'? '\n' -> channel(HIDDEN)
;

View File

@ -68,8 +68,9 @@ public class TestActionTranslation extends BaseTest {
@Test public void testComplicatedArgParsingWithTranslation() throws Exception {
String action = "x, $ID.text+\"3242\", (*$ID).foo(21,33), 3.2+1, '\\n', "+
"\"a,oo\\nick\", {bl, \"fdkj\"eck}";
String expected = "x, (_localctx._tID!=null?_localctx._tID.getText():null)+\"3242\"," +
" (*_localctx._tID).foo(21,33), 3.2+1, '\\n', \"a,oo\\nick\", {bl, \"fdkj\"eck}";
String expected =
"x, (((aContext)_localctx).ID!=null?((aContext)_localctx).ID.getText():null)+\"3242\", " +
"(*((aContext)_localctx).ID).foo(21,33), 3.2+1, '\\n', \"a,oo\\nick\", {bl, \"fdkj\"eck}";
testActions(attributeTemplate, "inline", action, expected);
}
@ -99,39 +100,39 @@ public class TestActionTranslation extends BaseTest {
@Test public void testReturnValues() throws Exception {
String action = "$lab.e; $b.e;";
String expected = "_localctx.lab.e; _localctx._rb.e;";
String expected = "((aContext)_localctx).lab.e; ((aContext)_localctx).b.e;";
testActions(attributeTemplate, "inline", action, expected);
}
@Test public void testReturnWithMultipleRuleRefs() throws Exception {
String action = "$c.x; $c.y;";
String expected = "_localctx._rc.x; _localctx._rc.y;";
String expected = "((aContext)_localctx).c.x; ((aContext)_localctx).c.y;";
testActions(attributeTemplate, "inline", action, expected);
}
@Test public void testTokenRefs() throws Exception {
String action = "$id; $ID; $id.text; $id.getText(); $id.line;";
String expected = "_localctx.id; _localctx._tID; (_localctx.id!=null?_localctx.id.getText():null); _localctx.id.getText(); (_localctx.id!=null?_localctx.id.getLine():0);";
String expected = "((aContext)_localctx).id; ((aContext)_localctx).ID; (((aContext)_localctx).id!=null?((aContext)_localctx).id.getText():null); ((aContext)_localctx).id.getText(); (((aContext)_localctx).id!=null?((aContext)_localctx).id.getLine():0);";
testActions(attributeTemplate, "inline", action, expected);
}
@Test public void testRuleRefs() throws Exception {
String action = "$lab.start;";
String expected = "(_localctx.lab!=null?(_localctx.lab.start):null);";
String action = "$lab.start; $c.text;";
String expected = "(((aContext)_localctx).lab!=null?(((aContext)_localctx).lab.start):null); (((aContext)_localctx).c!=null?_input.toString(((aContext)_localctx).c.start,((aContext)_localctx).c.stop):null);";
testActions(attributeTemplate, "inline", action, expected);
}
@Test public void testRefToTextAttributeForCurrentRule() throws Exception {
String action = "$a.text; $text";
String expected =
"(_localctx._ra!=null?_input.toString(_localctx._ra.start,_localctx._ra.stop):" +
"(_localctx.a!=null?_input.toString(_localctx.a.start,_localctx.a.stop):" +
"null); _input.toString(_localctx.start, _input.LT(-1))";
testActions(attributeTemplate, "init", action, expected);
expected =
"_input.toString(_localctx.start, _input.LT(-1)); _input.toString(_localctx.start, _input.LT(-1))";
testActions(attributeTemplate, "inline", action, expected);
expected =
"(_localctx._ra!=null?_input.toString(_localctx._ra.start,_localctx._ra.stop):null);" +
"(_localctx.a!=null?_input.toString(_localctx.a.start,_localctx.a.stop):null);" +
" _input.toString(_localctx.start, _input.LT(-1))";
testActions(attributeTemplate, "finally", action, expected);
}
@ -235,10 +236,6 @@ public class TestActionTranslation extends BaseTest {
@Test public void testRuleLabelWithoutOutputOption() throws Exception {
}
@Test public void testRuleLabelOnTwoDifferentRulesAST() throws Exception {
}
@Test public void testRuleLabelOnTwoDifferentRulesTemplate() throws Exception {
}
@Test public void testMissingArgs() throws Exception {
}
@Test public void testArgsWhenNoneDefined() throws Exception {

View File

@ -42,10 +42,14 @@ public class TestCompositeGrammars extends BaseTest {
String grammar =
"parser grammar S;\n" +
"a : B . C ;\n"; // not qualified ID
Grammar g = new Grammar(grammar);
mkdir(tmpdir);
Grammar g = new Grammar(tmpdir + "/S.g", grammar);
g.name = "S";
ErrorQueue equeue = new ErrorQueue();
Tool antlr = new Tool();
Tool antlr = g.tool;
antlr.outputDirectory = tmpdir;
antlr.libDirectory = tmpdir;
antlr.addListener(equeue);
antlr.process(g,true);

View File

@ -118,7 +118,7 @@ public class TestFullContextParsing extends BaseTest {
assertEquals(expecting, result);
assertEquals("line 1:5 reportAttemptingFullContext d=2: [(30,1,[20 10]), (22,2,[10])], input='34abc'\n" +
"line 1:2 reportContextSensitivity d=2: [(22,1,[10])],uniqueAlt=1, input='34'\n" +
"line 1:17 reportAttemptingFullContext d=2: [(30,1,[24 14]), (26,2,[14])], input='34abc'\n" +
"line 1:14 reportAttemptingFullContext d=2: [(30,1,[24 14]), (26,2,[14])], input='34abc'\n" +
"line 1:14 reportContextSensitivity d=2: [(8,2,[18]), (12,2,[18]), (1,2,[])],uniqueAlt=2, input='34abc'\n",
this.stderrDuringParse);
}

Some files were not shown because too many files have changed in this diff Show More