buffer-apg-js
Version:
JavaScript APG, an ABNF Parser Generator
123 lines (122 loc) • 4.35 kB
HTML
<html lang="en">
<head>
<title>apg-exp</title>
<meta charset="utf-8">
<link rel="stylesheet" href="./css/BrightSide.css" type="text/css" />
<script type="text/javascript" src="./import.js"></script>
</head>
<body>
<div id="wrap">
<div id="header"></div>
<div id="content-wrap">
<img src="./images/PointLobosCropped.jpg" width="820" height="120" alt="headerphoto" class="no-border" />
<div id="sidebar"></div>
<div id="main-2col">
<!-- page content goes here -->
<h1>Property: nodeHits and treeDepth</h1>
<p>
A well-known problem with recursive-descent parsers is that they may require
<a href="https://en.wikipedia.org/wiki/Recursive_descent_parser">exponential time</a>.
This is also sometimes referred to as <a href="http://www.regular-expressions.info/catastrophic.html">catastrophic backtracking</a>.
With <b>APG</b> parsers this is less of a problem than with most regular expression
pattern-matching engines because they never backtrack on repetitions—only
on alternates. And even with alternates, the "first match wins" algorithm<sup>†</sup> reduces
the amount of backtracking even further. Nonetheless, exponential-time patterns can occur.
The <kbd>nodeHits</kbd> and <kbd>treeDepth</kbd> parameters provide upper limits
on the number of unit steps the parser may take and the maximum parse tree depth
that the parser can reach, respectively.
</p>
<p>
<sup>†</sup><i>Note on "first match wins", also sometimes refered to as "prioritized choice":
Alternates are tried from left to right. The parser accepts the first
successful match and no further alternates are tried.</i>
</p>
<p>
</p>
<h3>Syntax</h3>
<pre>
var exp = new apgExp(pattern, "", nodeHits, treeDepth);
var result = exp.exec(input);
</pre>
<h3>Parameters</h3>
<p>
<ul>
<li><kbd>nodeHits</kbd>: integer > 0: default <kbd>Infinity</kbd>:
The maximum number of unit steps (parse tree node hits) that the parser is allowed
to take. The parser will throw an <kbd>Error</kbd> exception if the limit is exceeded.
</li>
<li><kbd>treeDepth</kbd>: integer > 0: default <kbd>Infinity</kbd>:
The maximum allowed parse tree depth.
The parser will throw an <kbd>Error</kbd> exception if the limit is exceeded.
</li>
</ul>
</p>
<h3>Return</h3>
<ul>
<li><kbd>exp.nodeHits</kbd> - The input value of <kbd>nodeHits</kbd>.</li>
<li><kbd>exp.treeDepth</kbd> - The input value of <kbd>treeDepth</kbd>.</li>
<li><kbd><a href="./result.html">result</a>.nodeHits</kbd> - The actual number of unit parser steps taken.</li>
<li><kbd><a href="./result.html">result</a>.treeDepth</kbd> - The actual maximum parse tree depth reached.</li>
</ul>
<h3>Examples</h3>
<p>
The following exponential pattern, suggested by
<a href="https://lists.csail.mit.edu/pipermail/peg/2009-March/000206.html">Bryan Ford</a>,
is used in the following examples.
</p>
<pre>
var pattern;
pattern = 'S = *A\n';
pattern += 'A = B / C / "a"\n';
pattern += 'B = "a" S "b"\n';
pattern += 'C = "a" S "c"\n';
</pre>
<h3>Example 1: nodeHits</h3>
<pre>
var pattern, str, exp, result;
exp = new apgExp(pattern, "", 100000);
str = "aaaaa";
try{
for (var i = 0; i < 5; i += 1) {
result = exp.exec(str);
console.log("input: "+str+" node hits: " + result.nodeHits);
str += "a";
}
}catch(e){
console.log("EXCEPTION: "+e.message);
}
/* result */
input: aaaaa node hits: 1817
input: aaaaaa node hits: 5462
input: aaaaaaa node hits: 16397
input: aaaaaaaa node hits: 49202
EXCEPTION: parser: maximum number of node hits exceeded: 100000
</pre>
<h3>Example 2: treeDepth</h3>
<pre>
var pattern, str, exp, result;
exp = new apgExp(pattern, "", null, 50);
str = "aaaaa";
try{
for (var i = 0; i < 5; i += 1) {
result = exp.exec(str);
console.log("input: "+str+" tree depth: " + result.treeDepth);
str += "a";
}
}catch(e){
console.log("EXCEPTION: "+e.message);
}
/* result */
input: aaaaa tree depth: 32
input: aaaaaa tree depth: 38
input: aaaaaaa tree depth: 44
input: aaaaaaaa tree depth: 50
EXCEPTION: parser: maximum parse tree depth exceeded: 50
</pre>
</div>
</div>
<div id="footer"></div>
</div>
</body>
</html>