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