Почему мой класс antlr lexer java "слишком большой код"? - PullRequest
5 голосов
/ 08 июня 2011

Это лексер в 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 ]

6 голосов
/ 09 июня 2011

На самом деле я бы не сказал, что это большая грамматика, и должна быть причина, по которой она не выдает код разумного размера.

Я думаю, что проблема напрямую связана с этим правилом:

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

Есть ли какая-то особая причина, по которой вы хотите, чтобы цитируемая часть была отдельным токеном, а не оставляла ее в сочетании с цитатой, как Барт также включил в свою грамматику? Это также сделает переменную textMode устаревшей.

Отбрасывание ЦИТАТЫ и замена ЦИТАТЫ на

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

, скорее всего, решит проблему, даже не разбив грамматику.

5 голосов
/ 09 июня 2011

Разделите вашу грамматику на несколько составных грамматик .Будьте осторожны, где вы размещаете.Например, вы не хотите помещать правило NAME в свою топ-грамматику и ключевые слова в импортированную грамматику: NAME "перезапишет" ключевые слова из совпадения.

Это работает:

Ag

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 на вашем "top-lexer" достаточно: ANTLR автоматически генерирует классы для импортированной грамматики.Если вам нужно импортировать больше грамматик, сделайте это следующим образом:

import A, B, C;

EDIT

Гюнтер прав: достаточно изменить правило QUOTED.Я оставлю свой ответ, потому что, когда вы собираетесь добавить больше ключевых слов или добавить довольно много правил синтаксического анализа (неизбежно для грамматик SQL), вы, скорее всего, снова наткнетесь на ошибку «слишком большой код».В этом случае вы можете использовать предложенное мной решение.

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

0 голосов
/ 08 июня 2011

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

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

...