我为类似Scheme的语言解释器创建了一个语法。最初,我有一个if-then-else语句的语义谓词来控制评估,即当条件为真时,只评估'then';当它为假时,只评估'else'。为了添加类型检查功能,我添加了第二个语义谓词,包含第一个语义谓词。不过,这是一个黑客攻击,因为要进行类型检查或评估,我必须手动将全局布尔值typeCheck
更改为true或false。
IF语句的AST现在有两个分支。第一个(IFT)用于对IF语句的参数进行类型检查。 [这就是两个谓词的原因;要进行类型检查,必须评估所有参数]第二个分支(IFE)用于评估if-then-else的短路。当我添加第二个包含第一个语义谓词的语义谓词时,这个问题就开始了,这个谓词声称臭名昭着的“输入时没有可行的选择”错误。在慢慢地无处可去之后,我创建了新的语法,只有必需品。同样的问题。这是被剥离的AST:
虽然我从未经历过一次,但我在Eclipse中看到过使用ANTLR IDE报告的问题。所以我启动了ANTLRWorks,调试了解析器语法,然后尝试调试树语法。版本1.4.3和1.4.2都弹出此框,“警告:远程解析器使用的语法不一样”。我单击OK然后在调试器中单击Step Forward一次,java.exe * 32进程就死了。作为最后的测试,我使用antlr-3.3和antlr-3.4完整的jar从命令行手动编译,没有变化。
解析器:
grammar NestedSemPreds;
options {
output = AST;
ASTLabelType = CommonTree;
}
tokens {
IF;
IFT;
IFE;
}
/** parser rules **/
ifstmt : '(' 'if' COND THEN ELSE ')' NEWLN
-> ^(IF ^(IFT COND THEN ELSE)
^(IFE COND THEN ELSE)
)
;
/** lexer rules **/
COND : 'true' ;
THEN : 'then' ;
ELSE : 'else' ;
COMMENT : ('//' .* NEWLN) { skip(); } ; //for lines in datafile I don't want processed
NEWLN : '\r'? '\n' ;
WS : (' '|'\t')+ { skip(); } ;
树语法:
tree grammar treeEval;
options {
tokenVocab = NestedSemPreds;
ASTLabelType = CommonTree;
}
@members {
boolean typeCheck = false;
}
ifstmt
@init {
boolean condition = true;
}
: ^(IF (
{typeCheck}? => //{System.out.println("typeCheck is true");}
^(IFT COND THEN ELSE) {System.out.println("IFT COND THEN ELSE");}
^(IFE . . .) {System.out.println(" SKIP IFE WITH . WILDCARD");}
| {!typeCheck}? => //{System.out.println("typeCheck is false");}
^(IFT . . .) {System.out.println("skip ift with . wildcard");}
^(IFE COND
( {condition}? => ({System.out.println(" condition is true");}
THEN . {System.out.println(" evaluate THEN");})
| {!condition}? => ({System.out.println(" condition is false");}
. ELSE {System.out.println(" evaluate else");})
)//close inner predicate
)//close ^IFE
)//close outer predicate
)//close ^IF
;
我找不到嵌套语义谓词的任何特定问题,但我也没有找到任何例子。为什么这段代码失败了?有关ANTLRWorks调试器问题的任何想法?
答案 0 :(得分:2)
使用Bart关于不需要“在第二种选择之前添加谓词”的评论,我做了一些额外的测试。所有测试选项都是有效的语法,所以我认为这是一个ANTLR错误。为了减少追逐,这是有效的:
ifstmt
@init {
boolean condition = true;
}
: ^(IF (
{typeCheck}? => ^(IFT COND THEN ELSE) {System.out.println("IFT COND THEN ELSE");}
. //MUST use only one dot
| {!typeCheck}? => . //also works with ^(IFT . . .) here
^(IFE COND
( {condition}? => ({System.out.println(" condition is true");}
THEN . {System.out.println(" evaluate THEN");})
| {!condition}? => //this inner 2nd predicate not required
. ELSE {System.out.println(" evaluate else");})
)//close inner predicates
)//close ^IFE
)//close outer predicates
)//close ^IF
;
这两个步骤必需:
{typeCheck}?
和{!typeCheck}?
都是必需的。 .
运算符,用于跳过整个子树如代码示例中所述,它仍适用于以下两种语法更改之一:
{!typeCheck}?
可以使用单个.
或原始^(IFT . . .)
语法。 另一个有效的解决方案是手动处理节点流并添加适当的代码,但这并不像让ANTLR做它那样干净。