From e6d316f3e96444f66c1109ce518f6f1954d5f0fb Mon Sep 17 00:00:00 2001 From: parrt Date: Sat, 12 Nov 2011 12:47:11 -0800 Subject: [PATCH] added {...} as option value. ); match(Token.UP); >> InvokeRule(r, argExprsChunks) ::= << -setState(); = }>(}>); +setState(); = }>(); >> MatchToken(m) ::= << @@ -446,9 +446,9 @@ ForcedAction(a, chunks) ::= "" ArgAction(a, chunks) ::= "" -SemPred(p, chunks) ::= << +SemPred(p, chunks, failChunks) ::= << setState(); -if (!()) throw new FailedPredicateException(this, ""); +if (!()) throw new FailedPredicateException(this, ); >> ActionText(t) ::= "" diff --git a/tool/src/org/antlr/v4/automata/ParserATNFactory.java b/tool/src/org/antlr/v4/automata/ParserATNFactory.java index c2efd2025..6d7cc8176 100644 --- a/tool/src/org/antlr/v4/automata/ParserATNFactory.java +++ b/tool/src/org/antlr/v4/automata/ParserATNFactory.java @@ -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; } diff --git a/tool/src/org/antlr/v4/codegen/CodeGenerator.java b/tool/src/org/antlr/v4/codegen/CodeGenerator.java index a26578d5f..c1ec15556 100644 --- a/tool/src/org/antlr/v4/codegen/CodeGenerator.java +++ b/tool/src/org/antlr/v4/codegen/CodeGenerator.java @@ -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) { diff --git a/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g b/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g index 5cb35b7cb..80ad568d1 100644 --- a/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g +++ b/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g @@ -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 diff --git a/tool/src/org/antlr/v4/codegen/Target.java b/tool/src/org/antlr/v4/codegen/Target.java index 374b6d5ed..d1b175e57 100644 --- a/tool/src/org/antlr/v4/codegen/Target.java +++ b/tool/src/org/antlr/v4/codegen/Target.java @@ -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 "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 ) { diff --git a/tool/src/org/antlr/v4/codegen/model/Parser.java b/tool/src/org/antlr/v4/codegen/model/Parser.java index 6053aca3c..b91ae27e2 100644 --- a/tool/src/org/antlr/v4/codegen/model/Parser.java +++ b/tool/src/org/antlr/v4/codegen/model/Parser.java @@ -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"); } } diff --git a/tool/src/org/antlr/v4/codegen/model/ParserFile.java b/tool/src/org/antlr/v4/codegen/model/ParserFile.java index c787bbe63..81cd889e6 100644 --- a/tool/src/org/antlr/v4/codegen/model/ParserFile.java +++ b/tool/src/org/antlr/v4/codegen/model/ParserFile.java @@ -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(); for (String name : g.namedActions.keySet()) { GrammarAST ast = g.namedActions.get(name); diff --git a/tool/src/org/antlr/v4/codegen/model/RuleFunction.java b/tool/src/org/antlr/v4/codegen/model/RuleFunction.java index f2582922f..ac51a46ce 100644 --- a/tool/src/org/antlr/v4/codegen/model/RuleFunction.java +++ b/tool/src/org/antlr/v4/codegen/model/RuleFunction.java @@ -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(); diff --git a/tool/src/org/antlr/v4/codegen/model/SemPred.java b/tool/src/org/antlr/v4/codegen/model/SemPred.java index 5bed0fe80..41a23f570 100644 --- a/tool/src/org/antlr/v4/codegen/model/SemPred.java +++ b/tool/src/org/antlr/v4/codegen/model/SemPred.java @@ -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 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()); } } } diff --git a/tool/src/org/antlr/v4/codegen/model/TreeParserModel.java b/tool/src/org/antlr/v4/codegen/model/TreeParserModel.java index b2ec2365b..cd4b7b2fc 100644 --- a/tool/src/org/antlr/v4/codegen/model/TreeParserModel.java +++ b/tool/src/org/antlr/v4/codegen/model/TreeParserModel.java @@ -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"); } } diff --git a/tool/src/org/antlr/v4/parse/ANTLRParser.g b/tool/src/org/antlr/v4/parse/ANTLRParser.g index 2a0038330..168d6718a 100644 --- a/tool/src/org/antlr/v4/parse/ANTLRParser.g +++ b/tool/src/org/antlr/v4/parse/ANTLRParser.g @@ -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 + | 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 diff --git a/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g b/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g index 97d890769..97027b8ee 100644 --- a/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g +++ b/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g @@ -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 modifiers, ActionAST arg, ActionAST returns, GrammarAST thrws, - GrammarAST options, List actions, + GrammarAST options, GrammarAST locals, + List 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 diff --git a/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java b/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java index ff53d8637..6c25716c7 100644 --- a/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java +++ b/tool/src/org/antlr/v4/parse/LeftRecursiveRuleAnalyzer.java @@ -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 = diff --git a/tool/src/org/antlr/v4/parse/ScopeParser.java b/tool/src/org/antlr/v4/parse/ScopeParser.java index 494d0485f..d4cfcd276 100644 --- a/tool/src/org/antlr/v4/parse/ScopeParser.java +++ b/tool/src/org/antlr/v4/parse/ScopeParser.java @@ -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; diff --git a/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java b/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java index 9902c47ac..558c0d3cb 100644 --- a/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java +++ b/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java @@ -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 modifiers, ActionAST arg, ActionAST returns, GrammarAST thrws, GrammarAST options, + GrammarAST locals, List 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 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 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 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 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 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, diff --git a/tool/src/org/antlr/v4/semantics/SymbolCollector.java b/tool/src/org/antlr/v4/semantics/SymbolCollector.java index 012ca3e84..876fc985e 100644 --- a/tool/src/org/antlr/v4/semantics/SymbolCollector.java +++ b/tool/src/org/antlr/v4/semantics/SymbolCollector.java @@ -100,7 +100,8 @@ public class SymbolCollector extends GrammarTreeVisitor { public void discoverRule(RuleAST rule, GrammarAST ID, List modifiers, ActionAST arg, ActionAST returns, GrammarAST thrws, - GrammarAST options, List actions, + GrammarAST options, GrammarAST locals, + List 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]; + } + } } diff --git a/tool/src/org/antlr/v4/tool/Grammar.java b/tool/src/org/antlr/v4/tool/Grammar.java index f14f6bd34..cbdce3f2c 100644 --- a/tool/src/org/antlr/v4/tool/Grammar.java +++ b/tool/src/org/antlr/v4/tool/Grammar.java @@ -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 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 diff --git a/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java b/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java index 83d567cfa..8d3be88a9 100644 --- a/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java +++ b/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java @@ -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 rules = new ArrayList(); 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) ); diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java b/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java index 1b9850ba5..469f90450 100644 --- a/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java +++ b/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java @@ -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 options; + protected Map 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(); - 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(); +// 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 getOptions() { return options; } + public Map getOptions() { return options; } } diff --git a/tool/test/org/antlr/v4/test/TestScopeParsing.java b/tool/test/org/antlr/v4/test/TestScopeParsing.java index 3ed6008ba..8c93bd378 100644 --- a/tool/test/org/antlr/v4/test/TestScopeParsing.java +++ b/tool/test/org/antlr/v4/test/TestScopeParsing.java @@ -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); } }