| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      1 | // Parser Combinators: Simple Version
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      2 | //====================================
 | 
| 742 |      3 | //
 | 
|  |      4 | // Call with
 | 
|  |      5 | //
 | 
|  |      6 | //  amm comb1.sc
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      7 | 
 | 
| 742 |      8 |  
 | 
| 906 |      9 | //  Note, in the lectures I did not show the type bound
 | 
|  |     10 | //  using is: I => Seq[_], which means that the input 
 | 
|  |     11 | //  type 'I' needs to be a sequence. 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     12 | 
 | 
| 940 |     13 | type IsSeq[I] = I => Seq[_]
 | 
|  |     14 | 
 | 
|  |     15 | abstract class Parser[I, T](using is: IsSeq[I])  {
 | 
| 852 |     16 |   def parse(in: I): Set[(T, I)]  
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     17 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     18 |   def parse_all(in: I) : Set[T] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     19 |     for ((hd, tl) <- parse(in); 
 | 
| 906 |     20 |         if is(tl).isEmpty) yield hd
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     21 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     22 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     23 | // parser combinators
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     24 | 
 | 
| 940 |     25 | 
 | 
| 799 |     26 | // alternative parser
 | 
| 940 |     27 | class AltParser[I : IsSeq, T](p: => Parser[I, T], 
 | 
|  |     28 |                               q: => Parser[I, T]) extends Parser[I, T] {
 | 
| 799 |     29 |   def parse(in: I) = p.parse(in) ++ q.parse(in)   
 | 
|  |     30 | }
 | 
|  |     31 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     32 | // sequence parser
 | 
| 940 |     33 | class SeqParser[I: IsSeq, T, S](p: => Parser[I, T], 
 | 
|  |     34 |                                 q: => Parser[I, S]) extends Parser[I, (T, S)] {
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     35 |   def parse(in: I) = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     36 |     for ((hd1, tl1) <- p.parse(in); 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 |          (hd2, tl2) <- q.parse(tl1)) yield ((hd1, hd2), tl2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     39 | 
 | 
| 742 |     40 | // map parser
 | 
| 940 |     41 | class MapParser[I : IsSeq, T, S](p: => Parser[I, T], 
 | 
|  |     42 |                          f: T => S) extends Parser[I, S] {
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 |   def parse(in: I) = for ((hd, tl) <- p.parse(in)) yield (f(hd), tl)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 | 
 | 
| 742 |     46 | 
 | 
|  |     47 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 | // an example of an atomic parser for characters
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 | case class CharParser(c: Char) extends Parser[String, Char] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 |   def parse(in: String) = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 |     if (in != "" && in.head == c) Set((c, in.tail)) else Set()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     52 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     53 | 
 | 
| 906 |     54 | CharParser('a').parse("abc")
 | 
| 799 |     55 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 | // an atomic parser for parsing strings according to a regex
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 | import scala.util.matching.Regex
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     58 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     59 | case class RegexParser(reg: Regex) extends Parser[String, String] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     60 |   def parse(in: String) = reg.findPrefixMatchOf(in) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 |     case None => Set()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 |     case Some(m) => Set((m.matched, m.after.toString))  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     64 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     65 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     66 | // atomic parsers for numbers and "verbatim" strings 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     67 | val NumParser = RegexParser("[0-9]+".r)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     68 | def StrParser(s: String) = RegexParser(Regex.quote(s).r)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     69 | 
 | 
| 897 |     70 | NumParser.parse("a123a123bc") 
 | 
| 906 |     71 | StrParser("else").parse("elsethen")
 | 
| 742 |     72 | 
 | 
| 799 |     73 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     74 | // NumParserInt transforms a "string integer" into a propper Int
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     75 | // (needs "new" because MapParser is not a case class)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     76 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     77 | val NumParserInt = new MapParser(NumParser, (s: String) => s.toInt)
 | 
| 897 |     78 | NumParserInt.parse("123abc")
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     79 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     80 | // the following string interpolation allows us to write 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     81 | // StrParser(_some_string_) more conveniently as 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     82 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     83 | // p"<_some_string_>" 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     84 | 
 | 
| 906 |     85 | extension (sc: StringContext) 
 | 
|  |     86 |   def p(args: Any*) = StrParser(sc.s(args:_*))
 | 
| 897 |     87 | 
 | 
|  |     88 | 
 | 
|  |     89 | (p"else").parse("elsethen")           
 | 
| 799 |     90 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 | // more convenient syntax for parser combinators
 | 
| 940 |     92 | extension [I: IsSeq, T](p: Parser[I, T]) {
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     93 |   def ||(q : => Parser[I, T]) = new AltParser[I, T](p, q)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     94 |   def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q)
 | 
| 919 |     95 |   def map[S](f: => T => S) = new MapParser[I, T, S](p, f)
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     96 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     97 | 
 | 
| 947 |     98 | // simple example of transforming the 
 | 
|  |     99 | // result into capital letters
 | 
| 897 |    100 | def toU(s: String) = s.map(_.toUpper)
 | 
|  |    101 | 
 | 
| 947 |    102 | (p"else").map(toU(_)).parse("elseifthen")  
 | 
| 897 |    103 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    104 | // these implicits allow us to use an infix notation for
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    105 | // sequences and alternatives; we also can write the usual
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    106 | // map for a MapParser
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    107 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    108 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    109 | // with this NumParserInt can now be written more conveniently
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    110 | // as:
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    111 | 
 | 
| 799 |    112 | val NumParserInt2 = NumParser.map(_.toInt)
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 | // A parser for palindromes (just returns them as string)
 | 
| 947 |    116 | //  since the parser is recursive it needs to be lazy
 | 
| 803 |    117 | lazy val Pal : Parser[String, String] = {
 | 
| 919 |    118 |    (p"a" ~ Pal ~ p"a").map{ case ((x, y), z) => s"$x$y$z" } || 
 | 
|  |    119 |    (p"b" ~ Pal ~ p"b").map{ case ((x, y), z) => s"$x$y$z" } || 
 | 
| 896 |    120 |     p"a" || p"b" || p""
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    121 | }  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    122 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    123 | // examples
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 | Pal.parse_all("abaaaba")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 | Pal.parse("abaaaba")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    126 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 | println("Palindrome: " + Pal.parse_all("abaaaba"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 | 
 | 
| 799 |    129 | // A parser for wellnested parentheses 
 | 
|  |    130 | //
 | 
|  |    131 | //   P ::= ( P ) P | epsilon
 | 
|  |    132 | //
 | 
|  |    133 | //   (transforms '(' -> '{' , ')' -> '}' )
 | 
|  |    134 | lazy val P : Parser[String, String] = {
 | 
| 919 |    135 |   (p"(" ~ P ~ p")" ~ P).map{ case (((_, x), _), y) => "{" + x + "}" + y } ||
 | 
| 799 |    136 |   p""
 | 
|  |    137 | }  
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 | println(P.parse_all("(((()()))())"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 | println(P.parse_all("(((()()))()))"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 | println(P.parse_all(")("))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 | println(P.parse_all("()"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 | // A parser for arithmetic expressions (Terms and Factors)
 | 
| 898 |    145 | 
 | 
| 799 |    146 | lazy val E: Parser[String, Int] = {
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 |   (T ~ p"+" ~ E).map{ case ((x, _), z) => x + z } ||
 | 
| 799 |    148 |   (T ~ p"-" ~ E).map{ case ((x, _), z) => x - z } || T }
 | 
|  |    149 | lazy val T: Parser[String, Int] = {
 | 
|  |    150 |   (F ~ p"*" ~ T).map{ case ((x, _), z) => x * z } || F }
 | 
|  |    151 | lazy val F: Parser[String, Int] = {
 | 
|  |    152 |   (p"(" ~ E ~ p")").map{ case ((_, y), _) => y } || NumParserInt }
 | 
| 898 |    153 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    154 | println(E.parse_all("1+3+4"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 | println(E.parse("1+3+4"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    156 | println(E.parse_all("4*2+3"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    157 | println(E.parse_all("4*(2+3)"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    158 | println(E.parse_all("(4)*((2+3))"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    159 | println(E.parse_all("4/2+3"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    160 | println(E.parse("1 + 2 * 3"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    161 | println(E.parse_all("(1+2)+3"))
 | 
| 799 |    162 | println(E.parse_all("1+2+3"))
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    163 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    164 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    165 | // with parser combinators (and other parsing algorithms)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    166 | // no left-recursion is allowed, otherwise the will loop
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    167 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    168 | lazy val EL: Parser[String, Int] = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 |   ((EL ~ p"+" ~ EL).map{ case ((x, y), z) => x + z} || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 |    (EL ~ p"*" ~ EL).map{ case ((x, y), z) => x * z} ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    171 |    (p"(" ~ EL ~ p")").map{ case ((x, y), z) => y} ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 |    NumParserInt)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    173 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    174 | // this will run forever:
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    175 | //println(EL.parse_all("1+2+3"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    176 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    177 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    178 | // non-ambiguous vs ambiguous grammars
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    180 | // ambiguous
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    181 | lazy val S : Parser[String, String] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    182 |   (p"1" ~ S ~ S).map{ case ((x, y), z) => x + y + z } || p""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    183 | 
 | 
| 850 |    184 | //println(time(S.parse("1" * 10)))
 | 
|  |    185 | //println(time(S.parse_all("1" * 10)))
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    186 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    187 | // non-ambiguous
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    188 | lazy val U : Parser[String, String] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    189 |   (p"1" ~ U).map{ case (x, y) => x + y } || p""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    190 | 
 | 
| 850 |    191 | //println(time(U.parse("1" * 10)))
 | 
|  |    192 | //println(time(U.parse_all("1" * 10)))
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    193 | println(U.parse("1" * 25))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    194 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    195 | U.parse("11")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    196 | U.parse("11111")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    197 | U.parse("11011")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    198 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    199 | U.parse_all("1" * 100)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    200 | U.parse_all("1" * 100 + "0")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    201 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    202 | // you can see the difference in second example
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    203 | //S.parse_all("1" * 100)         // succeeds
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    204 | //S.parse_all("1" * 100 + "0")   // fails
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    205 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    206 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    207 | // A variant which counts how many 1s are parsed
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    208 | lazy val UCount : Parser[String, Int] =
 | 
| 799 |    209 |   (p"1" ~ UCount).map{ case (_, y) => y + 1 } || p"".map{ _ => 0 }
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    210 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    211 | println(UCount.parse("11111"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    212 | println(UCount.parse_all("11111"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    213 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    214 | // Two single character parsers
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    215 | lazy val One : Parser[String, String] = p"a"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    216 | lazy val Two : Parser[String, String] = p"b"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    217 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    218 | One.parse("a")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    219 | One.parse("aaa")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    220 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    221 | // note how the pairs nest to the left with sequence parsers
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    222 | (One ~ One).parse("aaa")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    223 | (One ~ One ~ One).parse("aaa")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    224 | (One ~ One ~ One ~ One).parse("aaaa")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    225 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    226 | (One || Two).parse("aaa")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    227 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    228 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    229 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    230 | // a problem with the arithmetic expression parser: it 
 | 
| 742 |    231 | // gets very slow with deeply nested parentheses
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    232 | 
 | 
| 919 |    233 | println("A runtime problem")
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    234 | println(E.parse("1"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    235 | println(E.parse("(1)"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    236 | println(E.parse("((1))"))
 | 
| 906 |    237 | println(E.parse("(((1)))"))
 | 
|  |    238 | println(E.parse("((((1))))"))
 | 
| 919 |    239 | println(E.parse("((((((1))))))"))
 | 
|  |    240 | println(E.parse("(((((((1)))))))"))
 | 
| 906 |    241 | //println(E.parse("((((((((1))))))))"))
 | 
| 828 |    242 | 
 | 
|  |    243 | 
 | 
| 919 |    244 | // faster because of merge in the +/- case
 | 
| 906 |    245 | lazy val E2: Parser[String, Int] = {
 | 
| 919 |    246 |   (T2 ~ (p"+" || p"-") ~ E2).map[Int]{ case ((x, y), z) => if (y == "+") x + z else x - z} || T2 }
 | 
| 906 |    247 | lazy val T2: Parser[String, Int] = {
 | 
| 919 |    248 |   (F2 ~ p"*" ~ T2).map[Int]{ case ((x, _), z) => x * z } || F2 }
 | 
| 906 |    249 | lazy val F2: Parser[String, Int] = {
 | 
| 919 |    250 |   (p"(" ~ E2 ~ p")").map[Int]{ case ((_, y), _) => y } || NumParserInt }
 | 
| 828 |    251 | 
 | 
|  |    252 | 
 | 
| 919 |    253 | println("mitigated by merging clauses")
 | 
| 906 |    254 | println(E2.parse("1"))
 | 
|  |    255 | println(E2.parse("(1)"))
 | 
|  |    256 | println(E2.parse("((1))"))
 | 
|  |    257 | println(E2.parse("(((1)))"))
 | 
|  |    258 | println(E2.parse("((((1))))"))
 | 
| 919 |    259 | println(E2.parse("((((((1))))))"))
 | 
|  |    260 | println(E2.parse("(((((((1)))))))"))
 | 
| 936 |    261 | println(E2.parse("((((((((1))))))))"))
 |