ANTLR使用通配符运算符嵌套语义谓词

时间:2012-08-03 21:38:02

标签: antlr antlr3 abstract-syntax-tree antlrworks

我为类似Scheme的语言解释器创建了一个语法。最初,我有一个if-then-else语句的语义谓词来控制评估,即当条件为真时,只评估'then';当它为假时,只评估'else'。为了添加类型检查功能,我添加了第二个语义谓词,包含第一个语义谓词。不过,这是一个黑客攻击,因为要进行类型检查或评估,我必须手动将全局布尔值typeCheck更改为true或false。

IF语句的AST现在有两个分支。第一个(IFT)用于对IF语句的参数进行类型检查。 [这就是两个谓词的原因;要进行类型检查,必须评估所有参数]第二个分支(IFE)用于评估if-then-else的短路。当我添加第二个包含第一个语义谓词的语义谓词时,这个问题就开始了,这个谓词声称臭名昭着的“输入时没有可行的选择”错误。在慢慢地无处可去之后,我创建了新的语法,只有必需品。同样的问题。这是被剥离的AST:

IF 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调试器问题的任何想法?

1 个答案:

答案 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
 ;

这两个步骤必需

  1. 外部谓词{typeCheck}?{!typeCheck}?都是必需的。
  2. 第一个外部谓词,一个.运算符,用于跳过整个子树
  3. 如代码示例中所述,它仍适用于以下两种语法更改之一:

    1. 第二个外部谓词{!typeCheck}?可以使用单个.或原始^(IFT . . .)语法。
    2. 第二个内部谓词 是可选的,正如Bart所说。
    3. 另一个有效的解决方案是手动处理节点流并添加适当的代码,但这并不像让ANTLR做它那样干净。