Использование Alex в Haskell для создания лексера, анализирующего Dice Rolls - PullRequest
7 голосов
/ 13 июля 2020

Я делаю парсер для DSL в Haskell с помощью Alex + Happy. Мой DSL использует броски кубиков как часть возможных выражений.

Иногда у меня есть выражение, которое я хочу проанализировать, которое выглядит так:

[some code...]  3D6  [... rest of the code]

Что должно переводить примерно так:

TokenInt {... value = 3}, TokenD, TokenInt {... value = 6}

Мой DSL также использует переменные (в основном, строки), поэтому у меня есть специальный токен, который обрабатывает имена переменных. Итак, с этими токенами:

"D"                                 { \pos str -> TokenD pos }
$alpha [$alpha $digit \_ \']*       { \pos str -> TokenName pos str}
$digit+                             { \pos str -> TokenInt pos (read str) }

Результат, который я получаю при использовании моего синтаксического анализа сейчас:

TokenInt {... value = 3}, TokenName { ... , name = "D6"}

Это означает, что мой лексер «читает» целое число. и Переменная с именем «D6».

Я пробовал много вещей, например, я изменил токен D на:

$digit "D" $digit                   { \pos str -> TokenD pos }

Но это просто потребляет цифры: (

  • Могу ли я проанализировать бросок кубиков с числами?
  • Или хотя бы разобрать TokenInt-TokenD-TokenInt?

PS: Я использую PosN в качестве оболочки, не уверен, что это применимо.

Ответы [ 2 ]

1 голос
/ 14 июля 2020

Я бы сказал go о том, чтобы расширить тип TokenD до TokenD Int Int, поэтому, используя оболочку basic для удобства, я бы сделал

$digit+ D $digit+ { dice }
...
dice :: String -> Token
dice s = TokenD (read $ head ls) (read $ last ls)
  where ls = split 'D' s

split можно найти здесь .

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

Также Я не могу заставить Alex анализировать $alpha на TokenD вместо TokenName. Если бы у нас было Di вместо D, не было бы проблем. Из документации Алекса:

Когда входной поток соответствует более чем одному правилу, преимущество имеет правило, которое соответствует самому длинному префиксу входного потока. Если все еще есть несколько правил, которые соответствуют равному количеству символов, то выигрывает правило, которое появляется раньше в файле.

Но тогда ваш код должен работать. Я не знаю, проблема с Алексом.

0 голосов
/ 14 июля 2020

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

Мне все еще любопытно узнать, были ли другие решения, но проблема сама по себе была решена.

Спасибо всем!

...