Scala: анализ парсинга - PullRequest
       5

Scala: анализ парсинга

4 голосов
/ 02 сентября 2010

Я использую синтаксический анализатор Scala следующим образом:

def a = b ~ c ^^ { case x ~ y => A(x,y) }
def b = ... { B() }
def c = ... { C() }

теперь у меня есть изменение функции, которое изменяется при разборе ссылки ранее проанализированного B на val в C. Итак, конструктор C выглядит примерно так:

C(ref:B)

Я могу себе представить, что единственный способ добиться этого - это грязная работа с патчем, назначив экземпляр анализируемого объекта B для def c между синтаксическим анализом a. Примерно так:

var temp:B = null

def a = ( b ^^ { case x => temp = x } )
        ~ c(temp) ^^ {case x ~ y => A(x,y} )

Существует ли стандартный, чистый способ сделать это? Определение a не может быть нарушено, оно используется во многих местах в остальном коде.

Другое решение - использовать var вместо val и иметь следующее:

 def a = (b ~ c ) ^^ { case x ~ y => y.ref = c ; A(x,y) }

Но это также неприемлемо, так как сейчас это "сработало бы", но это потребовало бы дополнительных усилий и кода базовой платы в будущем развитии.

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

Ответы [ 3 ]

2 голосов
/ 02 сентября 2010

Я не уверен, правильно ли я понимаю проблему, но если C зависит от B, почему бы не выразить это функционально?

case class B(...)
case class C(b: B, ...)
case class A(b: B, c: C)

def b: Parser[B] = ... ^^ { B(...) }
def c: Parser[B => C] = ... ^^ { C(_, ...) }
def a: Parser[A] = b ~ c ^^ {  A(b, c(b)) }

Таким образом, ваша проблема решена, и ваши зависимости четко и кратко выражены.

2 голосов
/ 02 сентября 2010

Без изменения определения a невозможно сделать это чисто. Комбинатор ~ создает новый Parser, который последовательно применяет b и c, затем кортежирует (ну, логически кортежи) результаты и возвращает их как его результат. Ключевым моментом является то, что применение c не является функцией вывода b, поэтому вы ничего не можете сделать, чтобы получить результаты b внутри приложения c.

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

implicit def cleverParserSyntax[A](left: Parser[A]) = new {
  def ~%[B](right: A => Parser[B]): Parser[A ~ B] = for {
    lr <- left
    rr <- right(lr)
  } yield new ~(lr, rr)
}

def a = b ~% c ^^ { case x ~ y => A(x,y) }
def b = ... { B() }
def c(res: B) = ... { C(res) }
1 голос
/ 02 сентября 2010

Я бы сделал это:

case class B(x: String)
case class C(b: B, x: String)       
case class A(b: B, c: C)

class MyParser extends RegexParsers {               
  def a = b >> c ^^ { case x ~ y => A(x, y) }       
  def b = "\\w+".r ^^ B                             
  def c(b: B) = "\\d+".r ^^ (x => new ~(b, C(b, x)))
}

Теперь, если B произойдет намного раньше, чем C, все станет сложнее.Я предлагаю, если что-то не так, искать статью о Scala-парсере, в которой много полезных функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...