updated
authorChristian Urban <urbanc@in.tum.de>
Tue, 30 Jul 2019 20:19:40 +0100
changeset 628 8067d0a8ba04
parent 627 f5214da1976e
child 629 1b718d6065c2
updated
progs/comb1.scala
progs/comb2.scala
progs/compile_arrays.scala
progs/fun-bare.scala
progs/fun.scala
progs/funt.scala
--- a/progs/comb1.scala	Sun Jul 28 21:10:39 2019 +0100
+++ b/progs/comb1.scala	Tue Jul 30 20:19:40 2019 +0100
@@ -2,8 +2,8 @@
 import scala.language.reflectiveCalls
 
 /* Note, in the lectures I did not show the implicit type consraint
- * I => Seq[_] , which means that the input type I needs to be
- * a sequence, subtype of Seq. */
+ * I => Seq[_], which means that the input type 'I' needs to be
+ * a sequence. */
 
 abstract class Parser[I, T](implicit ev: I => Seq[_]) {
   def parse(ts: I): Set[(T, I)]
@@ -31,7 +31,7 @@
     for ((head, tail) <- p.parse(sb)) yield (f(head), tail)
 }
 
-// atomic parsers  
+// atomic parsers for characters, numbers and strings
 case class CharParser(c: Char) extends Parser[String, Char] {
   def parse(sb: String) = 
     if (sb != "" && sb.head == c) Set((c, sb.tail)) else Set()
@@ -48,9 +48,9 @@
 val NumParser = RegexParser("[0-9]+".r)
 def StringParser(s: String) = RegexParser(Regex.quote(s).r)
 
-// NumParserInt transforms a "string integer" into an Int;
+// NumParserInt2 transforms a "string integer" into an Int;
 // needs new, because FunParser is not a case class
-val NumParserInt = new FunParser(NumParser, (s: String) => s.toInt)
+val NumParserInt2 = new FunParser(NumParser, (s: String) => s.toInt)
 
 
 // convenience
@@ -58,14 +58,14 @@
 implicit def char2parser(c: Char) = CharParser(c)
 
 implicit def ParserOps[I, T](p: Parser[I, T])(implicit ev: I => Seq[_]) = new {
-  def | (q : => Parser[I, T]) = new AltParser[I, T](p, q)
+  def || (q : => Parser[I, T]) = new AltParser[I, T](p, q)
   def ==>[S] (f: => T => S) = new FunParser[I, T, S](p, f)
   def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q)
 }
 
 implicit def StringOps(s: String) = new {
-  def | (q : => Parser[String, String]) = new AltParser[String, String](s, q)
-  def | (r: String) = new AltParser[String, String](s, r)
+  def || (q : => Parser[String, String]) = new AltParser[String, String](s, q)
+  def || (r: String) = new AltParser[String, String](s, r)
   def ==>[S] (f: => String => S) = new FunParser[String, String, S](s, f)
   def ~[S] (q : => Parser[String, S]) = 
     new SeqParser[String, String, S](s, q)
@@ -78,8 +78,8 @@
 
 
 lazy val Pal : Parser[String, String] = 
-  (("a" ~ Pal ~ "a") ==> { case ((x, y), z) => x + y + z } |
-   ("b" ~ Pal ~ "b") ==> { case ((x, y), z) => x + y + z } | "a" | "b" | "")
+  (("a" ~ Pal ~ "a") ==> { case ((x, y), z) => x + y + z } ||
+   ("b" ~ Pal ~ "b") ==> { case ((x, y), z) => x + y + z } || "a" || "b" || "")
 
 Pal.parse_all("abaaaba")
 Pal.parse("abaaaba")
@@ -88,29 +88,31 @@
 
 // well-nested parentheses parser (transforms '(' -> '{' , ')' -> '}' )
 lazy val P : Parser[String, String] = 
-  "(" ~ P ~ ")" ~ P ==> { case (((_, x), _), y) => "{" + x + "}" + y } | ""
+  "(" ~ P ~ ")" ~ P ==> { case (((_, x), _), y) => "{" + x + "}" + y } || ""
 
 P.parse_all("(((()()))())")
 P.parse_all("(((()()))()))")
 P.parse_all(")(")
 P.parse_all("()")
 
-// Arithmetic Expressions
+// Arithmetic Expressions (Terms and Factors)
 
 lazy val E: Parser[String, Int] = 
-  (T ~ "+" ~ E) ==> { case ((x, y), z) => x + z } |
-  (T ~ "-" ~ E) ==> { case ((x, y), z) => x - z } | T 
+  (T ~ "+" ~ E) ==> { case ((x, y), z) => x + z } ||
+  (T ~ "-" ~ E) ==> { case ((x, y), z) => x - z } || T 
 lazy val T: Parser[String, Int] = 
-  (F ~ "*" ~ T) ==> { case ((x, y), z) => x * z } | F
+  (F ~ "*" ~ T) ==> { case ((x, y), z) => x * z } || F
 lazy val F: Parser[String, Int] = 
-  ("(" ~ E ~ ")") ==> { case ((x, y), z) => y } | NumParserInt
+  ("(" ~ E ~ ")") ==> { case ((x, y), z) => y } || NumParserInt
 
+/* same parser but producing a string
 lazy val E: Parser[String, String] = 
-  (T ~ "+" ~ E) ==> { case ((x, y), z) => "(" + x + ")+(" + z + ")"} | T 
+  (T ~ "+" ~ E) ==> { case ((x, y), z) => "(" + x + ")+(" + z + ")"} || T 
 lazy val T: Parser[String, String] = 
-  (F ~ "*" ~ T) ==> { case ((x, y), z) => "(" + x + ")*("+ z + ")"} | F
+  (F ~ "*" ~ T) ==> { case ((x, y), z) => "(" + x + ")*("+ z + ")"} || F
 lazy val F: Parser[String, String] = 
-  ("(" ~ E ~ ")") ==> { case ((x, y), z) => y } | NumParser
+  ("(" ~ E ~ ")") ==> { case ((x, y), z) => y } || NumParser
+*/
 
 println(E.parse_all("1+3+4"))
 println(E.parse("1+3+4"))
@@ -126,9 +128,9 @@
 
 // no left-recursion allowed, otherwise will loop
 lazy val EL: Parser[String, Int] = 
-  (EL ~ "+" ~ EL ==> { case ((x, y), z) => x + z} | 
-   EL ~ "*" ~ EL ==> { case ((x, y), z) => x * z} |
-   "(" ~ EL ~ ")" ==> { case ((x, y), z) => y} |
+  (EL ~ "+" ~ EL ==> { case ((x, y), z) => x + z} || 
+   EL ~ "*" ~ EL ==> { case ((x, y), z) => x * z} ||
+   "(" ~ EL ~ ")" ==> { case ((x, y), z) => y} ||
    NumParserInt)
 
 //println(EL.parse_all("1+2+3"))
@@ -137,13 +139,16 @@
 
 
 // non-ambiguous vs ambiguous grammars
+
+// ambiguous
 lazy val S : Parser[String, String] =
-  ("1" ~ S ~ S) ==> { case ((x, y), z) => x + y + z } | ""
+  ("1" ~ S ~ S) ==> { case ((x, y), z) => x + y + z } || ""
 
-S.parse("1" * 17)
+S.parse("1" * 10)
 
+// non-ambiguous
 lazy val U : Parser[String, String] =
-  ("1" ~ U) ==> { case (x, y) => x + y  } | ""
+  ("1" ~ U) ==> { case (x, y) => x + y  } || ""
 
 U.parse("1" * 25)
 
@@ -155,7 +160,7 @@
 U.parse_all("1" * 100 + "0")
 
 lazy val UCount : Parser[String, Int] =
-  ("1" ~ UCount) ==> { case (x, y) => y + 1 } | "" ==> { x => 0 }
+  ("1" ~ UCount) ==> { case (x, y) => y + 1 } || "" ==> { x => 0 }
 
 UCount.parse("11111")
 UCount.parse_all("11111")
@@ -173,7 +178,17 @@
 (One ~ One ~ One).parse("111")
 (One ~ One ~ One ~ One).parse("1111")
 
-(One | Two).parse("111")
+(One || Two).parse("111")
+
+
 
 
 
+// a problem with the parser -> gets slow with nestedness
+E.parse("1")
+E.parse("(1)")
+E.parse("((1))")
+E.parse("(((1)))")
+E.parse("((((1))))")
+E.parse("((((((1))))))")
+E.parse("(((((((1)))))))")
\ No newline at end of file
--- a/progs/comb2.scala	Sun Jul 28 21:10:39 2019 +0100
+++ b/progs/comb2.scala	Tue Jul 30 20:19:40 2019 +0100
@@ -110,7 +110,7 @@
 
 // boolean expressions with some simple nesting
 lazy val BExp: Parser[String, BExp] = 
-   (AExp ~ "==" ~ AExp) ==> { case ((x, y), z) => Bop("==", x, z) }: Bexp || 
+   (AExp ~ "==" ~ AExp) ==> { case ((x, y), z) => Bop("==", x, z): BExp } || 
    (AExp ~ "!=" ~ AExp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || 
    (AExp ~ "<" ~ AExp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || 
    (AExp ~ ">" ~ AExp) ==> { case ((x, y), z) => Bop(">", x, z): BExp } ||
@@ -120,7 +120,7 @@
    ("false" ==> ((_) => False: BExp )) ||
    ("(" ~ BExp ~ ")") ==> { case ((x, y), z) => y}
 
-// statements
+// statement / statements
 lazy val Stmt: Parser[String, Stmt] =
   (("skip" ==> ((_) => Skip: Stmt)) ||
    (IdParser ~ ":=" ~ AExp) ==> { case ((x, y), z) => Assign(x, z): Stmt } ||
@@ -133,6 +133,7 @@
   (Stmt ~ ";" ~ Stmts) ==> { case ((x, y), z) => x :: z : Block } ||
   (Stmt ==> ((s) => List(s) : Block))
 
+// blocks (enclosed in curly braces)
 lazy val Block: Parser[String, Block] =
   (("{" ~ Stmts ~ "}") ==> { case ((x, y), z) => y} || 
    (Stmt ==> ((s) => List(s))))
@@ -142,19 +143,20 @@
 Block.parse_all("{x:=5;y:=8}")
 Block.parse_all("if(false)then{x:=5}else{x:=10}")
 
-val fib = """{n := 10;
-              minus1 := 0;
-              minus2 := 1;
-              temp := 0;
-              while (n > 0) do {
+val fib = """n := 10;
+             minus1 := 0;
+             minus2 := 1;
+             temp := 0;
+             while (n > 0) do {
                  temp := minus2;
                  minus2 := minus1 + minus2;
                  minus1 := temp;
                  n := n - 1
-              };
-              result := minus2}""".replaceAll("\\s+", "")
+             };
+             result := minus2""".replaceAll("\\s+", "")
 
-Block.parse_all(fib)
+Stmts.parse_all(fib)
+
 
 // an interpreter for the WHILE language
 type Env = Map[String, Int]
@@ -198,7 +200,7 @@
 
 // parse + evaluate fib program; then lookup what is
 // stored under the variable result 
-println(eval(Block.parse_all(fib).head)("result"))
+println(eval(Stmts.parse_all(fib).head)("result"))
 
 
 // more examles
@@ -208,20 +210,20 @@
 println("Factors")
 
 val factors =  
-   """{n := 12;
+   """n := 12;
       f := 2;
       while (f < n / 2 + 1) do {
         if ((n / f) * f == n) then  { write(f) } else { skip };
         f := f + 1
-      }}""".replaceAll("\\s+", "")
+      }""".replaceAll("\\s+", "")
 
-eval(Block.parse_all(factors).head)
+eval(Stmts.parse_all(factors).head)
 
 // calculate all prime numbers up to a number 
 println("Primes")
 
 val primes =  
-   """{end := 100;
+   """end := 100;
       n := 2;
       while (n < end) do {
         f := 2;
@@ -232,6 +234,6 @@
         };
         if (tmp == 0) then { write(n) } else { skip };
         n  := n + 1
-      }}""".replaceAll("\\s+", "")
+      }""".replaceAll("\\s+", "")
 
-eval(Block.parse_all(primes).head)
+eval(Stmts.parse_all(primes).head)
--- a/progs/compile_arrays.scala	Sun Jul 28 21:10:39 2019 +0100
+++ b/progs/compile_arrays.scala	Tue Jul 30 20:19:40 2019 +0100
@@ -69,9 +69,9 @@
 .end method
 """
 
+
 // Compiler functions
 
-
 // for generating new labels
 var counter = -1
 
@@ -186,33 +186,21 @@
   (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name)
 }
 
-// compiling and running files
-//
-// JVM files can be assembled with 
-//
-//    java -jar jvm/jasmin-2.4/jasmin.jar fib.j
-//
-// and started with
-//
-//    java fib/fib
 
-
-
+// main compiler functions
 import scala.util._
 import scala.sys.process._
 import scala.io
 
 def compile_tofile(bl: Block, class_name: String) = {
   val output = compile(bl, class_name)
-  val fw = new java.io.FileWriter(class_name + ".j") 
-  fw.write(output) 
-  fw.close()
+  scala.tools.nsc.io.File(s"${class_name}.j").writeAll(output)
 }
 
 def compile_all(bl: Block, class_name: String) : Unit = {
   compile_tofile(bl, class_name)
   println("compiled ")
-  val test = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!!
+  (s"java -jar jvm/jasmin-2.4/jasmin.jar ${class_name}.j").!!
   println("assembled ")
 }
 
@@ -227,91 +215,20 @@
 def compile_run(bl: Block, class_name: String) : Unit = {
   println("Start compilation")
   compile_all(bl, class_name)
-  println("running")
-  println("Time: " + time_needed(1, ("java " + class_name + "/" + class_name).!))
-}
-
-
-// BF Part
-
-// simple instructions
-def instr(c: Char) : String = c match {
-  case '>' => "ptr := ptr + 1;"
-  case '<' => "ptr := ptr - 1;"
-  case '+' => "field[ptr] := field[ptr] + 1;"
-  case '-' => "field[ptr] := field[ptr] - 1;"
-  case '.' => "x := field[ptr]; write x;"
-  case '['  => "while (field[ptr] != 0) do {"
-  case ']'  => "skip};"
-  case _ => ""
-}
-
-def instrs(prog: String) : String =
-  prog.toList.map(instr).mkString
-
-
-// compound instructions
-def splice(cs: List[Char], acc: List[(Char, Int)]) : List[(Char, Int)] = (cs, acc) match {
-  case (Nil, acc) => acc
-  case (c :: cs, Nil) => splice(cs, List((c, 1)))
-  case (c :: cs, (d, n) :: acc) => 
-    if (c == d) splice(cs, (c, n + 1) :: acc)
-    else splice(cs, (c, 1) :: (d, n) :: acc)
+  println("Start running")
+  println("Time: " + time_needed(1, (s"java ${class_name}/${class_name}").!))
 }
 
-def spl(s: String) = splice(s.toList, Nil).reverse
-
-def instr2(c: Char, n: Int) : String = c match {
-  case '>' => s"ptr := ptr + $n;"
-  case '<' => s"ptr := ptr - $n;"
-  case '+' => s"field[ptr] := field[ptr] + $n;"
-  case '-' => s"field[ptr] := field[ptr] - $n;"
-  case '.' => s"x := field[ptr]; write x;" 
-  case '['  => s"while (field[ptr] != 0) do {" * n 
-  case ']'  => s"skip};" * n
-  case _ => ""
-}
-
-def instrs2(prog: String) : String =
-  spl(prog).map{ case (c, n) => instr2(c, n) }.mkString
-
-
-def bf_str(prog: String) : String = {
-  "\n" ++
-  //"new field[30000];\n" ++
-  "ptr := 15000;" ++
-  instrs2(prog) ++
-  "skip"
-}
+// a simple test case
+val arr_test = 
+  List(Array("a", 10),                 // a[10]
+       Array("b", 2),                  // b[2]
+       AssignA("a", Num(0), Num(10)),  // a[0] := 10
+       Assign("x", Ref("a", Num(0))),  // x := a[0]
+       Write("x"),                     // write x
+       AssignA("b", Num(1), Num(5)),   // b[1] := 5
+       Assign("x", Ref("b", Num(1))),  // x := b[1]
+       Write("x"))                     // write x
 
-def bf_run(bfprog: String, name: String) = {
-  println("BF processing start")
-  val bf_string = bf_str(bfprog).replaceAll("\\s", "")
-  println(s"BF parsing start (string length ${bf_string.length})")
-  val bf_prog = Stmts.parse_all(bf_string).toList.head
-  println("BF Compile start")
-  compile_run(Array("field", 30000) :: bf_prog, name)
-}
-
-
-
-val bf1 = """++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[-<<<[
-      ->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<
-      ]>.>+[>>]>+]"""
+compile_run(arr_test, "a")
 
-bf_run(bf1, "sier")
-
-bf_run("""++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++
-       ..+++.>>.<-.<.+++.------.--------.>>+.>++.""", "hello")
-
-bf_run("""+++++++++++
-      >+>>>>++++++++++++++++++++++++++++++++++++++++++++
-      >++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>
-      +<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-
-      <-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<
-      -]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]
-      >[<<+>>[-]]<<<<<<<]>>>>>[+++++++++++++++++++++++++
-      +++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++
-      ++++++++++++++++++++++++++++++++++++++++++++.[-]<<
-      <<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<
-      [-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]""", "fibs")
--- a/progs/fun-bare.scala	Sun Jul 28 21:10:39 2019 +0100
+++ b/progs/fun-bare.scala	Tue Jul 30 20:19:40 2019 +0100
@@ -1,5 +1,5 @@
 // A Small Compiler for a Simple Functional Language
-// (it does not use a parser and lexer)
+// (it does not include a parser and lexer)
 
 // Abstract syntax trees
 abstract class Exp
@@ -70,17 +70,18 @@
   x ++ "_" ++ counter.toString()
 }
 
-// convenient string interpolations 
-// for instructions, labels and methods
+// convenient string interpolations for
+// generating instructions, labels etc
 import scala.language.implicitConversions
 import scala.language.reflectiveCalls
 
 implicit def sring_inters(sc: StringContext) = new {
-    def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
-    def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
-    def m(args: Any*): String = sc.s(args:_*) ++ "\n"
+  def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
+  def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
+  def m(args: Any*): String = sc.s(args:_*) ++ "\n"
 }
 
+// variable / index environments
 type Env = Map[String, Int]
 
 // compile expressions
--- a/progs/fun.scala	Sun Jul 28 21:10:39 2019 +0100
+++ b/progs/fun.scala	Tue Jul 30 20:19:40 2019 +0100
@@ -252,11 +252,13 @@
   }
 }
 
+case class ~[+A, +B](_1: A, _2: B)
+
 class SeqParser[I, T, S](p: => Parser[I, T], 
-                         q: => Parser[I, S])(implicit ev: I => Seq[_]) extends Parser[I, (T, S)] {
+                         q: => Parser[I, S])(implicit ev: I => Seq[_]) extends Parser[I, ~[T, S]] {
   def parse(sb: I) = 
     for ((head1, tail1) <- p.parse(sb); 
-         (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2)
+         (head2, tail2) <- q.parse(tail1)) yield (new ~(head1, head2), tail2)
 }
 
 class AltParser[I, T](p: => Parser[I, T], 
@@ -278,7 +280,7 @@
 
 def ListParser[I, T, S](p: => Parser[I, T], 
                         q: => Parser[I, S])(implicit ev: I => Seq[_]): Parser[I, List[T]] = {
-  (p ~ q ~ ListParser(p, q)) ==> { case ((x, y), z) => x :: z : List[T] } ||
+  (p ~ q ~ ListParser(p, q)) ==> { case x ~ _ ~ z => x :: z : List[T] } ||
   (p ==> ((s) => List(s)))
 }
 
@@ -337,39 +339,39 @@
 // arithmetic expressions
 lazy val Exp: Parser[List[Token], Exp] = 
   (T_KWD("if") ~ BExp ~ T_KWD("then") ~ Exp ~ T_KWD("else") ~ Exp) ==>
-    { case (((((x, y), z), u), v), w) => If(y, u, w): Exp } ||
-  (M ~ T_SEMI ~ Exp) ==> { case ((x, y), z) => Sequence(x, z): Exp } || M
+    { case _ ~ x ~ _ ~ y ~ _ ~ z => If(x, y, z): Exp } ||
+  (M ~ T_SEMI ~ Exp) ==> { case x ~ _ ~ y => Sequence(x, y): Exp } || M
 lazy val M: Parser[List[Token], Exp] =
-  (T_KWD("write") ~ L) ==> { case (x, y) => Write(y): Exp } || L
+  (T_KWD("write") ~ L) ==> { case _ ~ y => Write(y): Exp } || L
 lazy val L: Parser[List[Token], Exp] = 
-  (T ~ T_OP("+") ~ Exp) ==> { case ((x, y), z) => Aop("+", x, z): Exp } ||
-  (T ~ T_OP("-") ~ Exp) ==> { case ((x, y), z) => Aop("-", x, z): Exp } || T  
+  (T ~ T_OP("+") ~ Exp) ==> { case x ~ _ ~ z => Aop("+", x, z): Exp } ||
+  (T ~ T_OP("-") ~ Exp) ==> { case x ~ _ ~ z => Aop("-", x, z): Exp } || T  
 lazy val T: Parser[List[Token], Exp] = 
-  (F ~ T_OP("*") ~ T) ==> { case ((x, y), z) => Aop("*", x, z): Exp } || 
-  (F ~ T_OP("/") ~ T) ==> { case ((x, y), z) => Aop("/", x, z): Exp } || 
-  (F ~ T_OP("%") ~ T) ==> { case ((x, y), z) => Aop("%", x, z): Exp } || F
+  (F ~ T_OP("*") ~ T) ==> { case x ~ _ ~ z => Aop("*", x, z): Exp } || 
+  (F ~ T_OP("/") ~ T) ==> { case x ~ _ ~ z => Aop("/", x, z): Exp } || 
+  (F ~ T_OP("%") ~ T) ==> { case x ~ _ ~ z => Aop("%", x, z): Exp } || F
 lazy val F: Parser[List[Token], Exp] = 
   (IdParser ~ T_LPAREN ~ ListParser(Exp, T_COMMA) ~ T_RPAREN) ==> 
-    { case (((x, y), z), w) => Call(x, z): Exp } ||
-  (T_LPAREN ~ Exp ~ T_RPAREN) ==> { case ((x, y), z) => y: Exp } || 
+    { case x ~ _ ~ z ~ _ => Call(x, z): Exp } ||
+  (T_LPAREN ~ Exp ~ T_RPAREN) ==> { case _ ~ y ~ _ => y: Exp } || 
   IdParser ==> { case x => Var(x): Exp } || 
   NumParser ==> { case x => Num(x): Exp }
 
 // boolean expressions
 lazy val BExp: Parser[List[Token], BExp] = 
-  (Exp ~ T_OP("==") ~ Exp) ==> { case ((x, y), z) => Bop("==", x, z): BExp } || 
-  (Exp ~ T_OP("!=") ~ Exp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || 
-  (Exp ~ T_OP("<") ~ Exp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || 
-  (Exp ~ T_OP(">") ~ Exp) ==> { case ((x, y), z) => Bop("<", z, x): BExp } || 
-  (Exp ~ T_OP("<=") ~ Exp) ==> { case ((x, y), z) => Bop("<=", x, z): BExp } || 
-  (Exp ~ T_OP("=>") ~ Exp) ==> { case ((x, y), z) => Bop("<=", z, x): BExp }  
+  (Exp ~ T_OP("==") ~ Exp) ==> { case x ~ _ ~ z => Bop("==", x, z): BExp } || 
+  (Exp ~ T_OP("!=") ~ Exp) ==> { case x ~ _ ~ z => Bop("!=", x, z): BExp } || 
+  (Exp ~ T_OP("<") ~ Exp) ==> { case x ~ _ ~ z => Bop("<", x, z): BExp } || 
+  (Exp ~ T_OP(">") ~ Exp) ==> { case x ~ _ ~ z => Bop("<", z, x): BExp } || 
+  (Exp ~ T_OP("<=") ~ Exp) ==> { case x ~ _ ~ z => Bop("<=", x, z): BExp } || 
+  (Exp ~ T_OP("=>") ~ Exp) ==> { case x ~ _ ~ z => Bop("<=", z, x): BExp }  
 
 lazy val Defn: Parser[List[Token], Decl] =
    (T_KWD("def") ~ IdParser ~ T_LPAREN ~ ListParser(IdParser, T_COMMA) ~ T_RPAREN ~ T_OP("=") ~ Exp) ==>
-     { case ((((((x, y), z), w), u), v), r) => Def(y, w, r): Decl }
+     { case _ ~ y ~ _ ~ w ~ _ ~ _ ~ r => Def(y, w, r): Decl }
 
 lazy val Prog: Parser[List[Token], List[Decl]] =
-  (Defn ~ T_SEMI ~ Prog) ==> { case ((x, y), z) => x :: z : List[Decl] } ||
+  (Defn ~ T_SEMI ~ Prog) ==> { case x ~ _ ~ z => x :: z : List[Decl] } ||
   (Exp ==> ((s) => List(Main(s)) : List[Decl]))
 
 
--- a/progs/funt.scala	Sun Jul 28 21:10:39 2019 +0100
+++ b/progs/funt.scala	Tue Jul 30 20:19:40 2019 +0100
@@ -252,11 +252,15 @@
   }
 }
 
+// convenience for matching later on
+case class ~[+A, +B](_1: A, _2: B)
+
+
 class SeqParser[I, T, S](p: => Parser[I, T], 
-                         q: => Parser[I, S])(implicit ev: I => Seq[_]) extends Parser[I, (T, S)] {
+                         q: => Parser[I, S])(implicit ev: I => Seq[_]) extends Parser[I, ~[T, S]] {
   def parse(sb: I) = 
     for ((head1, tail1) <- p.parse(sb); 
-         (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2)
+         (head2, tail2) <- q.parse(tail1)) yield (new ~(head1, head2), tail2)
 }
 
 class AltParser[I, T](p: => Parser[I, T], 
@@ -278,7 +282,7 @@
 
 def ListParser[I, T, S](p: => Parser[I, T], 
                         q: => Parser[I, S])(implicit ev: I => Seq[_]): Parser[I, List[T]] = {
-  (p ~ q ~ ListParser(p, q)) ==> { case ((x, y), z) => x :: z : List[T] } ||
+  (p ~ q ~ ListParser(p, q)) ==> { case x ~ _ ~ z => x :: z : List[T] } ||
   (p ==> ((s) => List(s)))
 }
 
@@ -337,39 +341,39 @@
 // arithmetic expressions
 lazy val Exp: Parser[List[Token], Exp] = 
   (T_KWD("if") ~ BExp ~ T_KWD("then") ~ Exp ~ T_KWD("else") ~ Exp) ==>
-    { case (((((x, y), z), u), v), w) => If(y, u, w): Exp } ||
-  (M ~ T_SEMI ~ Exp) ==> { case ((x, y), z) => Sequence(x, z): Exp } || M
+    { case _ ~ y ~ _ ~ u ~ _ ~ w => If(y, u, w): Exp } ||
+  (M ~ T_SEMI ~ Exp) ==> { case x ~ _ ~ z => Sequence(x, z): Exp } || M
 lazy val M: Parser[List[Token], Exp] =
-  (T_KWD("write") ~ L) ==> { case (x, y) => Write(y): Exp } || L
+  (T_KWD("write") ~ L) ==> { case _ ~ y => Write(y): Exp } || L
 lazy val L: Parser[List[Token], Exp] = 
-  (T ~ T_OP("+") ~ Exp) ==> { case ((x, y), z) => Aop("+", x, z): Exp } ||
-  (T ~ T_OP("-") ~ Exp) ==> { case ((x, y), z) => Aop("-", x, z): Exp } || T  
+  (T ~ T_OP("+") ~ Exp) ==> { case x ~ _ ~ z => Aop("+", x, z): Exp } ||
+  (T ~ T_OP("-") ~ Exp) ==> { case x ~ _ ~ z => Aop("-", x, z): Exp } || T  
 lazy val T: Parser[List[Token], Exp] = 
-  (F ~ T_OP("*") ~ T) ==> { case ((x, y), z) => Aop("*", x, z): Exp } || 
-  (F ~ T_OP("/") ~ T) ==> { case ((x, y), z) => Aop("/", x, z): Exp } || 
-  (F ~ T_OP("%") ~ T) ==> { case ((x, y), z) => Aop("%", x, z): Exp } || F
+  (F ~ T_OP("*") ~ T) ==> { case x ~ _ ~ z => Aop("*", x, z): Exp } || 
+  (F ~ T_OP("/") ~ T) ==> { case x ~ _ ~ z => Aop("/", x, z): Exp } || 
+  (F ~ T_OP("%") ~ T) ==> { case x ~ _ ~ z => Aop("%", x, z): Exp } || F
 lazy val F: Parser[List[Token], Exp] = 
   (IdParser ~ T_LPAREN ~ ListParser(Exp, T_COMMA) ~ T_RPAREN) ==> 
-    { case (((x, y), z), w) => Call(x, z): Exp } ||
-  (T_LPAREN ~ Exp ~ T_RPAREN) ==> { case ((x, y), z) => y: Exp } || 
+    { case x ~ _ ~ z ~ _ => Call(x, z): Exp } ||
+  (T_LPAREN ~ Exp ~ T_RPAREN) ==> { case _ ~ y ~ _ => y: Exp } || 
   IdParser ==> { case x => Var(x): Exp } || 
   NumParser ==> { case x => Num(x): Exp }
 
 // boolean expressions
 lazy val BExp: Parser[List[Token], BExp] = 
-  (Exp ~ T_OP("==") ~ Exp) ==> { case ((x, y), z) => Bop("==", x, z): BExp } || 
-  (Exp ~ T_OP("!=") ~ Exp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || 
-  (Exp ~ T_OP("<") ~ Exp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || 
-  (Exp ~ T_OP(">") ~ Exp) ==> { case ((x, y), z) => Bop("<", z, x): BExp } || 
-  (Exp ~ T_OP("<=") ~ Exp) ==> { case ((x, y), z) => Bop("<=", x, z): BExp } || 
-  (Exp ~ T_OP("=>") ~ Exp) ==> { case ((x, y), z) => Bop("<=", z, x): BExp }  
+  (Exp ~ T_OP("==") ~ Exp) ==> { case x ~ _ ~ z => Bop("==", x, z): BExp } || 
+  (Exp ~ T_OP("!=") ~ Exp) ==> { case x ~ _ ~ z => Bop("!=", x, z): BExp } || 
+  (Exp ~ T_OP("<") ~ Exp) ==> { case x ~ _ ~ z => Bop("<", x, z): BExp } || 
+  (Exp ~ T_OP(">") ~ Exp) ==> { case x ~ _ ~ z => Bop("<", z, x): BExp } || 
+  (Exp ~ T_OP("<=") ~ Exp) ==> { case x ~ _ ~ z => Bop("<=", x, z): BExp } || 
+  (Exp ~ T_OP("=>") ~ Exp) ==> { case x ~ _ ~ z => Bop("<=", z, x): BExp }  
 
 lazy val Defn: Parser[List[Token], Decl] =
    (T_KWD("def") ~ IdParser ~ T_LPAREN ~ ListParser(IdParser, T_COMMA) ~ T_RPAREN ~ T_OP("=") ~ Exp) ==>
-     { case ((((((x, y), z), w), u), v), r) => Def(y, w, r): Decl }
+     { case x ~ y ~ z ~ w ~ u ~ v ~ r => Def(y, w, r): Decl }
 
 lazy val Prog: Parser[List[Token], List[Decl]] =
-  (Defn ~ T_SEMI ~ Prog) ==> { case ((x, y), z) => x :: z : List[Decl] } ||
+  (Defn ~ T_SEMI ~ Prog) ==> { case x ~ _ ~ z => x :: z : List[Decl] } ||
   (Exp ==> ((s) => List(Main(s)) : List[Decl]))
 
 
@@ -543,25 +547,3 @@
 //examples
 compile_run("defs")
 compile_run("fact")
-
-
-
-
-
-// a problem with the parser 
-/*
-val text = "(((((1)))))"
-val tokens = tokenise(text)
-println(tokens)
-val ast = Prog.parse_single(tokens)
-println(ast)
-
-Exp.parse_single(tokens)
-
-
-
-val text = "((((1))))"
-val tokens = tokenise(text)
-println(tokens)
-Exp.parse(tokens)
-*/