antlr令牌长度和错误处理

时间:2012-04-30 03:25:56

标签: antlr

我正在使用altlr版本3.4。

第一个问题,请参阅语法:

request: 'C' DELIM source DELIM target
  { System.out.println("Hi"); }
  ;
source: ID ;
target: ID ;

DELIM: '|' ;
fragment ALPHA: 'a'..'z' | 'A'..'Z' ;
fragment NUM: '0'..'9' ;
ID: ALPHA (ALPHA | NUM)* ;

“source”和“target”不能为空。但我的测试显示如下:

  • 输入“C | n1 | n2”:正常情况,没问题。
  • 表示输入“C || n2”:语法错误,“Hi”未打印。预期。确定
  • 输入“C | n1 |” :语法错误,但打印“嗨”。不好。

如果达到“请求”令牌,我确实需要设置其他内容。但是从上面来说,即使语法错误,代码仍然达到“请求”令牌。为什么呢?

第二个问题:如何为固定长度令牌指定规则,例如,精确10位数的令牌?

第三个问题是关于错误处理。我在解析器中覆盖emitErrorMessage()以设置错误标志,但我在词法分析器中找到了另一个emitErrorMessage()。我不想在解析器和词法分析器对象之间共享错误标志。我可以覆盖lexer中的emitErrorMessage()来做什么,并完全依赖解析器报告错误?或换句话说,如果出现错误,解析器是否会捕获它?

如果错误标志设置为一个错误,解析器是否可以实际恢复并匹配其他规则,那么之前的错误是错误警报?

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

  
      
  • ...
  •   
  • 输入“C | n1 |” :语法错误,但打印“嗨”。不好。
  •   
     

如果达到“请求”令牌,我确实需要设置其他内容。但是从上面来说,即使语法错误,代码仍然达到“请求”令牌。为什么呢?

因为解析器试图从中恢复。如果您不希望解析器(尝试)从错误匹配的标记中恢复,只需抛出这样的异常:

grammar T;

// options...

@members {
  @Override
  public void emitErrorMessage(String message) {
    throw new RuntimeException(message);
  }
}

request
 : 'C' DELIM source DELIM target { System.out.println("Hi"); }
 ;

// more rules...

请注意,@members@parser::members的缩写,只会导致emitErrorMessage(...)在解析器中被覆盖,而不是词法分析器。对于词法分析者,您需要@lexer::members

  

第二个问题:如何为固定长度令牌指定规则,例如,精确10位数的令牌?

请参阅:ANTR3 set the number of accepted characters for a token

  

第三个问题是关于错误处理。 ...

请参阅我的答案的第一部分:只需覆盖emitErrorMessage()并在其中不执行任何操作(默认操作是在std.err上打印)。

  

我可以覆盖lexer中的emitErrorMessage()来做什么,完全依赖解析器来报告错误吗?

好吧,解析器和词法分析器处理不同的类型或错误,因此忽略词法分析器中的某些问题可能不会导致解析器产生警告/错误。

答案 1 :(得分:0)

巴特,你的帮助很棒。我也考虑过并理解问题#1的行为是合法的。像编译器一样,解析器将恢复并继续发现尽可能多的错误。

对于问题#2,我也想出了一些固定长度的方法。不知道这是否是流行的方式:

示例:exact3'|' exact4;

//方法1:
exact3:(d + = DIGIT)+ {$ d!= null&& $ d.size()== 3}? ;

//方法2
exact4:atmost4 {$ atmost4.text.length()== 4}? ;
atmost4:
@init {int n = 1;}
    :({n <= 4}?=&gt; DIGIT {n ++;})+
    ;

DIGIT:'0'..'9';

对于问题#3,我将在第一次错误时失败,即在词法分析器和解析器中覆盖emitErrorMessage()以引发异常。 emitErrorMessage(msg)的选择是因为它正确准备了错误消息。

感谢所有分享的人!