Scala парсер комбинаторы для (почти) тривиальной грамматики - PullRequest
3 голосов
/ 31 января 2012

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

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo blockZ{moooooo}

Я могу разбить его на части с помощью регулярных выражений:

.*?[^ ]*?\\{
.*?\\}

который, по сути, продолжит есть символы, пока не найдет что-то, что соответствует [^ ]*?\\{ или \\}: начало или конец блока.Мой вопрос: если я хочу сделать это с помощью Scala Parser Combinators, как мне это сделать?В настоящее время у меня есть:

   def expr: Parser[Any] = (block | text)+
   def text = ".+?".r
   def block = "[^ ]*?\\{".r ~ expr ~ "}"

, но это не работает:

parsed: List(b, l, o, c, k, {, y, o, u, a, r, e, a, c, o, w, t, o, o, b, l, k, A, {, b, u, t, m, a, y, b, e, n, o, t, }, a, n, d, s, o, i, s, h, e, }, h, e, a, r, m, e, m, o, o)

Кажется, что анализатор block не запускается, и поэтому анализатор text работаетвыстрелил несколько раз.но когда я удаляю парсер text:

   def expr: Parser[Any] = (block)+

я получаю:

failure: string matching regex `[^ ]*?\{' expected but `y' found

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo  
      ^

Так что, очевидно, парсер block работает , за исключением случаев, когдасинтаксический анализатор text присутствует.Что происходит?и есть ли «правильный» способ сделать это для такой базовой грамматики?

РЕДАКТИРОВАТЬ: изменил название, так как это больше не столько о нежелании больше, сколько просто решение проблемы

РЕДАКТИРОВАТЬ: Теперь у меня есть это:

def expr: Parser[Any] = (block | text)+

def text = "[^\\}]".r

def block = "[^ ]*?\\{".r ~ expr ~ "}"

Логика этого заключается в том, что для каждого символа он проверяет, является ли он началом блока.Если это не так, он переходит к следующему символу.Это дает мне:

parsed: List(((block{~List(y, o, u, a, r, e, a, c, o, w, t, o, o, ((blkA{~List(b, u, t, m, a, y, b, e, n, o, t))~}), a, n, d, s, o, i, s, h, e))~}), h, e, a, r, m, e, m, o, o)

, что отчасти правильно.Тем не менее, он разбирает неблокированные символы один за другим, что, вероятно, является проблемой производительности (я так думаю?).Есть ли способ проанализировать все эти неблокированные символы одновременно и оставить их в одной большой строке?

1 Ответ

2 голосов
/ 31 января 2012

Проблема в том, что text использует все закрывающие фигурные скобки (}). Это выглядит так:

expr -> block -> expr -> text.+ (until all input is consumed)

В этот момент он выходит из expr и пытается выполнить синтаксический анализ }, который не существует, дает сбой и возвращается к text в первый expr.

Вы можете использовать log, чтобы увидеть, что происходит при разборе.

...