2010-12-11 55 views
4

我尝试使用解析器组合器在scala中编写解析器。如果我递归匹配,从用Scala编写的解析器返回有意义的错误消息

def body: Parser[Body] = 
("begin" ~> statementList ) ^^ { 
    case s => { new Body(s); } 
} 

def statementList : Parser[List[Statement]] = 
    ("end" ^^ { _ => List() })| 
    (statement ~ statementList ^^ { case statement ~ statementList => statement :: statementList }) 

然后我得到很好的errormessages,只要有语句错误。 但是,这是难看的长码。所以我想写这个:

def body: Parser[Body] = 
("begin" ~> statementList <~ "end" ) ^^ { 
    case s => { new Body(s); } 
} 

def statementList : Parser[List[Statement]] = 
    rep(statement) 

此代码的工作原理,但只打印有意义的消息,如果在FIRST语句中有错误。如果是在后面的声明中,该消息成为痛苦无法使用,因为解析器希望看到更换整个错误陈述的“结束”标记:

Exception in thread "main" java.lang.RuntimeException: [4.2] error: "end" expected but "let" found 

let b : string = x(3,b,"WHAT???",!ERRORHERE!,7) 

^ 

我的问题:有没有办法让代表重新编辑与有意义的错误消息一起工作,将插入符号放在正确的位置而不是重复片段的开头?

回答

1

啊,找到解决方案!事实证明,您需要在主分析器上使用功能短语来返回一个新的分析器, 不太适合追踪。 (我想知道它到底意味着什么,也许如果它发现换行符不会追溯?) 追踪出现故障的最后一个位置。

改变:

def parseCode(code: String): Program = { 
program(new lexical.Scanner(code)) match { 
     case Success(program, _) => program 
     case x: Failure => throw new RuntimeException(x.toString()) 
     case x: Error => throw new RuntimeException(x.toString()) 
    } 

} 

def program : Parser[Program] ... 

到:

def parseCode(code: String): Program = { 
phrase(program)(new lexical.Scanner(code)) match { 
     case Success(program, _) => program 
     case x: Failure => throw new RuntimeException(x.toString()) 
     case x: Error => throw new RuntimeException(x.toString()) 
    } 

} 


def program : Parser[Program] ... 
+1

'phrase'返回一个'Parser',只有当它接受了某些东西后没有输入时才会成功。不过,我不知道为什么这会改变这种回溯方式。 – 2010-12-11 23:43:36

+0

事实证明,它根本不会改变回溯,但短语具有一点状态来检查具有最长匹配结果的故障。在Odersky书中关于解析器的章节中有一段称为“错误报告”。 – Jan 2010-12-15 11:56:08

1

您可以通过将 “自制” rep方法与非回溯中陈述做到这一点。例如:

scala> object X extends RegexParsers { 
    | def myrep[T](p: => Parser[T]): Parser[List[T]] = p ~! myrep(p) ^^ { case x ~ xs => x :: xs } | success(List()) 
    | def t1 = "this" ~ "is" ~ "war" 
    | def t2 = "this" ~! "is" ~ "war" 
    | def t3 = "begin" ~ rep(t1) ~ "end" 
    | def t4 = "begin" ~ myrep(t2) ~ "end" 
    | } 
defined module X 

scala> X.parse(X.t4, "begin this is war this is hell end") 
res13: X.ParseResult[X.~[X.~[String,List[X.~[X.~[String,String],String]]],String]] = 
[1.27] error: `war' expected but ` ' found 

begin this is war this is hell end 
         ^

scala> X.parse(X.t3, "begin this is war this is hell end") 
res14: X.ParseResult[X.~[X.~[String,List[X.~[X.~[String,String],String]]],String]] = 
[1.19] failure: `end' expected but ` ' found 

begin this is war this is hell end 
       ^
+0

嗨,丹尼尔。从scala 2.11开始,你的答案还是一样吗?或者增强了PC以提供原生的,更好的错误信息? – 2014-06-25 00:30:17

+0

@KevinMeredith我不知道,但我怀疑它。 – 2014-06-26 05:00:32

相关问题