为什么我的 antlr 词法分析器 Java 类是"code too large"?



这是Antlr中的lexer(很抱歉文件太长):

lexer grammar SqlServerDialectLexer;
/* T-SQL words */
AND: 'AND';
BIGINT: 'BIGINT';
BIT: 'BIT';
CASE: 'CASE';
CHAR: 'CHAR';
COUNT: 'COUNT';
CREATE: 'CREATE';
CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP';
DATETIME: 'DATETIME';
DECLARE: 'DECLARE';
ELSE: 'ELSE';
END: 'END';
FLOAT: 'FLOAT';
FROM: 'FROM';
GO: 'GO';
IMAGE: 'IMAGE';
INNER: 'INNER';
INSERT: 'INSERT';
INT: 'INT';
INTO: 'INTO';
IS: 'IS';
JOIN: 'JOIN';
NOT: 'NOT';
NULL: 'NULL';
NUMERIC: 'NUMERIC';
NVARCHAR: 'NVARCHAR';
ON: 'ON';
OR: 'OR';
SELECT: 'SELECT';
SET: 'SET';
SMALLINT: 'SMALLINT';
TABLE: 'TABLE';
THEN: 'THEN';
TINYINT: 'TINYINT';
UPDATE: 'UPDATE';
USE: 'USE';
VALUES: 'VALUES';
VARCHAR: 'VARCHAR';
WHEN: 'WHEN';
WHERE: 'WHERE';
QUOTE: ''' { textMode = !textMode; };
QUOTED: {textMode}?=> ~(''')*;
EQUALS: '=';
NOT_EQUALS: '!=';
SEMICOLON: ';';
COMMA: ',';
OPEN: '(';
CLOSE: ')';
VARIABLE: '@' NAME;
NAME:
    ( LETTER | '#' | '_' ) ( LETTER | NUMBER | '#' | '_' | '.' )*
    ;
NUMBER: DIGIT+;
fragment LETTER: 'a'..'z' | 'A'..'Z';
fragment DIGIT: '0'..'9';
SPACE
    :
    ( ' ' | 't' | 'n' | 'r' )+
    { skip(); }
    ;

JDK 1.6说code too large,但无法编译。为什么以及如何解决这个问题?

事实上,我不会说这是一个很大的语法,它不能产生合理大小的代码肯定是有原因的。

我认为问题与这个规则直接相关:

QUOTED: {textMode}?=> ~(''')*;

有什么特别的原因可以让你想把引号部分作为一个单独的标记,而不是像巴特在语法中所说的那样把它和引号结合在一起?这也会使textMode变量过时。

删除QUOTE并用替换QUOTED

QUOTED: ''' (~''')* ''';

即使不拆分语法,也很可能解决问题。

将语法分成几个复合语法。放什么地方要小心。例如,您不想将NAME规则放在顶级语法中,并将关键字放入导入的语法中:NAME会"覆盖"匹配的关键字。

这项工作:

A.g

lexer grammar A;
SELECT: 'SELECT';
SET: 'SET';
SMALLINT: 'SMALLINT';
TABLE: 'TABLE';
THEN: 'THEN';
TINYINT: 'TINYINT';
UPDATE: 'UPDATE';
USE: 'USE';
VALUES: 'VALUES';
VARCHAR: 'VARCHAR';
WHEN: 'WHEN';
WHERE: 'WHERE';
QUOTED: ''' ('''' | ~''')* ''';
EQUALS: '=';
NOT_EQUALS: '!=';
SEMICOLON: ';';
COMMA: ',';
OPEN: '(';
CLOSE: ')';
VARIABLE: '@' NAME;
NAME:
    ( LETTER | '#' | '_' ) ( LETTER | NUMBER | '#' | '_' | '.' )*
    ;
NUMBER: DIGIT+;
fragment LETTER: 'a'..'z' | 'A'..'Z';
fragment DIGIT: '0'..'9';
SPACE
    :
    ( ' ' | 't' | 'n' | 'r' )+
    { skip(); }
    ;

SqlServerDialectLexer.g

lexer grammar SqlServerDialectLexer;
import A;
AND: 'AND';
BIGINT: 'BIGINT';
BIT: 'BIT';
CASE: 'CASE';
CHAR: 'CHAR';
COUNT: 'COUNT';
CREATE: 'CREATE';
CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP';
DATETIME: 'DATETIME';
DECLARE: 'DECLARE';
ELSE: 'ELSE';
END: 'END';
FLOAT: 'FLOAT';
FROM: 'FROM';
GO: 'GO';
IMAGE: 'IMAGE';
INNER: 'INNER';
INSERT: 'INSERT';
INT: 'INT';
INTO: 'INTO';
IS: 'IS';
JOIN: 'JOIN';
NOT: 'NOT';
NULL: 'NULL';
NUMERIC: 'NUMERIC';
NVARCHAR: 'NVARCHAR';
ON: 'ON';
OR: 'OR';

它编译得很好:

java -cp antlr-3.3.jar org.antlr.Tool SqlServerDialectLexer.g 
javac -cp antlr-3.3.jar *.java

正如您所看到的,在您的"top lexer"上调用org.antlr.Tool就足够了:ANTLR自动为导入的语法生成类。如果您有更多语法要导入,请这样做:

import A, B, C;

编辑

Gunther是正确的:改变QUOTED规则就足够了。不过,我会留下我的答案,因为当你要添加更多的关键字,或者添加相当多的解析器规则(SQL语法不可避免)时,你很可能会再次遇到"代码太大"的错误。在这种情况下,您可以使用我提出的解决方案。

如果你要接受一个答案,请接受冈瑟的答案。

嗯。我想你不能用import语句把它进一步分解成单独的文件吗?

显然有人写了一个后处理器来自动拆分,但我还没有尝试过

最新更新