为什么我的antlr lexer java类是"代码太大"?

yeg*_*256 5 java antlr antlr3

这是Antlr中的词法分析器(对于长文件很抱歉):

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(); }
    ;
Run Code Online (Sandbox Code Playgroud)

JDK 1.6说code too large并且无法编译它.为什么以及如何解决问题?

Gun*_*her 6

实际上我不会说这是一个很大的语法,并且必须有一个原因,它不能产生合理大小的代码.

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

QUOTED: {textMode}?=> ~('\'')*;
Run Code Online (Sandbox Code Playgroud)

有没有什么特别的理由让你想把QUOTED部分作为一个单独的标记,而不是把它与引用结合起来,因为Bart还把它放在他的语法中?这也会使textMode变量过时.

删除QUOTE并替换QUOTED

QUOTED: '\'' (~'\'')* '\'';
Run Code Online (Sandbox Code Playgroud)

最有可能解决问题,即使没有拆分语法.


Bar*_*ers 5

将您的语法分成几个复合语法.小心你放在哪里.例如,您不希望将NAME规则放在top-grammar中,将关键字放入导入的语法中:NAME将"覆盖"匹配的关键字.

这有效:

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(); }
    ;
Run Code Online (Sandbox Code Playgroud)

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';
Run Code Online (Sandbox Code Playgroud)

编译很好:

java -cp antlr-3.3.jar org.antlr.Tool SqlServerDialectLexer.g 
javac -cp antlr-3.3.jar *.java
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,调用org.antlr.Tool"top-lexer"就足够了:ANTLR会自动为导入的语法生成类.如果要导入更多语法,请执行以下操作:

import A, B, C;
Run Code Online (Sandbox Code Playgroud)

编辑

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

如果您要接受答案,请接受Gunther's.