Compiler construction ANTLR if else模糊性错误

Compiler construction ANTLR if else模糊性错误,compiler-construction,antlr,grammar,antlr4,Compiler Construction,Antlr,Grammar,Antlr4,我试图为一种简单的编程语言创建ANTLR语法 它具有类似C的if语句: program : statement* EOF ; statement : block # blockStatement | SEMI

我试图为一种简单的编程语言创建ANTLR语法

它具有类似C的if语句:

program
    : statement* EOF
    ;

statement
    : block                                                                 # blockStatement
    | SEMI                                                                  # emptyStatement
    | assignment                                                            # assignmentStatement
    | declaration                                                           # variableDeclarationStatement
    | 'if' parExpression ifBody=statement ('else' elseBody=statement)?      # ifStatement
    ..........
    ;

block
    : '{' statement* '}'
    ;

expression
    : literal                                                           # literalExpression
    | Identifier                                                        # variableReference
    ..........
    ;

parExpression : '(' expression ')';

assignment : Identifier assignmentOp expression SEMI;

SEMI : ';';

Identifier : (LETTER | '_') (LETTER | DIGIT | '_')* ;
它似乎工作正常,但当我使用
diagnosticeerrorlistener
运行时,会出现错误

reportAttemptingFullContext d=1 (statement), input='else', Line 3:0
reportContextSensitivity d=1 (statement), input='else', Line 3:0
reportAttemptingFullContext d=1 (statement), input='else', Line 5:0
reportContextSensitivity d=1 (statement), input='else', Line 5:0
对于这样的代码

if (flag1)
    x = 42;
else if (flag2)
    x = 43;
else
    x = 44;
我不确定我是否理解这里的错误,但正如我在其他情况下所理解的那样(例如,
if(a)if(b)

我应该如何解决它?

这被称为悬空问题。 解析文本:

      if (flag1)
         if (flag2) x=2;
            else x=3;
可以通过两种方式匹配语法:

      if (flag1)
         if (flag2) x=2;
         else x=3; // belongs to if (flag2)

因为您使else子句成为可选匹配。这意味着语法规则提供了一个模棱两可的匹配,这就是您从ANTLR得到的抱怨

您想要的是强制else匹配最近的unclosed if语句;这是对“如果…”的解释。。。在大多数编程语言中

您必须修改语句分析规则:

statement
    : non_if_statement
    | if_statement
;

if_statement
    : 'if' parExpression 
         ifBody= ( non_if_statement 'else' elseBody=statement
                   | if_statement )
;  

non_if_statement
    :block                                                                 
    | SEMI
    | assignment 
    | declaration
    ..........
;
这写起来有点笨拙,但应该行得通

许多解析器生成器允许您在遇到令牌时“强制转换”。如果在原始语法中强制对else关键字进行移位,则会得到相同的效果。我不知道如何对ANTLR说,如果你真的可以的话


[Lischke说,如果忽略错误,您的原始语法可能会得到正确的结果。我认为他是对的;这是因为解析器生成器被迫选择两种解释中的一种作为它接受的解释。]

看起来可以在ANTLR中使用此语义谓词来避免此警告:

'if' parExpression ifBody=statement ('else' elseBody=statement | {_input.LA(1) != ELSE}?)
(从这个答案)


此外,据我从2013年以来更好的方式了解:
ifStmt:'if'ID stmt(options{sll=true;}:'else'stmt |)但它对我不起作用。

为什么使用java标记?我相信你不必在意。这里报告的是解析器试图自行解决歧义的内容。如果正常的解析运行返回您所期望的结果,那么语法似乎很好。谢谢。在代码示例中,您是指
if(flag1)if(flag2).
(在第一个
if
之后没有
x=1;
)?噢,是的,x=1;只是凌晨2点的小故障。打补丁。
'if' parExpression ifBody=statement ('else' elseBody=statement | {_input.LA(1) != ELSE}?)