Как я могу упростить прогнозирование токенов DFA?

Lexer DFA приводит к ошибке "слишком большой код"

Я пытаюсь разобрать страницы сервера Java с помощью ANTLR 3.

Java имеет ограничение в 64 КБ для байтового кода одного метода, и я продолжаю сталкиваться с ошибкой «слишком большой код» при компиляции исходного кода Java, созданного ANTLR.

В некоторых случаях мне удавалось исправить это, скомпрометировав лексер. Например, JSP использует токен XML «Name», который может включать в себя широкий спектр символов. Я решил принимать только символы ASCII в моем токене «Name», что значительно упростило некоторые тесты в лексере и позволило ему скомпилировать.

Однако я дошел до того, что больше не могу срезать углы, но DFA все еще слишком сложен.

Что мне с этим делать?

Есть ли распространенные ошибки, которые приводят к сложным DFA?

Есть ли способ запретить генерацию DFA, возможно, полагаясь на семантические предикаты или фиксированный просмотр вперед, чтобы помочь с предсказанием?

Написать этот лексер вручную будет легко, но прежде чем я откажусь от ANTLR, я хочу убедиться, что не упускаю из виду что-то очевидное.

Задний план

Лексеры ANTLR 3 используют DFA, чтобы решить, как токенизировать ввод. В созданном DFA есть метод specialStateTransition(). Этот метод содержит инструкцию switch с регистром для каждого состояния в DFA. В каждом случае есть серия if операторов, по одному для каждого перехода из состояния. Условие каждого оператора if проверяет входной символ, чтобы увидеть, соответствует ли он переходу.

Эти условия проверки характера могут быть очень сложными. Обычно они имеют следующую форму:

int ch = … ; /* "ch" is the next character in the input stream. */
switch(s) { /* "s" is the current state. */
  …
  case 13 :
    if ((('a' <= ch) && (ch <= 'z')) || (('A' <= ch) && (ch <= 'Z')) || … )
      s = 24; /* If the character matches, move to the next state. */
    else if …

Кажущееся незначительным изменение моего лексера может привести к десяткам сравнений для одного перехода, нескольких переходов для каждого состояния и множества состояний. Я думаю, что некоторые из рассматриваемых состояний невозможно достичь из-за моих семантических предикатов, но похоже, что семантические предикаты игнорируются DFA. (Я мог что-то неправильно понимать, хотя этот код определенно не то, что я мог бы написать вручную!)

Я нашел грамматику ANTLR 2 в инструменте Jsp2x, но меня не устраивает ее дерево синтаксического анализа, и я хочу обновить свои навыки ANTLR, поэтому я решил попробовать написать свою собственную. Я использую ANTLRWorks и пытался создать графики для DFA, но, похоже, в ANTLRWorks есть ошибки, которые мешают этому.


person erickson    schedule 22.09.2011    source источник
comment
См. этот вопрос для случая кода слишком большой, когда изменение грамматики полностью удаляет specialStateTransition.   -  person Gunther    schedule 22.09.2011
comment
@ Гюнтер, а, да, сказуемое внутри этой грамматики вызвало это! Я совершенно забыл, что это вопросы и ответы! Я сделаю из него любимую.   -  person Bart Kiers    schedule 23.09.2011


Ответы (2)


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

Иногда это можно исправить, установив определенные правила лексера fragments в отличие от «полных» правил лексера, которые производят токены, и / или изменив способ сопоставления символов внутри правил, но, посмотрев на то, как вы уже пробовали себя, я сомневаюсь в этом в вашем случае можно много выиграть. Однако, если вы желаете опубликовать свою грамматику лексера здесь, на SO, я или кто-то еще может увидеть что-то, что можно изменить.

В общем, эта проблема решается путем разделения грамматики лексера на 2 или более отдельных грамматик лексера и последующего импорта их в одну «основную» грамматику. В терминах ANTLR это называется составными грамматиками. См. О них на этой странице ANTLR Wiki: http://www.antlr.org/wiki/display/ANTLR3/Composite+Grammars

РЕДАКТИРОВАТЬ

Как справедливо упомянул @Gunther в комментарии под OP, см. Q&A: Почему у моего java-класса лексера antlr слишком большой код? где небольшое изменение (удаление определенного предиката) привело к исчезновению этой ошибки" code too large ".

person Bart Kiers    schedule 22.09.2011

Что ж, на самом деле не всегда легко составить составную грамматику. Во многих случаях помогает эта AntTask чтобы исправить эту проблему (его нужно запускать каждый раз после перекомпиляции грамматики, но этот процесс не такой уж и утомительный).

К сожалению, в некоторых сложных случаях даже этот волшебный скрипт не помогает. Компилятор может начать жаловаться на слишком большие блоки переходов DFA (статические поля String []).

Я нашел простой способ решить эту проблему, переместив (с помощью функций рефакторинга IDE) такие поля в другой класс с произвольно сгенерированным именем. Это всегда помогает при таком перемещении одного или нескольких полей.

person Andremoniy    schedule 18.09.2012