added {...} as option value. <fail={"value must be <= "+$max}>

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9303]
This commit is contained in:
parrt 2011-11-12 12:47:11 -08:00
parent 91ccd76e65
commit e6d316f3e9
20 changed files with 288 additions and 133 deletions

View File

@ -412,7 +412,7 @@ setState(<m.stateNumber>); match(Token.UP);
>>
InvokeRule(r, argExprsChunks) ::= <<
setState(<r.stateNumber>); <if(r.labels)><r.labels:{l | <labelref(l)> = }><endif><r.name>(<argExprsChunks:{e| <e>}>);
setState(<r.stateNumber>); <if(r.labels)><r.labels:{l | <labelref(l)> = }><endif><r.name>(<argExprsChunks>);
>>
MatchToken(m) ::= <<
@ -446,9 +446,9 @@ ForcedAction(a, chunks) ::= "<chunks>"
ArgAction(a, chunks) ::= "<chunks>"
SemPred(p, chunks) ::= <<
SemPred(p, chunks, failChunks) ::= <<
setState(<p.stateNumber>);
if (!(<chunks>)) throw new FailedPredicateException(this, "<p.msg>");
if (!(<chunks>)) throw new FailedPredicateException(this, <if(p.msg)><p.msg><else><failChunks><endif>);
>>
ActionText(t) ::= "<t.text>"

View File

