从这个语法开始:https://stackoverflow.com/a/14287002/1082002,我会实现一个简单的语法,它接受和评估简单的语言,如下所示:
{
if a==c {
a
if a==b {
b
} else {
c
}
}
}因此,如果为a==c,则执行a并计算if a==b,如果为真,则执行b,否则为c。非常简单。
解析器语法和树语法如下:
TreeEvaluator.g (组合语法以生成AST)
grammar TreeEvaluator;
options {
output = AST;
}
tokens {
CONDBLOCK;
CODEBLOCK;
DEFAULT;
}
compilationUnit : block EOF -> block;
condition : cif elif* celse? -> ^(IF cif elif* celse?);
cif : IF expr block -> ^(CONDBLOCK expr block);
elif : ELIF expr block -> ^(CONDBLOCK expr block);
celse : ELSE block -> ^(DEFAULT block);
expr : ID EQ^ ID;
block : LCUR instruction* RCUR -> ^(CODEBLOCK instruction*);
instruction : ID | condition;
IF : 'if';
ELIF: 'elif';
ELSE: 'else';
LCUR: '{';
RCUR: '}';
EQ : '==';
ID : ('a'..'z'|'A'..'Z')+;
WS : (' '|'\t'|'\f'|'\r'|'\n')+ {skip();};AstTreeEvaluatorParser.g (树解析器)
tree grammar AstTreeEvaluatorParser;
options {
output = AST;
tokenVocab = TreeEvaluator;
ASTLabelType = CommonTree;
}
@members {
private static final class Evaluation {
boolean matched = false;
boolean done = false;
}
private java.util.HashMap<String, Integer> vars = new java.util.HashMap<String, Integer>();
public void addVar(String name, int value){
vars.put(name, value);
}
}
compilationUnit : block+;
block : ^(CODEBLOCK instruction*);
instruction : ifStat | ID;
ifStat
@init { Evaluation eval = new Evaluation(); }
: ^(IF condition[eval]* defcond[eval]?)
;
condition [Evaluation eval]
: ^(CONDBLOCK exp {if ($exp.value) eval.matched = true;} evalblock[eval])
;
defcond [Evaluation eval]
: ^(DEFAULT {eval.matched = true;} evalblock[eval]) //force a match
;
evalblock [Evaluation eval]
: {eval.matched && !eval.done}? //Only do this when a condition is matched but not finished
block //call the execution code
{eval.done = true;} //evaluation is complete.
| ^(CODEBLOCK .*) //read the code node and continue without executing
;
exp returns [boolean value]
: ^(EQ lhs=ID rhs=ID)
{$value = vars.get($lhs.getText()) == vars.get($rhs.getText());}
;问题是生成的用于预测规则evalblock的SpecialStateTransition(),这个DFA有一个引用参数eval (在规则中指定)的方法,但是在生成的Java类中,该参数是不可见的。
我不明白为什么,是否有办法避免这个问题。
发布于 2013-03-15 00:05:36
您有一个语义谓词(语法{...}?),其中包含对由操作(语法{...})更改的值的引用。在本例中,值是字段Evaluation.matched和Evaluation.done。
您应该完全避免这种情况-永远不要包含依赖于操作执行的谓词。相反,可以通过将操作代码包装在if (eval.matched && !eval.done) { ... }中来检查操作中的这些值
²有些人编写的语法以这种方式交互,但我严格避免了它,因为可能会出现像您所看到的那样的问题,以及其他更糟糕的问题。
https://stackoverflow.com/questions/15410973
复制相似问题