我正在将一个用词典读取C++头文件的Antlr3项目转换为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.
我试着包装多字符的字元,如在 如何解决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中,或多或少都有未定义的行为。
在词典规则中。~
否定字符类,并将始终匹配一个字符。它不能否定整个字符串 ' WM_NEWUSER (WM_USER + 2)'
.
自己用输入法测试一下。#define foobar
. 将有2个令牌。
DEFINE
token, with text #define_
(注意到 _
后面是空格 define
!)VARNAME
标记,并附有文字 foobar
而如果你象征性地 #definefoobar
,你还可以得到2个令牌。
DEFINE
token, with text #definef
VARNAME
符号,并附有文本 oobar
正如你所看到的,被否定的部分后面的 '#define'
将始终匹配一个字符。
由于被否定的不是一个合适的字符集,你不妨这样写规则。
DEFINE : '#define' .;
是的,那将会表现得和:
DEFINE : '#define' ~(' WM_NEWUSER (WM_USER + 2)');
还有一些其他的意见:
#define WM_NEWUSER (WM_USER + 23)
. 当它偶然发现 3
它将不得不放弃规则。WM_USER_PLUS_2
但它无法为已经消耗的字符找到另一条词法规则,就会产生错误。.* '\n'
在你的词典中:这是一个坏习惯,尽量避免使用 .*
尽可能的使用。使用 ~('\n')* '\n'
而是WS
规则匹配一个空字符串,这对词典规则来说是不允许的(空字符串的数量是无限的,可能会导致你的词典在运行时停止。LINE_COMMENT
强制在结尾处有一个换行符。当你的输入的末尾有一行注释时,这将会失败(末尾没有换行符)。我的建议是:扔掉V3语法,从头开始,或者试着找一个 开源语法 适合您的需求。