因此,我正在将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个代币:
DEFINE
令牌,文本为#define_
(请注意,_
是define
后面的一个空格!(VARNAME
令牌,带文本foobar
如果你标记#definefoobar
,你也会得到2个标记:
DEFINE
令牌,带文本#definef
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语法,要么从头开始,要么尝试找到适合您需求的开源语法。