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