令牌的antlr长度和错误处理

令牌的antlr长度和错误处理,antlr,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)* ; “源”和“目标”不能为空。但我的

我正在使用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()以设置错误标志,但在lexer中找到了另一个emitErrorMessage()。我不想在解析器和lexer对象之间共享错误标志。我可以在lexer中重写emitErrorMessage()而不做任何事情,并完全依赖解析器来报告错误吗?或者换句话说,如果有错误,解析器会确定地捕获它吗

如果为一个错误设置了错误标志,那么解析器是否可以恢复并匹配另一个规则,从而使前一个错误成为假警报

谢谢你的帮助

  • 对于输入“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中被重写。对于lexer成员,您需要执行
@lexer::members

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

见:

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

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

我可以在lexer中重写emitErrorMessage()而不做任何事情,并完全依赖解析器来报告错误吗


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

Bart,您的帮助非常好。我也仔细考虑了一下,明白问题1的行为是合法的。与编译器一样,解析器将恢复并继续查找尽可能多的错误

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

示例:exact3'|'exact4

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

//方法2
exact4:atmost4{$atmost4.text.length()==4}
大气4:
@init{int n=1;}
:({nDIGIT{n++;})+
)

数字:'0'..'9'

对于问题#3,我将在第一个错误时失败,即在lexer和parser中重写emitErrorMessage()以引发异常。选择emitErrorMessage(msg)是因为它正确准备了错误消息


谢谢所有分享的人!

谢谢。你的回答在不同的背景下帮助了我。我不知道
@成员
只适用于解析器。