solutions/cw5/fun_parser.sc
author Christian Urban <christian.urban@kcl.ac.uk>
Fri, 09 Dec 2022 11:00:05 +0000
changeset 903 2f86ebda3629
parent 894 02ef5c3abc51
child 920 7af2eea19646
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     1
// Author: Zhuo Ying Jiang Li
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     2
// Starting code by Dr Christian Urban
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     3
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     4
// parser: convert sequence of tokens to AST
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     5
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     6
//
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     7
// Use this command to print parsed AST:
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
     8
// amm fun_parser.sc <name>.fun
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
     9
//
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    10
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    11
import $file.fun_tokens, fun_tokens._
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    12
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    13
// more convenience for the map parsers later on;
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    14
// it allows writing nested patterns as
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    15
// case x ~ y ~ z => ...
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    16
case class ~[+A, +B](x: A, y: B)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    17
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    18
// constraint for the input
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    19
type IsSeq[A] = A => Seq[_]
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    20
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    21
abstract class Parser[I : IsSeq, T]{
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    22
  def parse(in: I): Set[(T, I)]
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    23
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    24
  def parse_all(in: I) : Set[T] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    25
    for ((hd, tl) <- parse(in);
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    26
        if tl.isEmpty) yield hd
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    27
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    28
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    29
// parser combinators
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    30
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    31
// sequence parser
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    32
class SeqParser[I : IsSeq, T, S](p: => Parser[I, T],
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    33
                                 q: => Parser[I, S]) extends Parser[I, ~[T, S]] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    34
  def parse(in: I) =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    35
    for ((hd1, tl1) <- p.parse(in);
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    36
         (hd2, tl2) <- q.parse(tl1)) yield (new ~(hd1, hd2), tl2)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    37
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    38
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    39
// alternative parser
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    40
class AltParser[I : IsSeq, T](p: => Parser[I, T],
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    41
                              q: => Parser[I, T]) extends Parser[I, T] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    42
  def parse(in: I) = p.parse(in) ++ q.parse(in)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    43
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    44
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    45
// map parser
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    46
class MapParser[I : IsSeq, T, S](p: => Parser[I, T],
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    47
                                 f: T => S) extends Parser[I, S] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    48
  def parse(in: I) = for ((hd, tl) <- p.parse(in)) yield (f(hd), tl)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    49
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    50
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    51
// more convenient syntax for parser combinators
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    52
implicit def ParserOps[I : IsSeq, T](p: Parser[I, T]) = new {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    53
  def ||(q : => Parser[I, T]) = new AltParser[I, T](p, q)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    54
  def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q)
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    55
  def map[S](f: => T => S) = new MapParser[I, T, S](p, f)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    56
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    57
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    58
// -------------------------------------------------
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    59
// atomic parsers
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    60
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    61
// atomic parser for types
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    62
case class TypeParser(ty: Set[String]) extends Parser[Tokens, String] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    63
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    64
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    65
    case tk::tkns if tk._1 == "type" && ty.contains(tk._2) => Set((tk._2, tkns))
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    66
    case _ => Set()
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    67
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    68
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    69
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    70
// atomic parser for global ids
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    71
case object GlobalIdParser extends Parser[Tokens, String] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    72
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    73
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    74
    case tk::tkns if tk._1 == "global" => Set((tk._2, tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    75
    case _ => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    76
  }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    77
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    78
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    79
// atomic parser for ids
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    80
case object IdParser extends Parser[Tokens, String] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    81
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    82
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    83
    case tk::tkns if tk._1 == "id" => Set((tk._2, tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    84
    case _ => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    85
  }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    86
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    87
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    88
// atomic parser for doubles (I use Float because that's what is used in the AST structures given in CW5)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    89
case object DoubleParser extends Parser[Tokens, Float] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    90
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    91
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    92
    case tk::tkns if tk._1 == "double" => Set((tk._2.toFloat, tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    93
    case _ => Set()
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    94
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    95
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
    96
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    97
// atomic parser for integers
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    98
case object IntParser extends Parser[Tokens, Int] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
    99
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   100
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   101
    case tk::tkns if tk._1 == "int" => Set((tk._2.toInt, tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   102
    case _ => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   103
  }
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   104
}
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   105
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   106
// atomic parser for operators
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   107
case class OpParser(ops: Set[String]) extends Parser[Tokens, String] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   108
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   109
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   110
    case tk::tkns if tk._1 == "op" && ops.contains(tk._2) => Set((tk._2, tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   111
    case _ => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   112
  }
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   113
}
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   114
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   115
// atomic parser for character
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   116
case object CharParser extends Parser[Tokens, Char] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   117
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   118
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   119
    case tk::tkns if tk._1 == "ch" => {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   120
      val stripped = tk._2.slice(1, tk._2.length-1)  // strip off single quotes
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   121
      stripped match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   122
        case "\\n" => Set(('\n', tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   123
        case "\\t" => Set(('\t', tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   124
        case "\\r" => Set(('\r', tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   125
        case c => Set((c(0), tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   126
      }
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   127
    }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   128
    case _ => Set()
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   129
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   130
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   131
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   132
// parser for list of arguments
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   133
def ListParser[I, T, S](p: => Parser[I, T], 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   134
                        q: => Parser[I, S])(implicit ev: I => Seq[_]): Parser[I, List[T]] = {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   135
  (p ~ q ~ ListParser(p, q)).map{ case x ~ _ ~ z => x :: z : List[T] } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   136
  (p.map((s) => List(s)))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   137
}
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   138
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   139
// I may want to write string interpolations for:
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   140
// keywords, semicolon, colon, comma, parentheses
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   141
case class StrParser(s: String) extends Parser[Tokens, String] {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   142
  def parse(tokens: Tokens) = tokens match {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   143
    case Nil => Set()
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   144
    case tk::tkns if tk._2 == s => Set((s, tkns))
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   145
    case _ => Set()
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   146
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   147
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   148
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   149
implicit def parser_interpolation(sc: StringContext) = new {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   150
  def p(args: Any*) = StrParser(sc.s(args:_*))
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   151
}
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   152
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   153
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   154
// the AST datastructures for the FUN language
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   155
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   156
abstract class Exp
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   157
abstract class BExp
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   158
abstract class Decl
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   159
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   160
case class Def(name: String, args: List[(String, String)], ty: String, body: Exp) extends Decl
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   161
case class Main(e: Exp) extends Decl
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   162
case class Const(name: String, v: Int) extends Decl
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   163
case class FConst(name: String, x: Float) extends Decl
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   164
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   165
case class Call(name: String, args: List[Exp]) extends Exp
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   166
case class If(a: BExp, e1: Exp, e2: Exp) extends Exp
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   167
case class Var(s: String) extends Exp
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   168
case class Num(i: Int) extends Exp  // integer numbers
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   169
case class FNum(i: Float) extends Exp  // float numbers
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   170
case class ChConst(c: Int) extends Exp  // character constants
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   171
case class Aop(o: String, a1: Exp, a2: Exp) extends Exp
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   172
case class Sequence(e1: Exp, e2: Exp) extends Exp  // expressions separated by semicolons
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   173
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   174
case class Bop(o: String, a1: Exp, a2: Exp) extends BExp
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   175
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   176
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   177
lazy val Exps: Parser[Tokens, Exp] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   178
  (Exp ~ p";" ~ Exps).map[Exp]{ case x ~ _ ~ z => Sequence(x, z) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   179
  Exp
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   180
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   181
lazy val Exp: Parser[Tokens, Exp] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   182
  (p"if" ~ BExp ~ p"then" ~ Exp ~ p"else" ~ Exp).map[Exp]{ case _ ~ x ~ _ ~ y ~ _ ~ z => If(x, y, z) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   183
  M
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   184
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   185
lazy val M: Parser[Tokens, Exp] = 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   186
  (T ~ OpParser(Set("+", "-")) ~ M).map[Exp]{ case x ~ y ~ z => Aop(y, x, z) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   187
  T
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   188
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   189
lazy val T: Parser[Tokens, Exp] = 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   190
  (U ~ OpParser(Set("*", "/", "%")) ~ T).map[Exp]{ case x ~ y ~ z => Aop(y, x, z) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   191
  U
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   192
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   193
// includes negative factor
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   194
// a + - b CAN be recognised
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   195
// - - - b CAN be recognised
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   196
lazy val U: Parser[Tokens, Exp] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   197
  (OpParser(Set("-")) ~ U).map[Exp]{ case _ ~ y => Aop("*", Num(-1), y) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   198
  (OpParser(Set("+")) ~ U).map[Exp]{ case _ ~ y => y } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   199
  F
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   200
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   201
lazy val F: Parser[Tokens, Exp] = 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   202
  (p"(" ~ Exp ~ p")").map[Exp]{ case _ ~ y ~ _ => y } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   203
  (p"skip").map(_ => Call("skip", Nil)) ||  // hardcoded
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   204
  (p"skip" ~ p"(" ~ p")").map(_ => Call("skip", Nil)) ||  // hardcoded
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   205
  (IdParser ~ p"(" ~ ListParser(Exp, p",") ~ p")").map[Exp]{ case id ~ _ ~ args ~ _ => Call(id, args) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   206
  (IdParser ~ p"(" ~ p")").map[Exp]{ case id ~ _ ~ _ => Call(id, Nil) } ||  // NOTE: empty args are also accepted!
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   207
  (IdParser || GlobalIdParser).map(x => Var(x)) ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   208
  IntParser.map(x => Num(x)) ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   209
  DoubleParser.map(x => FNum(x)) ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   210
  CharParser.map(x => ChConst(x.toInt)) ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   211
  (p"{" ~ Exps ~ p"}").map[Exp]{ case _ ~ x ~ _ => x }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   212
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   213
lazy val BExp: Parser[Tokens, BExp] = 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   214
  (Exp ~ OpParser(Set("==", "!=", "<", ">", "<=", ">=")) ~ Exp).map[BExp]{ case x ~ y ~ z => Bop(y, x, z) } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   215
  (p"(" ~ BExp ~ p")").map[BExp]{ case _ ~ y ~ _ => y }
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   216
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   217
lazy val TypedIdParser: Parser[Tokens, (String, String)] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   218
  (IdParser ~ p":" ~ TypeParser(Set("Int", "Double"))).map{ case n ~ _ ~ t => (n, t) }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   219
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   220
lazy val Defn: Parser[Tokens, Decl] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   221
  (p"def" ~ IdParser ~ p"(" ~ ListParser(TypedIdParser, p",") ~ p")" ~ p":" ~ TypeParser(Set("Int", "Double", "Void")) ~ OpParser(Set("=")) ~ Exp).map[Decl]{
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   222
    case _ ~ y ~ _ ~ w ~ _ ~ _ ~ t ~ _ ~ b => Def(y, w, t, b)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   223
  } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   224
  (p"def" ~ IdParser ~ p"(" ~ p")" ~ p":" ~ TypeParser(Set("Int", "Double", "Void")) ~ OpParser(Set("=")) ~ Exp).map[Decl]{
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   225
    case _ ~ y ~ _ ~ _ ~ _ ~ t ~ _ ~ b => Def(y, Nil, t, b)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   226
  }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   227
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   228
lazy val Constp: Parser[Tokens, Decl] = 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   229
  (p"val" ~ GlobalIdParser ~ p":" ~ TypeParser(Set("Int")) ~ OpParser(Set("=")) ~ IntParser).map[Decl]{  // IntParser? Not Exp? For this AST, impossible to define Exp
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   230
    case _ ~ id ~ _ ~ _ ~ _ ~ n => Const(id, n)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   231
  } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   232
  (p"val" ~ GlobalIdParser ~ p":" ~ TypeParser(Set("Int")) ~ OpParser(Set("=")) ~ OpParser(Set("-")) ~ IntParser).map[Decl]{  // IntParser? Not Exp? For this AST, impossible to define Exp
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   233
    case _ ~ id ~ _ ~ _ ~ _ ~ _ ~ n => Const(id, -n)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   234
  }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   235
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   236
// Int can be converted to Double but not viceversa
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   237
lazy val FConstp: Parser[Tokens, Decl] =
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   238
  (p"val" ~ GlobalIdParser ~ p":" ~ TypeParser(Set("Double")) ~ OpParser(Set("=")) ~ (DoubleParser || IntParser.map[Float](i => i.toFloat))).map[Decl]{
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   239
    case _ ~ id ~ _ ~ _ ~ _ ~ n => FConst(id, n)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   240
  } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   241
  (p"val" ~ GlobalIdParser ~ p":" ~ TypeParser(Set("Double")) ~ OpParser(Set("=")) ~ OpParser(Set("-")) ~ (DoubleParser || IntParser.map[Float](i => i.toFloat))).map[Decl]{
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   242
    case _ ~ id ~ _ ~ _ ~ _ ~ _ ~ n => FConst(id, -n)
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   243
  }
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   244
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   245
// Prog consists of global const declarations, f(x) defs, and exp in ANY order
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   246
// restricted to main body at the bottom
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   247
lazy val Prog: Parser[Tokens, List[Decl]] = 
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   248
  (Defn ~ p";" ~ Prog).map[List[Decl]]{ case x ~ _ ~ z => x :: z } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   249
  (Constp ~ p";" ~ Prog).map[List[Decl]]{ case x ~ _ ~ z => x :: z } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   250
  (FConstp ~ p";" ~ Prog).map[List[Decl]]{ case x ~ _ ~ z => x :: z } ||
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   251
  Exp.map[List[Decl]](s => List(Main(s)))
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   252
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   253
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   254
def parse_tks(tokens: Tokens) = Prog.parse_all(tokens)
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   255
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   256
import scala.io.Source._
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   257
903
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   258
@main
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   259
def parse(filename: String) = {
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   260
  val fun_code = fromFile(filename).getLines.mkString("\n")
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   261
  // print the AST list to screen
2f86ebda3629 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 894
diff changeset
   262
  println(parse_tks(tokenise(fun_code)))
864
Christian Urban <christian.urban@kcl.ac.uk>
parents:
diff changeset
   263
}