2
2
** ________ ___ / / ___ Scala API **
3
** / __/ __// _ | / / / _ | (c) 2006-2011, LAMP/EPFL **
3
** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
4
4
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5
5
** /____/\___/_/ |_/____/_/ | | **
10
9
package scala.util.parsing.combinator
12
11
import scala.util.parsing.combinator._
13
12
import scala.util.parsing.input.{ Reader, Position }
14
13
import scala.collection.mutable
14
import scala.language.implicitConversions
18
* <code>PackratParsers</code> is a component that extends the parser combinators
19
* provided by <a href="Parsers.html"><code>Parsers</code></a> with a memoization facility
20
* (``Packrat Parsing'').
23
* Packrat Parsing is a technique for implementing backtracking, recursive-descent parsers, with the
24
* advantage that it guarantees unlimited lookahead and a linear parse time. Using this technique,
25
* left recursive grammars can also be accepted.
28
* Using <code>PackratParsers</code> is very similar to using <code>Parsers</code>:
30
* <li> any class/trait that extends <code>Parsers</code> (directly or through a subclass) can
31
* mix in <code>PackratParsers</code>. Example:
32
* <code>object MyGrammar extends StandardTokenParsers with PackratParsers </code>
33
* <li> each grammar production previously declared as a <code>def</code> without formal parameters
34
* becomes a <code>lazy val</code>, and its type is changed from <code>Parser[Elem]</code>
35
* to <code>PackratParser[Elem]</code>. So, for example, <code>def production: Parser[Int] = {...}</code>
36
* becomes <code>lazy val production: PackratParser[Int] = {...}</code>
37
* <li> Important: using <code>PackratParser</code>s is not an ``all or nothing'' decision. They
38
* can be free mixed with regular <code>Parser</code>s in a single grammar.
42
* Cached parse results are attached to the <i>input</i>, not the grammar.
43
* Therefore, <code>PackratsParser</code>s require a <code>PackratReader</code> as input, which
44
* adds memoization to an underlying <code>Reader</code>. Programmers can create <code>PackratReader</code>
45
* objects either manually, as in <code>production(new PackratReader(new lexical.Scanner("input")))</code>,
46
* but the common way should be to rely on the combinator <code>phrase</code> to wrap a given
47
* input with a <code>PackratReader</code> if the input is not one itself.
17
* `PackratParsers` is a component that extends the parser combinators
18
* provided by [[scala.util.parsing.combinator.Parsers]] with a memoization
19
* facility (''Packrat Parsing'').
21
* Packrat Parsing is a technique for implementing backtracking,
22
* recursive-descent parsers, with the advantage that it guarantees
23
* unlimited lookahead and a linear parse time. Using this technique,
24
* left recursive grammars can also be accepted.
26
* Using `PackratParsers` is very similar to using `Parsers`:
27
* - any class/trait that extends `Parsers` (directly or through a subclass)
28
* can mix in `PackratParsers`.
29
* Example: `'''object''' MyGrammar '''extends''' StandardTokenParsers '''with''' PackratParsers`
30
* - each grammar production previously declared as a `def` without formal
31
* parameters becomes a `lazy val`, and its type is changed from
32
* `Parser[Elem]` to `PackratParser[Elem]`.
33
* So, for example, `'''def''' production: Parser[Int] = {...}`
34
* becomes `'''lazy val''' production: PackratParser[Int] = {...}`
35
* - Important: using `PackratParser`s is not an ''all or nothing'' decision.
36
* They can be free mixed with regular `Parser`s in a single grammar.
38
* Cached parse results are attached to the ''input'', not the grammar.
39
* Therefore, `PackratsParser`s require a `PackratReader` as input, which
40
* adds memoization to an underlying `Reader`. Programmers can create
41
* `PackratReader` objects either manually, as in
42
* `production('''new''' PackratReader('''new''' lexical.Scanner("input")))`,
43
* but the common way should be to rely on the combinator `phrase` to wrap
44
* a given input with a `PackratReader` if the input is not one itself.
50
46
* @see Bryan Ford: "Packrat Parsing: Simple, Powerful, Lazy, Linear Time." ICFP'02
51
47
* @see Alessandro Warth, James R. Douglass, Todd Millstein: "Packrat Parsers Can Support Left Recursion." PEPM'08
54
* @author Manohar Jonnalagedda, Tiark Rompf
50
* @author Manohar Jonnalagedda
57
54
trait PackratParsers extends Parsers {
149
140
* Implicitly convert a parser to a packrat parser.
150
141
* The conversion is triggered by giving the appropriate target type:
151
* val myParser: PackratParser[MyResult] = aParser
143
* val myParser: PackratParser[MyResult] = aParser
153
145
implicit def parser2packrat[T](p: => super.Parser[T]): PackratParser[T] = {
155
147
memo(super.Parser {in => q(in)})
160
151
* An unspecified function that is called when a packrat reader is applied.
161
152
* It verifies whether we are in the process of growing a parse or not.
162
153
* In the former case, it makes sure that rules involved in the recursion are evaluated.
163
154
* It also prevents non-involved rules from getting evaluated further
166
156
private def recall(p: super.Parser[_], in: PackratReader[Elem]): Option[MemoEntry[_]] = {
167
157
val cached = in.getFromCache(p)
168
158
val head = in.recursionHeads.get(in.pos)