1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-16 22:14:23 +03:00
inform7/docs/words-module/4-ap.html
2020-05-20 11:36:42 +01:00

581 lines
60 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>About Preform</title>
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../docs-assets/Contents.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Progress.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Navigation.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Fonts.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script src="http://code.jquery.com/jquery-1.12.4.min.js"
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script src="../docs-assets/Bigfoot.js"></script>
<link href="../docs-assets/Bigfoot.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
<link href="../docs-assets/Preform-Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body class="commentary-font">
<nav role="navigation">
<h1><a href="../index.html">
<img src="../docs-assets/Inform.png" height=72">
</a></h1>
<ul><li><a href="../compiler.html">compiler tools</a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul><h2>Compiler Webs</h2><ul>
<li><a href="../inbuild/index.html">inbuild</a></li>
<li><a href="../inform7/index.html">inform7</a></li>
<li><a href="../inter/index.html">inter</a></li>
</ul><h2>Inbuild Modules</h2><ul>
<li><a href="../supervisor-module/index.html">supervisor</a></li>
</ul><h2>Inform7 Modules</h2><ul>
<li><a href="../core-module/index.html">core</a></li>
<li><a href="../kinds-module/index.html">kinds</a></li>
<li><a href="../if-module/index.html">if</a></li>
<li><a href="../multimedia-module/index.html">multimedia</a></li>
<li><a href="../index-module/index.html">index</a></li>
</ul><h2>Inter Modules</h2><ul>
<li><a href="../bytecode-module/index.html">bytecode</a></li>
<li><a href="../building-module/index.html">building</a></li>
<li><a href="../codegen-module/index.html">codegen</a></li>
</ul><h2>Services</h2><ul>
<li><a href="../arch-module/index.html">arch</a></li>
<li><a href="../syntax-module/index.html">syntax</a></li>
<li><a href="index.html"><span class="selectedlink">words</span></a></li>
<li><a href="../html-module/index.html">html</a></li>
<li><a href="../inflections-module/index.html">inflections</a></li>
<li><a href="../linguistics-module/index.html">linguistics</a></li>
<li><a href="../problems-module/index.html">problems</a></li>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'About Preform' generated by Inweb-->
<div class="breadcrumbs">
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../compiler.html">Services</a></li><li><a href="index.html">words</a></li><li><a href="index.html#4">Chapter 4: Parsing</a></li><li><b>About Preform</b></li></ul></div>
<p class="purpose">A brief guide to Preform and how to use it.</p>
<ul class="toc"><li><a href="4-ap.html#SP1">&#167;1. A Manual for Preform</a></li><li><a href="4-ap.html#SP10">&#167;10. Implementation notes</a></li></ul><hr class="tocbar">
<p class="commentary firstcommentary"><a id="SP1"></a><b>&#167;1. A Manual for Preform. </b>Preform is a meta-language for writing a simple grammar: it's in some sense
pre-Inform, because it defines the Inform language itself, and has to be read
by the <a href="index.html" class="internal">words</a> module (on behalf of Inform) before Inform can parse anything.
For example,
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span>
</pre>
<p class="commentary">The <span class="extract"><span class="Preform-extract-syntax">::=</span></span> indicates a definition: the following-on lines, divided by the
vertical stroke, are possibilities tried in turn. Each "non-terminal", written
in angle brackets, can in principle match (or not match) against any wording.
When writing code in InC (the slight extension of C granted by inweb: see
<a href="../../../inweb/docs/M-tid.html" class="internal">The InC Dialect (in inweb)</a>), this can actually be written as a function call:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (&lt;</span><span class="identifier-syntax">competitor</span><span class="plain-syntax">&gt;(</span><span class="identifier-syntax">W</span><span class="plain-syntax">)) ...</span>
</pre>
<p class="commentary">This function returns <span class="extract"><span class="extract-syntax">TRUE</span></span> if a match is made, and <span class="extract"><span class="extract-syntax">FALSE</span></span> if it is not.
But if a match is indeed made, there are side-effects too, as we shall see.
</p>
<p class="commentary">So, for example, the above grammar would match any of these possibilities:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> 7th runner</span>
<span class="plain-syntax"> third runner</span>
<span class="plain-syntax"> runner no 7</span>
<span class="plain-syntax"> runner no three</span>
</pre>
<p class="commentary">but would fail, for example,
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> runner</span>
<span class="plain-syntax"> 7 runner</span>
<span class="plain-syntax"> runner no 7th</span>
<span class="plain-syntax"> ice cream sandwich</span>
</pre>
<p class="commentary">A small number of nonterminals are "internal", meaning that they are defined
by the Inform compiler modules; all of the rest are called "regular" and are
defined rather like &lt;competitor&gt;, i.e., with grammar spelled out.
</p>
<p class="commentary firstcommentary"><a id="SP2"></a><b>&#167;2. </b>Preform grammar is stored in a text file which is read by Inform early in
its run: see <a href="4-lp.html#SP1" class="internal">LoadPreform::load</a>. In principle, different natural language
definitions can be made: thus, French translators could supply a French-localised
Preform grammar. In practice this whole area of Inform needs more work before
it can fully advance. Still, the principle is that the user can therefore
modify the underlying grammar used by Inform.
</p>
<p class="commentary">The standard Inform distribution comes with the English Preform: in fact, the
file is in <span class="extract"><span class="extract-syntax">inform7/Internal/Languages/English/Syntax.preform</span></span>. However,
this file is not the "original": it is mechanically generated from the source
code of Inform by <a href="../../../inweb/docs/index.html" class="internal">inweb</a>. For example, the excerpt of grammar might have
come from some (hypothetical) source code looking like this:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> TRUE</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> FALSE</span>
</pre>
<p class="commentary">Definitions like this one are scattered all across the Inform web, in order
to keep them close to the code which relates to them. <a href="../../../inweb/docs/index.html" class="internal">inweb</a> tears this
code in half lengthways: the left-hand side goes into the <span class="extract"><span class="Preform-extract-syntax">Syntax.preform</span></span>
file mentioned above, and is then read into Inform at run-time; and the
right-hand side, which is essentially C, becomes code which takes action
on any successful match against the grammar.
</p>
<p class="commentary firstcommentary"><a id="SP3"></a><b>&#167;3. </b>Each nonterminal, when successfully matched, can provide both or more usually
just one of two results: an integer, to be stored in a variable called <span class="extract"><span class="Preform-extract-syntax">*X</span></span>,
and a void pointer, to be stored in <span class="extract"><span class="Preform-extract-syntax">*XP</span></span>, which is usually an object.
</p>
<p class="commentary">The example above, <span class="extract"><span class="Preform-extract-syntax">&lt;competitor&gt;</span></span>, only results in an integer. The <span class="extract"><span class="Preform-extract-syntax">==&gt;</span></span> arrow
is optional, but if present, it says what the integer result is if the given
production is matched. So, for example, "runner bean" or "beetroot" would not
match &lt;competitor&gt;; "4th runner" would match with integer result <span class="extract"><span class="Preform-extract-syntax">TRUE</span></span>;
"runner no 17" would match with integer result <span class="extract"><span class="Preform-extract-syntax">FALSE</span></span>.
</p>
<p class="commentary">Usually, though, the result(s) of a nonterminal depend on the result(s) of
other nonterminals used to make the match. If that's so, then the expression
right of the arrow will have to combine these. In such a compositing expression,
so called because it composes together the various intermediate results into
one final result, <span class="extract"><span class="Preform-extract-syntax">R[1]</span></span> is the integer result of the first nonterminal in
the production, <span class="extract"><span class="Preform-extract-syntax">R[2]</span></span> the second, and so on; <span class="extract"><span class="Preform-extract-syntax">RP[1]</span></span> and so on hold the
pointer results. For example, you could make a very crude calculator with:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;arithmetic&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">plus</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]+R[2]</span>
</pre>
<p class="commentary">Here <span class="extract"><span class="Preform-extract-syntax">R[1]+R[2]</span></span> produces a result by composition of the two results of
the &lt;cardinal-number&gt; nontermimal which occurred when parsing the line.
So, for example, "seven" matches &lt;arithmetic&gt; with result 7, and "two plus
three" with result 5.
</p>
<p class="commentary">Or consider the following refinement of &lt;competitor&gt;:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">the</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">pacemaker</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 1</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
</pre>
<p class="commentary">Now "4th runner" matches with integer result 4, because &lt;ordinal-number&gt;
matches "4th" with integer result 4, and that goes into <span class="extract"><span class="Preform-extract-syntax">R[1]</span></span>. Similarly,
"runner no 17" ends up with integer result 17. "The pacemaker" matches
with integer result 1; here there are no intermediate results to make use
of, so <span class="extract"><span class="Preform-extract-syntax">R[...]</span></span> can't be used.
</p>
<p class="commentary firstcommentary"><a id="SP4"></a><b>&#167;4. </b>The arrows and expressions are optional, and if they are omitted, then the
result integer is set to the alternative number, counting up from 0. For
example, given the following, "polkadot" matches with result 1, and "green"
with result 2.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;race-jersey&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">yellow</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">polkadot</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">green</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">white</span>
</pre>
<p class="commentary firstcommentary"><a id="SP5"></a><b>&#167;5. </b>The material to the right of the <span class="extract"><span class="Preform-extract-syntax">==&gt;</span></span> is actually regular C code, and can
do more than simply evaluate one expression. For example, it can also set
the pointer result of the nonterminal; here, let's suppose, that will be a
pointer to a <span class="extract"><span class="Preform-extract-syntax">text_stream</span></span>.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">the</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">pacemaker</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 1; *XP = I"unnumbered";</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]; *XP = I"numbered";</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]; *XP = I"numbered";</span>
</pre>
<p class="commentary">It can also, if it wants to, kill off a line:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">the</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">pacemaker</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 1</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 0; return FALSE;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
</pre>
<p class="commentary">Here a match against <span class="extract"><span class="Preform-extract-syntax">&lt;ordinal-number&gt; runner</span></span> is forced to fail at the last
hurdle, just as it was about the succeed; it's as if the second row wasn't
there. (This is not useful unconditionally, but with an <span class="extract"><span class="Preform-extract-syntax">if</span></span> statement,
it can be.) More extremely:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">the</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">pacemaker</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 1</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 0; return FAIL_NONTERMINAL;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
</pre>
<p class="commentary">causes any successful match against <span class="extract"><span class="Preform-extract-syntax">&lt;ordinal-number&gt; runner</span></span> not only to be
failed, but to prevent any tries against the rows below it. (This is useful
when issuing problem messages, or to put exceptional syntaxes into the grammar,
since it can make subsequent productions only available in some cases.)
</p>
<p class="commentary">Finally, returning <span class="extract"><span class="Preform-extract-syntax">FAIL_NONTERMINAL + Q</span></span>, where <span class="extract"><span class="Preform-extract-syntax">Q</span></span> is a number between 1
and, currently, 999, performs a fail but applies a "quantum" to the lookahead
going on when Preform is trying to work out what's happening in a difficult
production using the one being referred to. This allows us to nudge past
potential ambiguities; it's not done much in Inform, but see for example
<a href="../if-module/4-anl.html" class="internal">Action Name Lists (in if)</a>.
</p>
<p class="commentary firstcommentary"><a id="SP6"></a><b>&#167;6. </b>As a convenient abbreviation, a slash character can be used to divide
alternative possibilities for a single word. For example:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;race-jersey&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">yellow</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">polkadot/polka-dot</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">green</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">white</span>
</pre>
<p class="commentary">matches "polka-dot" equivalently to "polkadot".
</p>
<p class="commentary">Another convenient notation is the caret <span class="extract"><span class="Preform-extract-syntax">^</span></span>, which negates the effect of
a token. For example,
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">the</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">^adjudicator</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 1</span>
</pre>
<p class="commentary">matches "the pacemaker", "the cyclist", etc. &mdash; the anything at all, but not
"the adjudicator".
</p>
<p class="commentary">The final modifying notation is the underscore <span class="extract"><span class="Preform-extract-syntax">_</span></span>, which forbids unexpected
use of upper casing. Thus
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;race-jersey&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">yellow</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">polkadot</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">_green</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">white</span>
</pre>
<p class="commentary">means that it will match Yellow, yellow, Polkadot, polkadot, green, White
and white, but not Green (except as the first word of a sentence, where
the use of capitalisation has no significance).
</p>
<p class="commentary">If the modifiers <span class="extract"><span class="Preform-extract-syntax">^</span></span> or <span class="extract"><span class="Preform-extract-syntax">_</span></span> are given for the first of a series of slashed
alternatives, they apply to all of the alternatives: thus <span class="extract"><span class="Preform-extract-syntax">^cat/dog</span></span> matches
any word which is neither "cat" nor "dog".
</p>
<p class="commentary">If these characters are needed in their literal form, a backslash <span class="extract"><span class="Preform-extract-syntax">\</span></span> can
be used to escape them. Thus <span class="extract"><span class="Preform-extract-syntax">\_green</span></span> actually matches <span class="extract"><span class="Preform-extract-syntax">_green</span></span>.
</p>
<p class="commentary firstcommentary"><a id="SP7"></a><b>&#167;7. </b>So far, the only ingredients of Preform syntax have been nonterminals and
fixed words, but Preform also has "wildcards". For example, in
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">man</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">with</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">...</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">on</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">his</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">...</span>
</pre>
<p class="commentary">would match, for example, "man with number 17 on his back", or "man with a
chip on his shoulder". <span class="extract"><span class="Preform-extract-syntax">...</span></span> matches any non-empty wording, and the text
actually matched is recorded for any successful match. Wordings like this
are numbered upwards from 1 to a maximum of 4, and are usually retrieved by
whatever part of Inform requested the parse, using the <span class="extract"><span class="Preform-extract-syntax">GET_RW</span></span> macro. For
example:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax">TEXT GET_RW(&lt;competitor&gt;, 1) GET_RW(&lt;competitor&gt;, 2)</span>
<span class="plain-syntax">man with number 17 on his back number 17 back</span>
<span class="plain-syntax">man with a chip on his shoulder a chip shoulder</span>
</pre>
<p class="commentary">A few internal nonterminals also generate word ranges, using <span class="extract"><span class="extract-syntax">PUT_RW</span></span> to do so,
and word ranges can also be inherited up from one nonterminal to another with
<span class="extract"><span class="extract-syntax">INHERIT_RANGES</span></span>: see <a href="4-lp.html" class="internal">Loading Preform</a> for definitions of these macros.
</p>
<p class="commentary">There are in fact several different wildcards:
</p>
<ul class="items"><li>(a) <span class="extract"><span class="extract-syntax">...</span></span> matches any non-empty text, as shown above.
</li><li>(b) <span class="extract"><span class="extract-syntax">***</span></span> matches any text, including possibly the empty text.
</li><li>(c) <span class="extract"><span class="extract-syntax">......</span></span> matches any non-empty text in which brackets are used in a
balanced way &mdash; thus they would match "alpha beta gamma" or "alpha (the
Greek letter)", but not "alpha (the" or "Greek letter)".
</li><li>(d) <span class="extract"><span class="extract-syntax">###</span></span> matches any single word, counting words as the lexer does.
</li></ul>
<p class="commentary">It is also possible to use braces to widen ranges. For example,
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">man</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">with</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{...</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">on</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">his</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">...}</span>
</pre>
<p class="commentary">groups together anything matching <span class="extract"><span class="Preform-extract-syntax">... on his ...</span></span> into a single range. There
need not even be a wildcard inside the braces:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{man}</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">with</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{...</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">on</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">his</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">...}</span>
</pre>
<p class="commentary">works fine, and makes two ranges, the first of which is always just "man".
</p>
<p class="commentary">Once again, literal brace characters can be achieved using the <span class="extract"><span class="Preform-extract-syntax">\</span></span> escape.
</p>
<p class="commentary firstcommentary"><a id="SP8"></a><b>&#167;8. </b>The alternative lines (or "productions", as they're called) in a regular
definition are normally given the internal numbers 0, 1, 2, 3... in the
order in which they appear. For example, in
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;competitor&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">the</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">pacemaker</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 1</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;ordinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">runner</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">no</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> R[1]</span>
</pre>
<p class="commentary">the <span class="extract"><span class="Preform-extract-syntax">the pacemaker</span></span> row is numbered 0, <span class="extract"><span class="Preform-extract-syntax">&lt;ordinal-number&gt; runner</span></span> is numbered 1,
and so on. Those "match numbers" have little outward significance, but help
to determine the result when a successful match is made. Consider:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;letter-score&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">alpha</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 10</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">beta</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 20</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">gamma</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 30</span>
</pre>
<p class="commentary">Here, matching against "beta" produces 20 &mdash; the result on the same row. But
we can mess with that:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;letter-score&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">/c/</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">alpha</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 10</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">/a/</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">beta</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 20</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">/b/</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">gamma</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 30</span>
</pre>
<p class="commentary">The special notation <span class="extract"><span class="Preform-extract-syntax">/X/</span></span>, where <span class="extract"><span class="Preform-extract-syntax">X</span></span> is a lower-case letter, marks the row
as having a different number from the obvious one. <span class="extract"><span class="Preform-extract-syntax">/a/</span></span> means 0, <span class="extract"><span class="Preform-extract-syntax">/b/</span></span> means
1, and so on. The practical effect of the above is to achieve the equivalent
of this:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;letter-score&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">beta</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 10</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">gamma</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 20</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">alpha</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> 30</span>
</pre>
<p class="commentary">That might seem a stupidly obfuscatory thing to do, and indeed it is, when
done in the main Inform source code &mdash; which is why we never do it. But
Preform can also be used by translators of Inform to other languages, who might
supply, e.g., a French version of <span class="extract"><span class="Preform-extract-syntax">Syntax.preform</span></span>. Or suppose in this instance
that the Inform source code contains &lt;letter-score&gt; but that a translator into
Hebrew wants to override that definition. Her Hebrew version of <span class="extract"><span class="Preform-extract-syntax">Syntax.preform</span></span>
could then write:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;letter-score&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">/a/</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">aleph</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">/a/</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">alef</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">/b/</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">beth</span>
</pre>
<p class="commentary">This translator wanted to provide two alternative ways to write the Hebrew
version of "alpha", one for "beta", but none for "gamma". Using the remappings
<span class="extract"><span class="Preform-extract-syntax">/a/</span></span> and <span class="extract"><span class="Preform-extract-syntax">/b/</span></span> here, she is able to make her lines behave as if they were
lines 1, 1, 2 of the original, rather than 1, 2, 3, which would have been the
default.
</p>
<p class="commentary">Because there are a few rather long nonterminal definitions in Inform, the
labelling runs <span class="extract"><span class="Preform-extract-syntax">/a/</span></span>, <span class="extract"><span class="Preform-extract-syntax">/b/</span></span>, ..., <span class="extract"><span class="Preform-extract-syntax">/z/</span></span> and then continues <span class="extract"><span class="Preform-extract-syntax">/aa/</span></span>, <span class="extract"><span class="Preform-extract-syntax">/bb/</span></span>,
..., <span class="extract"><span class="Preform-extract-syntax">/zz/</span></span>, thus allowing for up to 52 productions to be remapped in this way.
</p>
<p class="commentary firstcommentary"><a id="SP9"></a><b>&#167;9. </b>A similar form if remapping is allowed with word ranges, using a special
notation. Suppose the Inform source contained:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;coloured-thing&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;race-colour&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">}</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">jersey/helmet</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">}</span>
</pre>
<p class="commentary">but we want this in French, where adjectives usually come after nouns. So this:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;coloured-thing&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">maillot/casque</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">}</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;race-colour&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">}</span>
</pre>
<p class="commentary">wouldn't work &mdash; it would set the word ranges the wrong way around. Instead:
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;coloured-thing&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">maillot/casque</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">}?2</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;race-colour&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">}?1</span>
</pre>
<p class="commentary">says that word range 2 is to be the article of clothing, and word range 1 the
colour.
</p>
<p class="commentary firstcommentary"><a id="SP10"></a><b>&#167;10. Implementation notes. </b>Most organs of the human body are located in a single place &mdash; the heart, the
appendix, the brain &mdash; but others, like the blood vessels or the nervous
system, are distributed throughout. So also with compilers, but Inform is
unusual in having its syntax analyser be one of these distributed organs.
This was a choice, and it was made in the interests of clarity of the
Inform source code to readers.
</p>
<p class="commentary">In any case, it is only the Preform grammar and the connections to it &mdash;
compositor functions, calls to single named nonterminals, and so on &mdash; which
are dispersed throughout the body of Inform. The code to manage, internally
store and parse against Preform is all here in <a href="index.html" class="internal">words</a>, and the code to
represent the meaning of the result makes up <a href="../syntax-module/index.html" class="internal">syntax</a>.
</p>
<p class="commentary firstcommentary"><a id="SP11"></a><b>&#167;11. </b>The Preform parser which occupies the entire <a href="4-prf.html" class="internal">Preform</a> section is a
complex or even ingenious algorithm, which is always suspect. The main points
of difficulty are:
</p>
<ul class="items"><li>(a) The grammar must not be hard-coded since users need to change it, for
translation or other purposes, so it has to be read in from a file. But it
must also be explicitly referred to in the Inform source code. This is achieved
with a sort of symbiotic relationship between the Inform source code and the
pre-processor for it in <a href="../../../inweb/docs/index.html" class="internal">inweb</a>, which takes action at compile time to
build the syntax file <span class="extract"><span class="Preform-extract-syntax">Syntax.preform</span></span> read in, by default, at run time. The
arrangement works well in practice, but needs careful explanation. See
<a href="4-lp.html" class="internal">Loading Preform</a> for how <span class="extract"><span class="Preform-extract-syntax">Syntax.preform</span></span> is read in.
</li><li>(b) The Preform parser has two design goals: to avoid unpredictable spikes on
time or memory when given very long texts to match, and to be as simple as it
can be, consistent with consuming, in aggregate, no more than 5-10% of the
compiler's running time. It is a non-goal to be a fully general natural
language parser &mdash; if it can cope with Inform's needs, then that is enough.
</li></ul>
<p class="commentary firstcommentary"><a id="SP12"></a><b>&#167;12. </b>So, then, <a href="4-lp.html#SP1" class="internal">LoadPreform::load</a> loads the Preform grammar for a given
natural language from a file. This becomes a collection of <a href="4-nnt.html#SP5" class="internal">nonterminal</a>
objects, each of which is either "internal" or "regular". Regular NTs have
a list of <a href="4-lp.html#SP8" class="internal">production_list</a> objects, one for each natural language in
which they are defined. (The same NT can have one definition in English and
another in, say, French.)
</p>
<p class="commentary">What production lists list is <a href="4-lp.html#SP11" class="internal">production</a> objects, and each of those is
in turn a list of <a href="4-lp.html#SP12" class="internal">ptoken</a> objects.<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> These can also be marked as
negated or can have alternatives supplied. Ptokens come in three varieties:
fixed words, uses of other nonterminals, and wildcards.
</p>
<p class="commentary">For example,
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;product-specification&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">weight</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">kg</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">height</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">cm</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">colour/color</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">...</span>
</pre>
<p class="commentary">would be read into objects in memory as follows:
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="element-syntax">nonterminal</span><span class="plain-syntax"> </span><span class="function-syntax">REGULAR</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">production_list</span><span class="plain-syntax"> </span><span class="element-syntax">for</span><span class="plain-syntax"> </span><span class="element-syntax">its</span><span class="plain-syntax"> </span><span class="element-syntax">English</span><span class="plain-syntax"> </span><span class="element-syntax">definition</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">production</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">FIXED</span><span class="plain-syntax"> </span><span class="function-syntax">WORD</span><span class="plain-syntax"> </span><span class="element-syntax">weight</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">USAGE</span><span class="plain-syntax"> &lt;</span><span class="element-syntax">cardinal</span><span class="plain-syntax">-</span><span class="element-syntax">number</span><span class="plain-syntax">&gt;</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">FIXED</span><span class="plain-syntax"> </span><span class="function-syntax">WORD</span><span class="plain-syntax"> </span><span class="element-syntax">kg</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">production</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">FIXED</span><span class="plain-syntax"> </span><span class="function-syntax">WORD</span><span class="plain-syntax"> </span><span class="element-syntax">height</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">USAGE</span><span class="plain-syntax"> &lt;</span><span class="element-syntax">cardinal</span><span class="plain-syntax">-</span><span class="element-syntax">number</span><span class="plain-syntax">&gt;</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">FIXED</span><span class="plain-syntax"> </span><span class="function-syntax">WORD</span><span class="plain-syntax"> </span><span class="element-syntax">cm</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">production</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">FIXED</span><span class="plain-syntax"> </span><span class="function-syntax">WORD</span><span class="plain-syntax"> </span><span class="element-syntax">colour</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">FIXED</span><span class="plain-syntax"> </span><span class="function-syntax">WORD</span><span class="plain-syntax"> </span><span class="element-syntax">color</span>
<span class="plain-syntax"> -&gt; </span><span class="element-syntax">ptoken</span><span class="plain-syntax"> </span><span class="function-syntax">WILDCARD</span><span class="plain-syntax"> ...</span>
</pre>
<p class="commentary">The above grammar fell under the English production list because that was
the current language when it was read in. The current language can be
changed, e.g.,
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">language</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">French</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;product-specification&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">::=</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">poids</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">kg</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">hauteur</span><span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;cardinal-number&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">cm</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">|</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">couleur</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">...</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">language</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">English</span>
</pre>
<p class="commentary">changes the language to French, supplies a French version, then changes back
to English. There would then be two production lists for &lt;product-specification&gt;.
</p>
<ul class="footnotetexts"><li class="footnote" id="fn:1"><p class="inwebfootnote"><sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> The "p" is silent.
<a href="#fnref:1" title="return to text"> &#x21A9;</a></p></li></ul>
<p class="commentary firstcommentary"><a id="SP13"></a><b>&#167;13. </b>The most technically difficult code occurs in <a href="4-to.html" class="internal">The Optimiser</a>, which
precomputes &mdash;
</p>
<ul class="items"><li>&#9679; <a href="4-le.html" class="internal">Length Extremes</a> to constrain the number of words in any match;
</li><li>&#9679; <a href="4-ni.html" class="internal">Nonterminal Incidences</a> to constrain the type of words in any match;
</li><li>&#9679; "positions" of tokens and "struts" (runs of dividing words) inside productions.
</li></ul>
<p class="commentary">These are all devices to enable non-matching text to be rejected quickly.
For example, "fox" cannot match <span class="extract"><span class="Preform-extract-syntax">&lt;s-literal&gt; &lt;s-instance-name&gt;</span></span> because it
is too short (such a match would need at least two words), and "the fox"
cannot match <span class="extract"><span class="Preform-extract-syntax">&lt;s-adjective&gt; &lt;s-nounphrase&gt;</span></span> because it does not contain any
words which are in some contexts adjectives.
</p>
<p class="commentary firstcommentary"><a id="SP14"></a><b>&#167;14. </b>It will be evident that Inform doesn't use parser-generators such as <span class="extract"><span class="Preform-extract-syntax">yacc</span></span>,
<span class="extract"><span class="Preform-extract-syntax">bison</span></span> or <span class="extract"><span class="Preform-extract-syntax">antlr</span></span>. One reason is that they need the grammar to be fixed and
known at (the compiler's) compile time. Then, too, folk wisdom has it that
<span class="extract"><span class="Preform-extract-syntax">yacc</span></span> parsers are typically half as fast as a shrewdly hand-coded equivalent.<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>
In any case the elegant theory of LALR parsing, though ideal for token-based
programming languages, does not specify natural language well.<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>
</p>
<ul class="footnotetexts"><li class="footnote" id="fn:2"><p class="inwebfootnote"><sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup> The <span class="extract"><span class="Preform-extract-syntax">gcc</span></span> C compiler abandoned the use of <span class="extract"><span class="Preform-extract-syntax">bison</span></span> for exactly this reason.
<a href="#fnref:2" title="return to text"> &#x21A9;</a></p></li><li class="footnote" id="fn:3"><p class="inwebfootnote"><sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup> Which is perhaps ironic, considering that the relevant computer science
was strongly influenced by generative linguistics.
<a href="#fnref:3" title="return to text"> &#x21A9;</a></p></li></ul>
<nav role="progress"><div class="progresscontainer">
<ul class="progressbar"><li class="progressprev"><a href="3-idn.html">&#10094;</a></li><li class="progresschapter"><a href="P-wtmd.html">P</a></li><li class="progresschapter"><a href="1-wm.html">1</a></li><li class="progresschapter"><a href="2-vcb.html">2</a></li><li class="progresschapter"><a href="3-lxr.html">3</a></li><li class="progresscurrentchapter">4</li><li class="progresscurrent">ap</li><li class="progresssection"><a href="4-nnt.html">nnt</a></li><li class="progresssection"><a href="4-lp.html">lp</a></li><li class="progresssection"><a href="4-to.html">to</a></li><li class="progresssection"><a href="4-le.html">le</a></li><li class="progresssection"><a href="4-ni.html">ni</a></li><li class="progresssection"><a href="4-prf.html">prf</a></li><li class="progresssection"><a href="4-bn.html">bn</a></li><li class="progresssection"><a href="4-ins.html">ins</a></li><li class="progressnext"><a href="4-nnt.html">&#10095;</a></li></ul></div>
</nav><!--End of weave-->
</main>
</body>
</html>