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 |
|