Почему мой класс 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), вы, скорее всего, снова наткнетесь на ошибку "слишком большой код". В таком случае вы можете воспользоваться моим предложенным решением.Если ты собираешься ... примите ответ, Пожалуйста, примите ответ Гюнтера.
Хм. Я не думаю, что вы можете далее разбить это на отдельные файлы с инструкциями импорта?
Очевидно, кто-то написал постпроцессор, чтобы разделить вещи автоматически, но я этого не пробовал.