Я анализирую небольшой декларативный язык, в котором в области действия вы можете объявлять переменные (с типом), а затем позже, как и в большинстве других языков, используется имя (без типа).
Объявление переменной будет выглядеть так:
?varname
?varname1 ?varname2 - type1
?varname3 ?varname4 ?varname5 - type2
Если тип не указан, тип по умолчанию должен быть object
, как и в первом случае. Поэтому для этого у меня есть специальный синтаксический анализатор, который возвращает список моего собственного доменного объекта с именем LiftedTerm
(вы можете просто предположить, что это кортеж с именем переменной и типом переменной, на самом деле в нем есть еще кое-что, но не имеет отношения к этой проблеме):
def typed_list_variables : Parser[List[LiftedTerm]]= typed_variables.+ ^^ { case list => list.flatten.map(variable =>
LiftedTerm(variable._1, variable._2 match {
case "object" => ObjectType
case _ => TermType(variable._2)
})) }
def typed_variables = ((variable+) ~ (("-" ~> primitive_type)?)) ^^ {
case variables ~ primitive_type =>
for (variable <- variables) yield variable -> primitive_type.getOrElse("object")
}
def variable = """\?[a-zA-Z][a-zA-Z0-9_-]*""".r
def primitive_type = """[a-zA-Z][a-zA-Z0-9_-]*""".r
Все это прекрасно работает.
Теперь дальше в той же «области действия» я должен разобрать части, где есть ссылка на эти переменные. Переменная, очевидно, не будет снова объявлена полностью. Таким образом, в приведенном выше примере места, где используется ?varname1
, не будут включать type1
. Однако, когда я анализирую остальную часть ввода, я хочу получить ссылку на правильный объект LiftedTerm
, а не просто строку.
У меня есть некоторые рекурсивные структуры, поэтому я не хочу делать это сопоставление на синтаксическом анализаторе верхнего уровня. Я не хочу делать их "глобальное сопоставление" в моем объекте RegexParsers
, потому что большинство из них имеют область действия и относятся только к небольшому фрагменту ввода.
Есть ли способ передать контекстную информацию анализатору? В идеале я передаю список LiftedTerm
(или еще лучше карту из имен переменных String -> LiftedTerm
) в вызовы рекурсивного парсера.
(Извините, если это что-то очевидное, я все еще новичок в Scala и еще новичок в комбинаторах парсеров).
scala.util.parsing.ast.Binders
позволил бы вам сделать что-то в этом роде, но он уже давно устарел и находится на грани исчезновения. - person Philippe   schedule 02.01.2014