我需要實現類C解釋器。這裏是語法。構建一個類似C的解釋器使用Scala
Program ::= Commandlist
Commandlist ::= Command | Command; Commandlist;
Command ::= Left = Expression | while Expression : Commandlist end | print Left
Expression ::= Number | (Expression1 + Expression2) | (Expression1 - Expression2) | Left | &Left
Left ::= Variable | *Left
Number ::= string of digits
Variable ::= string of letters
這裏是解釋器使用的操作樹。
PTREE ::= [ CTREE+ ]
CTREE ::= Assign(LTREE, ETREE) | While(ETREE, CLIST) | Print(LTREE)
ETREE ::= Num(String) | Add(ETREE, ETREE) | Sub(ETREE, ETREE) | At(LTREE) | Amph(LTREE)
LTREE ::= Var(String) | Star(LTREE)
這裏是實現類C解釋器的代碼。
trait OpTree {
sealed abstract class Ltree
case class Var(x: String) extends Ltree
case class Star(l: Ltree) extends Ltree
sealed abstract class Etree
case class Num(s: String) extends Etree
case class Add(e1: Etree, e2: Etree) extends Etree
case class Sub(e1: Etree, e2: Etree) extends Etree
case At(l: Ltree) extends Etree
case Amph(l: Ltree) extends Etree
sealed abstract class Ctree
case class Assign(l: Ltree, e: Etree) extends Ctree
case class While(e: Etree, c: List[Ctree]) extends Ctree
case class Print(l: Ltree) extends Ctree
}
import scala.util.parsing.combinator.JavaTokenParsers
object MiniC extends JavaTokenParsers with OpTree {
def parse(source: String): List[Ctree] =
parseAll(prog, source) match {
case Success(optree,_) => optree
case _ => throw new Exception("Parse error!")
}
def prog: Parser[List[Ctree]] = commlist
def commlist: Parser[List[Ctree]] = rep1sep(comm, ";")
def comm: Parser[Ctree] = left~("="~>expr) ^^
{ case l~e => Assign(l, e) } |
"print"~>left ^^
{ case l => Print(l) } |
("while"~>expr<~":")~(commlist<~"end") ^^
{ case e~cs => While(e, cs) }
def expr: Parser[Etree] = wholeNumber ^^ (Num(_)) |
"("~>expr~op<~expr")" ^^
{ case e1~"+"~e2 => Add(e1, e2)
case e1~"-"~e2 => Sub(e1, e2) } |
left ^^ (At(_)) |
"&"~>left ^^ (Amph(_))
def left: Parser[Ltree] = ident ^^ (Var(_)) |
"*"~>left ^^ (Star(_))
def op: Parser[String] = "+" | "-"
//Interpreter
val memory = scala.collection.mutable.ArrayBuffer.empty[Int]
var env = Map.empty[String, Int]
def interpretPTREE(p: List[Ctree]): Unit = interpretCLIST(p)
def interpretCLIST(cs: List[Ctree]): Unit =
for(c <- cs) yield interpretCTREE(c)
def interpretCTREE(c: Ctree): Unit = c match {
case Assign(l, e) => env + (interpretLTREE(l).toString -> interpretETREE(e))
case Print(l) =>
if(env.contains(interpretLTREE(l).toString)) println(env(interpretLTREE(l).toString))
else throw new Exception("Error: " + l + " is undefined.")
env
case While(e, cs) =>
if (interpretETREE(e) != 0)
interpretCTREE(c)
else env
}
def interpretETREE(e: Etree): Int = e match {
case Num(s) => s.toInt
case Add(e1, e2) => interpretETREE(e1) + interpretETREE(e2)
case Sub(e1, e2) => interpretETREE(e1) - interpretETREE(e2)
case At(l) => interpretLTREE(l)
case Amph(l) => interpretLTREE(l)
}
def interpretLTREE(l: Ltree): Int = l match {
case Var(x) => if (env.contains(x)) env(x)
else throw new Exception("Error: " + x + " is undefined.")
case Star(l) => if (memory.contains(l)) memory(interpretLTREE(l))
else throw new Exception("Error: " + l + " is undefined.")
}
def main(args: Array[String]): Unit = {
try {
val source = args(0)
println("input : " + source)
val optree = parse(source)
println("optree : " + optree)
interpretPTREE(optree)
println("final memory : " + memory)
println("final namespace : " + env)
}
catch { case e: Exception => println(e)}
}
}
本方案的曖昧部分是interpretCTREE,所述interpretETREE和interpretLTREE的定義部分。如果我的
y = 4; z = &y; x = (7 + *z); *z = (y + 1)
參數運行這個程序optree的程序結果應該是這樣的:
List(Assign(Var("x"),Num("4")),
Assign(Var("z"),Amph(Var("y"))),
Assign(Var("x"),Add(Num("7"),Star(Var("z")))),
Assign(Star(Var("z")),Add(Var("y"),Num("1"))))
不過,我有一個結果是這樣的:
List(Assign(Var("x"),Num("4")),
Assign(Var("z"),Amph(Var("y"))),
Assign(Var("x"),Add(Num("7"),At(Star(Var("z"))))),
Assign(Star(Var("z")),Add(At(Var("y")),Num("1"))))
加,我想查看內存的值和env,但結果中包含錯誤消息。
java.lang.Exception: Error: y is undefined.
那麼,我該如何解決這個問題,以獲得正確的選擇權,內存的最終價值和環境?
我真的很感謝你的努力,但我覺得可能是這裏的一個小問題。用Fibonacci數字測試運行得很好,但是使用參數 「y = 4; z = y; x =(7 + * z); * z =(y + 1)」進行測試,它不給予期望記憶結果。預期的最終記憶結果是5,0,11,但它給出4,5,7。 –
下面是解釋。 y = 4; z =&y; #在z的單元格中存儲由y命名的位置# x =(7 + * z); #添加7到存儲在z位置存儲位置的int並將總和存儲在x所指向的位置# * z =(y + 1)#add 1添加到int y的單元格中,並將總和存儲在保存的位置z的位置# –
對不起,我沒有提到C語言的指針部分,但我希望你考慮上面提到的。 –