Antlr4 无需在ANTLR 4语法中进行所有(*)解析

Antlr4 无需在ANTLR 4语法中进行所有(*)解析,antlr4,Antlr4,我正在为一种语言编写一个ANTLR 4语法,这种语言将有switch语句,这些语句不允许出错(类似于C)。所有的case语句必须由break语句终止。多个case语句可以相互跟随,中间没有任何代码(同样,与C#中的情况相同)。下面是一段语法片段,它抓住了这一点: grammar MyGrammar; switchStmt : 'switch' '(' expression ')' '{' caseStmt+ '}' ; caseStmt : (caseOpener)+ statementLi

我正在为一种语言编写一个ANTLR 4语法,这种语言将有
switch
语句,这些语句不允许出错(类似于C)。所有的
case
语句必须由
break
语句终止。多个
case
语句可以相互跟随,中间没有任何代码(同样,与C#中的情况相同)。下面是一段语法片段,它抓住了这一点:

grammar MyGrammar;

switchStmt : 'switch' '(' expression ')' '{' caseStmt+ '}' ;

caseStmt : (caseOpener)+ statementList breakStmt ;

caseOpener : 'case' literal ':'  
           | 'default' ':' 
           ;

statementList : statement (statement)* ;

breakStmt : 'break' ';' ;
为了简洁起见,我省略了
表达式
语句
的定义。但是,需要注意的是,
语句
的定义包括
breakStmt
。这是因为
break
语句也可用于中断循环


一般来说,语法是好的——它按预期解析输入。但是,我在解析过程中收到了类似“第18:0行ReportAttentingFullContext d=10(statementList),input='break;”和“第18:0行reportContextSensitivity d=10(statementList),input='break;”的警告这是有意义的,因为解析器不确定是将
break
语句匹配为
statement
还是匹配为
breakStmt
,需要依赖于所有(*)解析。我的问题是,如何更改语法以消除解析过程中对语法的需要并避免性能下降?甚至可以在不更改语言语法的情况下执行此操作吗?

您应该从
caseStmt
末尾删除
breakStmt
引用,并在解析完成后在侦听器或访问者中执行此验证。这为您提供了以下优势:

  • 改进了当用户忽略所需的break语句时的错误处理
  • 通过消除
    caseStmt
    末尾的
    breakStmt
    与前面的
    statementList
    之间的歧义,提高了解析器性能
  • 我将使用以下规则:

    switchStmt
      : 'switch' '(' expression ')' '{' caseStmt* '}'
      ;
    
    caseStmt
      : caseOpener statementList?
      ;
    
    statementList
      : statement+
      ;
    

    谢谢关于我为什么应该使用
    caseStmt*
    而不是
    caseStmt+
    的原因,只需进行一次跟进。我会不会有一个没有case语句的switch语句,或者你是说我应该在使用侦听器或访问者遍历解析树时将其作为一个单独的错误来处理?@MrCodeMnky肯定是后者。我见过在代码生成过程中生成的空switch语句(例如),允许在解析器中生成空switch语句,但包含特定的语义错误,这大大提高了编译器的“友好性”。