got unit tests working again for interp; got args funcs in output

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 8902]
This commit is contained in:
parrt 2011-07-24 11:48:43 -08:00
parent d51784a250
commit 66da1f723a
31 changed files with 470 additions and 195 deletions

View File

@ -61,12 +61,8 @@ public class ParserRuleContext extends RuleContext {
super(parent, parent!=null ? parent.s : -1, stateNumber);
}
@Override
public Object getTree() { return tree; }
@Override
public ST getTemplate() { return st; }
@Override
public Token getStart() { return start; }
@Override
public Token getStop() { return stop; }
}

View File

@ -218,11 +218,15 @@ 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(RuleContext _localctx, 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(RuleContext _localctx, int ruleIndex, int actionIndex) {
public void action(RuleContext _localctx, int ruleIndex, int actionIndex) {
}
public ParserRuleContext args(RuleContext _localctx, int s, int ruleIndex, int actionIndex) {
return new ParserRuleContext(_localctx, s);
}
}

View File

@ -29,7 +29,6 @@
package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.*;
import org.stringtemplate.v4.ST;
/** Rules can return start/stop info as well as possible trees and templates.
* Each context knows about invoking context and pointer into ATN so we
@ -68,18 +67,6 @@ public class RuleContext {
*/
protected int cachedHashCode;
/** Return the start token or tree */
public Object getStart() { return null; }
/** Return the stop token or tree */
public Object getStop() { return null; }
/** Has a value potentially if output=AST; */
public Object getTree() { return null; }
/** Has a value potentially if output=template */
public ST getTemplate() { return null; }
public RuleContext() {}
// public RuleContext(RuleContext parent) {

View File

@ -129,10 +129,10 @@ public class ATNConfig {
public String toString(Recognizer<?> recog, boolean showAlt) {
StringBuffer buf = new StringBuffer();
if ( state.ruleIndex>0 ) {
if ( recog!=null ) buf.append(recog.getRuleNames()[state.ruleIndex]+":");
else buf.append(state.ruleIndex+":");
}
// if ( state.ruleIndex>=0 ) {
// if ( recog!=null ) buf.append(recog.getRuleNames()[state.ruleIndex]+":");
// else buf.append(state.ruleIndex+":");
// }
buf.append(state);
if ( showAlt ) {
buf.append("|");

View File

@ -148,7 +148,7 @@ public class LexerATNSimulator extends ATNSimulator {
recog.getRuleNames()[prevAcceptState.ruleIndex]+
":"+ actionIndex);
}
if ( actionIndex>=0 ) recog._action(null, 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(null, 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(null, pt.ruleIndex, pt.predIndex) ) {
if ( recog.sempred(null, pt.ruleIndex, pt.predIndex) ) {
c = new ATNConfig(config, t.target);
c.traversedPredicate = true;
}

View File

@ -37,7 +37,7 @@ import org.stringtemplate.v4.misc.MultiMap;
import java.util.*;
public class ParserATNSimulator extends ATNSimulator {
public static boolean debug = false;
public static boolean debug = true;
public static boolean dfa_debug = false;
public static int ATN_failover = 0;
@ -465,7 +465,10 @@ public class ParserATNSimulator extends ATNSimulator {
ATNState p = config.state;
RuleContext newContext =
new RuleContext(config.context, p.stateNumber, t.target.stateNumber);
// RuleContext xx = parser.args(config.context, t.target.stateNumber, t.target.ruleIndex, -999);
// xx.invokingState = p.stateNumber;
c = new ATNConfig(config, t.target, newContext);
// c = new ATNConfig(config, t.target, xx);
}
else if ( t instanceof PredicateTransition ) {
PredicateTransition pt = (PredicateTransition)t;
@ -473,7 +476,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(originalContext, pt.ruleIndex, pt.predIndex)) ) {
(evalPreds && parser.sempred(originalContext, pt.ruleIndex, pt.predIndex)) ) {
c = new ATNConfig(config, t.target);
c.traversedPredicate = true;
}
@ -484,7 +487,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(originalContext, at.ruleIndex, at.actionIndex);
parser.action(originalContext, at.ruleIndex, at.actionIndex);
}
else {
// non-forced action traversed to get to t.target

View File

@ -52,7 +52,7 @@ public class PredicateTransition extends Transition {
public boolean isEpsilon() { return true; }
public String toString() {
return "pred-"+ruleIndex+":"+predIndex;
return "pred_"+ruleIndex+":"+predIndex;
}
}

View File

@ -1,18 +1,56 @@
grammar T;
//options {output=AST;}
a : a PLUS a
| INT
;
/*
a : a_[0] ;
a_[int _p] : a_primary ( {$_p <= 2}? PLUS a{} )*
options {output=AST;}
s : e EOF ;
expressionList
: e (','! e)*
;
a_primary : INT ;
*/
/*
a : a_[0] ;
a_[int _p] : a_primary ( {_p <= 2}? B )* ;
a_primary : A ;
*/
e : '('! e ')'!
| 'this'
| 'super'
| INT
| ID
| type '.'^ 'class'
| e '.'^ ID
| e '.'^ 'this'
| e '.'^ 'super' '('^ expressionList? ')'!
| e '.'^ 'new'^ ID '('! expressionList? ')'!
| 'new'^ type ( '(' expressionList? ')'! | ('[' e ']'!)+)
| e '['^ e ']'!
| '('^ type ')'! e
| e ('++'^ | '--'^)
| e '('^ expressionList? ')'!
| ('+'^|'-'^|'++'^|'--'^) e
| ('~'^|'!'^) e
| e ('*'^|'/'^|'%'^) e
| e ('+'^|'-'^) e
| e ('<'^ '<' | '>'^ '>' '>' | '>'^ '>') e
| e ('<='^ | '>='^ | '>'^ | '<'^) e
| e 'instanceof'^ e
| e ('=='^ | '!='^) e
| e '&'^ e
| e '^'<assoc=right>^ e
| e '|'^ e
| e '&&'^ e
| e '||'^ e
| e '?' e ':' e
| e ('='<assoc=right>^
|'+='<assoc=right>^
|'-='<assoc=right>^
|'*='<assoc=right>^
|'/='<assoc=right>^
|'&='<assoc=right>^
|'|='<assoc=right>^
|'^='<assoc=right>^
|'>>='<assoc=right>^
|'>>>='<assoc=right>^
|'<<='<assoc=right>^
|'%='<assoc=right>^) e
;
type: ID
| ID '['^ ']'!
| 'int'
| 'int' '['^ ']'!
;
ID : ('a'..'z'|'A'..'Z'|'_'|'$')+;
INT : '0'..'9'+ ;
WS : (' '|'\n') {skip();} ;

View File

@ -13,7 +13,7 @@ public class TestT {
TLexer t = new TLexer(new ANTLRFileStream(args[0]));
CommonTokenStream tokens = new CommonTokenStream(t);
TParser p = new TParser(tokens);
ParserRuleContext ret = p.a();
ParserRuleContext ret = p.s();
System.out.println(((Tree)ret.tree).toStringTree());
}
@ -47,7 +47,7 @@ public class TestT {
ATN atn = f.createATN();
DOTGenerator dot = new DOTGenerator(g);
System.out.println(dot.getDOT(atn.ruleToStartState[g.getRule("d").index]));
System.out.println(dot.getDOT(atn.ruleToStartState[g.getRule("e_").index]));
}
public static class IntTokenStream implements TokenStream {

View File

@ -62,7 +62,7 @@ recRule(ruleName, precArgDef, argName, alts, setResultAction, buildAST,
}
<endif>
(
<alts; separator="\n | ">
(<alts; separator="\n | ">)
)*
;
>>

View File

@ -35,7 +35,7 @@ import java.util.ArrayList;
<parser>
>>
Parser(parser, scopes, funcs, atn, actionFuncs, sempredFuncs) ::= <<
Parser(parser, scopes, funcs, atn, argFuncs, actionFuncs, sempredFuncs) ::= <<
public class <parser.name> extends Parser {
public static final int
<parser.tokens:{k | <k>=<parser.tokens.(k)>}; separator=", ", wrap, anchor>;
@ -58,30 +58,40 @@ public class <parser.name> extends Parser {
@Override
public ATN getATN() { return _ATN; }
<dumpActions(parser, actionFuncs, sempredFuncs)>
<dumpActions(parser, argFuncs, actionFuncs, sempredFuncs)>
<atn>
}
>>
dumpActions(recog, actionFuncs, sempredFuncs) ::= <<
<if(actionFuncs)>
public void _action(RuleContext _localctx, int ruleIndex, int predIndex) {
dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= <<
<if(argFuncs)>
public ParserRuleContext args(RuleContext _localctx, int s, int ruleIndex, int actionIndex) {
switch ( ruleIndex ) {
<recog.actionFuncs:{f|
case <f.ruleIndex> : <f.name>_action((<f.ctxType>)_localctx, predIndex);}; separator="\n">
<recog.argFuncs.values:{f|
case <f.ruleIndex> : return <f.name>_arg((<f.ctxType>)_localctx, s, actionIndex);}; separator="\n">
}
return new ParserRuleContext(_localctx, s);
}
<argFuncs.values; separator="\n">
<endif>
<if(actionFuncs)>
public void action(RuleContext _localctx, int ruleIndex, int actionIndex) {
switch ( ruleIndex ) {
<recog.actionFuncs.values:{f|
case <f.ruleIndex> : <f.name>_action((<f.ctxType>)_localctx, actionIndex);}; separator="\n">
}
}
<actionFuncs; separator="\n">
<actionFuncs.values; separator="\n">
<endif>
<if(sempredFuncs)>
public boolean _sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
switch ( ruleIndex ) {
<recog.sempredFuncs:{f|
<recog.sempredFuncs.values:{f|
case <f.ruleIndex> : return <f.name>_sempred((<f.ctxType>)_localctx, predIndex);}; separator="\n">
}
return true;
}
<sempredFuncs; separator="\n">
<sempredFuncs.values; separator="\n">
<endif>
>>
@ -92,8 +102,19 @@ public <p.name>(TokenStream input) {
}
>>
RuleArgFunction(r, actions) ::= <<
/** arg computations for rules called FROM and evaluated in context of <r.name> */
public ParserRuleContext <r.name>_arg(ParserRuleContext _localctx, int s, int actionIndex) {
switch ( actionIndex ) {
<actions:{index|
case <index> : return new <r.actions.(index).ctxType>(_localctx, s, <actions.(index)>);}; separator="\n">
}
return null;
}
>>
RuleActionFunction(r, actions) ::= <<
public void <r.name>_action(<r.ctxType> _localctx, int actionIndex) {
public void <r.name>_action(<r.ctxType> _localctx, int s, int actionIndex) {
switch ( actionIndex ) {
<actions:{index|
case <index> : <actions.(index)> break;}; separator="\n">
@ -330,6 +351,8 @@ Action(a, chunks) ::= "<chunks>"
ForcedAction(a, chunks) ::= "<chunks>"
ArgAction(a, chunks) ::= "<chunks>"
SemPred(p, chunks) ::= <<
if (!(<chunks>)) throw new FailedPredicateException(this, input, "<currentRule.name>", ""<!"<chunks>"!>);
>>
@ -575,7 +598,7 @@ public class <lexer.name> extends Lexer {
<lexer.namedActions.members>
<dumpActions(lexer, actionFuncs, sempredFuncs)>
<dumpActions(lexer, {}, actionFuncs, sempredFuncs)>
<atn>
}
>>
@ -588,37 +611,10 @@ public static final ATN _ATN =
ATNSimulator.deserialize(_serializedATN.toCharArray());
static {
org.antlr.v4.tool.DOTGenerator dot = new org.antlr.v4.tool.DOTGenerator(null);
//System.out.println(dot.getDOT(_ATN.decisionToATNState.get(0)));
//System.out.println(dot.getDOT(_ATN.decisionToState.get(0), rulesNames));
}
>>
/*
actionMethod(name, ruleIndex, actions) ::= <<
public void <name>_actions(int action) {
System.out.println("exec action "+action);
switch ( action ) {
<actions:{a |
case <i0> :
<a>
break;
}>
}
}<\n>
>>
sempredMethod(name, ruleIndex, preds) ::= <<
public boolean <name>_sempreds(int pred) {
switch ( pred ) {
<preds:{p |
case <i0> :
return <p>;
}>
default : return false;
}
}<\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".
*/

View File

@ -96,23 +96,7 @@ public class OutputModelController {
Grammar g = delegate.getGrammar();
for (Rule r : g.rules.values()) {
String ctxType = gen.target.getRuleFunctionContextStructName(r);
for (ActionAST a : r.actions) {
if ( a instanceof PredAST ) {
PredAST p = (PredAST)a;
RuleSempredFunction rsf = new RuleSempredFunction(delegate, r, ctxType);
file.lexer.sempredFuncs.add(rsf);
rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
}
else if ( a.getType()==ANTLRParser.ACTION ||
a.getType()==ANTLRParser.FORCED_ACTION )
{
// lexer sees {{...}} and {..} as same; neither are done until accept
RuleActionFunction raf = new RuleActionFunction(delegate, r, ctxType);
file.lexer.actionFuncs.add(raf);
raf.actions.put(g.actions.get(a), new ForcedAction(delegate, a));
}
}
buildLexerRuleActions(file.lexer, r);
}
return file;
@ -168,21 +152,81 @@ public class OutputModelController {
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);
RuleSempredFunction rsf = parser.sempredFuncs.get(r);
if ( rsf==null ) {
rsf = new RuleSempredFunction(delegate, r, function.ctxType);
parser.sempredFuncs.put(r, 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);
RuleActionFunction raf = parser.actionFuncs.get(r);
if ( raf==null ) {
raf = new RuleActionFunction(delegate, r, function.ctxType);
parser.actionFuncs.put(r, raf);
}
raf.actions.put(g.actions.get(a), new ForcedAction(delegate, a));
}
else if ( a.getType()==ANTLRParser.ARG_ACTION ) {
RuleArgFunction raf = parser.argFuncs.get(r);
if ( raf==null ) {
raf = new RuleArgFunction(delegate, r, function.ctxType);
parser.argFuncs.put(r, raf);
}
GrammarAST callNode = (GrammarAST)a.getParent();
String invokedRuleName = callNode.getText();
Rule invokedRule = g.getRule(invokedRuleName);
String invokedCtxType = gen.target.getRuleFunctionContextStructName(invokedRule);
raf.actions.put(g.actions.get(a), new ArgAction(delegate, a, invokedCtxType));
}
}
if ( function.ruleCtx.isEmpty() ) function.ruleCtx = null;
popCurrentRule();
}
public void buildLexerRuleActions(Lexer lexer, Rule r) {
CodeGenerator gen = delegate.getGenerator();
Grammar g = delegate.getGrammar();
String ctxType = gen.target.getRuleFunctionContextStructName(r);
for (ActionAST a : r.actions) {
if ( a instanceof PredAST ) {
PredAST p = (PredAST)a;
RuleSempredFunction rsf = lexer.sempredFuncs.get(r);
if ( rsf==null ) {
rsf = new RuleSempredFunction(delegate, r, ctxType);
lexer.sempredFuncs.put(r, rsf);
}
rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
}
else if ( a.getType()== ANTLRParser.ACTION ||
a.getType()==ANTLRParser.FORCED_ACTION )
{
RuleActionFunction raf = lexer.sempredFuncs.get(r);
if ( raf==null ) {
raf = new RuleActionFunction(delegate, r, ctxType);
lexer.actionFuncs.put(r, raf);
}
raf.actions.put(g.actions.get(a), new ForcedAction(delegate, a));
}
if ( a instanceof PredAST ) {
PredAST p = (PredAST)a;
RuleSempredFunction rsf = new RuleSempredFunction(delegate, r, ctxType);
lexer.sempredFuncs.put(r, rsf);
rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
}
else if ( a.getType()==ANTLRParser.ACTION ||
a.getType()==ANTLRParser.FORCED_ACTION )
{
// lexer sees {{...}} and {..} as same; neither are done until accept
RuleActionFunction raf = new RuleActionFunction(delegate, r, ctxType);
lexer.actionFuncs.put(r, raf);
raf.actions.put(g.actions.get(a), new ForcedAction(delegate, a));
}
}
}
public RuleFunction rule(Rule r) {
RuleFunction rf = delegate.rule(r);
for (CodeGeneratorExtension ext : extensions) rf = ext.rule(rf);

View File

@ -0,0 +1,42 @@
/*
[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.GrammarAST;
public class ArgAction extends Action {
/** Context type of invoked rule */
public String ctxType;
public ArgAction(OutputModelFactory factory, GrammarAST ast, String ctxType) {
super(factory, ast);
this.ctxType = ctxType;
}
}

View File

@ -43,10 +43,10 @@ public class Lexer extends OutputModelObject {
public Collection<String> modes;
@ModelElement public SerializedATN atn;
@ModelElement public List<RuleActionFunction> actionFuncs =
new ArrayList<RuleActionFunction>();
@ModelElement public List<RuleSempredFunction> sempredFuncs =
new ArrayList<RuleSempredFunction>();
@ModelElement public LinkedHashMap<Rule, RuleActionFunction> actionFuncs =
new LinkedHashMap<Rule, RuleActionFunction>();
@ModelElement public LinkedHashMap<Rule, RuleSempredFunction> sempredFuncs =
new LinkedHashMap<Rule, RuleSempredFunction>();
public Lexer(OutputModelFactory factory, LexerFile file) {
this.factory = factory;

View File

@ -30,7 +30,7 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.*;
import java.util.*;
@ -44,10 +44,12 @@ public class Parser extends OutputModelObject {
@ModelElement public List<RuleFunction> funcs = new ArrayList<RuleFunction>();
@ModelElement public SerializedATN atn;
@ModelElement public List<RuleActionFunction> actionFuncs =
new ArrayList<RuleActionFunction>();
@ModelElement public List<RuleSempredFunction> sempredFuncs =
new ArrayList<RuleSempredFunction>();
@ModelElement public LinkedHashMap<Rule, RuleArgFunction> argFuncs =
new LinkedHashMap<Rule, RuleArgFunction>();
@ModelElement public LinkedHashMap<Rule, RuleActionFunction> actionFuncs =
new LinkedHashMap<Rule, RuleActionFunction>();
@ModelElement public LinkedHashMap<Rule, RuleSempredFunction> sempredFuncs =
new LinkedHashMap<Rule, RuleSempredFunction>();
public Parser(OutputModelFactory factory, ParserFile file) {
this.factory = factory;

View File

@ -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 RuleArgFunction extends RuleActionFunction {
public RuleArgFunction(OutputModelFactory factory, Rule r, String ctxType) {
super(factory, r, ctxType);
}
}

View File

@ -146,6 +146,12 @@ boolean buildAST;
// the method call from whence to obtain the AST for the parse.
//
grammarSpec
@after {
GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
if ( options!=null ) {
Grammar.setNodeOptions($tree, options);
}
}
:
// The grammar itself can have a documenation comment, which is the
// first terminal in the file.
@ -375,7 +381,13 @@ sync
// grammar type, such as using returns in lexer rules and so on.
rule
@init { paraphrases.push("matching a rule"); }
@after { paraphrases.pop(); }
@after {
paraphrases.pop();
GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
if ( options!=null ) {
Grammar.setNodeOptions($tree, options);
}
}
: // A rule may start with an optional documentation comment
DOC_COMMENT?
@ -690,7 +702,16 @@ ebnfSuffix
| PLUS -> POSITIVE_CLOSURE[$start]
;
atom: // Qualified reference delegate.rule. This must be
atom
@after {
if ( $tree.getType()==DOT ) {
GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
if ( options!=null ) {
Grammar.setNodeOptions($tree, options);
}
}
}
: // Qualified reference delegate.rule. This must be
// lexically contiguous (no spaces either side of the DOT)
// otherwise it is two references with a wildcard in between
// and not a qualified reference.
@ -756,6 +777,12 @@ setElement
// of options, which apply only to that block.
//
block
@after {
GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
if ( options!=null ) {
Grammar.setNodeOptions($tree, options);
}
}
: LPAREN
( optionsSpec? ra+=ruleAction* COLON )?
altList
@ -791,6 +818,12 @@ range
;
terminal
@after {
GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.ELEMENT_OPTIONS);
if ( options!=null ) {
Grammar.setNodeOptions($tree, options);
}
}
: TOKEN_REF elementOptions? -> ^(TOKEN_REF<TerminalAST> elementOptions?)
| STRING_LITERAL elementOptions? -> ^(STRING_LITERAL<TerminalAST> elementOptions?)
;
@ -798,7 +831,7 @@ terminal
// Terminals may be adorned with certain options when
// reference in the grammar: TOK<,,,>
elementOptions
: LT elementOption (COMMA elementOption)* GT -> ^(ELEMENT_OPTIONS elementOption+)
: LT elementOption (COMMA elementOption)* GT -> ^(ELEMENT_OPTIONS[$LT,"ELEMENT_OPTIONS"] elementOption+)
;
// WHen used with elements we can specify what the tree node type can
@ -860,6 +893,12 @@ rewriteTreeElement
;
rewriteTreeAtom
@after {
GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
if ( options!=null ) {
Grammar.setNodeOptions($tree, options);
}
}
: TOKEN_REF elementOptions? ARG_ACTION? -> ^(TOKEN_REF<TerminalAST> elementOptions? ARG_ACTION<ActionAST>?) // for imaginary nodes
| RULE_REF
| STRING_LITERAL elementOptions? -> ^(STRING_LITERAL<TerminalAST> elementOptions?)

View File

@ -413,7 +413,11 @@ block
;
ruleref
: ^(RULE_REF ARG_ACTION?) {ruleRef($RULE_REF, $ARG_ACTION);}
: ^(RULE_REF arg=ARG_ACTION?)
{
ruleRef($RULE_REF, $ARG_ACTION);
if ( $arg!=null ) actionInAlt((ActionAST)$arg);
}
;
range

View File

@ -90,14 +90,16 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
@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 ( t instanceof GrammarASTWithOptions ) {
if ( ((GrammarASTWithOptions)t).getOptions()!=null ) {
String a = ((GrammarASTWithOptions)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);
}
}
}
}

View File

@ -80,6 +80,18 @@ rec_rule returns [boolean isLeftRec]
// {if ($ruleBlock.isLeftRec) $r.setType(PREC_RULE);}
;
exceptionGroup
: exceptionHandler* finallyClause?
;
exceptionHandler
: ^(CATCH ARG_ACTION ACTION)
;
finallyClause
: ^(FINALLY ACTION)
;
ruleModifier
: PUBLIC
| PRIVATE
@ -150,21 +162,21 @@ token returns [GrammarAST t=null]
| ^(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;}
| b=STRING_LITERAL {$t = $b;}
| ^(b=STRING_LITERAL elementOptions) {$t = $b;}
| ^(c=TOKEN_REF elementOptions) {$t = $c;}
| c=TOKEN_REF {$t = $c;}
;
exceptionGroup
: exceptionHandler* finallyClause?
elementOptions
: ^(ELEMENT_OPTIONS elementOption+)
;
exceptionHandler
: ^(CATCH ARG_ACTION ACTION)
;
finallyClause
: ^(FINALLY ACTION)
;
elementOption
: ID
| ^(ASSIGN ID ID)
| ^(ASSIGN ID STRING_LITERAL)
;
element
: ^(ROOT element)
@ -210,8 +222,11 @@ tree_
atom
: ^(RULE_REF ARG_ACTION?)
| ^(TOKEN_REF ARG_ACTION?)
| ^(STRING_LITERAL elementOptions)
| STRING_LITERAL
| ^(TOKEN_REF elementOptions)
| TOKEN_REF
| ^(WILDCARD elementOptions)
| WILDCARD
| ^(DOT ID element)
;

View File

@ -196,12 +196,6 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
checkMode(ID.token);
}
@Override
public void grammarOption(GrammarAST ID, String value) {
boolean ok = checkOptions(g.ast, ID.token, value);
if ( ok ) g.ast.setOption(ID.getText(), value);
}
@Override
public void discoverRule(RuleAST rule, GrammarAST ID,
List<GrammarAST> modifiers,
@ -217,19 +211,25 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
checkInvalidRuleRef(ref.token);
}
@Override
public void grammarOption(GrammarAST ID, String value) {
boolean ok = checkOptions(g.ast, ID.token, value);
//if ( ok ) g.ast.setOption(ID.getText(), value);
}
@Override
public void terminalOption(TerminalAST t, GrammarAST ID, GrammarAST value) {
String v = null;
if ( value!=null ) v = value.getText();
boolean ok = checkTokenOptions(ID, v);
if ( ok ) {
if ( v!=null ) {
t.setOption(ID.getText(), v);
}
else {
t.setOption(TerminalAST.defaultTokenOption, v);
}
}
// if ( ok ) {
// if ( v!=null ) {
// t.setOption(ID.getText(), v);
// }
// else {
// t.setOption(TerminalAST.defaultTokenOption, v);
// }
// }
}
@Override

View File

@ -160,14 +160,14 @@ public class SemanticPipeline {
void assignTokenTypes(Grammar g, List<GrammarAST> tokensDefs,
List<GrammarAST> tokenIDs, Set<String> strings)
{
Grammar G = g.getOutermostGrammar(); // put in root, even if imported
//Grammar G = g.getOutermostGrammar(); // put in root, even if imported
// DEFINE tokens { X='x'; } ALIASES
for (GrammarAST alias : tokensDefs) {
if ( alias.getType()== ANTLRParser.ASSIGN ) {
String name = alias.getChild(0).getText();
String lit = alias.getChild(1).getText();
G.defineTokenAlias(name, lit);
g.defineTokenAlias(name, lit);
}
}
@ -182,11 +182,11 @@ public class SemanticPipeline {
*/
// DEFINE TOKEN TYPES FOR TOKEN REFS LIKE ID, INT
for (GrammarAST idAST : tokenIDs) { G.defineTokenName(idAST.getText()); }
for (GrammarAST idAST : tokenIDs) { g.defineTokenName(idAST.getText()); }
// DEFINE TOKEN TYPES FOR STRING LITERAL REFS LIKE 'while', ';'
for (String s : strings) { G.defineStringLiteral(s); }
System.out.println("tokens="+G.tokenNameToTypeMap);
System.out.println("strings="+G.stringLiteralToTypeMap);
for (String s : strings) { g.defineStringLiteral(s); }
System.out.println("tokens="+g.tokenNameToTypeMap);
System.out.println("strings="+g.stringLiteralToTypeMap);
}
}

View File

@ -35,7 +35,10 @@ import org.antlr.v4.tool.*;
import java.util.*;
/** Collects (create) rules, terminals, strings, actions, scopes etc... from AST
* side-effects: sets resolver field of asts for actions.
* side-effects: sets resolver field of asts for actions and
* defines predicates via definePredicateInAlt(), collects actions and stores
* in alts.
* TODO: remove side-effects!
*/
public class SymbolCollector extends GrammarTreeVisitor {
/** which grammar are we checking */

View File

@ -164,7 +164,7 @@ public class DOTGenerator {
public String getDOT(ATNState startState) {
Set<String> ruleNames = grammar.rules.keySet();
String[] names = new String[ruleNames.size()+1];
int i = 1;
int i = 0;
for (String s : ruleNames) names[i++] = s;
return getDOT(startState, names);
}
@ -196,17 +196,17 @@ public class DOTGenerator {
// special case: if decision point, then line up the alt start states
// unless it's an end of block
if ( s instanceof BlockStartState ) {
ST rankST = stlib.getInstanceOf("decision-rank");
DecisionState alt = (DecisionState)s;
for (int i=0; i<alt.getNumberOfTransitions(); i++) {
ATNState target = alt.transition(i).target;
if ( target!=null ) {
rankST.add("states", target.stateNumber);
}
}
dot.add("decisionRanks", rankST);
}
// if ( s instanceof BlockStartState ) {
// ST rankST = stlib.getInstanceOf("decision-rank");
// DecisionState alt = (DecisionState)s;
// for (int i=0; i<alt.getNumberOfTransitions(); i++) {
// ATNState target = alt.transition(i).target;
// if ( target!=null ) {
// rankST.add("states", target.stateNumber);
// }
// }
// dot.add("decisionRanks", rankST);
// }
// make a DOT edge for each transition
ST edgeST = null;

View File

@ -37,7 +37,6 @@ import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.semantics.SymbolCollector;
import java.io.*;
import java.util.*;
@ -545,7 +544,9 @@ public class Grammar implements AttributeResolver {
}
public int defineTokenName(String name) {
return defineTokenName(name, getNewTokenType());
Integer prev = tokenNameToTypeMap.get(name);
if ( prev==null ) return defineTokenName(name, getNewTokenType());
return prev;
}
public int defineTokenName(String name, int ttype) {
@ -691,6 +692,7 @@ public class Grammar implements AttributeResolver {
/** Manually get language option from tree */
// TODO: move to general tree visitor/parser class?
// TODO: don't need anymore as i set optins in parser?
public static String getLanguageOption(GrammarRootAST ast) {
GrammarAST options = (GrammarAST)ast.getFirstChildWithType(ANTLRParser.OPTIONS);
String language = "Java";
@ -707,6 +709,23 @@ public class Grammar implements AttributeResolver {
return language;
}
/** Given ^(TOKEN_REF ^(OPTIONS ^(ELEMENT_OPTIONS (= assoc right))))
* set option assoc=right in TOKEN_REF.
*/
public static void setNodeOptions(GrammarAST node, GrammarAST options) {
GrammarASTWithOptions t = (GrammarASTWithOptions)node;
if ( t.getChildCount()==0 ) return;
for (Object o : options.getChildren()) {
GrammarAST c = (GrammarAST)o;
if ( c.getType()==ANTLRParser.ASSIGN ) {
t.setOption(c.getChild(0).getText(), c.getChild(1).getText());
}
else {
t.setOption(c.getText(), null); // no arg such as ID<VarNodeType>
}
}
}
public static Map<String,String> getStringLiteralAliasesFromLexerRules(GrammarRootAST ast) {
GrammarAST combinedRulesRoot =
(GrammarAST)ast.getFirstChildWithType(ANTLRParser.RULES);
@ -736,10 +755,15 @@ public class Grammar implements AttributeResolver {
}
public Set<String> getStringLiterals() {
// TODO: super inefficient way to get these.
SymbolCollector collector = new SymbolCollector(this);
collector.process(ast); // no side-effects; find strings
return collector.strings;
final Set<String> strings = new HashSet<String>();
GrammarTreeVisitor collector = new GrammarTreeVisitor() {
@Override
public void stringRef(TerminalAST ref, GrammarAST options) {
strings.add(ref.getText());
}
};
collector.visitGrammar(ast);
return strings;
}

View File

@ -133,9 +133,19 @@ public class GrammarAST extends CommonTree {
public void setType(int type) {
token.setType(type);
}
//
// @Override
// public String getText() {
// if ( textOverride!=null ) return textOverride;
// if ( token!=null ) {
// return token.getText();
// }
// return "";
// }
public void setText(String text) {
textOverride = text; // don't alt tokens as others might see
// textOverride = text; // don't alt tokens as others might see
token.setText(text); // we delete surrounding tree, so ok to alter
}
// @Override
@ -170,7 +180,7 @@ public class GrammarAST extends CommonTree {
int type = adaptor.getType(o);
while ( type!=Token.EOF ) {
buf.append(" ");
buf.append(o.token.getText());
buf.append(o.getText());
nodes.consume();
o = (GrammarAST)nodes.LT(1);
type = adaptor.getType(o);

View File

@ -41,7 +41,7 @@ public class LexerGrammar extends Grammar {
public Grammar implicitLexerOwner;
/** DEFAULT_MODE rules are added first due to grammar syntax order */
public MultiMap<String, Rule> modes = new MultiMap<String, Rule>();
public MultiMap<String, Rule> modes;
public LexerGrammar(Tool tool, GrammarRootAST ast) {
super(tool, ast);
@ -62,6 +62,7 @@ public class LexerGrammar extends Grammar {
@Override
public void defineRule(Rule r) {
super.defineRule(r);
if ( modes==null ) modes = new MultiMap<String, Rule>();
modes.map(r.mode, r);
}
}

View File

@ -133,16 +133,22 @@ 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 ||
actionAST.getType()==ANTLRParser.ARG_ACTION )
{
actionIndex = g.actions.size();
g.actions.put(actionAST, actionIndex);
if ( g.actions.get(actionAST)==null ) {
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());
if ( g.sempreds.get(predAST)==null ) {
g.sempreds.put(predAST, g.sempreds.size());
}
}
public Attribute resolveRetvalOrProperty(String y) {

View File

@ -8,7 +8,11 @@ import org.junit.Test;
import java.util.List;
/** */
// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH
// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH
// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH
public class TestATNInterpreter extends BaseTest {
@Test public void testSimpleNoBlock() throws Exception {
LexerGrammar lg = new LexerGrammar(
@ -157,10 +161,10 @@ public class TestATNInterpreter extends BaseTest {
"D : 'd' ;\n");
Grammar g = new Grammar(
"parser grammar T;\n"+
"a : (A B | A B | D) C ;");
checkMatchedAlt(lg, g, "abc", 1);
checkMatchedAlt(lg, g, "abcd", 1);
checkMatchedAlt(lg, g, "dc", 3);
"a : (A B | A B | C) D ;");
checkMatchedAlt(lg, g, "abd", 1);
checkMatchedAlt(lg, g, "abdc", 1);
checkMatchedAlt(lg, g, "cd", 3);
}
@Test public void testAmbigAltChooseFirst2() throws Exception {
@ -244,6 +248,7 @@ public class TestATNInterpreter extends BaseTest {
);
Grammar g = new Grammar(
"parser grammar T;\n"+
"tokens {A;B;C;LP;RP;INT;}\n" +
"a : e B | e C ;\n" +
"e : LP e RP\n" +
" | INT\n" +

View File

@ -10,6 +10,10 @@ import org.junit.Test;
import java.util.List;
// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH
// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH
// NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH
public class TestATNParserPrediction extends BaseTest {
@Test public void testAorB() throws Exception {
LexerGrammar lg = new LexerGrammar(
@ -143,6 +147,7 @@ public class TestATNParserPrediction extends BaseTest {
"C : 'c' ;\n");
Grammar g = new Grammar(
"parser grammar T;\n"+
"tokens {A;B;C;}\n" +
"a : x B ;\n" +
"b : x C ;\n" +
"x : A | ;\n");
@ -255,6 +260,7 @@ public class TestATNParserPrediction extends BaseTest {
// AB predicted in both alts of e but in diff contexts.
Grammar g = new Grammar(
"parser grammar T;\n"+
"tokens {A;B;C;}\n" +
"a : e B ;\n" +
"b : e A B ;\n" +
"e : A | ;\n"); // TODO: try with three alts
@ -363,6 +369,7 @@ public class TestATNParserPrediction extends BaseTest {
);
Grammar g = new Grammar(
"parser grammar T;\n"+
"tokens {A;B;C;LP;RP;INT;}\n" +
"a : e B | e C ;\n" +
"e : LP e RP\n" +
" | INT\n" +
@ -421,6 +428,7 @@ public class TestATNParserPrediction extends BaseTest {
);
Grammar g = new Grammar(
"parser grammar T;\n"+
"tokens {A;B;C;LP;RP;INT;}\n" +
"a : e A | e A B ;\n" +
"e : LP e RP\n" +
" | INT\n" +

View File

@ -40,6 +40,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : e EOF ;\n" + // must indicate EOF can follow or 'a<EOF>' won't match
"e : e '*'^ e" +
" | e '+'^ e" +
" | e '?'<assoc=right>^ e ':'! e" +
@ -66,6 +67,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : declarator EOF ;\n" + // must indicate EOF can follow
"declarator\n" +
" : declarator '['^ e ']'!\n" +
" | declarator '['^ ']'!\n" +
@ -97,6 +99,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : declarator EOF ;\n" + // must indicate EOF can follow
"declarator\n" +
" : declarator '[' e ']' -> ^('[' declarator e)\n" +
" | declarator '[' ']' -> ^('[' declarator)\n" +
@ -128,6 +131,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : e EOF ;\n" + // must indicate EOF can follow
"e : e '.'^ ID\n" +
" | e '.'^ 'this'\n" +
" | '-'^ e\n" +
@ -160,6 +164,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : e EOF ;\n" + // must indicate EOF can follow
"e : e '.' ID -> ^('.' e ID)\n" +
" | e '.' 'this' -> ^('.' e 'this')\n" +
" | '-' e -> ^('-' e)\n" +
@ -191,6 +196,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : e EOF ;\n" + // must indicate EOF can follow
"e\n" +
" : e '.'^ ID\n" +
" | '-'^ e\n" +
@ -232,6 +238,7 @@ public class TestLeftRecursion extends BaseTest {
String grammar =
"grammar T;\n" +
"options {output=AST;}\n" +
"s : e EOF ;\n" + // must indicate EOF can follow
"expressionList\n" +
" : e (','! e)*\n" +
" ;\n" +
@ -245,7 +252,7 @@ public class TestLeftRecursion extends BaseTest {
" | e '.'^ 'this'\n" +
" | e '.'^ 'super' '('^ expressionList? ')'!\n" +
" | e '.'^ 'new'^ ID '('! expressionList? ')'!\n" +
" | 'new'^ type ( '(' expressionList? ')'! | (options {k=1;}:'[' e ']'!)+)\n" + // ugly; simplified
" | 'new'^ type ( '(' expressionList? ')'! | ('[' e ']'!)+)\n" +
" | e '['^ e ']'!\n" +
" | '('^ type ')'! e\n" +
" | e ('++'^ | '--'^)\n" +