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

问题描述 投票:0回答:1

我正在将一个用词典读取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';

那么有什么提示可以解决我的问题吗?

antlr antlr4 lexer
1个回答
1
投票

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

在词典规则中。~ 否定字符类,并将始终匹配一个字符。它不能否定整个字符串 ' WM_NEWUSER (WM_USER + 2)'.

自己用输入法测试一下。#define foobar. 将有2个令牌。

  1. DEFINE token, with text #define_ (注意到 _ 后面是空格 define!)
  2. VARNAME 标记,并附有文字 foobar

而如果你象征性地 #definefoobar,你还可以得到2个令牌。

  1. DEFINE token, with text #definef
  2. VARNAME 符号,并附有文本 oobar

正如你所看到的,被否定的部分后面的 '#define' 将始终匹配一个字符。

由于被否定的不是一个合适的字符集,你不妨这样写规则。

DEFINE : '#define' .;

是的,那将会表现得和:

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

还有一些其他的意见:

  • ANTLR3的词法器如果不能在 "后期 "创建一个标记,那么它的回溯能力就会很差。试试将 #define WM_NEWUSER (WM_USER + 23). 当它偶然发现 3它将不得不放弃规则。WM_USER_PLUS_2但它无法为已经消耗的字符找到另一条词法规则,就会产生错误。
  • 我看到很多 .* '\n' 在你的词典中:这是一个坏习惯,尽量避免使用 .* 尽可能的使用。使用 ~('\n')* '\n' 而是
  • WS 规则匹配一个空字符串,这对词典规则来说是不允许的(空字符串的数量是无限的,可能会导致你的词典在运行时停止。
  • 你的 LINE_COMMENT 强制在结尾处有一个换行符。当你的输入的末尾有一行注释时,这将会失败(末尾没有换行符)。

我的建议是:扔掉V3语法,从头开始,或者试着找一个 开源语法 适合您的需求。

© www.soinside.com 2019 - 2024. All rights reserved.