UNPKG

buffer-apg-js

Version:

JavaScript APG, an ABNF Parser Generator

123 lines (122 loc) 4.35 kB
<!DOCTYPE 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&mdash;only on alternates. And even with alternates, the "first match wins" algorithm<sup>&#134;</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>&#134;</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>