在ANTLR 4语法中消除了对ALL(*)解析的需求

时间:2014-01-13 16:27:50

标签: antlr4

我正在为一种语言编写一个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' ';' ;

为简洁起见,我省略了expressionstatement的定义。但是,请务必注意statement的定义包括breakStmt。这是因为break语句也可用于打破循环。

一般来说,语法很好 - 它按预期解析输入。但是,我在解析过程中收到警告,例如“第18行:0报告,调用FullContext d = 10(statementList),input ='break;”和“第18:0行reportContextSensitivity d = 10(statementList),input ='break;”这是有道理的,因为解析器不确定是否将break语句与statementbreakStmt匹配,并且需要回退到ALL(*)解析。我的问题是,我怎样才能改变语法,以便在解析过程中消除对此的需要并避免性能损失?甚至可以不改变语言语法吗?

1 个答案:

答案 0 :(得分:2)

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

  1. 当用户省略所需的break语句时改进了错误处理。
  2. 通过消除breakStmt末尾的caseStmt与其前面的statementList之间的歧义来提高解析器的效果。
  3. 我会使用以下规则:

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