Scala Parser - Длина сообщения - PullRequest
2 голосов
/ 11 июня 2011

Я играю с библиотекой Scala Parser. Я пытаюсь написать синтаксический анализатор для формата, где указана длина, а затем сообщение этой длины. Например:

x.parseAll(x.message, "5helloworld") // result: "hello", remaining: "world"

Я не уверен, как это сделать с помощью комбинаторов. Сначала мой разум обращается к:

def message = length ~ body

Но, очевидно, тело зависит от длины, и я не знаю, как это сделать: p

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

В любом случае, я - нянька-скала, я просто нахожу это классным:)

Ответы [ 3 ]

4 голосов
/ 11 июня 2011

Вы должны использовать into для этого или его сокращение, >>:

scala> object T extends RegexParsers {
     |   def length: Parser[String] = """\d+""".r
     |   def message: Parser[String] = length >> { length => """\w{%d}""".format(length.toInt).r }
     | }
defined module T

scala> T.parseAll(T.message, "5helloworld")
res0: T.ParseResult[String] =
[1.7] failure: string matching regex `\z' expected but `w' found

5helloworld
      ^

scala> T.parse(T.message, "5helloworld")
res1: T.ParseResult[String] = [1.7] parsed: hello

Будьте осторожны с приоритетом при его использовании. Например, если вы добавите «~ остаток» после указанной выше функции, Scala будет интерпретировать его как length >> ({ length => ...} ~ remainder) вместо (length >> { length => ...}) ~ remainder.

2 голосов
/ 11 июня 2011

Это не похоже на контекстно-свободный язык, поэтому вам нужно будет использовать flatMap:

def message = length.flatMap(l => bodyOfLength(n))

, где длина имеет тип Parser [Int] и bodyOfLength (n) будет основываться на repN, например

def bodyWithLength(n: Int) : Parser[String] 
  = repN(n, elem("any", _ => true)) ^^ {_.mkString}
1 голос
/ 11 июня 2011

Я бы не использовал для этого комбинаторы pasrer.Но если вам нужно или проблема усложняется, вы можете попробовать это:

def times(x :Long,what:String) : Parser[Any] = x match {
case 1 => what;
case x => what~times(x-1,what);
}

Не используйте parseAll, если вы хотите, чтобы что-то осталось, используйте parse.Вы можете проанализировать длину, сохранить результат в изменяемом поле x (я знаю, некрасиво, но полезно здесь) и проанализировать тело x раз, тогда вы получите анализируемую строку, а остальное останется в анализаторе.

...