UNPKG

apg

Version:

(Deprecated: use apg-js instead.) An ABNF Parser Generator - generates recursive-descent parsers from grammars written in a superset of Augmented Backus-Naur Form (ABNF)

1,173 lines (1,058 loc) 500 kB
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-AU"> <head> <title>apg</title> <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" /> <meta name="author" content="haran" /> <meta name="generator" content="author" /> <style> /* This file automatically generated by toless() and LESS. */ .apg-mono { font-family: monospace; } .apg-active { font-weight: bold; color: #000000; } .apg-match { font-weight: bold; color: #264BFF; } .apg-empty { font-weight: bold; color: #0fbd0f; } .apg-nomatch { font-weight: bold; color: #FF4000; } .apg-lh-match { font-weight: bold; color: #1A97BA; } .apg-lb-match { font-weight: bold; color: #5F1687; } .apg-remainder { font-weight: bold; color: #999999; } .apg-ctrl-char { font-weight: bolder; font-style: italic; font-size: .6em; } .apg-line-end { font-weight: bold; color: #000000; } .apg-error { font-weight: bold; color: #FF4000; } .apg-phrase { color: #000000; background-color: #8caae6; } .apg-empty-phrase { color: #0fbd0f; } table.apg-state { font-family: monospace; margin-top: 5px; font-size: 11px; line-height: 130%; text-align: left; border: 1px solid black; border-collapse: collapse; } table.apg-state th, table.apg-state td { text-align: left; border: 1px solid black; border-collapse: collapse; } table.apg-state th:nth-last-child(2), table.apg-state td:nth-last-child(2) { text-align: right; } table.apg-state caption { font-size: 125%; line-height: 130%; font-weight: bold; text-align: left; } table.apg-stats { font-family: monospace; margin-top: 5px; font-size: 11px; line-height: 130%; text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-stats th, table.apg-stats td { text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-stats caption { font-size: 125%; line-height: 130%; font-weight: bold; text-align: left; } table.apg-trace { font-family: monospace; margin-top: 5px; font-size: 11px; line-height: 130%; text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-trace caption { font-size: 125%; line-height: 130%; font-weight: bold; text-align: left; } table.apg-trace th, table.apg-trace td { text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-trace th:last-child, table.apg-trace th:nth-last-child(2), table.apg-trace td:last-child, table.apg-trace td:nth-last-child(2) { text-align: left; } table.apg-grammar { font-family: monospace; margin-top: 5px; font-size: 11px; line-height: 130%; text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-grammar caption { font-size: 125%; line-height: 130%; font-weight: bold; text-align: left; } table.apg-grammar th, table.apg-grammar td { text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-grammar th:last-child, table.apg-grammar td:last-child { text-align: left; } table.apg-rules { font-family: monospace; margin-top: 5px; font-size: 11px; line-height: 130%; text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-rules caption { font-size: 125%; line-height: 130%; font-weight: bold; text-align: left; } table.apg-rules th, table.apg-rules td { text-align: right; border: 1px solid black; border-collapse: collapse; } table.apg-rules a { color: #003399 !important; } table.apg-rules a:hover { color: #8caae6 !important; } table.apg-attrs { font-family: monospace; margin-top: 5px; font-size: 11px; line-height: 130%; text-align: center; border: 1px solid black; border-collapse: collapse; } table.apg-attrs caption { font-size: 125%; line-height: 130%; font-weight: bold; text-align: left; } table.apg-attrs th, table.apg-attrs td { text-align: center; border: 1px solid black; border-collapse: collapse; } table.apg-attrs th:nth-child(1), table.apg-attrs th:nth-child(2), table.apg-attrs th:nth-child(3) { text-align: right; } table.apg-attrs td:nth-child(1), table.apg-attrs td:nth-child(2), table.apg-attrs td:nth-child(3) { text-align: right; } table.apg-attrs a { color: #003399 !important; } table.apg-attrs a:hover { color: #8caae6 !important; } body { color: black; background-color: #eaf0fa; font-family: verdana, helvetica, arial, sans-serif; font-size: 71%; /* Enables font size scaling in MSIE */ font-size: 16px; margin: 0; padding: 0; } code { font-family: monospace; font-size: .8em; color: #404040; background-color: #f2f2f2; } #modal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 1; /* Sit on top */ top: 50%; left: 50%; margin-top: -300px; margin-left: -250px; width: 500px; height: 500px; overflow: auto; /* Enable scroll if needed */ background-color: #6487dc; border: 3px solid #003399; border-radius: 25px; padding: 10px 0 0 0; } #modal #modal-top { padding: 0 20px 0 20px; position: relative; height: 10%; color: white; } #modal #modal-content { padding: 5px 20px 5px 20px; position: relative; height: 80%; background-color: white; font-size: 80%; font-weight: bold; } #modal #modal-content a { font-size: 120%; } #modal .modal-cancel { float: right; font-size: 150%; color: white; line-height: 110%; } #modal .modal-cancel:hover, #modal .modal-cancel:focus { color: #003399; text-decoration: none; cursor: pointer; } .help-right { float: right; font-variant: small-caps; } .center-div { width: 100%; margin: 10px auto 0 auto; max-width: 1000px; color: black; background-color: white; } .super-header { box-sizing: border-box; height: 32px; font-size: 16px; width: 100%; font-weight: bold; color: white; background-color: #6487dc; } .mid-header { color: #003399; background-color: #8caae6; font-size: 337%; font-weight: normal; margin: 0; padding: .25em 0 .25em 0; } .mid-header a { padding: 0 0 0 .5em; color: inherit; background-color: inherit; text-decoration: none; } .sub-header { box-sizing: border-box; height: 32px; font-size: 16px; width: 100%; font-weight: bold; color: white; background-color: #6487dc; background-color: #003399; } .sub-header .band-container { /* padding: @bandPad; */ box-sizing: border-box; height: 16px; padding: 6.4px 1em 0 0.5em; } .sub-header .band-container a { color: white; background-color: transparent; text-decoration: none; font-weight: bold; margin: 0; padding: 0 0.75ex 0 0.5ex; } .sub-header .band-container a:hover { color: #FEC59A; } .sub-header .band-container a:focus { color: #FDA05B; } .sub-header .band-container a:active { color: #FDA05B; } .sub-header .band-container .active { color: #FDA05B; } .sub-header .band-container .float-right { float: right; } .sub-header .sub-band-container { /* padding: @bandPad; */ box-sizing: border-box; height: 16px; padding: 6.4px 1em 0 0.5em; margin: 5px 0 0 0; } .sub-header .sub-band-container a { color: white; background-color: transparent; text-decoration: none; font-weight: bold; margin: 0; padding: 0 0.75ex 0 0.5ex; } .sub-header .sub-band-container a:hover { color: #FEC59A; } .sub-header .sub-band-container a:focus { color: #FDA05B; } .sub-header .sub-band-container a:active { color: #FDA05B; } .sub-header .sub-band-container .active { color: #FDA05B; } .sub-header .sub-band-container .float-right { float: right; } .copy-header { box-sizing: border-box; height: 32px; font-size: 16px; width: 100%; font-weight: bold; color: white; background-color: #6487dc; } .copy-header .band-container { /* padding: @bandPad; */ box-sizing: border-box; height: 16px; padding: 6.4px 1em 0 0.5em; } .copy-header .band-container a { color: white; background-color: transparent; text-decoration: none; font-weight: bold; margin: 0; padding: 0 0.75ex 0 0.5ex; } .copy-header .band-container a:hover { color: #FEC59A; } .copy-header .band-container a:focus { color: #FDA05B; } .copy-header .band-container a:active { color: #FDA05B; } .copy-header .band-container .active { color: #FDA05B; } .copy-header .band-container .float-right { float: right; } .copy-header .sub-band-container { /* padding: @bandPad; */ box-sizing: border-box; height: 16px; padding: 6.4px 1em 0 0.5em; margin: 5px 0 0 0; } .copy-header .sub-band-container a { color: white; background-color: transparent; text-decoration: none; font-weight: bold; margin: 0; padding: 0 0.75ex 0 0.5ex; } .copy-header .sub-band-container a:hover { color: #FEC59A; } .copy-header .sub-band-container a:focus { color: #FDA05B; } .copy-header .sub-band-container a:active { color: #FDA05B; } .copy-header .sub-band-container .active { color: #FDA05B; } .copy-header .sub-band-container .float-right { float: right; } .copy-footer { box-sizing: border-box; height: 32px; font-size: 11px; color: white; background-color: #6487dc; margin-top: 4px; } .copy-footer .band-container { padding: .4em .5em 0 .5em; } .copy-footer .band-container a { color: white; font-weight: normal; text-decoration: underline; } .copy-footer .band-container a:hover { color: #FEC59A; } .copy-footer .band-container .float-right { float: right; } .show { display: inline; } .hide { display: none; } .center { text-align: center; } .main-container { color: black; background-color: white; text-align: left; line-height: 1.25em; margin: 0 0 0 0; padding: .25em 1em .25em 1em; } .main-container p { margin: .5em 0 .5em 0; padding: 0; } .help-container { font-family: verdana, helvetica, arial, sans-serif; margin: .5em; font-size: 1em; line-height: 1.4em; text-align: justify; } .help-container a { color: #6487dc; background-color: transparent; text-decoration: none; font-weight: bold; } .help-container a:hover { color: #003399; } .main-copy { font-size: 1em; line-height: 1.3em; padding: 0 .5em 0 .5em; margin: .25em 0 .25em 0; } .main-copy a { color: #6487dc; text-decoration: none; } .main-copy a:hover { color: #003399; } .main-copy textarea { width: 99%; margin-top: 3px; font-family: monospace; font-size: 0.9em; } .main-copy textarea::selection { color: white; background: #828282; } .main-copy iframe { width: 99%; font-family: monospace; font-size: 0.9em; margin-top: 3px; } .main-copy .form-content { width: 99%; font-size: 0.9em; line-height: 1em; margin-top: 3px; } .main-copy .form-content input[type=checkbox], .main-copy .form-content input[type=radio], .main-copy .form-content label { vertical-align: middle; margin: 0; } .main-copy .form-content input[type=text] { text-align: right; } .main-copy .form-content th, .main-copy .form-content td { margin: 0; padding: 0 3px 0 3px; vertical-align: middle; } .main-copy .form-content th span, .main-copy .form-content td span { font-family: monospace; font-size: .8em; letter-spacing: -1px; } .main-copy .form-content table.mono th, .main-copy .form-content table.mono td { margin: 0; padding: 0 3px 0 3px; vertical-align: middle; font-family: monospace; font-size: .8em; letter-spacing: -1px; } </style> </head> <body onload="apgweb.onPageLoad()"> <div class="center-div"> <!-- ##### BEGIN Header ##### --> <div id="header"> <div class="super-header"></div> <div class="mid-header"> <a id="headerLink" href="https://github.com/ldthomas/apg-js2" target="_blank">JavaScript <strong>APG</strong> </a> </div> <div class="sub-header"> <div class="band-container"> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(0)" title="type or paste SABNF grammar here">Generator</a> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(1)" title="annotated display of SABNF grammar">Grammar</a> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(2)" title="rules defined by the SABNF grammar">Rules</a> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(3)" title="the grammar rules attributes">Attributes</a> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(4)" title="the generated parser">Parser</a> | <div class="float-right"> <!-- | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(5)">Examples</a> --> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(5)">About</a> | <a class="tablinks" href="javascript:void(0)" onclick="apgweb.openTab(6)">Help |</a> </div> </div> </div> </div> <!-- ##### END Header ##### --> <!-- ##### BEGIN Main Copy ##### --> <div class="main-container"> <!-- #### BEGIN tab 0 - the parser generator #### --> <div class="tabcontent"> <!-- #### Parser Generator GUI #### --> <div class="copy-header"> <div class="band-container"> | <a href="javascript:void(0)" onclick="apgweb.generate()">Generate</a> | <a href="javascript:void(0)" onclick="apgweb.select('grammar-area')">Copy</a> | <a href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'grammar-area')">Full Screen</a> | </div> </div> <article id="generator" class="section"> <div class="main-copy"> <textarea id="grammar-area" spellcheck="false" placeholder="Type or paste SABNF grammar here."></textarea> </div> </article> <!-- <div class="copy-header"> --> <!-- <div class="band-container"> --> <!-- Generator --> <!-- </div> --> <!-- </div> --> </div> <!-- #### END tab 0 - the parser generator #### --> <!-- #### BEGIN tab 1 - the annotated SABNF grammar, with errors if any #### --> <div class="tabcontent"> <div class="copy-header"> <div class="band-container"> | <a href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'grammar-page')">Full Screen</a> | </div> </div> <div class="main-copy"> <article id="grammar-page"></article> </div> <!-- <div class="copy-header"> --> <!-- <div class="band-container"> --> <!-- Grammar --> <!-- </div> --> <!-- </div> --> </div> <!-- #### END tab 1 - the annotated SABNF grammar, with errors if any #### --> <!-- #### BEGIN tab 2 - the grammar rules with dependencies #### --> <div class="tabcontent"> <div class="copy-header"> <div class="band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.rules.showAll(true)">Show All</a> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.rules.showAll(false)">Hide All</a> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'rules-page')">Full Screen</a> | </div> </div> <div class="main-copy"> <article id="rules-page"></article> </div> <!-- <div class="copy-header"> --> <!-- <div class="band-container"> --> <!-- Rules --> <!-- </div> --> <!-- </div> --> </div> <!-- #### END tab 2 - the grammar rules with dependencies #### --> <!-- #### BEGIN tab 3 - the grammar attributes #### --> <div class="tabcontent"> <div class="copy-header"> <div class="band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'attrs-page')">Full Screen</a> | </div> </div> <div class="main-copy"> <article id="attrs-page"></article> </div> <!-- <div class="copy-header"> --> <!-- <div class="band-container"> --> <!-- Attributes --> <!-- <a class="float-right" href="#header" >^ TOP</a> --> <!-- </div> --> <!-- </div> --> </div> <!-- #### END tab 3 - the grammar attributes #### --> <!-- #### BEGIN tab 4 - the generated parser with a GUI for testing it with an input string #### --> <div class="tabcontent"> <div class="copy-header"> <div class="band-container"> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(0)">Parser</a> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(1)">Configure</a> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(2)">Input</a> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(3)">Phrases</a> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(4)">State</a> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(5)">Stats</a> | <a class="parser-tablinks" href="javascript:void(0)" onclick="apgweb.parser.openTab(6)">Trace</a> | </div> </div> <article id="parser"> <!-- #### the parser tabs #### --> <!-- #### the parser tabs #### --> <!-- #### parser tab 0 - the JS parser object #### --> <section class="parser-tabcontent"> <div class="copy-header"> <div class="sub-band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.select('parser-area')">Copy</a> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'parser-area')">Full Screen</a> | </div> </div> <div class="main-copy"> <textarea id="parser-area" spellcheck="false"></textarea> </div> </section> <!-- #### parser tab 1 - input and trace configuration #### --> <section class="parser-tabcontent"> <div class="main-copy"> <div class="form-content"> <!-- this section is not manipulated dynamically --> <p> <strong>Input Mode:</strong> </p> <p> &nbsp;&nbsp;<label><input type="radio" name="input-mode" value="auto" checked> auto</label><br /> &nbsp;&nbsp;<label><input type="radio" name="input-mode" value="ascii"> ASCII characters only</label><br> &nbsp;&nbsp;<label><input type="radio" name="input-mode" value="escaped"> escaped characters</label> </p> <!-- this section is not manipulated dynamically --> <p> <strong>Trace:</strong> <label><input type="radio" name="traceon" value="on" onclick="apgweb.parser.traceOnOff(this)"> on</label> <label><input type="radio" name="traceon" value="off" onclick="apgweb.parser.traceOnOff(this)" checked> off</label> </p> <div id="trace-config"> <table> <tr> <th colspan="2" >Display Mode</th> </tr> <tr> <td><label><input type="radio" name="trace-display" value="ascii" checked> ASCII</label></td> <td><label><input type="radio" name="trace-display" value="hexidecimal"> hexidecimal</label></td> </tr> <tr> <td><label><input type="radio" name="trace-display" value="decimal"> decimal</label></td> <td><label><input type="radio" name="trace-display" value="unicode"> Unicode</label></td> </tr> </table> <p> <strong>Records to Display:</strong> </p> <p> <input type="text" id="trace-max-records" value="5000"> max records </p> <p> <input type="text" id="trace-last-record" value="-1" checked> last record </p> <!-- this section is not manipulated dynamically --> <p> <strong>Operator Nodes:</strong> <label><input type="radio" name="operatorson" value="on" onclick="apgweb.parser.setOperators(this)"> all</label> <label><input type="radio" name="operatorson" value="off" onclick="apgweb.parser.setOperators(this)" checked> none</label> </p> <table> <tr> <td><label><input type="checkbox" name="operators" value="alt"><span> ALT (/)</span> alternate</label></td> <td><label><input type="checkbox" name="operators" value="cat"><span> CAT ( )</span> concatenation</label></td> <td><label><input type="checkbox" name="operators" value="rep"><span> REP (*)</span> repetition</label></td> <td><label><input type="checkbox" name="operators" value="abg"><span> ABG (%^)</span> begin of string</label></td> </tr> <tr> <td><label><input type="checkbox" name="operators" value="tls"><span> TLS ("abc")</span> literal string</label></td> <td><label><input type="checkbox" name="operators" value="tbs"><span> TBS (%d33.34)</span> binary string</label></td> <td><label><input type="checkbox" name="operators" value="trg"><span> TRG (%d33-34)</span> character range</label></td> <td><label><input type="checkbox" name="operators" value="aen"><span> AEN (%$)</span> end of string</label></td> </tr> <tr> <td><label><input type="checkbox" name="operators" value="and"><span> AND (&amp;)</span> positive look ahead</label></td> <td><label><input type="checkbox" name="operators" value="not"><span> NOT (!)</span> negative look ahead</label></td> <td><label><input type="checkbox" name="operators" value="bka"><span> BKA (&amp;&amp;)</span> positive look behind</label></td> <td><label><input type="checkbox" name="operators" value="bkn"><span> BKN (!!)</span> negative look behind</label></td> <td></td> </tr> <tr> <td><label><input type="checkbox" name="operators" value="bkr"><span> BKR (\)</span> back reference</label></td> </tr> </table> <!-- this section IS manipulated dynamically --> <p> <strong>Rule Nodes:</strong> <label><input type="radio" name="ruleson" value="on" onclick="apgweb.parser.setRules(this)" checked> all</label> <label><input type="radio" name="ruleson" value="off" onclick="apgweb.parser.setRules(this)"> none</label> </p> <table class="mono" id="rules-table"> </table> </div> <!-- end trace-config --> </div> </div> </section> <!-- #### parser tab 2 - input to the parser #### --> <section class="parser-tabcontent"> <div class="copy-header"> <div class="sub-band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.parser.parseInput('init')">Parse Input</a> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.select('input-area')">Copy</a> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'input-area')">Full Screen</a> | </div> </div> <div class="main-copy"> <div id="modal"> <div id="modal-top"> </div> <div id="modal-content"> </div> <span class="modal-cancel" onclick="apgweb.parser.closeModal('cancel')">&times;&nbsp;&nbsp;</span> </div> <textarea id="input-area" spellcheck="false" ondblclick="apgweb.parser.openModal(event)" placeholder="Type or paste parser input here."></textarea> </div> </section> <!-- #### parser tab 3 - the parsed phrases #### --> <section class="parser-tabcontent"> <div class="copy-header"> <div class="sub-band-container"> | <select id="ast-phrases" class="align-middle" onchange="apgweb.parser.phraseChange(event)"> </select> <a class="inner-header" href="javascript:void(0)" onclick="apgweb.parser.displayPhrase(event, 1)">&#9198;</a> <a class="inner-header" href="javascript:void(0)" onclick="apgweb.parser.displayPhrase(event, 2)">&#9204;</a> <a class="inner-header" href="javascript:void(0)" onclick="apgweb.parser.displayPhrase(event, 3)">phrases</a> <a class="inner-header" href="javascript:void(0)" onclick="apgweb.parser.displayPhrase(event, 4)">&#9205;</a> <a class="inner-header" href="javascript:void(0)" onclick="apgweb.parser.displayPhrase(event, 5)">&#9197;</a> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'phrases-frame')">Full Screen</a> | </div> </div> <div class="main-copy"> <iframe src="" id="phrases-frame"></iframe> </div> </section> <!-- #### parser tab 4 - parser state #### --> <section class="parser-tabcontent"> <div class="copy-header"> <div class="sub-band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'state-page')">Full Screen</a> | </div> </div> <div class="main-copy"> <div id="state-page"></div> </div> </section> <!-- #### parser tab 5 - the parsing statistics #### --> <section class="parser-tabcontent"> <div class="copy-header"> <div class="sub-band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'stats-page')">Full Screen</a> | </div> </div> <div class="main-copy"> <div id="stats-page"></div> </div> </section> <!-- #### parser tab 6 - the trace #### --> <section class="parser-tabcontent"> <div class="copy-header"> <div class="sub-band-container"> | <a class="inner-header" href="javascript:void(0)" onclick="apgweb.fullScreen(event, 'trace-frame')">Full Screen</a> | </div> </div> <div class="main-copy"> <iframe src="" id="trace-frame"></iframe> </div> </section> <!-- #### END the parser tabs #### --> </article> <!-- <div class="copy-header"> --> <!-- <div class="band-container"> --> <!-- Parser --> <!-- <a class="float-right" href="#header" >^ TOP</a> --> <!-- </div> --> <!-- </div> --> </div> <!-- end tab 4 tabcontent --> <!-- #### END tab 4 - the generated parser with a GUI for testing it with an input string #### --> <!-- #### BEGIN tab 5 - the "about" page #### --> <div class="tabcontent"> <div class="help-container"> <h2 id="about-apg">About APG</h2> <p><strong>APG</strong> was originally developed to generate parsers directly from the Augmented Backus-Naur Form (ABNF) syntax. ABNF is the grammar syntax used to describe many, if not most, Internet technical specifications. It has been standardized by the <a href="https://www.ietf.org/">IETF</a> with <a href="https://tools.ietf.org/html/rfc5234">RFC 5234</a> and recently updated it with <a href="https://tools.ietf.org/html/rfc7405">RFC 7405</a>. <strong>APG</strong> has since grown to include additional features and the syntax for those features generate additional syntax elements creating a “superset” of ABNF or <a href="https://github.com/ldthomas/apg-js2/blob/master/SABNF.md">SABNF</a>.</p> <p>Besides JavaScript, <strong>APG</strong> is available in the <a href="https://github.com/ldthomas/apg-6.3">C/C++</a> and <a href="https://github.com/ldthomas/apg-java">Java</a> languages. The C/C++ version has a small footprint, is fast and reliable and has been the parser of choice for a number of large Telecom companies. </p> <p><strong>APG</strong> is the generator and parser that powers the new pattern-matching alternative to RegExp, <a href="https://github.com/ldthomas/apg-js2-exp">apg-exp</a>. <em>(For an introduction to <strong>apg-exp</strong>, see this sitepoint.com <a href="https://www.sitepoint.com/alternative-to-regular-expressions/">tutorial</a>.)</em></p> <h2 id="about-the-author">About the Author</h2> <p>The author lives on the Gulf Coast of Florida, USA, loves JavaScript and has 30+ years experience with software development of many kinds in many languages. In his spare time he loves hard-boiled detective novels, historical fiction and outdoor photography among many other things. He serves as a volunteer executive director on the boards of multiple, local charitable organizations.</p> <p>February, 2017 <br> Lowell D. Thomas</p> <br> </div> <!-- end about.html --> </div> <!-- #### END tab 5 - the "about" page #### --> <!-- #### BEGIN tab 6 - the help page #### --> <div class="tabcontent"> <div class="help-container"> <h2 id="overviewtoc">Overview<span class="help-right"><a href="#help-top">↓toc</a></span></h2> <p>This file, <strong>apg.html</strong>, is a static, stand-alone web page interface to <strong>APG</strong>, an ABNF Parser Generator. It can be launched in any modern web browser from a local file and requires no external resources. It provides easy visual access to the grammar, any grammar errors, the rules and their dependencies, the rule attributes and the generated parser. Additionally, once a parser has been successfully generated, facilities are provided for testing it against input strings of your choice. The user interface consists of a series of panels. Each panel presents one specific result or input opportunity. Access to the panels is through the main menu, the fixed dark blue bar across the top, and sub-menus that appear in the various panels. This User’s Guide will walk you through each of the menu and sub-menu items to explain how this <strong>APG</strong> interface works.</p> <p>There are a couple of sub-menu items that appear on most panels consistently and those will be described here once and for all and not specifically referenced in the other panel specifics presented below.</p> <ul> <li><strong>Copy:</strong> Web browsers have no access to the local file system<sup>†</sup>, and since this is a stand-alone web page with no server behind it, there is no upload/download ability. Therefore, it is necessary to type or paste any input into a textarea. For output, to save the text in the textarea, it is necessary to copy and paste into a permanent file. This Copy menu action will copy the contents of the textarea onto the clipboard to facilitate this process.</li> <li><strong>Full Screen:</strong> Often it is desirable to see the panel contents in a full screen view. This Full Screen action will pop up the panel contents in a new, full-screen view.</li> </ul> <p><sup>†</sup><em>The HTML5 <a href="https://dev.w3.org/2009/dap/file-system/pub/FileSystem/">FIle API</a> does not have sufficiently universal support here to be considered.</em></p> <p><a id="help-top"></a></p> <h2 id="table-of-contents">Table of Contents</h2> <table> <thead> <tr> <th><strong><a href="#the-generatortoc">The Generator</a></strong></th> <th><strong><a href="#the-parsertoc">The Parser</a></strong></th> <th></th> </tr> </thead> <tbody><tr> <td><a href="#overviewtoc">Overview</a></td> <td><a href="#parsertoc">Parser</a></td> <td><a href="#statetoc">State</a></td> </tr> <tr> <td><a href="#grammartoc">Grammar</a></td> <td><a href="#configuretoc">Configure</a></td> <td><a href="#statstoc">Stats</a></td> </tr> <tr> <td><a href="#rulestoc">Rules</a></td> <td><a href="#inputtoc">Input</a></td> <td><a href="#tracetoc">Trace</a></td> </tr> <tr> <td><a href="#attributestoc">Attributes</a></td> <td><a href="#phrasestoc">Phrases</a></td> <td></td> </tr> </tbody></table> <h2 id="the-generatortoc">The Generator<span class="help-right"><a href="#help-top">↑toc</a></span></h2> <p>The first panel is the generator itself. It presents a sub-menu and a textarea. </p> <ul> <li><strong>sub-menu:</strong> <br> <ul><li><strong>Generate:</strong> Click this link to generate a parser from the grammar in the textarea. If the grammar has errors the <a href="#grammartoc">Grammar panel</a> will open automatically displaying an annotated version of the grammar with error messages. If there are no errors the <a href="#parsertoc">Parser panel</a> will open automatically, displaying the generated parser in a text area.</li></ul></li> <li><strong>textarea:</strong> The grammar to be used by the generator is typed or pasted into the textarea.</li> </ul> <h3 id="grammartoc">Grammar<span class="help-right"><a href="#help-top">↑toc</a></span></h3> <p>The generator will display an annotated version of the input grammar in this panel. If there are grammar errors, this panel will open automatically. However, the annotated grammar is always available here, with or without errors. The grammar is presented in tabular form with a row for each grammar line.</p> <ul> <li><strong>line no.:</strong> the line number of the grammar line displayed</li> <li><strong>first char:</strong> the character number of the first character of the line</li> <li><strong>length:</strong> the number of characters in the line</li> <li><strong>text:</strong> the ASCII text of the line. The control characters tab<code>(\t, 0x09)</code>, linefeed<code>(\n, 0x0A)</code> and carriage return<code>(\r, 0x0D</code>) are displayed as <em><code>TAB</code></em>, <em><code>LF</code></em> and <em><code>CR</code></em>, respectively.</li> </ul> <p>If there are errors in the grammar, a second table will follow the first, with two lines for each error. The first is the same as described above except that a red marker will precede the location of the discovered error. The second line will give a brief description of the error type.</p> <p><strong>APG</strong> generates four types of grammar errors.</p> <ul> <li><strong>invalid characters:</strong> The first step is to validate the input grammar’s character set. SABNF grammars accept only the printing ASCII character set, <code>0x20-7E</code> plus tab<code>(0x09)</code>, linefeed<code>(0x0A)</code> and carriage return<code>(0x0D)</code>. Any other character will generate a grammar error. Also, each line must end with a line end character<sup>†</sup>, including the last line. A missing line end will be reported as a part of this initial input validation. <em>(Note that forgetting or missing a last line end is a common and easy-to-make error and it may seem that it would be and easy fix to insert one on the user’s behalf. However, ABNF syntax requires a line end for each line and reporting this as an error rather than inserting one and proceeding is a considered feature, not an oversight.)</em></li> <li><strong>syntax errors:</strong> The second step is to parse the SABNF grammar against its <a href="https://github.com/ldthomas/apg-js2/blob/master/resources/abnf-for-sabnf-grammar.bnf">ABNF definition</a>. If the input is not a valid SABNF grammar, errors will be reported here.</li> <li><strong>semantic errors:</strong> The third step is to translate the Abstract Syntax Tree (AST) of the previous step into a parser object. Semantic, or translation errors, are reported here. A semantic error might be, for example, <code>%d57-48</code>. While this character range is syntactically correct, <code>min &gt; max</code> is a semantic error.</li> <li><strong>attribute errors:</strong> Recursive-descent parsers cannot accept left-recursive, cyclic or infinite grammars. These are characterized, respectively, in the simple examples below. <br> <code> <br> S = S "x" / "y" <br> S = S <br> S = "y" S <br> </code> <br> If any of these errors occur, the <a href="#attributestoc">Attributes panel</a> will automatically open with the errors appearing in the top lines, but the errors are also reported in the <a href="#grammartoc">Grammar panel</a>.</li> </ul> <p><a id="help-md-1"></a><sup>†</sup>Strict ABNF accepts only the carriage return, linefeed pair, <em><code>CRLF</code></em>, as a line end. However, because of the ways different browsers handle textareas, it is sometimes difficult or impossible to insert this line end pair into the grammar text. Therefore, the generator always follows the SABNF rules regarding line ends. That is, it accepts any of <em><code>CRLF</code></em>, <em><code>LF</code></em> or <em><code>CR</code></em> as a line end.</p> <h3 id="rulestoc">Rules<span class="help-right"><a href="#help-top">↑toc</a></span></h3> <p>This panel displays a table of all the rule and UDT names defined in the grammar. The first column is the rule index—the order in which the rules appear in the grammar. Clicking the <code>index</code> column label will toggle between ascending and descending ordering on the indexes.</p> <p>The second column is the rule name. Clicking the <code>rule</code> column label will toggle between ascending and descending alphabetic ordering on the names.</p> <p>The third column lists all of the rule names referenced by the named rule. The first entry, for each rule, is a <code>show/hide</code> link. This link will toggle the display of the rule dependencies on and off. For example, the first rule will usually reference all of the other rules. For large grammars this is a lot of uninteresting information that you may like to hide.</p> <p>The sub-menu has links to show or hide all of the rule dependencies for all of the rules and UDTs simultaneously.</p> <p>Note that UDTs, if present, are always listed below the rule names.</p> <h3 id="attributestoc">Attributes<span class="help-right"><a href="#help-top">↑toc</a></span></h3> <p>It is <a href="https://en.wikipedia.org/wiki/Left_recursion">well-known</a> that recursive-descent parsers cannot parse left-recursive grammars. Left-recursion is a fatal “attribute” of the grammar. <strong>APG</strong> looks for left-recursion and six other attributes as it analyses a grammar. These attributes are displayed here in table form. The seven attributes types, with simple examples of each are:</p> <ol> <li>left recursion (fatal)<br> <code>S = S "x" / "y"</code></li> <li>nested recursion (OK)<br> <code>S = "a" S "b" / "y"</code></li> <li>right recursion (OK)<br> <code>S = "x" S / "y"</code></li> <li>cyclic (fatal)<br> <code>S = S</code></li> <li>finite (fatal if not finite)<br> <code>S = "y" S</code> (defines only infinite strings)</li> <li>empty (OK, but very important to know about)<br> <code>S = "x" S / ""</code></li> <li>not empty (OK)<br> <code>S = "x" S / "y"</code></li> </ol> <p>Note that these are “aggregate” attributes, in that if the attribute is true it only means that it <em>can</em> be true, not that it will always be true for every input string. It also means that more than one attribute may be true for a given rule.</p> <p>You may wonder why we would be interested in both <code>empty</code> and <code>not empty</code> as separate attributes. The importance is not apparent here, and won’t be explained in detail, but they are not mutually exclusive and both attributes turn out to be important to the algorithms that determine the recursiveness of a rule.</p> <ul> <li>first column, the rule index: the order in which the rules appear in the grammar. Clicking the “index” column label will toggle between ascending and descending ordering on the indexes.</li> <li>second column, the rule name: Clicking the <code>rule</code> column label will toggle between ascending and descending ordering on the names.</li> <li>third column, the recursive type: Clicking the <code>type</code> column label will toggle between ascending and descending ordering on the types.</li> <li>the attribute columns: each has <code>yes/no</code> entries indicating whether the attribute is true or false. Clicking on the column heading will toggle a column sort on the <code>yes/no</code> values.</li> </ul> <p>Fatal attributes—left-recursion, cyclic, infinite—will appear in red. A checkbox will also appear at the top. When checked, rules with attribute errors will always remain at the top of the list.</p> <p>Note that UDTs, if present, are always listed below the rule names. <br> <a id="help-id-parser"></a></p> <h2 id="the-parsertoc">The Parser<span class="help-right"><a href="#help-top">↑toc</a></span></h2> <p>If the grammar is error-free, the Generator will be successful and this panel will open automatically. The generated parser will be in the textarea and can be copied and pasted into your parser application. Numerous <a href="https://github.com/ldthomas/apg-js2-examples">examples</a> are available to show you how to use this parser in both <a href="https://nodejs.org/api/">node.js</a> and web page applications. However, the parser can also be tested right here. The sub-menu has panels that let you try the parser against various input strings. You can view the phrases matched by the individual rules, look at the parsing statistics and a trace of the parser’s path through the parse tree. The trace is especially useful as a debugging tool for failed parses. The details are in the following discussions of the sub-menu panels.</p> <p><em>Note that if the grammar has UDTs, parsing here will not be possible. In this case the parser is incomplete without the user-written code for the UDTs and there are no facilities here for code writing.</em></p> <h3 id="parsertoc">Parser<span class="help-right"><a href="#help-top">↑toc</a></span></h3> <p>This panel is a textarea containing the generated parser as a JavaScript function. You might want to change the variable name before you copy it into your application, but any other changes may invalidate the parser.</p> <p>To test the parser, use the <a href="#inputtoc">Input</a> and <a href="#configuretoc">Configure</a> panels.</p> <h3 id="configuretoc">Configure<span class="help-right"><a href="#help-top">↑toc</a></span></h3> <p>This panel allows a degree of control over how the input string is interpreted and what tracing information is produced.</p> <h4 id="input-mode">Input Mode:</h4> <p>Only the printing ASCII characters, <code>0x20-7F</code> plus the control characters, tab<code>(0x09</code>, linefeed<code>(0x0A)</code> and carriage return<code>(0x0D)</code> are allowed in the input <code>&lt;textarea&gt;</code>. Any other character, in any mode, will be flagged as an input error. For non-ASCII characters, however, an escaped mode, as well as a base 64 option, are available.</p> <ul> <li>auto (default) - the application will scan the input to determine which mode to use. If all of the characters (ignoring white space and control characters \r and \n) are limited to the base 64 character set, a dialog will allow the user to select the underlying encoding. If any escape sequences are found, `x or `u, it will choose escaped mode. Otherwise, it will select ASCII mode.</li> <li>ASCII characters only - the ASCII characters are interpreted literally. The grammar defining the parser in this case must only define ASCII sentences and phrases.</li> <li>escaped characters - escaped characters can be used to generate a string of non-ASCII character codes as input to the parser. (See the <a href="#inputtoc">Input</a> section for a complete description.)</li> </ul> <h4 id="trace">Trace:</h4> <ul> <li>on - Turns tracing on. Opens further tracing configuration options.</li> <li>off - (default) No tracing is done. The other tracing options are hidden.</li> </ul> <h4 id="display-mode">Display Mode:</h4> <p>For each step the parser takes, the trace will display the portion of the string that the parser is trying to match. If any of the characters are non-ASCII, they will be displayed as Unicode values (<code>U+HH[HH[HHHH]]</code>) However, the trace strings may be displayed in other formats, which may be preferred, depending on the input.</p> <ul> <li>ASCII - (default) printing characters are displayed normally. Control characters are displayed as, <em><code>TAB</code></em>, <em><code>LF</code></em> and <em><code>CF</code></em>. All others are displayed in Unicode format, <em><code>U+HH[HH[HHHH]]</code></em>. The non-printing character representations are in small-cap italics to distinguish from possible conflicts with similar text.</li> <li>decimal - all character codes are display as comma-delimited decimal integers.</li> <li>hexidecimal - all character codes are displayed as comma-delimited hex integers of the form <code>\xHH[HH[HHHH]]</code>.</li> <li>Unicode - all character codes are displayed as comma-delimited Unicode integers of the form <code>U+HH[HH[HHHH]]</code>.</li> <li><code>H</code> - 0-9 or A-F</li> </ul> <h4 id="records-to-display">Records to Display:</h4> <p>As the parser completes its recursive-descent traversal of the parse tree, it will visit each tree node twice, once going down and again on the way up. For large grammars and input strings this can amount to hundreds of thousands of node visits. The visits themselves are not very time consuming. Modern JavaScript engines perform well for large grammars. However, when tracing the parser, a trace record is generated for each node visit and the accumulation and display of these can easily overwhelm the capacity of the browser, slowing it or even grinding it to a virtual halt. The number of records can be limited with selections here.</p> <ul> <li>max records - The maximum number of records to retain.</li> <li>last record - Normally, it is the last group of records that is of interest. If the parser fails, the failure will usually appear near the end of the parse. Use a negative value, <code>-1</code>, to indicate that the last to keep is to be the actual last record (unknown prior to parsing.) Use a positive number to indicate a specific value for the last saved record. Note that some boundary conditions apply.</li> </ul> <p>Suppose the total number of records generated is 10,000. </p> <ul> <li>example 1: Choosing <code>max records = 5000</code> and <code>last record = -1</code> will display records 5001 - 10000.</li> <li>example 2: Choosing <code>max records = 5000</code> and <code>last record = 9000</code> will display records 4001 - 9000.</li> <li>example 2: Choosing <code>max records = 10000</code> and <code>last record = 5000</code> will display records 1-10000. The number of records takes precedence if the last record would limit the number of records to less than <code>max records</code> (or the total number of records, if less.)</li> </ul> <h4 id="operator-nodes">Operator Nodes:</h4> <p>The node visits to the non-rule name nodes are often not of interest and trace records for these are not kept by default. However, these may be turned on by checking the boxes by the operator names. The <code>all/none</code> buttons can be used to turn them all on or off with one click. In either state, the check boxes can be selected individually.</p> <ul> <li>all - check all operator boxes</li> <li>none - (default) uncheck all operator boxes</li> </ul> <h4 id="rule-nodes">Rule Nodes:</h4> <p>Once a parser has been successfully generated from a grammar, all rule names defined by the grammar will appear here in alphabetical order. Often there are many rule names of little or no interest. For example, if an alphanumeric name is defined, the name is usually of interest, but the individual characters are not. The rule names to trace can be selected with the checkbox by each name.</p> <ul> <li>all - (default) check all rule name boxes</li> <li>none - uncheck all rule name boxes</li> </ul> <p>Note that only the checked rules will appear in the phrases displayed in the <a href="#phrasestoc">Phrases panel</a>.</p> <h3 id="inputtoc">Input<span class="help-right"><a href="#help-top">↑toc</a></span></h3> <p>Testing the parser is as simple as typing or pasting an input string into the textarea and clicking <code>Parse Input</code>. The <a href="#phrasestoc">Phrases panel</a> will open up automatically to display the parsed phrases.</p> <p>While an SABNF grammar can easily define sentences and phrases with arbitrary character codes, handling anything other than the printing ASCII characters in a <code>&lt;textarea&gt;</code> is tricky to impossible. <strong>apg.html</strong> offers two ways to handle non-ASCII characters—base 64 encoded and escaped format. <em>(To convert your data to either of these formats, see <a href="https://github.com/ldthomas/apg-conv">apg-conv</a>.)</em></p> <h4 id="base-64">Base 6