forked from jasder/antlr
snapshot
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 8899]
This commit is contained in:
parent
40f9e867cd
commit
3b52eb4e6a
|
@ -218,11 +218,11 @@ public class Recognizer<ATNInterpreter> {
|
|||
|
||||
// subclass needs to override these if there are sempreds or actions
|
||||
// that the ATN interp needs to execute
|
||||
public boolean sempred(int ruleIndex, int actionIndex) {
|
||||
public boolean _sempred(RuleContext _localctx, int ruleIndex, int actionIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** In lexer, both indexes are same; one action per rule. */
|
||||
public void action(int ruleIndex, int actionIndex) {
|
||||
public void _action(RuleContext _localctx, int ruleIndex, int actionIndex) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
recog.getRuleNames()[prevAcceptState.ruleIndex]+
|
||||
":"+ actionIndex);
|
||||
}
|
||||
if ( actionIndex>=0 ) recog.action(prevAcceptState.ruleIndex, actionIndex);
|
||||
if ( actionIndex>=0 ) recog._action(null, prevAcceptState.ruleIndex, actionIndex);
|
||||
}
|
||||
input.seek(prevAcceptMarker);
|
||||
return prevAcceptState.prediction;
|
||||
|
@ -237,7 +237,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
else System.out.println("ACTION "+ruleIndex+":"+ruleIndex);
|
||||
}
|
||||
int actionIndex = atn.ruleToActionIndex[ruleIndex];
|
||||
if ( actionIndex>=0 ) recog.action(ruleIndex, actionIndex);
|
||||
if ( actionIndex>=0 ) recog._action(null, ruleIndex, actionIndex);
|
||||
return ttype;
|
||||
}
|
||||
|
||||
|
@ -338,7 +338,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
else if ( t.getClass() == PredicateTransition.class ) {
|
||||
PredicateTransition pt = (PredicateTransition)t;
|
||||
if ( recog.sempred(pt.ruleIndex, pt.predIndex) ) {
|
||||
if ( recog._sempred(null, pt.ruleIndex, pt.predIndex) ) {
|
||||
c = new ATNConfig(config, t.target);
|
||||
c.traversedPredicate = true;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,14 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
|
||||
protected Set<ATNConfig> closureBusy = new HashSet<ATNConfig>();
|
||||
|
||||
/** Upon entry for prediction, we might need to execute actions and
|
||||
* we need to know original context passed to us from parser or
|
||||
* lexer. This is the stack and any args, locals, labels, etc...
|
||||
* Meaningless across adaptivePredict() calls but easier as field
|
||||
* than passing down many function calls.
|
||||
protected RuleContext _ctx;
|
||||
*/
|
||||
|
||||
public ParserATNSimulator(ATN atn) {
|
||||
super(atn);
|
||||
ctxToDFAs = new HashMap<RuleContext, DFA[]>();
|
||||
|
@ -68,20 +76,21 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
// System.out.println(dot.getDOT(atn.rules.get(1), parser.getRuleNames()));
|
||||
}
|
||||
|
||||
public int adaptivePredict(TokenStream input, int decision, RuleContext ctx) {
|
||||
public int adaptivePredict(TokenStream input, int decision, RuleContext originalContext) {
|
||||
predict_calls++;
|
||||
// this._ctx = originalContext;
|
||||
DFA dfa = decisionToDFA[decision];
|
||||
if ( dfa==null || dfa.s0==null ) {
|
||||
ATNState startState = atn.decisionToState.get(decision);
|
||||
decisionToDFA[decision] = dfa = new DFA(startState);
|
||||
dfa.decision = decision;
|
||||
return predictATN(dfa, input, decision, ctx, false);
|
||||
return predictATN(dfa, input, decision, originalContext, false);
|
||||
}
|
||||
else {
|
||||
//dump(dfa);
|
||||
// start with the DFA
|
||||
int m = input.mark();
|
||||
int alt = execDFA(input, dfa, dfa.s0, ctx);
|
||||
int alt = execDFA(input, dfa, dfa.s0, originalContext);
|
||||
input.seek(m);
|
||||
return alt;
|
||||
}
|
||||
|
@ -95,7 +104,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
if ( originalContext==null ) originalContext = RuleContext.EMPTY;
|
||||
RuleContext ctx = RuleContext.EMPTY;
|
||||
if ( useContext ) ctx = originalContext;
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(dfa.atnStartState, ctx);
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(dfa.atnStartState, ctx, originalContext);
|
||||
dfa.s0 = addDFAState(dfa, s0_closure);
|
||||
if ( prevAccept!=null ) {
|
||||
dfa.s0.isAcceptState = true;
|
||||
|
@ -119,7 +128,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
public int matchATN(TokenStream input, ATNState startState) {
|
||||
DFA dfa = new DFA(startState);
|
||||
RuleContext ctx = new ParserRuleContext();
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(startState, ctx);
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(startState, ctx, RuleContext.EMPTY);
|
||||
return execATN(input, dfa, input.index(), s0_closure, ctx, false);
|
||||
}
|
||||
|
||||
|
@ -243,7 +252,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
Transition trans = c.state.transition(ti);
|
||||
ATNState target = getReachableTarget(trans, t);
|
||||
if ( target!=null ) {
|
||||
closure(new ATNConfig(c, target), reach);
|
||||
closure(new ATNConfig(c, target), reach, originalContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -367,9 +376,10 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
return predictedAlt;
|
||||
}
|
||||
|
||||
public OrderedHashSet<ATNConfig> computeStartState(ATNState p, RuleContext ctx) {
|
||||
RuleContext initialContext = null;
|
||||
initialContext = ctx; // always at least the implicit call to start rule
|
||||
public OrderedHashSet<ATNConfig> computeStartState(ATNState p, RuleContext ctx,
|
||||
RuleContext originalContext)
|
||||
{
|
||||
RuleContext initialContext = ctx; // always at least the implicit call to start rule
|
||||
OrderedHashSet<ATNConfig> configs = new OrderedHashSet<ATNConfig>();
|
||||
prevAccept = null; // might reach end rule; track
|
||||
prevAcceptIndex = -1;
|
||||
|
@ -377,7 +387,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
for (int i=0; i<p.getNumberOfTransitions(); i++) {
|
||||
ATNState target = p.transition(i).target;
|
||||
ATNConfig c = new ATNConfig(target, i+1, initialContext);
|
||||
closure(c, configs);
|
||||
closure(c, configs, originalContext);
|
||||
}
|
||||
|
||||
return configs;
|
||||
|
@ -405,13 +415,15 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected void closure(ATNConfig config, OrderedHashSet<ATNConfig> configs) {
|
||||
protected void closure(ATNConfig config, OrderedHashSet<ATNConfig> configs,
|
||||
RuleContext originalContext) {
|
||||
closureBusy.clear();
|
||||
closure(config, configs, closureBusy);
|
||||
closure(config, configs, originalContext, closureBusy);
|
||||
}
|
||||
|
||||
protected void closure(ATNConfig config,
|
||||
OrderedHashSet<ATNConfig> configs,
|
||||
RuleContext originalContext,
|
||||
Set<ATNConfig> closureBusy)
|
||||
{
|
||||
if ( debug ) System.out.println("closure("+config+")");
|
||||
|
@ -427,7 +439,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
RuleTransition rt = (RuleTransition)invokingState.transition(0);
|
||||
ATNState retState = rt.followState;
|
||||
ATNConfig c = new ATNConfig(retState, config.alt, newContext);
|
||||
closure(c, configs, closureBusy);
|
||||
closure(c, configs, originalContext, closureBusy);
|
||||
return;
|
||||
}
|
||||
// else if we have no context info, just chase follow links
|
||||
|
@ -440,12 +452,14 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
for (int i=0; i<p.getNumberOfTransitions(); i++) {
|
||||
Transition t = p.transition(i);
|
||||
boolean evalPreds = !config.traversedAction;
|
||||
ATNConfig c = getEpsilonTarget(config, t, evalPreds);
|
||||
if ( c!=null ) closure(c, configs, closureBusy);
|
||||
ATNConfig c = getEpsilonTarget(config, t, originalContext, evalPreds);
|
||||
if ( c!=null ) closure(c, configs, originalContext, closureBusy);
|
||||
}
|
||||
}
|
||||
|
||||
public ATNConfig getEpsilonTarget(ATNConfig config, Transition t, boolean evalPreds) {
|
||||
public ATNConfig getEpsilonTarget(ATNConfig config, Transition t,
|
||||
RuleContext originalContext, boolean evalPreds)
|
||||
{
|
||||
ATNConfig c = null;
|
||||
if ( t instanceof RuleTransition ) {
|
||||
ATNState p = config.state;
|
||||
|
@ -459,7 +473,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
// preds are epsilon if we're not doing preds.
|
||||
// if we are doing preds, pred must eval to true
|
||||
if ( !evalPreds ||
|
||||
(evalPreds && parser.sempred(pt.ruleIndex, pt.predIndex)) ) {
|
||||
(evalPreds && parser._sempred(originalContext, pt.ruleIndex, pt.predIndex)) ) {
|
||||
c = new ATNConfig(config, t.target);
|
||||
c.traversedPredicate = true;
|
||||
}
|
||||
|
@ -470,7 +484,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
if ( debug ) System.out.println("ACTION edge "+at.ruleIndex+":"+at.actionIndex);
|
||||
if ( at.actionIndex>=0 ) {
|
||||
if ( debug ) System.out.println("DO ACTION "+at.ruleIndex+":"+at.actionIndex);
|
||||
parser.action(at.ruleIndex, at.actionIndex);
|
||||
parser._action(originalContext, at.ruleIndex, at.actionIndex);
|
||||
}
|
||||
else {
|
||||
// non-forced action traversed to get to t.target
|
||||
|
|
|
@ -1,32 +1,18 @@
|
|||
grammar T;
|
||||
options {output=AST;}
|
||||
tokens {DUH;}
|
||||
a : (A|B) ;
|
||||
b : (A|B) -> A ;
|
||||
/*
|
||||
type returns [int i] : ID;
|
||||
ID : 'a'..'z'+ ;
|
||||
INT : '0'..'9'+;
|
||||
PLUS : '+';
|
||||
WS : (' '|'\n') {$channel=HIDDEN;} ;
|
||||
*/
|
||||
//options {output=AST;}
|
||||
|
||||
a : a PLUS a
|
||||
| INT
|
||||
;
|
||||
|
||||
/*
|
||||
c : A B C -> A ( D A B C*)* (B A*)? ;
|
||||
|
||||
A : 'a';
|
||||
B : 'b';
|
||||
C : 'c';
|
||||
D : 'd';
|
||||
SEMI : ';';
|
||||
WS : ' '|'\t'|'\n' {skip();} ;
|
||||
a : a_[0] ;
|
||||
a_[int _p] : a_primary ( {$_p <= 2}? PLUS a{} )*
|
||||
;
|
||||
a_primary : INT ;
|
||||
*/
|
||||
|
||||
/*
|
||||
r[int a] returns [int b]
|
||||
scope {int qq;}
|
||||
: x=ID y=r[34] z+=b {$b = 99;}
|
||||
;
|
||||
|
||||
b : r[34] {$r::qq = 3;} ;
|
||||
a : a_[0] ;
|
||||
a_[int _p] : a_primary ( {_p <= 2}? B )* ;
|
||||
a_primary : A ;
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2010 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.
|
||||
*/
|
||||
|
||||
/** How to generate rules derived from left-recursive rules.
|
||||
* These rely on recRuleDefArg(), recRuleAltPredicate(),
|
||||
* recRuleArg(), recRuleSetResultAction(), recRuleSetReturnAction()
|
||||
* templates in main language.stg
|
||||
*/
|
||||
group LeftRecursiveRules;
|
||||
|
||||
recRuleName(ruleName) ::= "<ruleName>_"
|
||||
recPrimaryName(ruleName) ::= "<ruleName>_primary"
|
||||
|
||||
recRuleStart(ruleName, minPrec, userRetvals, userRetvalAssignments) ::= <<
|
||||
<ruleName><if(userRetvals)> returns [<userRetvals>]<endif>
|
||||
: <recRuleName(...)>[<minPrec>]
|
||||
<if(userRetvals)>
|
||||
{
|
||||
<userRetvalAssignments; separator="\n">
|
||||
}
|
||||
<endif>
|
||||
;
|
||||
>>
|
||||
|
||||
recRule(ruleName, precArgDef, argName, alts, setResultAction, buildAST,
|
||||
userRetvals, userRetvalAssignments) ::= <<
|
||||
<recRuleName(...)>[<precArgDef>]<if(userRetvals)> returns [<userRetvals>]<endif>
|
||||
: <recPrimaryName(...)>
|
||||
<if(buildAST)>
|
||||
{
|
||||
<setResultAction>
|
||||
}
|
||||
<endif>
|
||||
<if(userRetvals)>
|
||||
{
|
||||
<userRetvalAssignments; separator="\n">
|
||||
}
|
||||
<endif>
|
||||
(
|
||||
<alts; separator="\n | ">
|
||||
)*
|
||||
;
|
||||
>>
|
||||
|
||||
recPrimaryRule(ruleName, alts, userRetvals) ::= <<
|
||||
<recPrimaryName(...)><if(userRetvals)> returns [<userRetvals>]<endif>
|
||||
: <alts; separator="\n | ">
|
||||
;
|
||||
>>
|
||||
|
||||
recRuleAlt(alt, pred) ::= "{<pred>}? <alt>"
|
||||
|
||||
recRuleRef(ruleName, arg) ::= "<recRuleName(...)>[<arg>]"
|
||||
|
|
@ -35,7 +35,7 @@ import java.util.ArrayList;
|
|||
<parser>
|
||||
>>
|
||||
|
||||
Parser(parser, scopes, funcs, atn, actions, sempreds) ::= <<
|
||||
Parser(parser, scopes, funcs, atn, actionFuncs, sempredFuncs) ::= <<
|
||||
public class <parser.name> extends Parser {
|
||||
public static final int
|
||||
<parser.tokens:{k | <k>=<parser.tokens.(k)>}; separator=", ", wrap, anchor>;
|
||||
|
@ -44,7 +44,6 @@ public class <parser.name> extends Parser {
|
|||
<parser.tokenNames:{k | "<k>"}; separator=", ", wrap, anchor>
|
||||
};
|
||||
public static final String[] ruleNames = {
|
||||
"\<INVALID>",
|
||||
<parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor>
|
||||
};
|
||||
<scopes>
|
||||
|
@ -59,21 +58,32 @@ public class <parser.name> extends Parser {
|
|||
@Override
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
<dumpActions(actions,sempreds)>
|
||||
<if(actionFuncs)>
|
||||
public void _action(RuleContext _localctx, int ruleIndex, int predIndex) {
|
||||
switch ( predIndex ) {
|
||||
<parser.actionFuncs:{f|
|
||||
case <f.ruleIndex> : <f.name>_action((<f.ctxType>)_localctx, predIndex);}; separator="\n">
|
||||
}
|
||||
}
|
||||
<actionFuncs; separator="\n">
|
||||
<endif>
|
||||
<if(sempredFuncs)>
|
||||
public boolean _sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
|
||||
switch ( predIndex ) {
|
||||
<parser.sempredFuncs:{f|
|
||||
case <f.ruleIndex> : return <f.name>_sempred((<f.ctxType>)_localctx, predIndex);}; separator="\n">
|
||||
}
|
||||
return true;
|
||||
}
|
||||
<sempredFuncs; separator="\n">
|
||||
<endif>
|
||||
|
||||
<atn>
|
||||
}
|
||||
>>
|
||||
|
||||
dumpActions(actions,sempreds) ::= <<
|
||||
<if(sempreds)>
|
||||
public boolean sempred(int ruleIndex, int predIndex) {
|
||||
switch ( predIndex ) {
|
||||
<sempreds:{index|
|
||||
case <index> : return <sempreds.(index)>;}; separator="\n">
|
||||
}
|
||||
return true;
|
||||
}
|
||||
<endif>
|
||||
/*
|
||||
dumpActions(actions) ::= <<
|
||||
<if(actions)>
|
||||
public void action(int ruleIndex, int actionIndex) {
|
||||
switch ( actionIndex ) {
|
||||
|
@ -83,6 +93,7 @@ case <index> : <actions.(index)> break;}; separator="\n">
|
|||
}
|
||||
<endif>
|
||||
>>
|
||||
*/
|
||||
|
||||
ctor(p) ::= <<
|
||||
public <p.name>(TokenStream input) {
|
||||
|
@ -91,6 +102,25 @@ public <p.name>(TokenStream input) {
|
|||
}
|
||||
>>
|
||||
|
||||
RuleActionFunction(r, actions) ::= <<
|
||||
public void <r.name>_action(<r.ctxType> _localctx, int actionIndex) {
|
||||
switch ( actionIndex ) {
|
||||
<actions:{index|
|
||||
case <index> : <actions.(index)> break;}; separator="\n">
|
||||
}
|
||||
}
|
||||
>>
|
||||
|
||||
RuleSempredFunction(r, actions) ::= <<
|
||||
public boolean <r.name>_sempred(<r.ctxType> _localctx, int predIndex) {
|
||||
switch ( predIndex ) {
|
||||
<actions:{index|
|
||||
case <index> : return <actions.(index)>;}; separator="\n">
|
||||
}
|
||||
return true;
|
||||
}
|
||||
>>
|
||||
|
||||
RuleFunction(currentRule,code,locals,ruleCtx,namedActions,finallyAction,postamble) ::= <<
|
||||
<ruleCtx>
|
||||
public QStack\<<currentRule.ctxType>\> <currentRule.name>_stk = new QStack\<<currentRule.ctxType>\>();
|
||||
|
@ -395,6 +425,13 @@ AttributeDecl(d) ::= "<d.decl>"
|
|||
/** If we don't know location of label def x, use this template */
|
||||
labelref(x) ::= "<if(!x.isLocal)>_localctx.<endif><x.name>"
|
||||
|
||||
// used for left-recursive rules
|
||||
recRuleDefArg() ::= "int _p"
|
||||
recRuleArg() ::= "$_p"
|
||||
recRuleAltPredicate(ruleName,opPrec) ::= "<recRuleArg()> \<= <opPrec>"
|
||||
recRuleSetResultAction() ::= "root_0=$<ruleName>_primary.tree;"
|
||||
recRuleSetReturnAction(src,name) ::= "$<name>=$<src>.<name>;"
|
||||
|
||||
// AST stuff (TODO: separate?)
|
||||
|
||||
RootDecl(d) ::= "Object <d.name> = _adaptor.nil();"
|
||||
|
@ -548,7 +585,7 @@ public class <lexer.name> extends Lexer {
|
|||
|
||||
<lexer.namedActions.members>
|
||||
|
||||
<dumpActions(actions,sempreds)>
|
||||
<! <dumpActions(actions)> !>
|
||||
<atn>
|
||||
}
|
||||
>>
|
||||
|
@ -565,6 +602,7 @@ static {
|
|||
}
|
||||
>>
|
||||
|
||||
/*
|
||||
actionMethod(name, ruleIndex, actions) ::= <<
|
||||
public void <name>_actions(int action) {
|
||||
System.out.println("exec action "+action);
|
||||
|
@ -589,6 +627,7 @@ public boolean <name>_sempreds(int pred) {
|
|||
}
|
||||
}<\n>
|
||||
>>
|
||||
*/
|
||||
|
||||
/** Using a type to init value map, try to init a type; if not in table
|
||||
* must be an object, default value is "null".
|
||||
|
|
|
@ -227,7 +227,7 @@ public class Tool {
|
|||
|
||||
integrateImportedGrammars(g);
|
||||
|
||||
GrammarTransformPipeline transform = new GrammarTransformPipeline();
|
||||
GrammarTransformPipeline transform = new GrammarTransformPipeline(this);
|
||||
transform.process(g.ast);
|
||||
|
||||
LexerGrammar lexerg = null;
|
||||
|
@ -341,7 +341,8 @@ public class Tool {
|
|||
ParserRuleReturnScope r = p.grammarSpec();
|
||||
GrammarRootAST root = (GrammarRootAST)r.getTree();
|
||||
if ( root instanceof GrammarRootAST ) {
|
||||
((GrammarRootAST)root).hasErrors = p.getNumberOfSyntaxErrors()>0;
|
||||
root.hasErrors = p.getNumberOfSyntaxErrors()>0;
|
||||
root.tokens = tokens;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ public class ActionTranslator implements ActionSplitterListener {
|
|||
put("int", TokenPropertyRef_int.class);
|
||||
}};
|
||||
|
||||
CodeGenerator gen;
|
||||
ActionAST node;
|
||||
RuleFunction rf;
|
||||
List<ActionChunk> chunks = new ArrayList<ActionChunk>();
|
||||
|
@ -75,6 +76,7 @@ public class ActionTranslator implements ActionSplitterListener {
|
|||
public ActionTranslator(OutputModelFactory factory, ActionAST node) {
|
||||
this.factory = factory;
|
||||
this.node = node;
|
||||
this.gen = factory.getGenerator();
|
||||
}
|
||||
|
||||
public static String toString(List<ActionChunk> chunks) {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
package org.antlr.v4.codegen;
|
||||
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.codegen.model.OutputModelObject;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
@ -48,14 +49,19 @@ public class CodeGenerator {
|
|||
"<literals.keys:{t | <t>=<literals.(t)>\n}>";
|
||||
|
||||
public Grammar g;
|
||||
public Tool tool;
|
||||
public Target target;
|
||||
public STGroup templates;
|
||||
|
||||
public int lineWidth = 72;
|
||||
|
||||
public CodeGenerator(Grammar g) {
|
||||
this(g.tool, g, g.getOption("language", "Java"));
|
||||
}
|
||||
|
||||
public CodeGenerator(Tool tool, Grammar g, String language) {
|
||||
this.g = g;
|
||||
String language = g.getOption("language", "Java");
|
||||
this.tool = tool;
|
||||
loadLanguageTarget(language);
|
||||
loadTemplates(language);
|
||||
}
|
||||
|
@ -74,17 +80,17 @@ public class CodeGenerator {
|
|||
target = new Target(this); // use default
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
g.tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
ite,
|
||||
targetName);
|
||||
}
|
||||
catch (InstantiationException ie) {
|
||||
g.tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
ie,
|
||||
targetName);
|
||||
}
|
||||
catch (IllegalAccessException cnfe) {
|
||||
g.tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
cnfe,
|
||||
targetName);
|
||||
}
|
||||
|
@ -96,7 +102,7 @@ public class CodeGenerator {
|
|||
templates.registerRenderer(Integer.class, new NumberRenderer());
|
||||
}
|
||||
catch (IllegalArgumentException iae) {
|
||||
g.tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
|
||||
iae,
|
||||
language);
|
||||
}
|
||||
|
@ -121,10 +127,10 @@ public class CodeGenerator {
|
|||
else outputModel = controller.buildParserOutputModel();
|
||||
|
||||
// CREATE TEMPLATES BY WALKING MODEL
|
||||
OutputModelWalker walker = new OutputModelWalker(g.tool, templates);
|
||||
OutputModelWalker walker = new OutputModelWalker(tool, templates);
|
||||
ST st = walker.walk(outputModel);
|
||||
|
||||
if ( g.tool.launch_ST_inspector ) {
|
||||
if ( tool.launch_ST_inspector ) {
|
||||
st.inspect();
|
||||
//if ( templates.isDefined("headerFile") ) headerFileST.inspect();
|
||||
}
|
||||
|
@ -185,7 +191,7 @@ public class CodeGenerator {
|
|||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
g.tool.errMgr.toolError(ErrorType.CANNOT_WRITE_FILE,
|
||||
tool.errMgr.toolError(ErrorType.CANNOT_WRITE_FILE,
|
||||
ioe,
|
||||
fileName);
|
||||
}
|
||||
|
@ -193,7 +199,7 @@ public class CodeGenerator {
|
|||
|
||||
public void write(ST code, String fileName) throws IOException {
|
||||
long start = System.currentTimeMillis();
|
||||
Writer w = g.tool.getOutputFileWriter(g, fileName);
|
||||
Writer w = tool.getOutputFileWriter(g, fileName);
|
||||
STWriter wr = new AutoIndentWriter(w);
|
||||
wr.setLineWidth(lineWidth);
|
||||
code.write(wr);
|
||||
|
|
|
@ -82,29 +82,7 @@ public class OutputModelController {
|
|||
file.parser = parser;
|
||||
|
||||
for (Rule r : g.rules.values()) {
|
||||
RuleFunction function = rule(r);
|
||||
parser.funcs.add(function);
|
||||
|
||||
// TRIGGER factory functions for rule alts, elements
|
||||
pushCurrentRule(function);
|
||||
GrammarASTAdaptor adaptor = new GrammarASTAdaptor(r.ast.token.getInputStream());
|
||||
GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
|
||||
CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
|
||||
walker = new SourceGenTriggers(nodes, this);
|
||||
try {
|
||||
function.code = DefaultOutputModelFactory.list(walker.block(null, null, null)); // walk AST of rule alts/elements
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
function.ctxType = gen.target.getRuleFunctionContextStructName(function);
|
||||
function.ruleCtx.name = function.ctxType;
|
||||
|
||||
function.postamble = rulePostamble(function, r);
|
||||
|
||||
if ( function.ruleCtx.isEmpty() ) function.ruleCtx = null;
|
||||
popCurrentRule();
|
||||
buildRuleFunction(parser, r);
|
||||
}
|
||||
|
||||
return file;
|
||||
|
@ -138,6 +116,51 @@ public class OutputModelController {
|
|||
return new Lexer(delegate, file);
|
||||
}
|
||||
|
||||
/** Create RuleFunction per rule and update sempreds,actions of parser
|
||||
* output object with stuff found in r.
|
||||
*/
|
||||
public void buildRuleFunction(Parser parser, Rule r) {
|
||||
CodeGenerator gen = delegate.getGenerator();
|
||||
RuleFunction function = rule(r);
|
||||
parser.funcs.add(function);
|
||||
|
||||
// TRIGGER factory functions for rule alts, elements
|
||||
pushCurrentRule(function);
|
||||
GrammarASTAdaptor adaptor = new GrammarASTAdaptor(r.ast.token.getInputStream());
|
||||
GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
|
||||
CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
|
||||
walker = new SourceGenTriggers(nodes, this);
|
||||
try {
|
||||
function.code = DefaultOutputModelFactory.list(walker.block(null, null, null)); // walk AST of rule alts/elements
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
function.ctxType = gen.target.getRuleFunctionContextStructName(function);
|
||||
function.ruleCtx.name = function.ctxType;
|
||||
|
||||
function.postamble = rulePostamble(function, r);
|
||||
|
||||
Grammar g = getGrammar();
|
||||
for (ActionAST a : r.actions) {
|
||||
if ( a instanceof PredAST ) {
|
||||
PredAST p = (PredAST)a;
|
||||
RuleSempredFunction rsf = new RuleSempredFunction(delegate, r, function.ctxType);
|
||||
parser.sempredFuncs.add(rsf);
|
||||
rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
|
||||
}
|
||||
else if ( a.getType()==ANTLRParser.FORCED_ACTION ) {
|
||||
RuleActionFunction raf = new RuleActionFunction(delegate, r, function.ctxType);
|
||||
parser.actionFuncs.add(raf);
|
||||
raf.actions.put(g.actions.get(a), new ForcedAction(delegate, a));
|
||||
}
|
||||
}
|
||||
|
||||
if ( function.ruleCtx.isEmpty() ) function.ruleCtx = null;
|
||||
popCurrentRule();
|
||||
}
|
||||
|
||||
public RuleFunction rule(Rule r) {
|
||||
RuleFunction rf = delegate.rule(r);
|
||||
for (CodeGeneratorExtension ext : extensions) rf = ext.rule(rf);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
package org.antlr.v4.codegen.model;
|
||||
|
||||
import org.antlr.v4.codegen.OutputModelFactory;
|
||||
import org.antlr.v4.tool.*;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -44,8 +44,10 @@ public class Parser extends OutputModelObject {
|
|||
|
||||
@ModelElement public List<RuleFunction> funcs = new ArrayList<RuleFunction>();
|
||||
@ModelElement public SerializedATN atn;
|
||||
@ModelElement public LinkedHashMap<Integer, ForcedAction> actions;
|
||||
@ModelElement public LinkedHashMap<Integer, Action> sempreds;
|
||||
@ModelElement public List<RuleActionFunction> actionFuncs =
|
||||
new ArrayList<RuleActionFunction>();
|
||||
@ModelElement public List<RuleSempredFunction> sempredFuncs =
|
||||
new ArrayList<RuleSempredFunction>();
|
||||
|
||||
public Parser(OutputModelFactory factory, ParserFile file) {
|
||||
this.factory = factory;
|
||||
|
@ -61,6 +63,7 @@ public class Parser extends OutputModelObject {
|
|||
ruleNames = g.rules.keySet();
|
||||
atn = new SerializedATN(factory, g.atn);
|
||||
|
||||
/*
|
||||
sempreds = new LinkedHashMap<Integer, Action>();
|
||||
for (PredAST p : g.sempreds.keySet()) {
|
||||
sempreds.put(g.sempreds.get(p), new Action(factory, p));
|
||||
|
@ -69,5 +72,6 @@ public class Parser extends OutputModelObject {
|
|||
for (ActionAST a : g.actions.keySet()) {
|
||||
actions.put(g.actions.get(a), new ForcedAction(factory, a));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
[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.codegen.model;
|
||||
|
||||
import org.antlr.v4.codegen.OutputModelFactory;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class RuleActionFunction extends OutputModelObject {
|
||||
public String name;
|
||||
public String ctxType;
|
||||
public int ruleIndex;
|
||||
|
||||
@ModelElement public LinkedHashMap<Integer, Action> actions =
|
||||
new LinkedHashMap<Integer, Action>();
|
||||
|
||||
public RuleActionFunction(OutputModelFactory factory, Rule r, String ctxType) {
|
||||
super(factory);
|
||||
name = r.name;
|
||||
ruleIndex = r.index;
|
||||
this.ctxType = ctxType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
[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.codegen.model;
|
||||
|
||||
import org.antlr.v4.codegen.OutputModelFactory;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
|
||||
public class RuleSempredFunction extends RuleActionFunction {
|
||||
public RuleSempredFunction(OutputModelFactory factory, Rule r, String ctxType) {
|
||||
super(factory, r, ctxType);
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ options {
|
|||
tokens {
|
||||
LEXER;
|
||||
RULE;
|
||||
PREC_RULE; // flip to this if we find that it's left-recursive
|
||||
RULES;
|
||||
RULEMODIFIERS;
|
||||
RULEACTIONS;
|
||||
|
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
[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.parse;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.codegen.CodeGenerator;
|
||||
import org.antlr.v4.tool.*;
|
||||
import org.stringtemplate.v4.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** */
|
||||
public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
|
||||
public static enum ASSOC { left, right };
|
||||
|
||||
public Tool tool;
|
||||
public String ruleName;
|
||||
public LinkedHashMap<Integer, String> binaryAlts = new LinkedHashMap<Integer, String>();
|
||||
public LinkedHashMap<Integer, String> ternaryAlts = new LinkedHashMap<Integer, String>();
|
||||
public LinkedHashMap<Integer, String> suffixAlts = new LinkedHashMap<Integer, String>();
|
||||
public List<String> prefixAlts = new ArrayList<String>();
|
||||
public List<String> otherAlts = new ArrayList<String>();
|
||||
|
||||
public GrammarAST retvals;
|
||||
|
||||
public STGroup recRuleTemplates;
|
||||
public STGroup codegenTemplates;
|
||||
public String language;
|
||||
|
||||
public Map<Integer, ASSOC> altAssociativity = new HashMap<Integer, ASSOC>();
|
||||
|
||||
public LeftRecursiveRuleAnalyzer(TokenStream tokens, GrammarAST ruleAST,
|
||||
Tool tool, String ruleName, String language)
|
||||
{
|
||||
super(new CommonTreeNodeStream(new GrammarASTAdaptor(ruleAST.token.getInputStream()), ruleAST));
|
||||
((CommonTreeNodeStream)input).setTokenStream(tokens);
|
||||
this.tool = tool;
|
||||
this.ruleName = ruleName;
|
||||
this.language = language;
|
||||
loadPrecRuleTemplates();
|
||||
}
|
||||
|
||||
public void loadPrecRuleTemplates() {
|
||||
String templateGroupFile = "org/antlr/v4/tool/templates/LeftRecursiveRules.stg";
|
||||
recRuleTemplates = new STGroupFile(templateGroupFile);
|
||||
if ( recRuleTemplates==null || !recRuleTemplates.isDefined("recRuleName") ) {
|
||||
tool.errMgr.toolError(ErrorType.MISSING_CODE_GEN_TEMPLATES, "LeftRecursiveRules");
|
||||
}
|
||||
|
||||
// use codegen to get correct language templates; that's it though
|
||||
CodeGenerator gen = new CodeGenerator(tool, null, language);
|
||||
codegenTemplates = gen.templates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReturnValues(GrammarAST t) {
|
||||
System.out.println(t);
|
||||
retvals = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTokenPrec(GrammarAST t, int alt) {
|
||||
ASSOC assoc = ASSOC.left;
|
||||
if ( ((TerminalAST)t).getOptions()!=null ) {
|
||||
String a = ((TerminalAST)t).getOption("assoc");
|
||||
if ( a!=null ) {
|
||||
if ( a.equals(ASSOC.right.toString()) ) {
|
||||
assoc = ASSOC.right;
|
||||
}
|
||||
else {
|
||||
tool.errMgr.toolError(ErrorType.ILLEGAL_OPTION_VALUE, "assoc", assoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( altAssociativity.get(alt)!=null && altAssociativity.get(alt)!=assoc ) {
|
||||
tool.errMgr.toolError(ErrorType.ALL_OPS_NEED_SAME_ASSOC, alt);
|
||||
}
|
||||
altAssociativity.put(alt, assoc);
|
||||
|
||||
//System.out.println("op " + alt + ": " + t.getText()+", assoc="+assoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binaryAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {
|
||||
altTree = altTree.dupTree();
|
||||
|
||||
stripLeftRecursion(altTree);
|
||||
|
||||
// rewrite e to be e_[rec_arg]
|
||||
int nextPrec = nextPrecedence(alt);
|
||||
ST refST = recRuleTemplates.getInstanceOf("recRuleRef");
|
||||
refST.add("ruleName", ruleName);
|
||||
refST.add("arg", nextPrec);
|
||||
altTree = replaceRuleRefs(altTree, refST.render());
|
||||
|
||||
String altText = text(altTree);
|
||||
altText = altText.trim();
|
||||
altText += "{}"; // add empty alt to prevent pred hoisting
|
||||
ST nameST = recRuleTemplates.getInstanceOf("recRuleName");
|
||||
nameST.add("ruleName", ruleName);
|
||||
if ( rewriteTree!=null ) {
|
||||
rewriteTree = rewriteTree.dupTree();
|
||||
rewriteTree = replaceRuleRefs(rewriteTree, "$" + nameST.render());
|
||||
}
|
||||
String rewriteText = text(rewriteTree);
|
||||
binaryAlts.put(alt, altText + " " + rewriteText);
|
||||
//System.out.println("binaryAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
|
||||
}
|
||||
|
||||
/** Convert e ? e : e -> ? e : e_[nextPrec] */
|
||||
@Override
|
||||
public void ternaryAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {
|
||||
altTree = altTree.dupTree();
|
||||
|
||||
stripLeftRecursion(altTree);
|
||||
|
||||
int nextPrec = nextPrecedence(alt);
|
||||
ST refST = recRuleTemplates.getInstanceOf("recRuleRef");
|
||||
refST.add("ruleName", ruleName);
|
||||
refST.add("arg", nextPrec);
|
||||
altTree = replaceLastRuleRef(altTree, refST.render());
|
||||
|
||||
String altText = text(altTree);
|
||||
altText = altText.trim();
|
||||
altText += "{}"; // add empty alt to prevent pred hoisting
|
||||
ST nameST = recRuleTemplates.getInstanceOf("recRuleName");
|
||||
nameST.add("ruleName", ruleName);
|
||||
if ( rewriteTree!=null ) {
|
||||
rewriteTree = rewriteTree.dupTree();
|
||||
rewriteTree = replaceRuleRefs(rewriteTree, "$" + nameST.render());
|
||||
}
|
||||
String rewriteText = text(rewriteTree);
|
||||
ternaryAlts.put(alt, altText + " " + rewriteText);
|
||||
//System.out.println("ternaryAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prefixAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {
|
||||
altTree = altTree.dupTree();
|
||||
|
||||
int nextPrec = precedence(alt);
|
||||
// rewrite e to be e_[rec_arg]
|
||||
ST refST = recRuleTemplates.getInstanceOf("recRuleRef");
|
||||
refST.add("ruleName", ruleName);
|
||||
refST.add("arg", nextPrec);
|
||||
altTree = replaceRuleRefs(altTree, refST.render());
|
||||
String altText = text(altTree);
|
||||
altText = altText.trim();
|
||||
altText += "{}"; // add empty alt to prevent pred hoisting
|
||||
|
||||
ST nameST = recRuleTemplates.getInstanceOf("recRuleName");
|
||||
nameST.add("ruleName", ruleName);
|
||||
if ( rewriteTree!=null ) {
|
||||
rewriteTree = rewriteTree.dupTree();
|
||||
rewriteTree = replaceRuleRefs(rewriteTree, nameST.render());
|
||||
}
|
||||
String rewriteText = text(rewriteTree);
|
||||
|
||||
prefixAlts.add(altText + " " + rewriteText);
|
||||
//System.out.println("prefixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suffixAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {
|
||||
altTree = altTree.dupTree();
|
||||
stripLeftRecursion(altTree);
|
||||
ST nameST = recRuleTemplates.getInstanceOf("recRuleName");
|
||||
nameST.add("ruleName", ruleName);
|
||||
if ( rewriteTree!=null ) {
|
||||
rewriteTree = rewriteTree.dupTree();
|
||||
rewriteTree = replaceRuleRefs(rewriteTree, "$" + nameST.render());
|
||||
}
|
||||
String rewriteText = text(rewriteTree);
|
||||
String altText = text(altTree);
|
||||
altText = altText.trim();
|
||||
suffixAlts.put(alt, altText + " " + rewriteText);
|
||||
// System.out.println("suffixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void otherAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {
|
||||
altTree = altTree.dupTree();
|
||||
if ( rewriteTree!=null ) rewriteTree = rewriteTree.dupTree();
|
||||
stripLeftRecursion(altTree);
|
||||
String altText = text(altTree);
|
||||
|
||||
String rewriteText = text(rewriteTree);
|
||||
otherAlts.add(altText + " " + rewriteText);
|
||||
//System.out.println("otherAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
|
||||
}
|
||||
|
||||
// --------- get transformed rules ----------------
|
||||
|
||||
public String getArtificialPrecStartRule() {
|
||||
ST ruleST = recRuleTemplates.getInstanceOf("recRuleStart");
|
||||
ruleST.add("ruleName", ruleName);
|
||||
ruleST.add("minPrec", 0);
|
||||
ruleST.add("userRetvals", retvals);
|
||||
fillRetValAssignments(ruleST, "recRuleName");
|
||||
|
||||
System.out.println(ruleST.render());
|
||||
return ruleST.render();
|
||||
}
|
||||
|
||||
public String getArtificialOpPrecRule() {
|
||||
ST ruleST = recRuleTemplates.getInstanceOf("recRule");
|
||||
ruleST.add("ruleName", ruleName);
|
||||
// TODO: ruleST.add("buildAST", grammar.hasASTOption());
|
||||
ST argDefST =
|
||||
codegenTemplates.getInstanceOf("recRuleDefArg");
|
||||
ruleST.add("precArgDef", argDefST);
|
||||
ST ruleArgST =
|
||||
codegenTemplates.getInstanceOf("recRuleArg");
|
||||
ruleST.add("argName", ruleArgST);
|
||||
ST setResultST =
|
||||
codegenTemplates.getInstanceOf("recRuleSetResultAction");
|
||||
ruleST.add("setResultAction", setResultST);
|
||||
ruleST.add("userRetvals", retvals);
|
||||
fillRetValAssignments(ruleST, "recPrimaryName");
|
||||
|
||||
LinkedHashMap<Integer, String> opPrecRuleAlts = new LinkedHashMap<Integer, String>();
|
||||
opPrecRuleAlts.putAll(binaryAlts);
|
||||
opPrecRuleAlts.putAll(ternaryAlts);
|
||||
opPrecRuleAlts.putAll(suffixAlts);
|
||||
for (int alt : opPrecRuleAlts.keySet()) {
|
||||
String altText = opPrecRuleAlts.get(alt);
|
||||
ST altST = recRuleTemplates.getInstanceOf("recRuleAlt");
|
||||
ST predST =
|
||||
codegenTemplates.getInstanceOf("recRuleAltPredicate");
|
||||
predST.add("opPrec", precedence(alt));
|
||||
predST.add("ruleName", ruleName);
|
||||
altST.add("pred", predST);
|
||||
altST.add("alt", altText);
|
||||
ruleST.add("alts", altST);
|
||||
}
|
||||
|
||||
System.out.println(ruleST.render());
|
||||
|
||||
return ruleST.render();
|
||||
}
|
||||
|
||||
public String getArtificialPrimaryRule() {
|
||||
ST ruleST = recRuleTemplates.getInstanceOf("recPrimaryRule");
|
||||
ruleST.add("ruleName", ruleName);
|
||||
ruleST.add("alts", prefixAlts);
|
||||
ruleST.add("alts", otherAlts);
|
||||
ruleST.add("userRetvals", retvals);
|
||||
System.out.println(ruleST.render());
|
||||
return ruleST.render();
|
||||
}
|
||||
|
||||
public GrammarAST replaceRuleRefs(GrammarAST t, String name) {
|
||||
if ( t==null ) return null;
|
||||
for (GrammarAST rref : t.getNodesWithType(RULE_REF)) {
|
||||
if ( rref.getText().equals(ruleName) ) rref.setText(name);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public static boolean hasImmediateRecursiveRuleRefs(GrammarAST t, String ruleName) {
|
||||
if ( t==null ) return false;
|
||||
for (GrammarAST rref : t.getNodesWithType(RULE_REF)) {
|
||||
if ( rref.getText().equals(ruleName) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public GrammarAST replaceLastRuleRef(GrammarAST t, String name) {
|
||||
if ( t==null ) return null;
|
||||
GrammarAST last = null;
|
||||
for (GrammarAST rref : t.getNodesWithType(RULE_REF)) { last = rref; }
|
||||
if ( last !=null && last.getText().equals(ruleName) ) last.setText(name);
|
||||
return t;
|
||||
}
|
||||
|
||||
public void stripLeftRecursion(GrammarAST altAST) {
|
||||
GrammarAST rref = (GrammarAST)altAST.getChild(0);
|
||||
if ( rref.getType()== ANTLRParser.RULE_REF &&
|
||||
rref.getText().equals(ruleName))
|
||||
{
|
||||
// remove rule ref
|
||||
altAST.deleteChild(0);
|
||||
// reset index so it prints properly
|
||||
GrammarAST newFirstChild = (GrammarAST) altAST.getChild(0);
|
||||
altAST.setTokenStartIndex(newFirstChild.getTokenStartIndex());
|
||||
}
|
||||
}
|
||||
|
||||
public String text(GrammarAST t) {
|
||||
if ( t==null ) return "";
|
||||
TokenStream tokens = input.getTokenStream();
|
||||
CommonToken ta = (CommonToken)tokens.get(t.getTokenStartIndex());
|
||||
CommonToken tb = (CommonToken)tokens.get(t.getTokenStopIndex());
|
||||
return tokens.toString(ta, tb);
|
||||
}
|
||||
|
||||
public int precedence(int alt) {
|
||||
return numAlts-alt+1;
|
||||
}
|
||||
|
||||
public int nextPrecedence(int alt) {
|
||||
int p = precedence(alt);
|
||||
if ( altAssociativity.get(alt)==ASSOC.left ) p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
public void fillRetValAssignments(ST ruleST, String srcName) {
|
||||
if ( retvals==null ) return;
|
||||
|
||||
// complicated since we must be target-independent
|
||||
AttributeDict args = ScopeParser.parseTypeList(retvals.token.getText());
|
||||
|
||||
for (String name : args.attributes.keySet()) {
|
||||
ST setRetValST =
|
||||
codegenTemplates.getInstanceOf("recRuleSetReturnAction");
|
||||
ST ruleNameST = recRuleTemplates.getInstanceOf(srcName);
|
||||
ruleNameST.add("ruleName", ruleName);
|
||||
setRetValST.add("src", ruleNameST);
|
||||
setRetValST.add("name", name);
|
||||
ruleST.add("userRetvalAssignments",setRetValST);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PrecRuleOperatorCollector{" +
|
||||
"binaryAlts=" + binaryAlts +
|
||||
", ternaryAlts=" + ternaryAlts +
|
||||
", suffixAlts=" + suffixAlts +
|
||||
", prefixAlts=" + prefixAlts +
|
||||
", otherAlts=" + otherAlts +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2011 Terence Parr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Grammar conversion to ANTLR v3:
|
||||
* Copyright (c) 2011 Sam Harwell
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** Find left-recursive rules */
|
||||
tree grammar LeftRecursiveRuleWalker;
|
||||
|
||||
options {
|
||||
tokenVocab=ANTLRParser;
|
||||
ASTLabelType=GrammarAST;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.antlr.v4.parse;
|
||||
|
||||
import org.antlr.v4.misc.*;
|
||||
import org.antlr.v4.tool.*;
|
||||
}
|
||||
|
||||
@members {
|
||||
private String ruleName;
|
||||
private int currentOuterAltNumber; // which outer alt of rule?
|
||||
public int numAlts; // how many alts for this rule total?
|
||||
|
||||
public void setTokenPrec(GrammarAST t, int alt) {}
|
||||
public void binaryAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {}
|
||||
public void ternaryAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {}
|
||||
public void prefixAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {}
|
||||
public void suffixAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {}
|
||||
public void otherAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) {}
|
||||
public void setReturnValues(GrammarAST t) {}
|
||||
}
|
||||
|
||||
public
|
||||
rec_rule returns [boolean isLeftRec]
|
||||
@init
|
||||
{
|
||||
currentOuterAltNumber = 1;
|
||||
}
|
||||
: ^( r=RULE id=ID {ruleName=$id.getText();}
|
||||
ruleModifier?
|
||||
(^(ARG ARG_ACTION))?
|
||||
(^(RET ARG_ACTION))?
|
||||
( ^(THROWS .+) )?
|
||||
( ^(OPTIONS .*)
|
||||
| ^(AT ID ACTION)
|
||||
)*
|
||||
ruleBlock {$isLeftRec = $ruleBlock.isLeftRec;}
|
||||
exceptionGroup
|
||||
)
|
||||
// why do this?
|
||||
// {if ($ruleBlock.isLeftRec) $r.setType(PREC_RULE);}
|
||||
;
|
||||
|
||||
ruleModifier
|
||||
: PUBLIC
|
||||
| PRIVATE
|
||||
| PROTECTED
|
||||
| FRAGMENT
|
||||
;
|
||||
|
||||
ruleBlock returns [boolean isLeftRec]
|
||||
@init{boolean lr=false; this.numAlts = $start.getChildCount();}
|
||||
: ^( BLOCK
|
||||
(
|
||||
( o=outerAlternative[null]
|
||||
| ^( r=ALT_REWRITE o=outerAlternative[(GrammarAST)$r.getChild(1)] rewrite )
|
||||
)
|
||||
{if ($o.isLeftRec) $isLeftRec = true;}
|
||||
{currentOuterAltNumber++;}
|
||||
)+
|
||||
)
|
||||
;
|
||||
|
||||
/** An alt is either prefix, suffix, binary, or ternary operation or "other" */
|
||||
outerAlternative[GrammarAST rew] returns [boolean isLeftRec]
|
||||
: (binaryMultipleOp)=> binaryMultipleOp
|
||||
{binaryAlt($start, $rew, currentOuterAltNumber); $isLeftRec=true;}
|
||||
| (binary)=> binary
|
||||
{binaryAlt($start, $rew, currentOuterAltNumber); $isLeftRec=true;}
|
||||
| (ternary)=> ternary
|
||||
{ternaryAlt($start, $rew, currentOuterAltNumber); $isLeftRec=true;}
|
||||
| (prefix)=> prefix
|
||||
{prefixAlt($start, $rew, currentOuterAltNumber);}
|
||||
| (suffix)=> suffix
|
||||
{suffixAlt($start, $rew, currentOuterAltNumber); $isLeftRec=true;}
|
||||
| ^(ALT element+) // "other" case
|
||||
{otherAlt($start, $rew, currentOuterAltNumber);}
|
||||
;
|
||||
|
||||
binary
|
||||
: ^( ALT recurseNoLabel op=token recurse ) {setTokenPrec($op.t, currentOuterAltNumber);}
|
||||
;
|
||||
|
||||
binaryMultipleOp
|
||||
: ^( ALT recurseNoLabel ^( BLOCK ( ^( ALT op=token {setTokenPrec($op.t, currentOuterAltNumber);} ) )+ ) recurse )
|
||||
;
|
||||
|
||||
ternary
|
||||
: ^( ALT recurseNoLabel op=token recurse token recurse ) {setTokenPrec($op.t, currentOuterAltNumber);}
|
||||
;
|
||||
|
||||
prefix
|
||||
: ^( ALT {setTokenPrec((GrammarAST)input.LT(1), currentOuterAltNumber);}
|
||||
({!((CommonTree)input.LT(1)).getText().equals(ruleName)}? element)+
|
||||
recurse
|
||||
)
|
||||
;
|
||||
|
||||
suffix : ^( ALT recurseNoLabel {setTokenPrec((GrammarAST)input.LT(1), currentOuterAltNumber);} element+ ) ;
|
||||
|
||||
recurse
|
||||
: ^(ASSIGN ID recurseNoLabel)
|
||||
| ^(PLUS_ASSIGN ID recurseNoLabel)
|
||||
| recurseNoLabel
|
||||
;
|
||||
|
||||
recurseNoLabel : {((CommonTree)input.LT(1)).getText().equals(ruleName)}? RULE_REF;
|
||||
|
||||
token returns [GrammarAST t=null]
|
||||
: ^(ASSIGN ID s=token {$t = $s.t;})
|
||||
| ^(PLUS_ASSIGN ID s=token {$t = $s.t;})
|
||||
| ^(ROOT s=token {$t = $s.t;})
|
||||
| ^(BANG s=token {$t = $s.t;})
|
||||
| b=STRING_LITERAL {$t = $b;}
|
||||
| c=TOKEN_REF {$t = $c;}
|
||||
;
|
||||
|
||||
exceptionGroup
|
||||
: exceptionHandler* finallyClause?
|
||||
;
|
||||
|
||||
exceptionHandler
|
||||
: ^(CATCH ARG_ACTION ACTION)
|
||||
;
|
||||
|
||||
finallyClause
|
||||
: ^(FINALLY ACTION)
|
||||
;
|
||||
|
||||
element
|
||||
: ^(ROOT element)
|
||||
| ^(BANG element)
|
||||
| atom
|
||||
| ^(NOT element)
|
||||
| ^(RANGE atom atom)
|
||||
| ^(ASSIGN ID element)
|
||||
| ^(PLUS_ASSIGN ID element)
|
||||
| ^(SET setElement+)
|
||||
| RULE_REF
|
||||
| ebnf
|
||||
| tree_
|
||||
| FORCED_ACTION
|
||||
| ACTION
|
||||
| SEMPRED
|
||||
| EPSILON
|
||||
;
|
||||
|
||||
setElement
|
||||
: STRING_LITERAL
|
||||
| TOKEN_REF
|
||||
;
|
||||
|
||||
ebnf: block
|
||||
| ^( OPTIONAL block )
|
||||
| ^( CLOSURE block )
|
||||
| ^( POSITIVE_CLOSURE block )
|
||||
;
|
||||
|
||||
block
|
||||
: ^(BLOCK ACTION? alternative+)
|
||||
;
|
||||
|
||||
alternative
|
||||
: ^(ALT_REWRITE alternative rewrite)
|
||||
| ^(ALT element+)
|
||||
;
|
||||
|
||||
tree_
|
||||
: ^(TREE_BEGIN element+)
|
||||
;
|
||||
|
||||
atom
|
||||
: ^(RULE_REF ARG_ACTION?)
|
||||
| ^(TOKEN_REF ARG_ACTION?)
|
||||
| STRING_LITERAL
|
||||
| WILDCARD
|
||||
| ^(DOT ID element)
|
||||
;
|
||||
|
||||
ast_suffix
|
||||
: ROOT
|
||||
| BANG
|
||||
;
|
||||
|
||||
rewrite
|
||||
: rewrite_result*
|
||||
;
|
||||
|
||||
rewrite_result
|
||||
: ^(ST_RESULT .*)
|
||||
| ^(RESULT .*)
|
||||
;
|
|
@ -65,6 +65,8 @@ public class Alternative implements AttributeResolver {
|
|||
* and catch/finally (not in an alt). Also tracks predicates, rewrite actions.
|
||||
* We need to examine these actions before code generation so
|
||||
* that we can detect refs to $rule.attr etc...
|
||||
*
|
||||
* This tracks per alt
|
||||
*/
|
||||
public List<ActionAST> actions = new ArrayList<ActionAST>();
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ public enum ErrorType {
|
|||
ARGS_ON_TOKEN_REF("token reference <arg> may not have parameters", ErrorSeverity.ERROR),
|
||||
RULE_REF_AMBIG_WITH_RULE_IN_ALT("", ErrorSeverity.ERROR),
|
||||
ILLEGAL_OPTION("illegal option <arg>", ErrorSeverity.WARNING),
|
||||
ILLEGAL_OPTION_VALUE("illegal option value <arg>=<arg2>", ErrorSeverity.WARNING),
|
||||
LIST_LABEL_INVALID_UNLESS_RETVAL_STRUCT("", ErrorSeverity.ERROR),
|
||||
REWRITE_ELEMENT_NOT_PRESENT_ON_LHS("reference to rewrite element <arg> not found to left of ->", ErrorSeverity.ERROR),
|
||||
UNDEFINED_TOKEN_REF_IN_REWRITE("token <arg> in rewrite is undefined", ErrorSeverity.ERROR),
|
||||
|
@ -136,9 +137,7 @@ public enum ErrorType {
|
|||
AST_OP_IN_ALT_WITH_REWRITE("rule <arg> alt <arg2> uses rewrite syntax and also an AST operator", ErrorSeverity.ERROR),
|
||||
WILDCARD_AS_ROOT("Wildcard invalid as root; wildcard can itself be a tree", ErrorSeverity.ERROR),
|
||||
CONFLICTING_OPTION_IN_TREE_FILTER("option <arg>=<arg2> conflicts with tree grammar filter mode", ErrorSeverity.ERROR),
|
||||
|
||||
AMBIGUITY("", ErrorSeverity.ERROR),
|
||||
UNREACHABLE_ALTS("", ErrorSeverity.ERROR),
|
||||
ALL_OPS_NEED_SAME_ASSOC("all operators of alt <alt> of left-recursive rule must have same associativity", ErrorSeverity.WARNING),
|
||||
|
||||
// these next 3 can happen in recursion-limited LL("", *)
|
||||
//RECURSION_OVERFLOW("", ErrorSeverity.ERROR),
|
||||
|
|
|
@ -644,6 +644,11 @@ public class Grammar implements AttributeResolver {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public org.antlr.runtime.TokenStream getTokenStream() {
|
||||
if ( ast!=null ) return ast.tokens;
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isLexer() { return getType()==ANTLRParser.LEXER; }
|
||||
public boolean isParser() { return getType()==ANTLRParser.PARSER; }
|
||||
public boolean isTreeGrammar() { return getType()==ANTLRParser.TREE; }
|
||||
|
@ -684,6 +689,24 @@ public class Grammar implements AttributeResolver {
|
|||
return outputOption!=null && outputOption.equals("AST");
|
||||
}
|
||||
|
||||
/** Manually get language option from tree */
|
||||
// TODO: move to general tree visitor/parser class?
|
||||
public static String getLanguageOption(GrammarRootAST ast) {
|
||||
GrammarAST options = (GrammarAST)ast.getFirstChildWithType(ANTLRParser.OPTIONS);
|
||||
String language = "Java";
|
||||
if ( options!=null ) {
|
||||
for (Object o : options.getChildren()) {
|
||||
GrammarAST c = (GrammarAST)o;
|
||||
if ( c.getType() == ANTLRParser.ASSIGN &&
|
||||
c.getChild(0).getText().equals("language") )
|
||||
{
|
||||
language = c.getChild(1).getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
public static Map<String,String> getStringLiteralAliasesFromLexerRules(GrammarRootAST ast) {
|
||||
GrammarAST combinedRulesRoot =
|
||||
(GrammarAST)ast.getFirstChildWithType(ANTLRParser.RULES);
|
||||
|
|
|
@ -45,6 +45,8 @@ public class GrammarAST extends CommonTree {
|
|||
/** If we build an ATN, we make AST node point at left edge of ATN construct */
|
||||
public ATNState atnState;
|
||||
|
||||
public String textOverride;
|
||||
|
||||
public GrammarAST() {;}
|
||||
public GrammarAST(Token t) { super(t); }
|
||||
public GrammarAST(GrammarAST node) { super(node); }
|
||||
|
@ -128,6 +130,14 @@ public class GrammarAST extends CommonTree {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
token.setType(type);
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
textOverride = text; // don't alt tokens as others might see
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean equals(Object obj) {
|
||||
// return super.equals(obj);
|
||||
|
@ -138,6 +148,13 @@ public class GrammarAST extends CommonTree {
|
|||
return new GrammarAST(this);
|
||||
}
|
||||
|
||||
public GrammarAST dupTree() {
|
||||
GrammarAST t = this;
|
||||
CharStream input = this.token.getInputStream();
|
||||
GrammarASTAdaptor adaptor = new GrammarASTAdaptor(input);
|
||||
return (GrammarAST)adaptor.dupTree(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
package org.antlr.v4.tool;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -43,6 +43,8 @@ public class GrammarRootAST extends GrammarASTWithOptions {
|
|||
};
|
||||
public int grammarType; // LEXER, PARSER, TREE, GRAMMAR (combined)
|
||||
public boolean hasErrors;
|
||||
/** Track stream used to create this tree */
|
||||
public TokenStream tokens;
|
||||
|
||||
public GrammarRootAST(GrammarAST node) {
|
||||
super(node);
|
||||
|
|
|
@ -29,26 +29,106 @@
|
|||
|
||||
package org.antlr.v4.tool;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.parse.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/** Handle left-recursion and block-set transforms */
|
||||
public class GrammarTransformPipeline {
|
||||
//public GrammarAST ast;
|
||||
public Tool tool;
|
||||
|
||||
public GrammarTransformPipeline() {
|
||||
// this.ast = ast;
|
||||
public GrammarTransformPipeline(Tool tool) {
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
public void process(GrammarAST ast) {
|
||||
public void process(GrammarRootAST ast) {
|
||||
if ( ast==null ) return;
|
||||
System.out.println("before: "+ast.toStringTree());
|
||||
|
||||
if ( ast.grammarType==ANTLRParser.PARSER || ast.grammarType==ANTLRParser.COMBINED ) {
|
||||
translateLeftRecursiveRules(ast);
|
||||
}
|
||||
|
||||
reduceBlocksToSets(ast);
|
||||
System.out.println("after: "+ast.toStringTree());
|
||||
}
|
||||
|
||||
public void reduceBlocksToSets(GrammarRootAST ast) {
|
||||
org.antlr.runtime.tree.CommonTreeNodeStream nodes =
|
||||
new org.antlr.runtime.tree.CommonTreeNodeStream(ast);
|
||||
GrammarASTAdaptor adaptor = new GrammarASTAdaptor();
|
||||
BlockSetTransformer transformer = new BlockSetTransformer(nodes);
|
||||
transformer.setTreeAdaptor(adaptor);
|
||||
// System.out.println("before: "+ast.toStringTree());
|
||||
transformer.downup(ast);
|
||||
// System.out.println("after: "+ast.toStringTree());
|
||||
}
|
||||
|
||||
public void translateLeftRecursiveRules(GrammarRootAST ast) {
|
||||
String language = Grammar.getLanguageOption(ast);
|
||||
for (GrammarAST r : ast.getNodesWithType(ANTLRParser.RULE)) {
|
||||
String ruleName = r.getChild(0).getText();
|
||||
if ( !Character.isUpperCase(ruleName.charAt(0)) ) {
|
||||
if ( LeftRecursiveRuleAnalyzer.hasImmediateRecursiveRuleRefs(r, ruleName) ) {
|
||||
translateLeftRecursiveRule(ast, r, language);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void translateLeftRecursiveRule(GrammarRootAST ast,
|
||||
GrammarAST ruleAST,
|
||||
String language)
|
||||
{
|
||||
//System.out.println(ruleAST.toStringTree());
|
||||
TokenStream tokens = ast.tokens;
|
||||
String ruleName = ruleAST.getChild(0).getText();
|
||||
LeftRecursiveRuleAnalyzer leftRecursiveRuleWalker =
|
||||
new LeftRecursiveRuleAnalyzer(tokens, ruleAST, tool, ruleName, language);
|
||||
boolean isLeftRec = false;
|
||||
try {
|
||||
// System.out.println("TESTING ---------------\n"+
|
||||
// leftRecursiveRuleWalker.text(ruleAST));
|
||||
isLeftRec = leftRecursiveRuleWalker.rec_rule();
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "bad ast structure", re);
|
||||
}
|
||||
if ( !isLeftRec ) return;
|
||||
|
||||
// delete old rule
|
||||
GrammarAST RULES = (GrammarAST)ast.getFirstChildWithType(ANTLRParser.RULES);
|
||||
RULES.deleteChild(ruleAST);
|
||||
|
||||
List<String> rules = new ArrayList<String>();
|
||||
rules.add( leftRecursiveRuleWalker.getArtificialPrecStartRule() ) ;
|
||||
rules.add( leftRecursiveRuleWalker.getArtificialOpPrecRule() );
|
||||
rules.add( leftRecursiveRuleWalker.getArtificialPrimaryRule() );
|
||||
for (String ruleText : rules) {
|
||||
// System.out.println("created: "+ruleText);
|
||||
GrammarAST t = parseArtificialRule(ruleText);
|
||||
// insert into grammar tree
|
||||
RULES.addChild(t);
|
||||
System.out.println("added: "+t.toStringTree());
|
||||
}
|
||||
}
|
||||
|
||||
public GrammarAST parseArtificialRule(String ruleText) {
|
||||
ANTLRLexer lexer = new ANTLRLexer(new ANTLRStringStream(ruleText));
|
||||
GrammarASTAdaptor adaptor = new GrammarASTAdaptor();
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
ToolANTLRParser p = new ToolANTLRParser(tokens, tool);
|
||||
p.setTreeAdaptor(adaptor);
|
||||
try {
|
||||
ParserRuleReturnScope r = p.rule();
|
||||
return (GrammarAST)r.getTree();
|
||||
}
|
||||
catch (Exception e) {
|
||||
tool.errMgr.toolError(ErrorType.INTERNAL_ERROR,
|
||||
"error parsing rule created during left-recursion detection: "+ruleText,
|
||||
e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -99,6 +99,15 @@ public class Rule implements AttributeResolver {
|
|||
*/
|
||||
public List<ActionAST> exceptionActions = new ArrayList<ActionAST>();
|
||||
|
||||
/** Track all executable actions other than named actions like @init
|
||||
* and catch/finally (not in an alt). Also tracks predicates, rewrite actions.
|
||||
* We need to examine these actions before code generation so
|
||||
* that we can detect refs to $rule.attr etc...
|
||||
*
|
||||
* This tracks per rule; Alternative objs also track per alt.
|
||||
*/
|
||||
public List<ActionAST> actions = new ArrayList<ActionAST>();
|
||||
|
||||
public ActionAST finallyAction;
|
||||
|
||||
public int numberOfAlts;
|
||||
|
@ -122,14 +131,16 @@ public class Rule implements AttributeResolver {
|
|||
}
|
||||
|
||||
public void defineActionInAlt(int currentAlt, ActionAST actionAST) {
|
||||
actions.add(actionAST);
|
||||
alt[currentAlt].actions.add(actionAST);
|
||||
if ( g.isLexer() || actionAST.getType()== ANTLRParser.FORCED_ACTION ) {
|
||||
if ( g.isLexer() || actionAST.getType()==ANTLRParser.FORCED_ACTION ) {
|
||||
actionIndex = g.actions.size();
|
||||
g.actions.put(actionAST, actionIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public void definePredicateInAlt(int currentAlt, PredAST predAST) {
|
||||
actions.add(predAST);
|
||||
alt[currentAlt].actions.add(predAST);
|
||||
g.sempreds.put(predAST, g.sempreds.size());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue