1

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

IF 语句的 AST 现在有两个分支。第一个(IFT)用于对 IF 语句的参数进行类型检查。[这就是为什么有两个谓词;要进行类型检查,必须评估所有参数] 第二个分支 (IFE) 用于评估短路 if-then-else。当我添加包含第一个语义谓词的第二个语义谓词时,问题就开始了,得到了臭名昭著的“输入时没有可行的替代方案”错误。在慢慢无处可去之后,我只用基本要素创建了新语法。同样的问题。这是精简的 AST:

如果AST

虽然我从未经历过,但我已经看到在 Eclipse 中使用 ANTLR IDE 报告的 SO 问题。所以我启动了 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 调试器问题的任何想法?

4

1 回答 1

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. 第一个外部谓词,单个.运算符跳过整个子树

如代码示例中所述,它仍然适用于以下两种语法更改中的任何一种:

  1. 第二个外部谓词 ,{!typeCheck}?可以使用单个语法.或原始^(IFT . . .)语法。
  2. 正如 Bart 提到的,第二个内部谓词是可选的。

另一个可行的解决方案是手动处理节点流并添加适当的代码,但这并不像让 ANTLR 做它的那样干净。

于 2012-08-05T20:35:16.937 回答