0

我正在使用 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)* ;

“源”和“目标”不能为空。但我的测试显示以下内容:

  • 对于输入 "C|n1|n2" :正常情况,没问题。
  • 对于输入“C||n2”:语法错误,并且未打印“Hi”。预期的。好的
  • 对于输入“C|n1|” : 语法错误,但打印“Hi”。不好。

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

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

第三个问题是关于错误处理的。我在解析器中覆盖了 emitErrorMessage() 以设置错误标志,但我在词法分析器中发现了另一个 emitErrorMessage() 。我不想在解析器和词法分析器对象之间共享错误标志。我可以在词法分析器中覆盖 emitErrorMessage() 而不做任何事情,并且完全依赖解析器来报告错误吗?或者换一种说法,如果有错误,解析器会确定捕获它吗?

并且如果为一个错误设置了错误标志,那么解析器是否真的可以恢复并匹配另一个规则,所以之前的错误是误报?

谢谢你的帮助!

4

2 回答 2

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

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

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

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 设置令牌接受的字符数

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

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

我可以在词法分析器中覆盖 emitErrorMessage() 而不做任何事情,并且完全依赖解析器来报告错误吗?

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

于 2012-04-30T06:41:14.647 回答
0

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

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

示例:精确 3 '|' 精确4;

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

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

数字:'0'..'9';

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

感谢所有分享的人!

于 2012-05-01T01:35:40.020 回答