Почему мой класс 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 5

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), вы, скорее всего, снова наткнетесь на ошибку "слишком большой код". В таком случае вы можете воспользоваться моим предложенным решением.

Если ты собираешься ... примите ответ, Пожалуйста, примите ответ Гюнтера.

Хм. Я не думаю, что вы можете далее разбить это на отдельные файлы с инструкциями импорта?

Очевидно, кто-то написал постпроцессор, чтобы разделить вещи автоматически, но я этого не пробовал.