【问题标题】:Parser Combinators - Simple grammarParser Combinators - 简单语法
【发布时间】:2013-04-01 06:48:24
【问题描述】:

我正在尝试在从书中复制的简单语法上使用 Scala 中的解析器组合器。当我运行以下代码时,它会在第一个令牌被错误解析后立即停止

[1.3] failure: string matching regex '\z' expected but '+' found

我明白为什么会出错。第一个标记是一个表达式,因此它是唯一需要根据语法进行解析的东西。但是我不知道什么是修复它的好方法。

object SimpleParser extends RegexParsers 
{
    def Name = """[a-zA-Z]+""".r
    def Int = """[0-9]+""".r

    def Main:Parser[Any] = Expr
    def Expr:Parser[Any] = 
    (
          Term
        | Term <~ "+" ~> Expr
        | Term <~ "-" ~> Expr
    )

    def Term:Parser[Any] = 
    (
          Factor
        | Factor <~ "*" ~> Term
    )

    def Factor:Parser[Any] =
    (
          Name
        | Int 
        | "-" ~> Int 
        | "(" ~> Expr <~ ")" 
        | "let" ~> Name <~ "=" ~> Expr <~ "in" ~> Expr <~ "end" 
    )

    def main(args: Array[String]) 
    {
        var input = "2 + 2"
        println(input)
        println(parseAll(Main, input))
    }
}

【问题讨论】:

    标签: parsing scala context-free-grammar parser-combinators


    【解决方案1】:

    Factor &lt;~ "*" ~&gt; Term 表示Factor.&lt;~("*" ~&gt; Term),因此整个右侧部分被删除。 使用Factor ~ "*" ~ Term ^^ { case f ~ _ ~ t =&gt; ??? }rep1sep

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    import scala.util.parsing.combinator.RegexParsers
    
    object SimpleParser extends RegexParsers
    {
        def Name = """[a-zA-Z]+""".r
        def Int = """[0-9]+""".r
    
        def Main:Parser[Any] = Expr
        def Expr:Parser[Any] = rep1sep(Term, "+" | "-")
    
        def Term:Parser[Any] = rep1sep(Factor, "*")
    
        def Factor:Parser[Any] =
        (
              "let" ~> Name ~ "=" ~ Expr ~ "in" ~ Expr <~ "end" ^^ { case n ~ _ ~ e1 ~ _ ~ e2 => (n, e1, e2)
            | Int
            | "-" ~> Int
            | "(" ~> Expr <~ ")"
            | Name }
        )
    }
    
    SimpleParser.parseAll(SimpleParser.Main, "2 + 2")
    
    // Exiting paste mode, now interpreting.
    
    import scala.util.parsing.combinator.RegexParsers
    defined module SimpleParser
    res1: SimpleParser.ParseResult[Any] = [1.6] parsed: List(List(2), List(2))
    

    解析器def Term:Parser[Any] = Factor | Factor &lt;~ "*" ~&gt; Term的第二部分没用。第一部分 Factor 可以解析(使用非空 next)第二部分 Factor &lt;~ "*" ~&gt; Term 能够解析的任何 Input

    【讨论】:

    • 谢谢!我可以理解我以错误的方式使用 。但我不明白为什么有必要使用rep1sep。以前的方式有什么问题?
    • rep1sep 只是更短。
    • 您可以将def Term:Parser[Any] = rep1sep(Factor, "*") 替换为def Term:Parser[Any] = Factor ~ "*" ~ Term ^^ { case f ~ _ ~ t =&gt; (f, t) } | Factor
    • @MadsAndersen,必须使用Factor ~ "*" ~ Term | Factor 而不是Factor | Factor ~ "*" ~ Term。查看更新的答案。
    • 感谢您的帮助!我想我已经了解到规则的顺序很重要。 Fx,let-definition必须在name-definition之前。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多