forked from jasder/antlr
added {...} as option value. <fail={"value must be <= "+$max}>
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9303]
This commit is contained in:
parent
91ccd76e65
commit
e6d316f3e9
|
@ -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>"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) );
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue