Рекурсивный анализ на основе номеров уровней - PullRequest
3 голосов
/ 30 декабря 2011

У меня каверзный вопрос (по крайней мере, с моей точки зрения), касающийся комбинаторов парсера Scalas и рекурсивного разбора.В настоящее время я создаю небольшой синтаксический анализатор, который должен иметь возможность анализировать структуры PL / 1, например:

  dcl 1 data,
    3 subData,
      5 tmp char(15),
      5 tmp1 char(15),
    3 subData2,
      5 tmp2 char(10),
      5 tmp3 char(5);

. В этом сценарии я хочу построить AST следующим образом:

Record(data)  -> (Record(subData),Record(subData2))

  Record(subData) -> (Char(tmp),Char(tmp1))

  Record(subData2) -> (Char(tmp2),Char(tmp3))  

Значениечто родительский элемент должен быть связан с его дочерними элементами.В моем мире это должно каким-то образом привести к рекурсивному парсеру, однако моя проблема в том, как контролировать, когда перестать падать на подуровнях.Например, при синтаксическом анализе структуры записи «3 подданных» он должен останавливаться при достижении номера уровня, который сам по себе не является более низким, в данном случае это строка «3 subData2».

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

Заранее спасибо.

С уважением, Стефан

1 Ответ

3 голосов
/ 30 декабря 2011

По сути, все, что вам нужно, это Parser.into (он имеет псевдоним >>), он создает комбинатор синтаксического анализатора, основанный на результате текущего.

Я подготовил для вас простой пример REPLable

import util.parsing.combinator.RegexParsers

case class Record(data: String, children: List[Record])

object RecordParser extends RegexParsers {
  override def skipWhitespace = false

  def ws = "\\s*".r
  def numberGT(min: Int) = "\\d+".r ^^ {  _.toInt } ^? {
    case i if i > min => i
  }

  def subData(n: Int): Parser[Record] = ws ~> numberGT(n) ~ ws ~ ".*".r <~ "\n" >> {
    case sub ~ _ ~ data => rep(subData(sub)) ^^ { new Record(data, _) }
  }
}

val testData = """
1 data
 2 subdata
  3 child1
  3 child2
 2 sub2
"""

RecordParser.parse(RecordParser.subData(0),test)
res7: RecordParser.ParseResult[Record] = [7.1] parsed: Record(data,List(Record(subdata,List(Record(child1,List()), Record(child2,List()))), Record(sub2,List())))
...