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