| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Sun, 19 Oct 2025 09:51:35 +0200 | |
| changeset 1012 | c01dfa3ff177 | 
| parent 742 | b5b5583a3a08 | 
| permissions | -rw-r--r-- | 
| 471 | 1 | // A parser and evaluator for the while language | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 2 | // | 
| 85 
1a4065f965fb
added packages
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
74diff
changeset | 3 | import matcher._ | 
| 
1a4065f965fb
added packages
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
74diff
changeset | 4 | import parser._ | 
| 
1a4065f965fb
added packages
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
74diff
changeset | 5 | |
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 6 | |
| 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 7 | // some regular expressions | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 8 | val SYM = RANGE("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz_")
 | 
| 68 
a09ecb1e7384
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
66diff
changeset | 9 | val DIGIT = RANGE("0123456789")
 | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 10 | val ID = SEQ(SYM, STAR(ALT(SYM, DIGIT))) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 11 | val NUM = PLUS(DIGIT) | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 12 | val KEYWORD = ALTS("skip", "while", "do", "if", "then", "else", "true", "false") 
 | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 13 | val SEMI: Rexp = ";" | 
| 74 
8f85d1f61663
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
73diff
changeset | 14 | val OP: Rexp = ALTS(":=", "=", "-", "+", "*", "!=", "<", ">")
 | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 15 | val WHITESPACE = PLUS(RANGE(" \n"))
 | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 16 | val RPAREN: Rexp = ")" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 17 | val LPAREN: Rexp = "("
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 18 | val BEGIN: Rexp = "{"
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 19 | val END: Rexp = "}" | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 20 | |
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 21 | // tokens for classifying the strings that have been recognised | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 22 | abstract class Token | 
| 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 23 | case object T_WHITESPACE extends Token | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 24 | case object T_SEMI extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 25 | case object T_LPAREN extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 26 | case object T_RPAREN extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 27 | case object T_BEGIN extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 28 | case object T_END extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 29 | case class T_ID(s: String) extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 30 | case class T_OP(s: String) extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 31 | case class T_NUM(s: String) extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 32 | case class T_KWD(s: String) extends Token | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 33 | |
| 85 
1a4065f965fb
added packages
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
74diff
changeset | 34 | val lexing_rules: List[(Rexp, List[Char] => Token)] = | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 35 | List((KEYWORD, (s) => T_KWD(s.mkString)), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 36 | (ID, (s) => T_ID(s.mkString)), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 37 | (OP, (s) => T_OP(s.mkString)), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 38 | (NUM, (s) => T_NUM(s.mkString)), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 39 | (SEMI, (s) => T_SEMI), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 40 | (LPAREN, (s) => T_LPAREN), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 41 | (RPAREN, (s) => T_RPAREN), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 42 | (BEGIN, (s) => T_BEGIN), | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 43 | (END, (s) => T_END), | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 44 | (WHITESPACE, (s) => T_WHITESPACE)) | 
| 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 45 | |
| 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 46 | // the tokenizer | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 47 | val Tok = Tokenizer(lexing_rules, List(T_WHITESPACE)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 48 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 49 | // the abstract syntax trees | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 50 | abstract class Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 51 | abstract class AExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 52 | abstract class BExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 53 | type Block = List[Stmt] | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 54 | case object Skip extends Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 55 | case class If(a: BExp, bl1: Block, bl2: Block) extends Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 56 | case class While(b: BExp, bl: Block) extends Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 57 | case class Assign(s: String, a: AExp) extends Stmt | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 58 | |
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 59 | case class Var(s: String) extends AExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 60 | case class Num(i: Int) extends AExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 61 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 62 | |
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 63 | case object True extends BExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 64 | case object False extends BExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 65 | case class Bop(o: String, a1: AExp, a2: AExp) extends BExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 66 | |
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 67 | // atomic parsers | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 68 | case class TokParser(tok: Token) extends Parser[List[Token], Token] {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 69 |   def parse(ts: List[Token]) = ts match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 70 | case t::ts if (t == tok) => Set((t, ts)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 71 | case _ => Set () | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 72 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 73 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 74 | implicit def token2tparser(t: Token) = TokParser(t) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 75 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 76 | case object NumParser extends Parser[List[Token], Int] {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 77 |   def parse(ts: List[Token]) = ts match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 78 | case T_NUM(s)::ts => Set((s.toInt, ts)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 79 | case _ => Set () | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 80 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 81 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 82 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 83 | case object IdParser extends Parser[List[Token], String] {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 84 |   def parse(ts: List[Token]) = ts match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 85 | case T_ID(s)::ts => Set((s, ts)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 86 | case _ => Set () | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 87 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 88 | } | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 89 | |
| 470 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 90 | def len(xs: List[(Int, Int)]): Int = xs match {
 | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 91 | case Nil => 0 | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 92 | case (1, x)::xs => len(xs) + 1 | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 93 | case (_, x)::xs => len(xs) | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 94 | } | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 95 | |
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 96 | def fst(p: (Int, Int)): Int = p match {
 | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 97 | case Nil => 0 | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 98 | case (1, x)::xs => len(xs) + 1 | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 99 | case (_, x)::xs => len(xs) | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 100 | } | 
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 101 | |
| 
8df654e9eb4e
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
93diff
changeset | 102 | |
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 103 | |
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 104 | // arithmetic expressions | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 105 | lazy val AExp: Parser[List[Token], AExp] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 106 |   (T ~ T_OP("+") ~ AExp) ==> { case ((x, y), z) => Aop("+", x, z): AExp } ||
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 107 |   (T ~ T_OP("-") ~ AExp) ==> { case ((x, y), z) => Aop("-", x, z): AExp } || T  
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 108 | lazy val T: Parser[List[Token], AExp] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 109 |   (F ~ T_OP("*") ~ T) ==> { case ((x, y), z) => Aop("*", x, z): AExp } || F
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 110 | lazy val F: Parser[List[Token], AExp] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 111 | (T_LPAREN ~> AExp <~ T_RPAREN) || | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 112 | IdParser ==> Var || | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 113 | NumParser ==> Num | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 114 | |
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 115 | // boolean expressions | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 116 | lazy val BExp: Parser[List[Token], BExp] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 117 |   (AExp ~ T_OP("=") ~ AExp) ==> { case ((x, y), z) => Bop("=", x, z): BExp } || 
 | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 118 |   (AExp ~ T_OP("!=") ~ AExp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || 
 | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 119 |   (AExp ~ T_OP("<") ~ AExp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || 
 | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 120 |   (AExp ~ T_OP(">") ~ AExp) ==> { case ((x, y), z) => Bop(">", x, z): BExp } || 
 | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 121 |   (T_KWD("true") ==> ((_) => True)) || 
 | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 122 |   (T_KWD("false") ==> ((_) => False: BExp))
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 123 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 124 | lazy val Stmt: Parser[List[Token], Stmt] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 125 |   (T_KWD("skip") ==> ((_) => Skip: Stmt)) ||
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 126 |   (IdParser ~ T_OP(":=") ~ AExp) ==> { case ((x, y), z) => Assign(x, z): Stmt } ||
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 127 |   (T_KWD("if") ~ BExp ~ T_KWD("then") ~ Block ~ T_KWD("else") ~ Block) ==>
 | 
| 71 
7717f20f0504
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
70diff
changeset | 128 |     { case (((((x,y),z),u),v),w) => If(y, u, w): Stmt } ||
 | 
| 
7717f20f0504
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
70diff
changeset | 129 |   (T_KWD("while") ~ BExp ~ T_KWD("do") ~ Block) ==> { case (((x, y), z), w) => While(y, w) } 
 | 
| 
7717f20f0504
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
70diff
changeset | 130 | |
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 131 | lazy val Stmts: Parser[List[Token], Block] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 132 |   (Stmt ~ T_SEMI ~ Stmts) ==> { case ((x, y), z) => x :: z : Block } ||
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 133 | (Stmt ==> ((s) => List(s) : Block)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 134 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 135 | lazy val Block: Parser[List[Token], Block] = | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 136 | (T_BEGIN ~> Stmts <~ T_END) || | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 137 | (Stmt ==> ((s) => List(s))) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 138 | |
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 139 | |
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 140 | // examples | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 141 | val p1 = "x := 5" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 142 | val p1_toks = Tok.fromString(p1) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 143 | val p1_ast = Block.parse_all(p1_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 144 | println(p1_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 145 | println(p1_ast) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 146 | |
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 147 | val p1a = "{ x := 5; y := 8}"
 | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 148 | val p1a_toks = Tok.fromString(p1a) | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 149 | val p1a_ast = Block.parse_all(p1a_toks) | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 150 | println(p1a_ast) | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 151 | |
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 152 | val p2 = "5 = 6" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 153 | val p2_toks = Tok.fromString(p2) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 154 | val p2_ast = BExp.parse_all(p2_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 155 | println(p2_ast) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 156 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 157 | val p2a = "true" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 158 | val p2a_toks = Tok.fromString(p2a) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 159 | val p2a_ast = BExp.parse_all(p2a_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 160 | println(p2a_ast) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 161 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 162 | val p3 = "if true then skip else skip" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 163 | val p3_toks = Tok.fromString(p3) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 164 | val p3_ast = Stmt.parse_all(p3_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 165 | println(p3_ast) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 166 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 167 | val p3a = "if true then x := 5 else x := 10" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 168 | val p3a_toks = Tok.fromString(p3a) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 169 | val p3a_ast = Stmt.parse_all(p3a_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 170 | println(p3a_ast) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 171 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 172 | val p3b = "if false then x := 5 else x := 10" | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 173 | val p3b_toks = Tok.fromString(p3b) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 174 | val p3b_ast = Stmt.parse_all(p3b_toks) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 175 | println(p3b_ast) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 176 | |
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 177 | // multiplication | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 178 | val p4 = """{ x := 5;
 | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 179 | y := 4; | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 180 | r := 0; | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 181 |               while y > 0 do {
 | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 182 | r := r + x; | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 183 | y := y - 1 | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 184 | } | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 185 | }""" | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 186 | val p4_toks = Tok.fromString(p4) | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 187 | val p4_ast = Block.parse_all(p4_toks) | 
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 188 | println(p4_ast) | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 189 | |
| 73 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 190 | val p5 = """ | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 191 | n := 9; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 192 | minus1 := 0; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 193 | minus2 := 1; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 194 | temp := 0; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 195 |  while n > 0 do  {
 | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 196 | temp := minus2; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 197 | minus2 := minus1 + minus2; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 198 | minus1 := temp; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 199 | n := n - 1 | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 200 | }; | 
| 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 201 | fib_res := minus2 | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 202 | """ | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 203 | val p5_toks = Tok.fromString(p5) | 
| 73 
27469183da75
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
72diff
changeset | 204 | val p5_ast = Stmts.parse_all(p5_toks) | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 205 | |
| 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 206 | // interpreter | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 207 | type Env = Map[String, Int] | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 208 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 209 | def eval_bexp(b: BExp, env: Env) : Boolean = b match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 210 | case True => true | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 211 | case False => false | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 212 |   case Bop("=", a1, a2) => eval_aexp(a1, env) == eval_aexp(a2, env)
 | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 213 |   case Bop("!=", a1, a2) => !(eval_aexp(a1, env) == eval_aexp(a2, env))
 | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 214 |   case Bop(">", a1, a2) => eval_aexp(a1, env) > eval_aexp(a2, env)
 | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 215 |   case Bop("<", a1, a2) => eval_aexp(a1, env) < eval_aexp(a2, env)
 | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 216 | } | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 217 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 218 | def eval_aexp(a: AExp, env : Env) : Int = a match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 219 | case Num(i) => i | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 220 | case Var(s) => env(s) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 221 |   case Aop("+", a1, a2) => eval_aexp(a1, env) + eval_aexp(a2, env)
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 222 |   case Aop("-", a1, a2) => eval_aexp(a1, env) - eval_aexp(a2, env)
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 223 |   case Aop("*", a1, a2) => eval_aexp(a1, env) * eval_aexp(a2, env)
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 224 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 225 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 226 | def eval_stmt(s: Stmt, env: Env) : Env = s match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 227 | case Skip => env | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 228 | case Assign(x, a) => env + (x -> eval_aexp(a, env)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 229 | case If(b, bl1, bl2) => if (eval_bexp(b, env)) eval_bl(bl1, env) else eval_bl(bl2, env) | 
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 230 | case While(b, bl) => | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 231 | if (eval_bexp(b, env)) eval_stmt(While(b, bl), eval_bl(bl, env)) | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 232 | else env | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 233 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 234 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 235 | def eval_bl(bl: Block, env: Env) : Env = bl match {
 | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 236 | case Nil => env | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 237 | case s::bl => eval_bl(bl, eval_stmt(s, env)) | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 238 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 239 | |
| 72 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 240 | //examples | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 241 | println(eval_stmt(p3a_ast.head, Map.empty)) | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 242 | println(eval_stmt(p3b_ast.head, Map.empty)) | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 243 | println(eval_bl(p4_ast.head, Map.empty)) | 
| 
d65525aeca08
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
71diff
changeset | 244 | println(eval_bl(p5_ast.head, Map.empty)) |