修复Antlr4中Antlr3语法中的"不允许使用多字符文字"错误



因此,我正在将Antlr3项目转换为Antlr4,该项目使用lexer读取C++头文件。我在将特定行转换为新的Antlr4语法时遇到问题。

Antlr3语法的原始行是:

DEFINE                  :   '#define' ~(' WM_NEWUSER (WM_USER + 2)');

使用此选项将导致

multi-character literals are not allowed in lexer sets: 'WM_NEWUSER' error in the antlr4 lexer.

我尝试包装多字符文字,如How to fix the"不允许使用多字符文字";antlr4 lexer规则出错?但它不起作用,或者我做错了什么。

编辑:原始语法

grammar Grammar;
@lexer::header {package main;}
WS                      :   (' '|'t')*;
NEW_LINE                :   'r'? 'n';
IGNORE_LINES            :   '//@MySQL:IGNORE LINES:' ('0'..'9')+ (' '|'t')* 'r'? 'n';
IGNORE_LINES2           :   '/*@MySQL:IGNORE LINES:' ('0'..'9')+ (' '|'t'|'r'|'n')* '*/';
IGNORE_KEY              :   '//@MySQL:IGNORE KEY' (' '|'t')* 'r'? 'n';
IGNORE_KEY2             :   '/*@MySQL:IGNORE KEY' (' '|'t'|'r'|'n')* '*/';
IGNORE_STRUCT           :   '//@MySQL:IGNORE STRUCT' (' '|'t')* 'r'? 'n';
IGNORE_STRUCT2          :   '/*@MySQL:IGNORE STRUCT' (' '|'t'|'r'|'n')* '*/';
PRIMARY                 :   '//@MySQL:PRIMARY' (' '|'t')* 'r'? 'n';
PRIMARY2                :   '/*@MySQL:PRIMARY' (' '|'t'|'r'|'n')* '*/';
OPKZ_ZUORD              :   '//@MySQL:OPKZ:' (VARNAME ';')+ (' '|'t')* 'r'? 'n';
OPKZ_ZUORD2             :   '/*@MySQL:OPKZ:' (VARNAME ';')+ (' '|'t'|'r'|'n')* '*/';
DESC_KEY                :   '//@MySQL:DESC' (' '|'t')* 'r'? 'n';
DESC_KEY2               :   '/*@MySQL:DESC' (' '|'t'|'r'|'n')* '*/';
MYSQL_KEY_INFO_MULTI    :   '//@MySQL:MULTIKEY:' .* 'n';
MYSQL_KEY_INFO_MULTI2   :   '/*@MySQL:MULTIKEY:' .* '*/';
MYSQL_KEY_INFO_SPECIAL  :   '//@MySQL:SPECIALKEY:' .* 'n';
MYSQL_KEY_INFO_SPECIAL2 :   '/*@MySQL:SPECIALKEY:' .* '*/';
MYSQL_KEY_INSENSITIVE   :   '//@MySQL:INSENSITIVEKEY:' .* 'n';
COMMENT                 :   '/*' .* '*/';
LINE_COMMENT            :   '//' ~('n'|'r')* 'r'? 'n';
SIGNED_UNSIGNED         :   'signed'|'unsigned';
TYPE                    :   ('char'|'short'|'int'|'long'|'__int8'|'__int16'|'__int32'|'__int64'|'bool'|'float'|'double');
RESERVE                 :   'reserve'|'szReserve';
TYPEDEF                 :   'typedef';
ENUM                    :   'enum';
STRUCT                  :   'struct';
UNION                   :   'union';
CONST                   :   'const';
DEFINE                  :   '#define' ~(' WM_NEWUSER (WM_USER + 2)');
WM_USER_PLUS_2          :   '#define WM_NEWUSER (WM_USER + 2)' (' '|'t')* 'r'? 'n';
BRACKET_OPEN            :   '(';
BRACKET_CLOSE           :   ')';
CURLY_BRACE_OPEN        :   '{';
CURLY_BRACE_CLOSE       :   '}';
SQUARE_BRACKET_OPEN     :   '[';
SQUARE_BRACKET_CLOSE    :   ']';
SEMI                    :   ';';
PLUS                    :   '+';
MINUS                   :   '-';
EQUALS                  :   '=';
MAL                     :   '*';
BACKSLASH               :   '\';
KOMMA                   :   ',';
NUMBER                  :   (('0'..'9')+)|(('0x') (('0'..'9')|('a'..'f')|('A'..'F'))+)|(''' '\'? ('a'..'z'|'A'..'Z') ''');
VARNAME                 :       ('a'..'z' | 'A'..'Z' | '_' ) ('0'..'9' | 'a'..'z' | 'A'..'Z' | '_' )*;
VERODERT                :   '(' (' '|'t')* VARNAME (' '|'t')* ('|' (' '|'t')* VARNAME (' '|'t')* )* ')';
PRAGMA_ONCE             :   '#pragma' (' '|'t')+ 'once';
IF_NOT_DEFINED1         :   '#if' (' '|'t')+ '!' (' '|'t')* 'defined' (' '|'t')* VARNAME (' '|'t')* 'r'? 'n';
IF_DEFINED1             :   '#if' (' '|'t')+ 'defined' (' '|'t')* VARNAME (' '|'t')* 'r'? 'n';
IF_NOT_DEFINED2         :   '#if' (' '|'t')+ '!' 'defined' (' '|'t')* '(' (' '|'t')* VARNAME (' '|'t')* ')' 'r'? 'n';
IF_DEFINED2             :   '#if' (' '|'t')+ 'defined' (' '|'t')* '(' (' '|'t')* VARNAME (' '|'t')* ')' 'r'? 'n';
ENDIF                   :   '#endif';

那么,有什么建议可以解决我的问题吗?

' WM_NEWUSER (WM_USER + 2)'的否定在ANTLR 3中或多或少有未定义的行为。

在lexer规则中,~否定字符类。并且将始终与单个字符匹配。它不能否定整个字符串' WM_NEWUSER (WM_USER + 2)'

用输入#define foobar自己测试。将有2个代币:

  1. DEFINE令牌,文本为#define_(请注意,_define后面的一个空格!(
  2. VARNAME令牌,带文本foobar

如果你标记#definefoobar,你也会得到2个标记:

  1. DEFINE令牌,带文本#definef
  2. VARNAME令牌,带文本oobar

如您所见,'#define'之后的否定部分将始终与单个字符匹配。

既然被否定的不是一个合适的字符集,你不妨写下这样的规则:

DEFINE : '#define' .;

是的,这将表现为:

DEFINE : '#define' ~(' WM_NEWUSER (WM_USER + 2)');

其他几个观察结果:

  • ANTLR3的lexer如果不能在"后期"创建令牌,那么它就不善于回溯。尝试标记#define WM_NEWUSER (WM_USER + 23)。当它偶然发现3时,它将不得不放弃规则WM_USER_PLUS_2,但它无法为已经消耗的字符找到另一个lexer规则,并将产生错误
  • 我在你的lexer中看到了很多.* 'n':这是一个坏习惯,尽可能避免使用.*。改为使用~('n')* 'n'
  • WS规则匹配一个空字符串,这对于lexer规则来说是不允许的(有无限多的空字符串,可能会导致lexer在运行时陷入停顿(
  • 你的LINE_COMMENT迫使在最后出现断线。当输入的末尾有一行注释(末尾没有换行符(时,这将失败

我的建议是:放弃v3语法,要么从头开始,要么尝试找到适合您需求的开源语法。

最新更新