Предоставление приоритета токену над другим - PullRequest
0 голосов
/ 26 апреля 2019

Я пытаюсь понять немного о LEXERS и мне интересно, как я могу отдать приоритет одному токену над другим.Я использую реальную проблему, с которой я столкнулся в качестве ссылки.

Я сделал два токена, один из которых представляет ТЕКСТ, а другой - список.Они оба имеют общий символ, что означает, что список также может быть прочитан как текст.

Есть ли способ дать какой-то приоритет тому токену, который я хочу получить?

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

TOKEN: {
    <#DIGIT: ["0"-"9"]>
    <#LETTER: ["a"-"z", "A"-"Z"]>
    <#SYMBOLS: ["@" , "."]>
    <#WORD: (<LETTER>|<DIGIT>|<SYMBOLS>)+>
} 


TOKEN: {
     ...
     <LI:  ((<DIGIT>)+)(".")>
     <TEXT:  <WORD>+ >
     ...
 }

Если я использую, введите это как ввод для LEXER,

1.this is a list

Я рассчитываю вернуться,

LI as 1.
TEXT as this is a list

но фактический результат, который я получаю,

TEXT is 1.this is a list

Спасибо

Ответы [ 2 ]

0 голосов
/ 06 мая 2019

Вопрос в том, "Есть ли способ дать какой-то приоритет тому токену, который я хочу получить [match]?"

Есть несколько способов.


Первый способ это

  • Перечислите правила токена, чтобы на первом месте было правило с наивысшим приоритетом.

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

В вашем случае вы хотите, чтобы «1.this» соответствовало <LI>, за которым следует <TEXT>. Но текстовое правило будет соответствовать 6 символам, в то время как правило <LI> будет соответствовать только 2. Таким образом, как объяснено в FAQ и ответе @ sarath, правило <TEXT> победит.


Второй способ.

  • Используйте лексические состояния, чтобы отключить правило, которое вы не хотите выигрывать.

Этот подход не подходит для вашей проблемы, потому что вам нужно, чтобы оба правила были активными одновременно.


Третий путь.

  • Переписать правила, чтобы правила с более низким приоритетом не могли применяться к более длинной строке, когда применяется правило с более высоким приоритетом.

В вашем случае вы хотите, чтобы значение "1234.this" не совпадало с <TEXT>, чтобы можно было применить правило <LI>. Мы перепишем правило <TEXT>, чтобы оно не распространялось ни на одну из этих строк

"1234.this"
"1234.thi"
"1234.th"
"1234.t"
"1234."

(На самом деле, мы могли бы разрешить последнюю строку, а затем упорядочить правила так, чтобы <LI> был первым. Но я обнаружил, что также проще исключить последнюю строку.)

Новый токен будет называться <TEXT1>, чтобы избежать путаницы. Таким образом, наше правило для <TEXT1> будет соответствовать любой строке, которая

  • соответствует <TEXT> и
  • не соответствует <LI> и
  • не имеет префикса, соответствующего <LI>.

Было бы очень хорошо, если бы JavaCC предоставил хороший синтаксис для такого рода ситуаций, но это не так. Мы должны найти регулярное выражение.

Способ, которым мне нравится получать регулярные выражения в подобных случаях, состоит в том, чтобы начать с распознавателя конечных состояний регулярного выражения (REFR), а затем извлечь из него регулярное выражение. Определение REFR приведено в наборе слайдов 1.2 здесь , как и алгоритм для превращения REFR в регулярное выражение.

Первый REFR для TEXT1 выглядит следующим образом.

    0s ---P|S|L---> 1f
    0s ---D-------> 2f
    1f --P|S|L|D--> 1f
    2f --D--------> 2f
    2f --S|L------> 1f

L означает букву, D означает цифру. P означает период. S означает любой символ, отличный от точки, то есть знак "at". Есть 3 состояния: 0s, 1f и 2f. Конечные (т.е. принимающие) состояния имеют в своем имени букву "f". Начальное состояние имеет в своем имени "s".

Надеюсь, правильность машины очевидна. В частности, обратите внимание, что после ввода D, DD, DDD и т. Д. Набор состояний, в которых может находиться машина, равен {2f}; и, если машина находится в состоянии 2f, а P является следующим символом, у машины нет состояния для перехода, и поэтому строка отклоняется. Таким образом, любая строка, которая соответствует LI или имеет префикс, который соответствует LI, будет отклонена.

Первым шагом является уменьшение количества принимающих состояний до 1 и обеспечение отсутствия исходящих переходов из принимающего состояния. (Мы также хотим убедиться, что нет входящих переходов в начальное состояние, но это уже имеет место.) Новая машина

    0s ---P|S|L---> 1
    0s ---D-------> 2
    1  --P|S|L|D--> 1
    1  --epsilon--> 3f
    2  --D--------> 2
    2  --S|L-----> 1
    2  --epsilon--> 3f

Далее устранить состояние 2.

    0s ---P|S|L----> 1
    0s --D+(S|L)---> 1
    0s ---D+-------> 3f
    1  --P|S|L|D---> 1
    1  --epsilon---> 3f

Объедините два перехода от 0 до 1

    0s ---P|S|L|D+(S|L)----> 1
    0s ---D+---------------> 3f
    1  ---P|S|L|D----------> 1
    1  ---epsilon----------> 3f

Устранить состояние 1.

    0s ---(P|S|L|D+(S|L)) (P|S|L|D)*---> 3f
    0s ---D+---------------------------> 3f

Объедините переходы, чтобы получить

     (P|S|L|D+(S|L)) (P|S|L|D)*  | D+
0s--------------------------------------> 3f

Наконец, мы посмотрим на RE, чтобы увидеть, что это действительно имеет смысл, и искать любые упрощения.

Мне это кажется правильным, и я не вижу способа упростить его.

И мы закончили.

0 голосов
/ 01 мая 2019

На самом деле есть два правила, которые Javacc использует для определения приоритета,

ПРАВИЛО 1: приоритет по порядку, который возникает при объявлении токенов.

ПРАВИЛО 2: максимально возможное совпадение на основе приоритета.

ПРАВИЛО 2 всегда имеет приоритет над ПРАВИЛО 1. То есть JavaCC всегда соответствует самому длинному сопоставимому префиксу ввода;и затем, если существует более одного токена, совпадающего с самым длинным соответствием, он использует ПРАВИЛО 1, чтобы определить, какой токен создавать.

В вашем случае вы ожидаете применения ПРАВИЛА 1, но JavaCC использует Правило 2,самый длинный матч;следовательно, результат.

Более того TEXT не может соответствовать this is a list, потому что он содержит пробел между ними, что не допускается по определению TEXT.

Раздел токенатолько для проведения лексического анализа.Поэтому используйте правила производства для синтаксического анализа.

...