@ -507,7 +507,7 @@ public class ParserATNFactory implements ATNFactory {
public boolean isGreedy(BlockAST blkAST) {
boolean greedy = true;
String greedyOption = blkAST.getOption("greedy");
String greedyOption = blkAST.getOptionString("greedy");
if ( blockHasWildcardAlt(blkAST) || greedyOption!=null&&greedyOption.equals("false") ) {
greedy = false;
}

View File

@ -32,16 +32,12 @@ 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.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.*;
import org.stringtemplate.v4.*;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
/** General controller for code gen. Can instantiate sub generator(s).
*/
@ -60,7 +56,7 @@ public class CodeGenerator {
public int lineWidth = 72;
public CodeGenerator(Grammar g) {
this(g.tool, g, g.getOption("language", "Java"));
this(g.tool, g, g.getOptionString("language", "Java"));
}
public CodeGenerator(Tool tool, Grammar g, String language) {

View File

@ -212,6 +212,7 @@ elementOption
| ^(ASSIGN ID ID)
| ^(ASSIGN ID STRING_LITERAL)
| ^(ASSIGN ID DOUBLE_QUOTE_STRING_LITERAL)
| ^(ASSIGN ID ACTION)
;
// R E W R I T E S T U F F

View File

@ -31,10 +31,8 @@ package org.antlr.v4.codegen;
import org.antlr.v4.codegen.model.RuleFunction;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.runtime.*;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.GrammarAST;
import org.stringtemplate.v4.ST;
@ -179,6 +177,130 @@ public class Target {
return buf.toString();
}
/** Given a random string of Java unicode chars, return a new string with
* optionally appropriate quote characters for target language and possibly
* with some escaped characters. For example, if the incoming string has
* actual newline characters, the output of this method would convert them
* to the two char sequence \n for Java, C, C++, ... The new string has
* double-quotes around it as well. Example String in memory:
*
* a"[newlinechar]b'c[carriagereturnchar]d[tab]e\f
*
* would be converted to the valid Java s:
*
* "a\"\nb'c\rd\te\\f"
*
* or
*
* a\"\nb'c\rd\te\\f
*
* depending on the quoted arg.
*/
public String getTargetStringLiteralFromString(String s, boolean quoted) {
if ( s==null ) {
return null;
}
StringBuffer buf = new StringBuffer();
if ( quoted ) {
buf.append('"');
}
for (int i=0; i<s.length(); i++) {
int c = s.charAt(i);
if ( c!='\'' && // don't escape single quotes in strings for java
c<targetCharValueEscape.length &&
targetCharValueEscape[c]!=null )
{
buf.append(targetCharValueEscape[c]);
}
else {
buf.append((char)c);
}
}
if ( quoted ) {
buf.append('"');
}
return buf.toString();
}
public String getTargetStringLiteralFromString(String s) {
return getTargetStringLiteralFromString(s, false);
}
/** Convert from an ANTLR string literal found in a grammar file to
* an equivalent string literal in the target language. For Java, this
* is the translation 'a\n"' -> "a\n\"". Expect single quotes
* around the incoming literal. Just flip the quotes and replace
* double quotes with \"
*
* Note that we have decided to allow poeple to use '\"' without
* penalty, so we must build the target string in a loop as Utils.replae
* cannot handle both \" and " without a lot of messing around.
*
*/
public String getTargetStringLiteralFromANTLRStringLiteral(
CodeGenerator generator,
String literal)
{
StringBuilder sb = new StringBuilder();
StringBuffer is = new StringBuffer(literal);
// Opening quote
//
sb.append('"');
for (int i = 1; i < is.length() -1; i++) {
if (is.charAt(i) == '\\') {
// Anything escaped is what it is! We assume that
// people know how to escape characters correctly. However
// we catch anything that does not need an escape in Java (which
// is what the default implementation is dealing with and remove
// the escape. The C target does this for instance.
//
switch (is.charAt(i+1)) {
// Pass through any escapes that Java also needs
//
case '"':
case 'n':
case 'r':
case 't':
case 'b':
case 'f':
case '\\':
case 'u': // Assume unnnn
sb.append('\\'); // Pass the escape through
break;
default:
// Remove the escape by virtue of not adding it here
// Thus \' becomes ' and so on
//
break;
}
// Go past the \ character
//
i++;
} else {
// Chracters that don't need \ in ANTLR 'strings' but do in Java
//
if (is.charAt(i) == '"') {
// We need to escape " in Java
//
sb.append('\\');
}
}
// Add in the next character, which may have been escaped
//
sb.append(is.charAt(i));
}
// Append closing " and return
//
sb.append('"');
return sb.toString();
}
/** Assume 16-bit char */
public String encodeIntAsCharEscape(int v) {
if ( v>=0 && v<=127 ) {

View File

@ -65,6 +65,6 @@ public class Parser extends OutputModelObject {
ruleNames = g.rules.keySet();
rules = g.rules.values();
atn = new SerializedATN(factory, g.atn);
superclass = g.getOption("superClass", "Parser");
superclass = g.getOptionString("superClass", "Parser");
}
}

View File

@ -33,8 +33,7 @@ import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.ast.GrammarAST;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
/** */
public class ParserFile extends OutputModelObject {
@ -49,8 +48,8 @@ public class ParserFile extends OutputModelObject {
super(factory);
this.fileName = fileName;
Grammar g = factory.getGrammar();
TokenLabelType = g.getOption("TokenLabelType");
ASTLabelType = g.getOption("ASTLabelType", "CommonAST");
TokenLabelType = g.getOptionString("TokenLabelType");
ASTLabelType = g.getOptionString("ASTLabelType", "CommonAST");
namedActions = new HashMap<String, Action>();
for (String name : g.namedActions.keySet()) {
GrammarAST ast = g.namedActions.get(name);

View File

@ -30,15 +30,11 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.decl.AltLabelStructDecl;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.StructDecl;
import org.antlr.v4.codegen.model.decl.TreeParserStructDecl;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.misc.Utils;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.GrammarAST;
import java.util.*;
@ -97,8 +93,8 @@ public class RuleFunction extends OutputModelObject {
if ( r.retvals!=null ) {
ruleCtx.addDecls(r.retvals.attributes.values());
}
if ( r.scope!=null ) {
ruleCtx.addDecls(r.scope.attributes.values());
if ( r.locals!=null ) {
ruleCtx.addDecls(r.locals.attributes.values());
}
ruleLabels = r.getElementLabelNames();

View File

@ -29,18 +29,38 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.*;
import org.antlr.v4.codegen.model.actions.ActionChunk;
import org.antlr.v4.tool.ast.*;
import java.util.List;
/** */
public class SemPred extends Action {
public String msg; // user-specified in grammar option
@ModelElement public List<ActionChunk> failChunks;
public SemPred(OutputModelFactory factory, GrammarAST ast) {
super(factory,ast);
this.msg = ((PredAST)ast).getOption("fail");
if ( msg==null ) {
GrammarAST failNode = ((PredAST)ast).getOption("fail");
CodeGenerator gen = factory.getGenerator();
if ( failNode==null ) {
msg = "failed predicate: "+ast.getText();
msg = gen.target.getTargetStringLiteralFromString(msg);
return;
}
if ( failNode instanceof ActionAST ) {
ActionAST failActionNode = (ActionAST)failNode;
RuleFunction rf = factory.getCurrentRuleFunction();
failChunks = ActionTranslator.translateAction(factory, rf,
failActionNode.token,
failActionNode);
}
else {
msg = gen.target.getTargetStringLiteralFromANTLRStringLiteral(gen,
failNode.getText());
}
}
}

View File

@ -36,6 +36,6 @@ public class TreeParserModel extends Parser {
public TreeParserModel(OutputModelFactory factory, ParserFile file) {
super(factory, file);
Grammar g = factory.getGrammar();
superclass = g.getOption("superClass", "TreeParser");
superclass = g.getOptionString("superClass", "TreeParser");
}
}

View File

@ -271,22 +271,11 @@ optionValue
: // If the option value is a single word that conforms to the
// lexical rules of token or rule names, then the user may skip quotes
// and so on. Many option values meet this description
//
qid
| // The value is a long string
//
STRING_LITERAL
| STRING_LITERAL
| DOUBLE_QUOTE_STRING_LITERAL
| // The value was an integer number
//
INT
| // Asterisk, used for things like k=*
//
STAR
| ACTION<ActionAST>
| INT
;
// A list of grammars to which this grammar will delegate certain
@ -849,9 +838,7 @@ elementOptions
elementOption
: // This format indicates the default element option
qid
| // This format indicates option assignment
id ASSIGN^ (qid | STRING_LITERAL | DOUBLE_QUOTE_STRING_LITERAL)
| id ASSIGN^ optionValue
;
rewrite

View File

@ -122,9 +122,9 @@ public void discoverGrammar(GrammarRootAST root, GrammarAST ID) { }
public void finishPrequels(GrammarAST firstPrequel) { }
public void finishGrammar(GrammarRootAST root, GrammarAST ID) { }
public void grammarOption(GrammarAST ID, String value) { }
public void ruleOption(GrammarAST ID, String value) { }
public void blockOption(GrammarAST ID, String value) { }
public void grammarOption(GrammarAST ID, GrammarAST valueAST) { }
public void ruleOption(GrammarAST ID, GrammarAST valueAST) { }
public void blockOption(GrammarAST ID, GrammarAST valueAST) { }
public void tokenAlias(GrammarAST ID, GrammarAST literal) { }
public void globalNamedAction(GrammarAST scope, GrammarAST ID, ActionAST action) { }
public void importGrammar(GrammarAST label, GrammarAST ID) { }
@ -135,7 +135,8 @@ public void discoverRules(GrammarAST rules) { }
public void finishRules(GrammarAST rule) { }
public void discoverRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers,
ActionAST arg, ActionAST returns, GrammarAST thrws,
GrammarAST options, List<GrammarAST> actions,
GrammarAST options, GrammarAST locals,
List<GrammarAST> actions,
GrammarAST block) { }
public void finishRule(GrammarAST rule, GrammarAST ID, GrammarAST block) { }
public void ruleCatch(GrammarAST arg, ActionAST action) { }
@ -153,7 +154,7 @@ public void discoverTreeRewrite(GrammarAST rew) { }
public void ruleRef(GrammarAST ref, ActionAST arg) { }
public void tokenRef(TerminalAST ref) { }
public void elementOption(GrammarASTWithOptions t, GrammarAST ID, GrammarAST value) { }
public void elementOption(GrammarASTWithOptions t, GrammarAST ID, GrammarAST valueAST) { }
public void stringRef(TerminalAST ref) { }
public void wildcardRef(GrammarAST ref) { }
public void actionInAlt(ActionAST action) { }
@ -212,11 +213,11 @@ option
boolean rule = inContext("RULE ...");
boolean block = inContext("BLOCK ...");
}
: ^(a=ASSIGN ID optionValue)
: ^(a=ASSIGN ID v=optionValue)
{
if ( block ) blockOption($ID, $optionValue.v); // most specific first
else if ( rule ) ruleOption($ID, $optionValue.v);
else grammarOption($ID, $optionValue.v);
if ( block ) blockOption($ID, $v.start); // most specific first
else if ( rule ) ruleOption($ID, $v.start);
else grammarOption($ID, $v.start);
}
;
@ -226,7 +227,6 @@ optionValue returns [String v]
| STRING_LITERAL
| DOUBLE_QUOTE_STRING_LITERAL
| INT
| STAR
;
delegateGrammars
@ -274,7 +274,9 @@ currentOuterAltNumber=0;
)*
{discoverRule((RuleAST)$RULE, $ID, mods, (ActionAST)$ARG_ACTION,
$ret.start!=null?(ActionAST)$ret.start.getChild(0):null,
$thr.start, $opts.start, actions, (GrammarAST)input.LT(1));}
$thr.start, $opts.start,
$loc.start!=null?(ActionAST)$loc.start.getChild(0):null,
actions, (GrammarAST)input.LT(1));}
ruleBlock exceptionGroup
{finishRule($RULE, $ID, $ruleBlock.start); currentRuleName=null; currentRuleAST=null;}
)
@ -456,6 +458,7 @@ elementOption[GrammarASTWithOptions t]
| ^(ASSIGN id=ID v=ID) {elementOption(t, $id, $v);}
| ^(ASSIGN ID v=STRING_LITERAL) {elementOption(t, $ID, $v);}
| ^(ASSIGN ID v=DOUBLE_QUOTE_STRING_LITERAL) {elementOption(t, $ID, $v);}
| ^(ASSIGN ID v=ACTION) {elementOption(t, $ID, $v);}
;
rewrite

View File

@ -29,18 +29,13 @@
package org.antlr.v4.parse;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.TokenStream;
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.AttributeDict;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.GrammarASTWithOptions;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import org.stringtemplate.v4.*;
import java.util.*;
@ -97,7 +92,7 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
ASSOC assoc = ASSOC.left;
if ( t instanceof GrammarASTWithOptions ) {
if ( ((GrammarASTWithOptions)t).getOptions()!=null ) {
String a = ((GrammarASTWithOptions)t).getOption("assoc");
String a = ((GrammarASTWithOptions)t).getOptionString("assoc");
if ( a!=null ) {
if ( a.equals(ASSOC.right.toString()) ) {
assoc = ASSOC.right;
@ -351,7 +346,7 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
if ( retvals==null ) return;
// complicated since we must be target-independent
AttributeDict args = ScopeParser.parseTypeList(retvals.token.getText());
AttributeDict args = ScopeParser.parseTypedArgList(retvals.token.getText());
for (String name : args.attributes.keySet()) {
ST setRetValST =

View File

@ -56,7 +56,7 @@ public class ScopeParser {
*
* convert to an attribute scope.
*/
public static AttributeDict parseTypeList(String s) { return parse(s, ','); }
public static AttributeDict parseTypedArgList(String s) { return parse(s, ','); }
public static AttributeDict parse(String s, char separator) {
int i = 0;

View File

@ -173,7 +173,7 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
@Override
public void finishGrammar(GrammarRootAST root, GrammarAST ID) {
checkTreeFilterOptions(root, g.ast.getOptions());
checkTreeFilterOptions(root);
}
@Override
@ -211,6 +211,7 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
List<GrammarAST> modifiers,
ActionAST arg, ActionAST returns,
GrammarAST thrws, GrammarAST options,
GrammarAST locals,
List<GrammarAST> actions, GrammarAST block)
{
// TODO: chk that all or no alts have "# label"
@ -223,16 +224,15 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
@Override
public void grammarOption(GrammarAST ID, String value) {
boolean ok = checkOptions(g.ast, ID.token, value);
public void grammarOption(GrammarAST ID, GrammarAST valueAST) {
boolean ok = checkOptions(g.ast, ID.token, valueAST);
//if ( ok ) g.ast.setOption(ID.getText(), value);
}
@Override
public void elementOption(GrammarASTWithOptions elem, GrammarAST ID, GrammarAST value) {
public void elementOption(GrammarASTWithOptions elem, GrammarAST ID, GrammarAST valueAST) {
String v = null;
if ( value!=null ) v = value.getText();
boolean ok = checkElementOptions(elem, ID, v);
boolean ok = checkElementOptions(elem, ID, valueAST);
// if ( ok ) {
// if ( v!=null ) {
// t.setOption(ID.getText(), v);
@ -246,29 +246,29 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
@Override
public void discoverAltWithRewrite(AltAST alt) {
GrammarAST firstNode = (GrammarAST)alt.getChild(0);
checkRewriteForMultiRootAltInTreeGrammar(g.ast.getOptions(),
checkRewriteForMultiRootAltInTreeGrammar(g.ast,
firstNode.token,
currentOuterAltNumber);
}
@Override
public void rootOp(GrammarAST op, GrammarAST opnd) {
checkASTOps(g.ast.getOptions(), op, opnd);
checkASTOps(g.ast, op, opnd);
}
@Override
public void bangOp(GrammarAST op, GrammarAST opnd) {
checkASTOps(g.ast.getOptions(), op, opnd);
checkASTOps(g.ast, op, opnd);
}
@Override
public void discoverTreeRewrite(GrammarAST rew) {
checkRewriteOk(g.ast.getOptions(), rew);
checkRewriteOk(g.ast, rew);
}
@Override
public void discoverSTRewrite(GrammarAST rew) {
checkRewriteOk(g.ast.getOptions(), rew);
checkRewriteOk(g.ast, rew);
}
@Override
@ -371,7 +371,7 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
/** Check option is appropriate for grammar, rule, subrule */
boolean checkOptions(GrammarAST parent,
Token optionID, String value)
Token optionID, GrammarAST valueAST)
{
boolean ok = true;
if ( parent.getType()==ANTLRParser.BLOCK ) {
@ -405,9 +405,11 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
/** Check option is appropriate for elem; parent of ID is ELEMENT_OPTIONS */
boolean checkElementOptions(GrammarASTWithOptions elem, GrammarAST ID, String value) {
boolean checkElementOptions(GrammarASTWithOptions elem, GrammarAST ID,
GrammarAST valueAST)
{
if ( elem instanceof TerminalAST ) {
return checkTokenOptions((TerminalAST)elem, ID, value);
return checkTokenOptions((TerminalAST)elem, ID, valueAST);
}
if ( elem.getType()==ANTLRParser.ACTION ) {
return false;
@ -415,7 +417,7 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
if ( elem.getType()==ANTLRParser.SEMPRED ) {
Token optionID = ID.token;
String fileName = optionID.getInputStream().getSourceName();
if ( value!=null && !legalSemPredOptions.contains(optionID.getText()) ) {
if ( valueAST!=null && !legalSemPredOptions.contains(optionID.getText()) ) {
g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
fileName,
optionID,
@ -427,11 +429,11 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
boolean checkTokenOptions(TerminalAST elem, GrammarAST ID, String value) {
boolean checkTokenOptions(TerminalAST elem, GrammarAST ID, GrammarAST valueAST) {
Token optionID = ID.token;
String fileName = optionID.getInputStream().getSourceName();
// don't care about ID<ASTNodeName> options
if ( value!=null && !legalTokenOptions.contains(optionID.getText()) ) {
if ( valueAST!=null && !legalTokenOptions.contains(optionID.getText()) ) {
g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
fileName,
optionID,
@ -467,15 +469,15 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
* that match either nodes or trees.
*/
void checkRewriteForMultiRootAltInTreeGrammar(
Map<String, String> options,
GrammarRootAST root,
Token altStart,
int alt)
{
if ( g.isTreeGrammar() &&
options!=null && options.get("output")!=null &&
options.get("output").equals("template") &&
options.get("rewrite")!=null &&
options.get("rewrite").equals("true") )
root.getOptions()!=null && root.getOptionString("output")!=null &&
root.getOptionString("output").equals("template") &&
root.getOptionString("rewrite")!=null &&
root.getOptionString("rewrite").equals("true") )
{
String fileName = altStart.getInputStream().getSourceName();
g.tool.errMgr.grammarError(ErrorType.REWRITE_FOR_MULTI_ELEMENT_ALT,
@ -485,20 +487,20 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
}
void checkASTOps(Map<String, String> options,
void checkASTOps(GrammarRootAST root,
GrammarAST op,
GrammarAST elementRoot)
{
RuleAST rule = (RuleAST)op.getAncestor(ANTLRParser.RULE);
String ruleName = rule.getChild(0).getText();
String fileName = elementRoot.token.getInputStream().getSourceName();
if ( options==null || !options.get("output").equals("AST") ) {
if ( root.getOptions()==null || !root.getOptionString("output").equals("AST") ) {
g.tool.errMgr.grammarError(ErrorType.AST_OP_WITH_NON_AST_OUTPUT_OPTION,
fileName,
elementRoot.token,
op.getText());
}
if ( options!=null && options.get("output")==null ) {
if ( root.getOptions()!=null && root.getOptionString("output")==null ) {
g.tool.errMgr.grammarError(ErrorType.REWRITE_OR_OP_WITH_NO_OUTPUT_OPTION,
fileName,
elementRoot.token,
@ -515,10 +517,10 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
}
void checkRewriteOk(Map<String, String> options, GrammarAST elementRoot) {
void checkRewriteOk(GrammarRootAST root, GrammarAST elementRoot) {
String ruleName = currentRuleAST.getChild(0).getText();
String fileName = elementRoot.token.getInputStream().getSourceName();
if ( options!=null && options.get("output")==null ) {
if ( root.getOptions()!=null && root.getOptionString("output")==null ) {
g.tool.errMgr.grammarError(ErrorType.REWRITE_OR_OP_WITH_NO_OUTPUT_OPTION,
fileName,
elementRoot.token,
@ -526,21 +528,19 @@ public class BasicSemanticChecks extends GrammarTreeVisitor {
}
}
void checkTreeFilterOptions(GrammarRootAST root,
Map<String, String> options)
{
if ( options==null ) return;
void checkTreeFilterOptions(GrammarRootAST root) {
if ( root.getOptions()==null ) return;
String fileName = root.token.getInputStream().getSourceName();
String filter = options.get("filter");
String filter = root.getOptionString("filter");
if ( g.isTreeGrammar() && filter!=null && filter.equals("true") ) {
// check for conflicting options
// filter => backtrack=true (can't be false)
// filter&&output!=AST => error
// filter&&output=AST => rewrite=true
// any deviation from valid option set is an error
String backtrack = options.get("backtrack");
String output = options.get("output");
String rewrite = options.get("rewrite");
String backtrack = root.getOptionString("backtrack");
String output = root.getOptionString("output");
String rewrite = root.getOptionString("rewrite");
if ( backtrack!=null && !backtrack.toString().equals("true") ) {
g.tool.errMgr.grammarError(ErrorType.CONFLICTING_OPTION_IN_TREE_FILTER,
fileName,

View File

@ -100,7 +100,8 @@ public class SymbolCollector extends GrammarTreeVisitor {
public void discoverRule(RuleAST rule, GrammarAST ID,
List<GrammarAST> modifiers, ActionAST arg,
ActionAST returns, GrammarAST thrws,
GrammarAST options, List<GrammarAST> actions,
GrammarAST options, GrammarAST locals,
List<GrammarAST> actions,
GrammarAST block)
{
int numAlts = block.getChildCount();
@ -111,18 +112,24 @@ public class SymbolCollector extends GrammarTreeVisitor {
currentRule = r;
if ( arg!=null ) {
r.args = ScopeParser.parseTypeList(arg.getText());
r.args = ScopeParser.parseTypedArgList(arg.getText());
r.args.type = AttributeDict.DictType.ARG;
r.args.ast = arg;
arg.resolver = r.alt[currentOuterAltNumber];
}
if ( returns!=null ) {
r.retvals = ScopeParser.parseTypeList(returns.getText());
r.retvals = ScopeParser.parseTypedArgList(returns.getText());
r.retvals.type = AttributeDict.DictType.RET;
r.retvals.ast = returns;
}
if ( locals!=null ) {
r.locals = ScopeParser.parseTypedArgList(locals.getText());
r.locals.type = AttributeDict.DictType.LOCAL;
r.locals.ast = returns;
}
for (GrammarAST a : actions) {
// a = ^(AT ID ACTION)
ActionAST action = (ActionAST) a.getChild(1);
@ -218,4 +225,31 @@ public class SymbolCollector extends GrammarTreeVisitor {
public void rewriteAction(ActionAST ast) {
ast.resolver = currentRule.alt[currentOuterAltNumber];
}
@Override
public void grammarOption(GrammarAST ID, GrammarAST valueAST) {
setActionResolver(valueAST);
}
@Override
public void ruleOption(GrammarAST ID, GrammarAST valueAST) {
setActionResolver(valueAST);
}
@Override
public void blockOption(GrammarAST ID, GrammarAST valueAST) {
setActionResolver(valueAST);
}
@Override
public void elementOption(GrammarASTWithOptions t, GrammarAST ID, GrammarAST valueAST) {
setActionResolver(valueAST);
}
/** In case of option id={...}, set resolve in case they use $foo */
private void setActionResolver(GrammarAST valueAST) {
if ( valueAST instanceof ActionAST) {
((ActionAST)valueAST).resolver = currentRule.alt[currentOuterAltNumber];
}
}
}

View File

@ -511,7 +511,7 @@ public class Grammar implements AttributeResolver {
}
public void importTokensFromTokensFile() {
String vocab = getOption("tokenVocab");
String vocab = getOptionString("tokenVocab");
if ( vocab!=null ) {
TokenVocabParser vparser = new TokenVocabParser(tool, vocab);
Map<String,Integer> tokens = vparser.load();
@ -666,16 +666,17 @@ public class Grammar implements AttributeResolver {
}
}
public String getOption(String key) { return ast.getOption(key); }
public String getOptionString(String key) { return ast.getOptionString(key); }
public GrammarAST getOption(String key) { return ast.getOption(key); }
public String getOption(String key, String defaultValue) {
String v = ast.getOption(key);
public String getOptionString(String key, String defaultValue) {
String v = ast.getOptionString(key);
if ( v!=null ) return v;
return defaultValue;
}
public boolean hasASTOption() {
String outputOption = getOption("output");
String outputOption = getOptionString("output");
return outputOption!=null && outputOption.equals("AST");
}
@ -707,7 +708,7 @@ public class Grammar implements AttributeResolver {
for (Object o : options.getChildren()) {
GrammarAST c = (GrammarAST)o;
if ( c.getType()==ANTLRParser.ASSIGN ) {
t.setOption(c.getChild(0).getText(), c.getChild(1).getText());
t.setOption(c.getChild(0).getText(), (GrammarAST)c.getChild(1));
}
else {
t.setOption(c.getText(), null); // no arg such as ID<VarNodeType>

View File

@ -31,9 +31,7 @@ package org.antlr.v4.tool;
import org.antlr.runtime.*;
import org.antlr.runtime.misc.DoubleKeyMap;
import org.antlr.runtime.tree.Tree;
import org.antlr.runtime.tree.TreeVisitor;
import org.antlr.runtime.tree.TreeVisitorAction;
import org.antlr.runtime.tree.*;
import org.antlr.v4.Tool;
import org.antlr.v4.parse.*;
import org.antlr.v4.tool.ast.*;
@ -112,7 +110,7 @@ public class GrammarTransformPipeline {
List<String> rules = new ArrayList<String>();
rules.add( leftRecursiveRuleWalker.getArtificialPrecStartRule() ) ;
String outputOption = ast.getOption("output");
String outputOption = ast.getOptionString("output");
boolean buildAST = outputOption!=null && outputOption.equals("AST");
rules.add( leftRecursiveRuleWalker.getArtificialOpPrecRule(buildAST) );

View File

@ -30,12 +30,11 @@
package org.antlr.v4.tool.ast;
import org.antlr.runtime.Token;
import org.antlr.v4.misc.CharSupport;
import java.util.*;
public abstract class GrammarASTWithOptions extends GrammarAST {
protected Map<String, String> options;
protected Map<String, GrammarAST> options;
public GrammarASTWithOptions(GrammarAST node) {
super(node);
@ -47,15 +46,19 @@ public abstract class GrammarASTWithOptions extends GrammarAST {
public GrammarASTWithOptions(int type, Token t) { super(type, t); }
public GrammarASTWithOptions(int type, Token t, String text) { super(type,t,text); }
public void setOption(String key, String value) {
if ( options==null ) options = new HashMap<String, String>();
if ( value.startsWith("'") || value.startsWith("\"") ) {
value = CharSupport.getStringFromGrammarStringLiteral(value);
}
options.put(key, value);
public void setOption(String key, GrammarAST node) {
if ( options==null ) options = new HashMap<String, GrammarAST>();
// if ( value.startsWith("'") || value.startsWith("\"") ) {
// value = CharSupport.getStringFromGrammarStringLiteral(value);
// }
options.put(key, node);
}
public String getOption(String key) {
public String getOptionString(String key) {
return null;
}
public GrammarAST getOption(String key) {
if ( options==null ) return null;
return options.get(key);
}
@ -64,5 +67,5 @@ public abstract class GrammarASTWithOptions extends GrammarAST {
return options==null ? 0 : options.size();
}
public Map<String, String> getOptions() { return options; }
public Map<String, GrammarAST> getOptions() { return options; }
}

View File

@ -24,7 +24,7 @@ public class TestScopeParsing extends BaseTest {
for (int i = 0; i < argPairs.length; i+=2) {
String input = argPairs[i];
String expected = argPairs[i+1];
String actual = ScopeParser.parseTypeList(input).attributes.toString();
String actual = ScopeParser.parseTypedArgList(input).attributes.toString();
assertEquals(expected, actual);
}
}