我正在尝试为Scala中的Icon programming language构建一个解释器。现在我正在为它设置一个解析器。
到目前为止我写的代码是:
package interpreter
import scala.util.parsing.combinator.syntactical._
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.combinator.PackratParsers
import scala.util.parsing.combinator.JavaTokenParsers
object ExprParser extends JavaTokenParsers with PackratParsers{
def exp : Parser[expr] =
andexp |
fail |
ifexp |
fromTo |
write |
string |
arithm |
"(" ~> exp <~ ")" |
exp
def integer : Parser[CstInt] = wholeNumber ^^ { s => { //println("matching int");
new CstInt(s.toInt)}}
def string : Parser[CstStr] = stringLiteral ^^ { s => { //println("matching string");
new CstStr(s)}}
def fail : Parser[Fail] = "&fail" ^^ { e => Fail()}
def write : Parser[Write] = "write" ~> "(" ~> exp <~ ")" ^^ { e => Write(e)}
def ifexp : Parser[If] = ("if" ~> exp) ~ ("then" ~> exp) ~ ("else" ~> exp) ^^ { case cond ~ suc ~ fail => If(cond, suc, fail)}
// Arithmetic
def arithm : Parser[expr] =
term ~ ("+" ~> arithm) ^^ { case l ~ r => Prim("+", l, r)} |
term ~ ("-" ~> arithm) ^^{ case l ~ r => Prim("-", l, r)} |
term
def term : Parser[expr] =
factor ~ ("*" ~> term) ^^ { case l ~ r => Prim("*", l, r)} |
factor ~ ("/" ~> term) ^^ { case l ~ r => Prim("/", l, r)} |
factor
def factor : Parser[expr] =
integer |
"-" ~> arithm |
"(" ~> arithm <~ ")"
//PackratParser to allow left recursive grammars
lazy val fromTo : PackratParser[FromTo] = exp ~ ("to" ~> exp) ^^ { case from ~ to => FromTo(from, to)}
lazy val andexp : PackratParser[And] = exp ~ ("&" ~> exp) ^^ { case e1 ~ e2 =>{ println("matching and" + e1); println(" arg2: " + e2); And(e1, e2)}}
def parseInput(input: String) : expr =
parseAll (exp, input) match {
case Success(tree, _) => tree
case e: NoSuccess => throw new IllegalArgumentException(e.toString())
}
}
现在,我的问题是,当我在此输入上运行此代码时:
写(1到5)&amp;写(3到5)
我得到以下输出:
matching andWrite(FromTo(CstInt(1),CstInt(5)))
arg2: Write(FromTo(CstInt(3),CstInt(5)))
matching andWrite(FromTo(CstInt(1),CstInt(5)))
arg2: Write(FromTo(CstInt(3),CstInt(5)))
java.lang.IllegalArgumentException: [1.30] failure: `&' expected but `' found
write(1 to 5) & write(3 to 5)
^
at interpreter.ExprParser$.parseInput(parser.scala:62)
at interpreter.Main$.main(main.scala:9)
at interpreter.Main.main(main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sbt.Run.run0(Run.scala:60)
at sbt.Run.execute$1(Run.scala:47)
at sbt.Run$$anonfun$run$2.apply(Run.scala:50)
at sbt.Run$$anonfun$run$2.apply(Run.scala:50)
at sbt.TrapExit$.executeMain$1(TrapExit.scala:33)
at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)
我添加了打印输出,以确定它是否与&amp;运营商。
代码在其他奇怪的输入上运行良好,例如:
写((如果&amp;失败然后3其他5)到(3到5))
所以它似乎是一个与andexp解析器特别相关的问题。
任何帮助都会非常感激,因为我对Scala和解析器组合器完全不熟悉,而且我认为找到好的文档有点难。
答案 0 :(得分:1)
这可能是由于def exp = ... | exp
中的周期吗?
答案 1 :(得分:0)
请注意,对于左递归,packrat解析器有limitations。并且在一个变异的递归规则上混合packrat与非packrat是很奇怪的。我不知道它是如何工作的(或不是),我只是避免发现。
答案 2 :(得分:0)
所以,正如我对Ben Jacksons回答的评论中提到的,问题是我需要exp
PackratParser
,工作代码在这里:
package interpreter
import scala.util.parsing.combinator.syntactical._
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.combinator.PackratParsers
import scala.util.parsing.combinator.JavaTokenParsers
object ExprParser extends JavaTokenParsers with PackratParsers{
lazy val exp : PackratParser[expr] =
andexp |
fail |
ifexp |
fromTo |
write |
string |
arithm |
"(" ~> exp <~ ")"
def integer : Parser[CstInt] = wholeNumber ^^ { s => { //println("matching int");
new CstInt(s.toInt)}}
def string : Parser[CstStr] = stringLiteral ^^ { s => { //println("matching string");
new CstStr(s)}}
def fail : Parser[Fail] = "&fail" ^^ { e => Fail()}
def write : Parser[Write] = "write" ~> "(" ~> exp <~ ")" ^^ { e => Write(e)}
def ifexp : Parser[If] = ("if" ~> exp) ~ ("then" ~> exp) ~ ("else" ~> exp) ^^ { case cond ~ suc ~ fail => If(cond, suc, fail)}
// Arithmetic
def arithm : Parser[expr] =
term ~ ("+" ~> arithm) ^^ { case l ~ r => Prim("+", l, r)} |
term ~ ("-" ~> arithm) ^^{ case l ~ r => Prim("-", l, r)} |
term
def term : Parser[expr] =
factor ~ ("*" ~> term) ^^ { case l ~ r => Prim("*", l, r)} |
factor ~ ("/" ~> term) ^^ { case l ~ r => Prim("/", l, r)} |
factor
def factor : Parser[expr] =
integer |
"-" ~> arithm |
"(" ~> arithm <~ ")"
//PackratParser to allow left recursive grammars
lazy val fromTo : PackratParser[FromTo] = exp ~ ("to" ~> exp) ^^ { case from ~ to => FromTo(from, to)}
lazy val andexp : PackratParser[And] = exp ~ ("&" ~> exp) ^^ { case e1 ~ e2 =>{ println("matching and" + e1); println(" arg2: " + e2); And(e1, e2)}}
def parseInput(input: String) : expr =
parseAll (exp, input) match {
case Success(tree, _) => tree
case e: NoSuccess => throw new IllegalArgumentException(e.toString())
}
}
使用我之前的代码,我似乎已经允许左递归,这是普通解析器无法处理的。
如果任何人都可以澄清为什么fromTo
在没有exp
成为PackratParser
的情况下工作,而andexp
则没有,我仍然会有兴趣听到为什么会这样。