Почему мой класс java antlr lexer "слишком большой код"?
Это лексер в 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(); }
;
JDK 1.6 говорит code too large и не может его скомпилировать. Почему и как решить эту проблему?
3 ответа:
На самом деле я бы не сказал, что это большая грамматика, и должна быть причина, по которой она не производит код разумного размера.
Я думаю, что проблема напрямую связана с этим правилом:
Есть ли какая-то конкретная причина, по которой вы хотите, чтобы цитируемая часть была отдельным знаком, а не оставляла его в сочетании с цитатой, как это сделал Барт в своей грамматике? Это также сделает переменнуюQUOTED: {textMode}?=> ~('\'')*;textModeустаревшей.Удаление цитаты и замена цитаты с
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Как вы можете видеть, достаточно вызвать
org.antlr.Toolна вашем "топ-лексере": ANTLR автоматически создает классы для импортированных грамматик. Если у вас есть еще грамматики для импорта, сделайте это следующим образом:import A, B, C;EDIT
Гюнтер прав: достаточно изменить правилоQUOTED. Я оставлю свой ответ, потому что, когда вы собираетесь добавить больше ключевых слов или добавить довольно много правил синтаксического анализа (неизбежных с грамматиками SQL), вы, скорее всего, снова наткнетесь на ошибку "слишком большой код". В таком случае вы можете воспользоваться моим предложенным решением.Если ты собираешься ... примите ответ, Пожалуйста, примите ответ Гюнтера.
Хм. Я не думаю, что вы можете далее разбить это на отдельные файлы с инструкциями импорта?
Очевидно, кто-то написал постпроцессор, чтобы разделить вещи автоматически, но я этого не пробовал.