forked from jasder/antlr
got more symbol resolution in
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 6687]
This commit is contained in:
parent
e825a77466
commit
b3f7c8e3cc
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
[The "BSD license"]
|
||||
Copyright (c) 2005-2009 Terence Parr
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.runtime;
|
||||
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.Token;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class CommonToken implements Token, Serializable {
|
||||
protected int type;
|
||||
protected int line;
|
||||
protected int charPositionInLine = -1; // set to invalid position
|
||||
protected int channel=DEFAULT_CHANNEL;
|
||||
protected transient CharStream input;
|
||||
|
||||
/** We need to be able to change the text once in a while. If
|
||||
* this is non-null, then getText should return this. Note that
|
||||
* start/stop are not affected by changing this.
|
||||
*/
|
||||
protected String text;
|
||||
|
||||
/** What token number is this from 0..n-1 tokens; < 0 implies invalid index */
|
||||
protected int index = -1;
|
||||
|
||||
/** The char position into the input buffer where this token starts */
|
||||
protected int start;
|
||||
|
||||
/** The char position into the input buffer where this token stops */
|
||||
protected int stop;
|
||||
|
||||
public CommonToken(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public CommonToken(CharStream input, int type, int channel, int start, int stop) {
|
||||
this.input = input;
|
||||
this.type = type;
|
||||
this.channel = channel;
|
||||
this.start = start;
|
||||
this.stop = stop;
|
||||
this.line = input.getLine();
|
||||
this.charPositionInLine = input.getCharPositionInLine();
|
||||
}
|
||||
|
||||
public CommonToken(int type, String text) {
|
||||
this.type = type;
|
||||
this.channel = DEFAULT_CHANNEL;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public CommonToken(Token oldToken) {
|
||||
text = oldToken.getText();
|
||||
type = oldToken.getType();
|
||||
line = oldToken.getLine();
|
||||
index = oldToken.getTokenIndex();
|
||||
charPositionInLine = oldToken.getCharPositionInLine();
|
||||
channel = oldToken.getChannel();
|
||||
input = oldToken.getInputStream();
|
||||
if ( oldToken instanceof CommonToken ) {
|
||||
start = ((CommonToken)oldToken).start;
|
||||
stop = ((CommonToken)oldToken).stop;
|
||||
}
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setLine(int line) {
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
if ( text!=null ) {
|
||||
return text;
|
||||
}
|
||||
if ( input==null ) {
|
||||
return null;
|
||||
}
|
||||
if ( start<input.size() && stop<input.size() ) {
|
||||
text = input.substring(start,stop);
|
||||
}
|
||||
else {
|
||||
text = "<EOF>";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/** Override the text for this token. getText() will return this text
|
||||
* rather than pulling from the buffer. Note that this does not mean
|
||||
* that start/stop indexes are not valid. It means that that input
|
||||
* was converted to a new string in the token object.
|
||||
*/
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getCharPositionInLine() {
|
||||
return charPositionInLine;
|
||||
}
|
||||
|
||||
public void setCharPositionInLine(int charPositionInLine) {
|
||||
this.charPositionInLine = charPositionInLine;
|
||||
}
|
||||
|
||||
public int getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(int channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getStartIndex() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStartIndex(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public int getStopIndex() {
|
||||
return stop;
|
||||
}
|
||||
|
||||
public void setStopIndex(int stop) {
|
||||
this.stop = stop;
|
||||
}
|
||||
|
||||
public int getTokenIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setTokenIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public CharStream getInputStream() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInputStream(CharStream input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String channelStr = "";
|
||||
if ( channel>0 ) {
|
||||
channelStr=",channel="+channel;
|
||||
}
|
||||
String txt = getText();
|
||||
if ( txt!=null ) {
|
||||
txt = txt.replaceAll("\n","\\\\n");
|
||||
txt = txt.replaceAll("\r","\\\\r");
|
||||
txt = txt.replaceAll("\t","\\\\t");
|
||||
}
|
||||
else {
|
||||
txt = "<no text>";
|
||||
}
|
||||
return "[@"+getTokenIndex()+","+start+":"+stop+"='"+txt+"',<"+type+">"+channelStr+","+line+":"+getCharPositionInLine()+"]";
|
||||
}
|
||||
}
|
|
@ -4,29 +4,11 @@ options { filter=true; }
|
|||
|
||||
@header {
|
||||
package org.antlr.v4.parse;
|
||||
import org.antlr.v4.runtime.CommonToken;
|
||||
import org.antlr.v4.tool.*;
|
||||
}
|
||||
|
||||
@members {
|
||||
/*
|
||||
public void setQualifiedAttr(Token x, Token y, Token expr) { }
|
||||
public void qualifiedAttr(Token x, Token y) { }
|
||||
public void setDynamicScopeAttr(Token x, Token y, Token expr) { }
|
||||
public void dynamicScopeAttr(Token x, Token y) { }
|
||||
public void setDynamicNegativeIndexedScopeAttr(Token x, Token y, Token index, Token expr) { }
|
||||
public void dynamicNegativeIndexedScopeAttr(Token x, Token y, Token index) { }
|
||||
public void setDynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index, Token expr) { }
|
||||
public void dynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index) { }
|
||||
public void setAttr(Token x, Token expr) { }
|
||||
public void attr(Token x) { }
|
||||
public void templateInstance() { }
|
||||
public void indirectTemplateInstance() { }
|
||||
public void setExprAttribute() { }
|
||||
public void setAttribute() { }
|
||||
public void templateExpr() { }
|
||||
public void unknownSyntax(String text) { }
|
||||
public void text(String text) { }
|
||||
*/
|
||||
ActionSplitterListener delegate;
|
||||
|
||||
public ActionSplitter(CharStream input, ActionSplitterListener delegate) {
|
||||
|
@ -34,6 +16,11 @@ public ActionSplitter(CharStream input, ActionSplitterListener delegate) {
|
|||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public void emit(Token token) {
|
||||
super.emit(token);
|
||||
|
||||
}
|
||||
|
||||
/** force filtering (and return tokens). triggers all above actions. */
|
||||
public List<Token> getActionChunks() {
|
||||
List<Token> chunks = new ArrayList<Token>();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,36 +5,23 @@ import org.antlr.runtime.Token;
|
|||
/** */
|
||||
public interface ActionSplitterListener {
|
||||
void setQualifiedAttr(Token x, Token y, Token expr);
|
||||
|
||||
void qualifiedAttr(Token x, Token y);
|
||||
|
||||
void setAttr(Token x, Token expr);
|
||||
void attr(Token x);
|
||||
|
||||
void setDynamicScopeAttr(Token x, Token y, Token expr);
|
||||
|
||||
void dynamicScopeAttr(Token x, Token y);
|
||||
|
||||
void setDynamicNegativeIndexedScopeAttr(Token x, Token y, Token index, Token expr);
|
||||
|
||||
void dynamicNegativeIndexedScopeAttr(Token x, Token y, Token index);
|
||||
|
||||
void setDynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index, Token expr);
|
||||
|
||||
void dynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index);
|
||||
|
||||
void setAttr(Token x, Token expr);
|
||||
|
||||
void attr(Token x);
|
||||
|
||||
void templateInstance();
|
||||
|
||||
void indirectTemplateInstance();
|
||||
|
||||
void setExprAttribute();
|
||||
|
||||
void setAttribute();
|
||||
|
||||
void templateExpr();
|
||||
|
||||
void unknownSyntax(String text);
|
||||
|
||||
void text(String text);
|
||||
}
|
||||
|
|
|
@ -4,51 +4,76 @@ import org.antlr.runtime.ANTLRStringStream;
|
|||
import org.antlr.runtime.Token;
|
||||
import org.antlr.v4.parse.ActionSplitter;
|
||||
import org.antlr.v4.parse.ActionSplitterListener;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.antlr.v4.tool.GrammarAST;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Trigger checks for various kinds of attribute expressions. no side-effects */
|
||||
public class AttributeChecks implements ActionSplitterListener {
|
||||
public Grammar g;
|
||||
public Rule r;
|
||||
public Rule r; // null if action outside of rule
|
||||
public Alternative alt; // null if action outside of rule
|
||||
public GrammarAST node;
|
||||
String action;
|
||||
public String action;
|
||||
|
||||
public AttributeChecks(Grammar g, Rule r, GrammarAST node, String action) {
|
||||
public AttributeChecks(Grammar g, Rule r, Alternative alt, GrammarAST node, String action) {
|
||||
this.g = g;
|
||||
this.r = r;
|
||||
this.alt = alt;
|
||||
this.node = node;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public void examine() {
|
||||
ActionSplitter splitter =
|
||||
new ActionSplitter(new ANTLRStringStream(action), this);
|
||||
ANTLRStringStream in = new ANTLRStringStream(action);
|
||||
in.setLine(node.getLine());
|
||||
in.setCharPositionInLine(node.getCharPositionInLine());
|
||||
ActionSplitter splitter = new ActionSplitter(in, this);
|
||||
splitter.getActionChunks(); // forces eval, fills extractor
|
||||
}
|
||||
|
||||
|
||||
|
||||
// LISTENER METHODS
|
||||
|
||||
public void setQualifiedAttr(Token x, Token y, Token expr) {
|
||||
System.out.println(x+"."+y+"="+expr);
|
||||
new AttributeChecks(g, r, node, expr.getText()).examine();
|
||||
new AttributeChecks(g, r, alt, node, expr.getText()).examine();
|
||||
}
|
||||
|
||||
public void qualifiedAttr(Token x, Token y) {
|
||||
System.out.println(x+"."+y);
|
||||
AttributeScope s = r.resolveScope(x.getText(), alt);
|
||||
if ( s==null ) {
|
||||
System.err.println("not found: "+x);
|
||||
}
|
||||
}
|
||||
public void setDynamicScopeAttr(Token x, Token y, Token expr) { }
|
||||
public void dynamicScopeAttr(Token x, Token y) { }
|
||||
public void setDynamicNegativeIndexedScopeAttr(Token x, Token y, Token index, Token expr) { }
|
||||
public void dynamicNegativeIndexedScopeAttr(Token x, Token y, Token index) { }
|
||||
public void setDynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index, Token expr) { }
|
||||
public void dynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index) { }
|
||||
|
||||
public void setAttr(Token x, Token expr) {
|
||||
System.out.println(x+"="+expr);
|
||||
new AttributeChecks(g, r, node, expr.getText()).examine();
|
||||
System.out.println(x+"="+expr);
|
||||
if ( !r.resolves(x.getText(), alt) ) System.err.println("not found: "+x);
|
||||
new AttributeChecks(g, r, alt, node, expr.getText()).examine();
|
||||
}
|
||||
public void attr(Token x) {
|
||||
|
||||
public void attr(Token x) { // arg, retval, predefined, token ref, rule ref, current rule
|
||||
System.out.println(x);
|
||||
if ( !r.resolves(x.getText(), alt) ) System.err.println("not found: "+x);
|
||||
}
|
||||
|
||||
public void setDynamicScopeAttr(Token x, Token y, Token expr) { }
|
||||
|
||||
public void dynamicScopeAttr(Token x, Token y) { }
|
||||
|
||||
public void setDynamicNegativeIndexedScopeAttr(Token x, Token y, Token index, Token expr) { }
|
||||
|
||||
public void dynamicNegativeIndexedScopeAttr(Token x, Token y, Token index) { }
|
||||
|
||||
public void setDynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index, Token expr) { }
|
||||
|
||||
public void dynamicAbsoluteIndexedScopeAttr(Token x, Token y, Token index) { }
|
||||
|
||||
public void unknownSyntax(String text) { }
|
||||
|
||||
public void text(String text) { }
|
||||
|
||||
// don't care
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package org.antlr.v4.semantics;
|
||||
|
||||
import org.antlr.misc.MultiMap;
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.v4.misc.Utils;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.tool.*;
|
||||
import org.stringtemplate.v4.misc.MultiMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
@ -114,8 +114,6 @@ public class BasicSemanticChecks {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO: track errors?
|
||||
|
||||
protected static void checkGrammarName(Grammar g, Token nameToken) {
|
||||
if ( g.implicitLexer==null ) return;
|
||||
String fullyQualifiedName = nameToken.getInputStream().getSourceName();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 BasicSemanticTriggers.g 2010-02-11 11:14:49
|
||||
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 BasicSemanticTriggers.g 2010-02-11 12:59:15
|
||||
|
||||
/*
|
||||
[The "BSD license"]
|
||||
|
@ -26,14 +26,15 @@
|
|||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.semantics;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.TreeNodeStream;
|
||||
import org.antlr.runtime.tree.TreeRuleReturnScope;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.*;import java.util.Stack;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
/** Triggers for the basic semantics of the input. Side-effects:
|
||||
* Set token, block, rule options in the tree. Load field option
|
||||
* with grammar options. Only legal options are set.
|
||||
|
|
|
@ -135,7 +135,7 @@ tokensSection
|
|||
rule: ^( RULE name=ID .+)
|
||||
{
|
||||
int numAlts = $RULE.getFirstChildWithType(BLOCK).getChildCount();
|
||||
Rule r = new Rule($name.text, (GrammarASTWithOptions)$RULE, numAlts);
|
||||
Rule r = new Rule(g, $name.text, (GrammarASTWithOptions)$RULE, numAlts);
|
||||
rules.add(r);
|
||||
currentRule = r;
|
||||
currentAlt = 1;
|
||||
|
@ -157,15 +157,15 @@ rulelNamedAction
|
|||
;
|
||||
|
||||
ruleAction
|
||||
: {inContext("RULE ...")}? ACTION {currentRule.inlineActions.add($ACTION);}
|
||||
: {inContext("RULE ...")}? ACTION {currentRule.alt[currentAlt].actions.add($ACTION);}
|
||||
;
|
||||
|
||||
exceptionHandler
|
||||
: ^(CATCH ARG_ACTION ACTION) {currentRule.inlineActions.add($ACTION);}
|
||||
: ^(CATCH ARG_ACTION ACTION) {currentRule.exceptionActions.add($ACTION);}
|
||||
;
|
||||
|
||||
finallyClause
|
||||
: ^(FINALLY ACTION) {currentRule.inlineActions.add($ACTION);}
|
||||
: ^(FINALLY ACTION) {currentRule.exceptionActions.add($ACTION);}
|
||||
;
|
||||
|
||||
ruleArg
|
||||
|
@ -206,7 +206,7 @@ labeledElement
|
|||
@after {
|
||||
LabelElementPair lp = new LabelElementPair(g, $id, $e, $start.getType());
|
||||
currentRule.labelDefs.map($id.text, lp);
|
||||
currentRule.alt[currentAlt].labelRefs.map($id.text, $id);
|
||||
currentRule.alt[currentAlt].labelDefs.map($id.text, $id);
|
||||
}
|
||||
: {inContext("RULE ...")}?
|
||||
( ^(ASSIGN id=ID e=.)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 CollectSymbols.g 2010-02-11 11:14:49
|
||||
// $ANTLR 3.2.1-SNAPSHOT Jan 26, 2010 15:12:28 CollectSymbols.g 2010-02-11 12:59:15
|
||||
|
||||
/*
|
||||
[The "BSD license"]
|
||||
|
@ -26,15 +26,19 @@
|
|||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.semantics;
|
||||
import org.antlr.v4.tool.*;
|
||||
import org.antlr.v4.parse.*;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import org.stringtemplate.v4.misc.MultiMap;
|
||||
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.TreeNodeStream;
|
||||
import org.antlr.runtime.tree.TreeRuleReturnScope;
|
||||
import org.antlr.v4.parse.ScopeParser;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.antlr.runtime.tree.*;import java.util.Stack;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
/** Collects rules, terminals, strings, actions, scopes etc... from AST
|
||||
* Side-effects: None
|
||||
*/
|
||||
|
@ -620,7 +624,7 @@ public class CollectSymbols extends org.antlr.v4.runtime.tree.TreeFilter {
|
|||
if ( state.backtracking==1 ) {
|
||||
|
||||
int numAlts = RULE5.getFirstChildWithType(BLOCK).getChildCount();
|
||||
Rule r = new Rule((name!=null?name.getText():null), (GrammarASTWithOptions)RULE5, numAlts);
|
||||
Rule r = new Rule(g, (name!=null?name.getText():null), (GrammarASTWithOptions)RULE5, numAlts);
|
||||
rules.add(r);
|
||||
currentRule = r;
|
||||
currentAlt = 1;
|
||||
|
@ -765,7 +769,7 @@ public class CollectSymbols extends org.antlr.v4.runtime.tree.TreeFilter {
|
|||
}
|
||||
ACTION8=(GrammarAST)match(input,ACTION,FOLLOW_ACTION_in_ruleAction430); if (state.failed) return ;
|
||||
if ( state.backtracking==1 ) {
|
||||
currentRule.inlineActions.add(ACTION8);
|
||||
currentRule.alt[currentAlt].actions.add(ACTION8);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -799,7 +803,7 @@ public class CollectSymbols extends org.antlr.v4.runtime.tree.TreeFilter {
|
|||
|
||||
match(input, Token.UP, null); if (state.failed) return ;
|
||||
if ( state.backtracking==1 ) {
|
||||
currentRule.inlineActions.add(ACTION9);
|
||||
currentRule.exceptionActions.add(ACTION9);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -832,7 +836,7 @@ public class CollectSymbols extends org.antlr.v4.runtime.tree.TreeFilter {
|
|||
|
||||
match(input, Token.UP, null); if (state.failed) return ;
|
||||
if ( state.backtracking==1 ) {
|
||||
currentRule.inlineActions.add(ACTION10);
|
||||
currentRule.exceptionActions.add(ACTION10);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1178,7 +1182,7 @@ public class CollectSymbols extends org.antlr.v4.runtime.tree.TreeFilter {
|
|||
|
||||
LabelElementPair lp = new LabelElementPair(g, id, e, ((GrammarAST)retval.start).getType());
|
||||
currentRule.labelDefs.map((id!=null?id.getText():null), lp);
|
||||
currentRule.alt[currentAlt].labelRefs.map((id!=null?id.getText():null), id);
|
||||
currentRule.alt[currentAlt].labelDefs.map((id!=null?id.getText():null), id);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,7 @@ import org.antlr.runtime.RecognitionException;
|
|||
import org.antlr.runtime.tree.BufferedTreeNodeStream;
|
||||
import org.antlr.v4.parse.ASTVerifier;
|
||||
import org.antlr.v4.parse.GrammarASTAdaptor;
|
||||
import org.antlr.v4.tool.ErrorManager;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.antlr.v4.tool.GrammarAST;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.antlr.v4.tool.*;
|
||||
|
||||
/** */
|
||||
public class SemanticPipeline {
|
||||
|
@ -59,12 +56,16 @@ public class SemanticPipeline {
|
|||
public void checkAttributeExpressions(Grammar g, CollectSymbols collector) {
|
||||
for (Rule r : collector.rules) {
|
||||
for (GrammarAST a : r.namedActions.values()) {
|
||||
AttributeChecks checker = new AttributeChecks(g, r, a, a.getText());
|
||||
AttributeChecks checker = new AttributeChecks(g, r, null, a, a.getText());
|
||||
checker.examine();
|
||||
}
|
||||
for (GrammarAST a : r.inlineActions) {
|
||||
AttributeChecks checker = new AttributeChecks(g, r, a, a.getText());
|
||||
checker.examine();
|
||||
for (int i=1; i<=r.numberOfAlts; i++) {
|
||||
Alternative alt = r.alt[i];
|
||||
for (GrammarAST a : alt.actions) {
|
||||
AttributeChecks checker =
|
||||
new AttributeChecks(g, r, alt, a, a.getText());
|
||||
checker.examine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,7 +284,7 @@ public class SymbolChecks {
|
|||
for (GrammarAST e : alt.rewriteElements) {
|
||||
if ( !(alt.ruleRefs.containsKey(e.getText()) ||
|
||||
alt.tokenRefs.containsKey(e.getText()) ||
|
||||
alt.labelRefs.containsKey(e.getText())) ) {
|
||||
alt.labelDefs.containsKey(e.getText())) ) {
|
||||
ErrorManager.grammarError(ErrorType.REWRITE_ELEMENT_NOT_PRESENT_ON_LHS,
|
||||
g.fileName, e.token, e.getText());
|
||||
}
|
||||
|
|
|
@ -13,15 +13,22 @@ public class Alternative {
|
|||
// token IDs, string literals in this alt
|
||||
public MultiMap<String, GrammarAST> tokenRefs = new MultiMap<String, GrammarAST>();
|
||||
|
||||
// token IDs, string literals in this alt
|
||||
public MultiMap<String, GrammarAST> labelRefs = new MultiMap<String, GrammarAST>();
|
||||
|
||||
// all rule refs in this alt
|
||||
public MultiMap<String, GrammarAST> ruleRefs = new MultiMap<String, GrammarAST>();
|
||||
|
||||
/** A list of all LabelElementPair attached to tokens like id=ID, ids+=ID */
|
||||
public MultiMap<String, GrammarAST> labelDefs = new MultiMap<String, GrammarAST>();
|
||||
|
||||
// track all token, rule, label refs in rewrite (right of ->)
|
||||
public List<GrammarAST> rewriteElements = new ArrayList<GrammarAST>();
|
||||
|
||||
/** 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...
|
||||
*/
|
||||
public List<GrammarAST> actions = new ArrayList<GrammarAST>();
|
||||
|
||||
public Alternative() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ public class Attribute {
|
|||
public String initValue;
|
||||
|
||||
public Attribute() {;}
|
||||
|
||||
|
||||
public Attribute(String name) { this(name,null); }
|
||||
|
||||
public Attribute(String name, String decl) {
|
||||
this.name = name;
|
||||
this.decl = decl;
|
||||
|
|
|
@ -16,6 +16,21 @@ public class AttributeScope {
|
|||
protected String name;
|
||||
public GrammarAST ast;
|
||||
|
||||
/** All token scopes (token labels) share the same fixed scope of
|
||||
* of predefined attributes. I keep this out of the runtime.Token
|
||||
* object to avoid a runtime type leakage.
|
||||
*/
|
||||
public static AttributeScope predefinedTokenScope = new AttributeScope() {{
|
||||
add(new Attribute("text"));
|
||||
add(new Attribute("type"));
|
||||
add(new Attribute("line"));
|
||||
add(new Attribute("index"));
|
||||
add(new Attribute("pos"));
|
||||
add(new Attribute("channel"));
|
||||
add(new Attribute("tree"));
|
||||
add(new Attribute("int"));
|
||||
}};
|
||||
|
||||
public static enum Type {
|
||||
ARG, RET, TOKEN, PREDEFINED_RULE, PREDEFINED_LEXER_RULE,
|
||||
GLOBAL_SCOPE, // scope symbols { ...}
|
||||
|
@ -27,6 +42,7 @@ public class AttributeScope {
|
|||
public LinkedHashMap<String, Attribute> attributes =
|
||||
new LinkedHashMap<String, Attribute>();
|
||||
|
||||
public Attribute add(Attribute a) { return attributes.put(a.name, a); }
|
||||
public Attribute get(String name) { return attributes.get(name); }
|
||||
|
||||
public String getName() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.antlr.v4.Tool;
|
|||
import org.antlr.v4.parse.ANTLRLexer;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.antlr.v4.parse.GrammarASTAdaptor;
|
||||
import org.stringtemplate.v4.misc.MultiMap;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -20,6 +21,19 @@ public class Grammar {
|
|||
}
|
||||
};
|
||||
|
||||
public static Map<String, AttributeScope> grammarAndLabelRefTypeToScope =
|
||||
new HashMap<String, AttributeScope>() {{
|
||||
put("lexer:RULE_LABEL", Rule.predefinedLexerRulePropertiesScope);
|
||||
put("lexer:LEXER_STRING_LABEL", Rule.predefinedLexerRulePropertiesScope);
|
||||
put("parser:RULE_LABEL", Rule.predefinedRulePropertiesScope);
|
||||
put("parser:TOKEN_LABEL", AttributeScope.predefinedTokenScope);
|
||||
put("tree:RULE_LABEL", Rule.predefinedTreeRulePropertiesScope);
|
||||
put("tree:TOKEN_LABEL", AttributeScope.predefinedTokenScope);
|
||||
put("tree:WILDCARD_TREE_LABEL", AttributeScope.predefinedTokenScope);
|
||||
put("combined:RULE_LABEL", Rule.predefinedRulePropertiesScope);
|
||||
put("combined:TOKEN_LABEL", AttributeScope.predefinedTokenScope);
|
||||
}};
|
||||
|
||||
public Tool tool;
|
||||
public String name;
|
||||
public GrammarRootAST ast;
|
||||
|
|
|
@ -32,7 +32,7 @@ public class LabelElementPair {
|
|||
// now reset if lexer and string
|
||||
if ( g.getType() == ANTLRParser.LEXER ) {
|
||||
if ( element.getFirstDescendantWithType(ANTLRParser.STRING_LITERAL)!=null ) {
|
||||
if ( labelOp==ANTLRParser.ASSIGN ) type = LabelType.CHAR_LABEL;
|
||||
if ( labelOp==ANTLRParser.ASSIGN ) type = LabelType.LEXER_STRING_LABEL;
|
||||
}
|
||||
}
|
||||
else if ( g.getType() == ANTLRParser.TREE ) {
|
||||
|
|
|
@ -6,7 +6,7 @@ public enum LabelType {
|
|||
TOKEN_LABEL,
|
||||
RULE_LIST_LABEL,
|
||||
TOKEN_LIST_LABEL,
|
||||
CHAR_LABEL, // used in lexer for x='a'
|
||||
LEXER_STRING_LABEL, // used in lexer for x='a'
|
||||
SUBRULE_LABEL, // x=(...)
|
||||
SUBRULE_LIST_LABEL, // x+=(...)
|
||||
WILDCARD_TREE_LABEL, // Used in tree grammar x=.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.antlr.v4.tool;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.v4.parse.ANTLRParser;
|
||||
import org.stringtemplate.v4.misc.MultiMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -9,6 +10,39 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
public class Rule {
|
||||
/** Rule refs have a predefined set of attributes as well as
|
||||
* the return values and args.
|
||||
*/
|
||||
public static AttributeScope predefinedRulePropertiesScope =
|
||||
new AttributeScope() {{
|
||||
add(new Attribute("text"));
|
||||
add(new Attribute("start"));
|
||||
add(new Attribute("stop"));
|
||||
add(new Attribute("tree"));
|
||||
add(new Attribute("st"));
|
||||
}};
|
||||
|
||||
public static AttributeScope predefinedTreeRulePropertiesScope =
|
||||
new AttributeScope() {{
|
||||
add(new Attribute("text"));
|
||||
add(new Attribute("start")); // note: no stop; not meaningful
|
||||
add(new Attribute("tree"));
|
||||
add(new Attribute("st"));
|
||||
}};
|
||||
|
||||
public static AttributeScope predefinedLexerRulePropertiesScope =
|
||||
new AttributeScope() {{
|
||||
add(new Attribute("text"));
|
||||
add(new Attribute("type"));
|
||||
add(new Attribute("line"));
|
||||
add(new Attribute("index"));
|
||||
add(new Attribute("pos"));
|
||||
add(new Attribute("channel"));
|
||||
add(new Attribute("start"));
|
||||
add(new Attribute("stop"));
|
||||
add(new Attribute("int"));
|
||||
}};
|
||||
|
||||
public String name;
|
||||
public GrammarASTWithOptions ast;
|
||||
public AttributeScope args;
|
||||
|
@ -16,6 +50,7 @@ public class Rule {
|
|||
public AttributeScope scope;
|
||||
/** A list of scope names used by this rule */
|
||||
public List<Token> useScopes;
|
||||
public Grammar g;
|
||||
|
||||
/** Map a name to an action for this rule like @init {...}.
|
||||
* The code generator will use this to fill holes in the rule template.
|
||||
|
@ -25,13 +60,8 @@ public class Rule {
|
|||
public Map<String, GrammarAST> namedActions =
|
||||
new HashMap<String, GrammarAST>();
|
||||
|
||||
/** Track all executable actions other than named actions like @init
|
||||
* including catch/finally so we can sniff attribute expressions.
|
||||
* Also tracks exception handlers, predicates, and rewrite rewrites.
|
||||
* We need to examine these actions before code generation so
|
||||
* that we can detect refs to $rule.attr etc...
|
||||
*/
|
||||
public List<GrammarAST> inlineActions = new ArrayList<GrammarAST>();
|
||||
/** Track exception handlers, finally action */
|
||||
public List<GrammarAST> exceptionActions = new ArrayList<GrammarAST>();
|
||||
|
||||
public int numberOfAlts;
|
||||
|
||||
|
@ -44,7 +74,8 @@ public class Rule {
|
|||
|
||||
public Alternative[] alt;
|
||||
|
||||
public Rule(String name, GrammarASTWithOptions ast, int numberOfAlts) {
|
||||
public Rule(Grammar g, String name, GrammarASTWithOptions ast, int numberOfAlts) {
|
||||
this.g = g;
|
||||
this.name = name;
|
||||
this.ast = ast;
|
||||
this.numberOfAlts = numberOfAlts;
|
||||
|
@ -52,6 +83,60 @@ public class Rule {
|
|||
for (int i=1; i<=numberOfAlts; i++) alt[i] = new Alternative();
|
||||
}
|
||||
|
||||
public boolean resolves(String name, Alternative alt) {
|
||||
Attribute a = resolve(name);
|
||||
if ( a!=null ) return true; // ok
|
||||
if ( alt.tokenRefs.get(name)!=null||
|
||||
alt.ruleRefs.get(name)!=null ||
|
||||
alt.labelDefs.get(name)!=null )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Look up name from context of this rule and an alternative.
|
||||
* Find an arg, retval, predefined property, or label/rule/token ref.
|
||||
*/
|
||||
public Attribute resolve(String name) {
|
||||
Attribute a = args.get(name); if ( a!=null ) return a;
|
||||
a = retvals.get(name); if ( a!=null ) return a;
|
||||
String grammarLabelKey = g.getTypeString() + ":" + LabelType.RULE_LABEL;
|
||||
AttributeScope properties =
|
||||
Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
|
||||
a = properties.get(name);
|
||||
if ( a!=null ) return a;
|
||||
|
||||
//alt[currentAlt].tokenRefs
|
||||
// not here? look in grammar for global scope
|
||||
return null;
|
||||
}
|
||||
|
||||
public AttributeScope resolveScope(String name, Alternative alt) {
|
||||
AttributeScope s = args; if ( s.get(name)!=null ) return s;
|
||||
s = retvals; if ( s.get(name)!=null ) return s;
|
||||
s = retvals; if ( s.get(name)!=null ) return s;
|
||||
String grammarLabelKey = g.getTypeString() + ":" + LabelType.RULE_LABEL;
|
||||
s = Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
|
||||
if ( s.get(name)!=null ) return s;
|
||||
if ( alt.tokenRefs.get(name)!=null ) {
|
||||
grammarLabelKey = g.getTypeString() + ":" + LabelType.TOKEN_LABEL;
|
||||
return Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
|
||||
}
|
||||
if ( alt.ruleRefs.get(name)!=null ) {
|
||||
grammarLabelKey = g.getTypeString() + ":" + LabelType.RULE_LABEL;
|
||||
return Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
|
||||
}
|
||||
List<LabelElementPair> labels = labelDefs.get(name);
|
||||
if ( labels!=null ) {
|
||||
// it's a label ref, compute scope from label type and grammar type
|
||||
LabelElementPair anyLabelDef = labels.get(0);
|
||||
grammarLabelKey = g.getTypeString() + ":" + anyLabelDef.type;
|
||||
return Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Rule{" +
|
||||
|
|
Loading…
Reference in New Issue