Bef*_*rem 10 parsing scala bnf ebnf parser-combinators
我正在尝试为下面的命令定义语法.
object ParserWorkshop {
def main(args: Array[String]) = {
ChoiceParser("todo link todo to database")
ChoiceParser("todo link todo to database deadline: next tuesday context: app.model")
}
}
Run Code Online (Sandbox Code Playgroud)
第二个命令应该标记为:
action = todo
message = link todo to database
properties = [deadline: next tuesday, context: app.model]
Run Code Online (Sandbox Code Playgroud)
当我在下面定义的语法上运行此输入时,我收到以下错误消息:
[1.27] parsed: Command(todo,link todo to database,List())
[1.36] failure: string matching regex `\z' expected but `:' found
todo link todo to database deadline: next tuesday context: app.model
^
Run Code Online (Sandbox Code Playgroud)
据我所知,它失败了,因为匹配消息的单词的模式几乎与属性键的键的模式相同:值对,因此解析器无法分辨消息的结束位置和属性的开始.我可以通过坚持为每个属性使用开始令牌来解决这个问题,如下所示:
todo link todo to database :deadline: next tuesday :context: app.model
Run Code Online (Sandbox Code Playgroud)
但我宁愿保持命令尽可能接近自然语言.我有两个问题:
错误信息实际上意味着什么?如何修改现有语法以适应给定的输入字符串?
import scala.util.parsing.combinator._
case class Command(action: String, message: String, properties: List[Property])
case class Property(name: String, value: String)
object ChoiceParser extends JavaTokenParsers {
def apply(input: String) = println(parseAll(command, input))
def command = action~message~properties ^^ {case a~m~p => new Command(a, m, p)}
def action = ident
def message = """[\w\d\s\.]+""".r
def properties = rep(property)
def property = propertyName~":"~propertyValue ^^ {
case n~":"~v => new Property(n, v)
}
def propertyName: Parser[String] = ident
def propertyValue: Parser[String] = """[\w\d\s\.]+""".r
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*ral 22
这很简单.当你使用时~,你必须明白,已经成功完成的单个解析器没有回溯.
因此,例如,message在结肠之前得到一切,因为所有这些都是可接受的模式.接着,properties是rep的property,这就要求propertyName,但它只能找到冒号(第一个字符不被吞并message).所以propertyName失败,property失败.现在,properties如上所述,它是一个rep,所以它成功完成0次重复,然后command成功完成.
所以,回到parseAll.该command解析器成功地返回,有冒号前消耗一切.然后它问了一个问题:我们是在input(\z)的末尾吗?不,因为接下来就有一个冒号.因此,它预计输入结束,但得到冒号.
您必须更改正则表达式,以便它不会消耗冒号之前的最后一个标识符.例如:
def message = """[\w\d\s\.]+(?![:\w])""".r
Run Code Online (Sandbox Code Playgroud)
顺便说一句,当你使用时def,强制重新评估表达式.换句话说,每次调用每个defs都会创建一个解析器.每次处理它们所属的解析器时,都会实例化正则表达式.如果你改变一切val,你将获得更好的表现.
请记住,这些东西定义了解析器,它们不运行它.它parseAll运行解析器.
| 归档时间: |
|
| 查看次数: |
4904 次 |
| 最近记录: |