Комбинирование парсеров при лексировании документа SGMLish в Scala

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

Some text<%tag attribute="value"%>more stuff.

Мой лексер прямо сейчас пытается вытащить часть тега и токенизировать, поэтому у меня есть что-то вроде:

def document: Parser[Token] = tag | regular

def tag: Parser[Token] = elem('<') ~ elem('%') ~ rep1(validTagName) ~ tagAttribute.* ~ elem('%') ~ elem('>') ^^ {
    case a ~ b ~ tagName ~ tagAttributes ~ c ~ d => {
        Tag(tagName.foldLeft("")(_+_)) :: tagAttributes.flatMap(_)
    }
}

def validTagName: Parser[Token] = elem("",Character.isLetter(_))  // over-simplified

... Other code for tagAttribute and Tag extends Token here

Вы, вероятно, можете обнаружить около полдюжины проблем прямо сейчас, я знаю, что могу определить несколько самостоятельно, но это то место, где я сейчас нахожусь. В конечном итоге функция токена должна возвращать синтаксический анализатор, и, если я все правильно понимаю, синтаксический анализатор может состоять из других синтаксических анализаторов. Я считаю, что я смогу создать синтаксический анализатор, объединив несколько других Parser[Token] объектов. Я не знаю, как это сделать, и не совсем понимаю, лучший ли это способ сделать это.


person PlexQ    schedule 27.05.2012    source источник


Ответы (1)


Похоже, вы путаете лексический и синактический синтаксические анализаторы. Если вы хотите пойти по пути написания собственного лексера, вам понадобятся два синтаксических анализатора, первый из которых расширяет lexical.Scanners (и, следовательно, предоставляет метод token типа Parser[Token]), а другой расширяет syntactical.TokenParsers и ссылается на первый в своем реализация абстрактного lexical метода этой черты.

Однако, если у вас нет особых причин для написания собственного лексера, может быть проще использовать что-то вроде _ 6_:

import scala.util.parsing.combinator._

object MyParser extends RegexParsers {
  def name = "\\p{Alpha}+".r
  def value = "\"" ~> "[^\"]*".r <~ "\""
  def attr = name ~ "=" ~ value ^^ { case k ~ _ ~ v => k -> v }

  def tag: Parser[(String, Map[String, String])] =
    "<%" ~> name ~ rep(attr) <~ "%>" ^^ {
      case tagName ~ attrs => tagName -> attrs.toMap
    }
}

Теперь что-то вроде MyParser.parseAll(MyParser.tag, "<%tag attribute=\"value\"%>") работает должным образом.

Обратите внимание: поскольку мы не пишем лексический анализатор, мы не обязаны предоставлять метод Parser[Token].

person Travis Brown    schedule 28.05.2012
comment
Блестяще! Да, я подумал, что могу немного запутать. Моя первая проблема заключалась в том, что RegexParsers съедает пробелы, что в некоторых случаях имеет значение, скажем, JSP, который генерирует выходной файл, занимающий много места, затем я обнаружил skipWhitespace, и с этим примером выше у меня он отлично работает! - person PlexQ; 28.05.2012