1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 10:04:21 +03:00
inform7/docs/core-module/10-aots.html
2020-08-25 21:47:14 +01:00

448 lines
71 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Architecture of the S-Parser</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>
function togglePopup(material_id) {
var popup = document.getElementById(material_id);
popup.classList.toggle("show");
}
</script>
<link href="../docs-assets/Popups.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="index.html"><span class="selectedlink">core</span></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="../calculus-module/index.html">calculus</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="../kinds-module/index.html">kinds</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="../syntax-module/index.html">syntax</a></li>
<li><a href="../words-module/index.html">words</a></li>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'Architecture of the S-Parser' generated by Inweb-->
<div class="breadcrumbs">
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../compiler.html">Inform7 Modules</a></li><li><a href="index.html">core</a></li><li><a href="index.html#10">Chapter 10: The S-Parser</a></li><li><b>Architecture of the S-Parser</b></li></ul></div>
<p class="purpose">Top-level structure of the S-parser, which turns text into S-nodes.</p>
<ul class="toc"><li><a href="10-aots.html#SP1">&#167;1. Introduction</a></li><li><a href="10-aots.html#SP3">&#167;3. Top-level nonterminals</a></li><li><a href="10-aots.html#SP11">&#167;11. The cache</a></li><li><a href="10-aots.html#SP15">&#167;15. Void phrases</a></li></ul><hr class="tocbar">
<p class="commentary firstcommentary"><a id="SP1" class="paragraph-anchor"></a><b>&#167;1. Introduction. </b>The purpose of the S-parser is to turn excerpts of text into specification
nodes. Nonterminals here almost all have names beginning with the "s-" prefix,
which indicates that their results are S-nodes.
</p>
<p class="commentary">The simplest nonterminal in the S-grammar is &lt;s-plain-text&gt;, which
accepts any non-empty piece of text. (The same can be said exactly of
&lt;np-unparsed&gt;, and the difference is purely to do with how Inform stores
the results: &lt;np-unparsed&gt; makes nodes in the main parse tree, a rather
permanent structure, whereas &lt;s-plain-text&gt; makes an S-node.)
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-plain-text&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><a href="14-sp.html#SP10" class="function-link"><span class="Preform-function-syntax">Specifications::new_UNKNOWN</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">) };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP2" class="paragraph-anchor"></a><b>&#167;2. </b>And here is a curious variation, which is needed because equations are
parsed with completely different spacing rules, and don't respect words. It
matches any non-empty text where one of the words contains an equals sign
as one of its characters: thus
</p>
<blockquote>
<p>V = fl</p>
</blockquote>
<blockquote>
<p>F=ma</p>
</blockquote>
<p class="commentary">both match this, the first example being three words long, the second only one.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-plain-text-with-equals&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">LOOP_THROUGH_WORDING</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">i</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">) {</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">wchar_t</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">Lexer::word_raw_text</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">i</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">for</span><span class="Preform-plain-syntax"> (</span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">j</span><span class="Preform-plain-syntax">=0; </span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax">[</span><span class="Preform-identifier-syntax">j</span><span class="Preform-plain-syntax">]; </span><span class="Preform-identifier-syntax">j</span><span class="Preform-plain-syntax">++)</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax">[</span><span class="Preform-identifier-syntax">j</span><span class="Preform-plain-syntax">] == </span><span class="Preform-character-syntax">'='</span><span class="Preform-plain-syntax">) {</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><a href="14-sp.html#SP10" class="function-link"><span class="Preform-function-syntax">Specifications::new_UNKNOWN</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">) };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> }</span>
<span class="Preform-plain-syntax"> }</span>
<span class="Preform-plain-syntax"> ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP3" class="paragraph-anchor"></a><b>&#167;3. Top-level nonterminals. </b>These five nonterminals are the most useful and powerful, so they're the
main junction between the S-parser and the rest of Inform.
</p>
<p class="commentary">These are coded as internals for efficiency's sake. We will often reparse the
same wording over and over, so we cache the results. But &lt;s-value&gt; matches
exactly the same text as &lt;s-value-uncached&gt;, and so on for the other four.
</p>
<p class="commentary">&lt;s-value&gt; looks for source text which can be evaluated &mdash; a constant, a
variable or other storage object, or a phrase to decide a value.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-value&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> = </span><a href="10-aots.html#SP13" class="function-link"><span class="Preform-function-syntax">ExParser::parse_with_cache</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">, </span><span class="Preform-constant-syntax">0</span><span class="Preform-plain-syntax">, </span><span class="Preform-function-syntax">&lt;s-value-uncached&gt;</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">Node::is</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">UNKNOWN_NT</span><span class="Preform-plain-syntax">)) { ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> }; }</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP4" class="paragraph-anchor"></a><b>&#167;4. </b>&lt;s-condition&gt; looks for a condition &mdash; anything legal after an
"if", in short. This includes sentence-like excerpts such as "six
animals have been in the Stables".
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-condition&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><a href="24-lv.html#SP31" class="function-link"><span class="Preform-function-syntax">LocalVariables::make_necessary_callings</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> = </span><a href="10-aots.html#SP13" class="function-link"><span class="Preform-function-syntax">ExParser::parse_with_cache</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">, </span><span class="Preform-constant-syntax">1</span><span class="Preform-plain-syntax">, </span><span class="Preform-function-syntax">&lt;s-condition-uncached&gt;</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">Node::is</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">UNKNOWN_NT</span><span class="Preform-plain-syntax">)) { ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> }; }</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP5" class="paragraph-anchor"></a><b>&#167;5. </b>&lt;s-non-action-condition&gt; is the same, but disallowing action patterns
as conditions, so for example "taking something" would not match.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-non-action-condition&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><a href="24-lv.html#SP31" class="function-link"><span class="Preform-function-syntax">LocalVariables::make_necessary_callings</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">ifdef</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">IF_MODULE</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">old_state</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">PL::Actions::Patterns::suppress</span><span class="Preform-plain-syntax">();</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">endif</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> = </span><a href="10-aots.html#SP13" class="function-link"><span class="Preform-function-syntax">ExParser::parse_with_cache</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">, </span><span class="Preform-constant-syntax">2</span><span class="Preform-plain-syntax">, </span><span class="Preform-function-syntax">&lt;s-condition-uncached&gt;</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">ifdef</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">IF_MODULE</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">PL::Actions::Patterns::resume</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">old_state</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">endif</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">Node::is</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">UNKNOWN_NT</span><span class="Preform-plain-syntax">)) { ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> }; }</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP6" class="paragraph-anchor"></a><b>&#167;6. </b>&lt;s-type-expression&gt; is for where we expect to find the "type" of something
&mdash; for instance, the kind of value to be stored in a variable, or the
specification of a phrase argument.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-type-expression&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> = </span><a href="10-aots.html#SP13" class="function-link"><span class="Preform-function-syntax">ExParser::parse_with_cache</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">, </span><span class="Preform-constant-syntax">3</span><span class="Preform-plain-syntax">, </span><span class="Preform-function-syntax">&lt;s-type-expression-uncached&gt;</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">Node::is</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">UNKNOWN_NT</span><span class="Preform-plain-syntax">)) { ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> }; }</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP7" class="paragraph-anchor"></a><b>&#167;7. </b>&lt;s-descriptive-type-expression&gt; is the same thing, with one difference: it
allows nounless descriptions, such as "open opaque fixed in place", and to
this end it treats bare adjective names as descriptions rather than values. If
we have said "Colour is a kind of value. The colours are red, green and taupe.
A thing has a colour.", then "green" is parsed by &lt;s-descriptive-type-expression&gt;
as a description meaning "any thing which is green", but by &lt;s-type-expression&gt;
and &lt;s-value&gt; as a constant value of the kind "colour".
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-descriptive-type-expression&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> = </span><a href="10-aots.html#SP13" class="function-link"><span class="Preform-function-syntax">ExParser::parse_with_cache</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">, </span><span class="Preform-constant-syntax">4</span><span class="Preform-plain-syntax">, </span><span class="Preform-function-syntax">&lt;s-descriptive-type-expression-uncached&gt;</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">Node::is</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">UNKNOWN_NT</span><span class="Preform-plain-syntax">)) { ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> }; }</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">spec</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP8" class="paragraph-anchor"></a><b>&#167;8. </b>The following internal is just a shell for &lt;s-descriptive-type-expression&gt;,
but it temporarily changes the parsing mode to phrase token parsing, so that
kind variables will be read as formal prototypes.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-phrase-token-type&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">s</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">kind_parsing_mode</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">kind_parsing_mode</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">PHRASE_TOKEN_KIND_PARSING</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">t</span><span class="Preform-plain-syntax"> = </span><span class="Preform-function-syntax">&lt;s-descriptive-type-expression&gt;</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">);</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">kind_parsing_mode</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">s</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">t</span><span class="Preform-plain-syntax">) { ==&gt; { </span><span class="Preform-function-syntax">&lt;&lt;r&gt;&gt;</span><span class="Preform-plain-syntax">, </span><span class="Preform-function-syntax">&lt;&lt;rp&gt;&gt;</span><span class="Preform-plain-syntax"> }; </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">; }</span>
<span class="Preform-plain-syntax"> ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP9" class="paragraph-anchor"></a><b>&#167;9. </b>That's it for the cached nonterminals, but we will also define a convenient
super-nonterminal which matches almost any meaningful reference to data, so
it's frequently used as a way of finding out whether a new name will clash
with some existing meaning.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-type-expression-or-value&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;s-type-expression&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"> { pass 1 }</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-function-syntax">&lt;s-value&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">==&gt;</span><span class="Preform-plain-syntax"> { pass 1 }</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP10" class="paragraph-anchor"></a><b>&#167;10. </b>One further convenience is for text which describes an explicit action in
a noun-like way.
</p>
<pre class="Preform-displayed-code all-displayed-code code-font">
<span class="Preform-function-syntax">&lt;s-explicit-action&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">ifdef</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">IF_MODULE</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">NULL</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">permit_trying_omission</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">permit_trying_omission</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-function-syntax">&lt;s-condition-uncached&gt;</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">)) </span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax"> = </span><span class="Preform-function-syntax">&lt;&lt;rp&gt;&gt;</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">permit_trying_omission</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">) {</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><a href="14-rv.html#SP20" class="function-link"><span class="Preform-function-syntax">Rvalues::is_CONSTANT_of_kind</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">K_stored_action</span><span class="Preform-plain-syntax">)) {</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> } </span><span class="Preform-reserved-syntax">else</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><a href="14-cn.html#SP10" class="function-link"><span class="Preform-function-syntax">Conditions::is_TEST_ACTION</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">)) {</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">-&gt;</span><span class="Preform-element-syntax">down</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> } </span><span class="Preform-reserved-syntax">else</span><span class="Preform-plain-syntax"> {</span>
<span class="Preform-plain-syntax"> ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> }</span>
<span class="Preform-plain-syntax"> }</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">endif</span>
<span class="Preform-plain-syntax"> ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax">}</span>
<span class="Preform-function-syntax">&lt;s-constant-action&gt;</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">internal</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">{</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">ifdef</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">IF_MODULE</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">parse_node</span><span class="Preform-plain-syntax"> *</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">NULL</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">permit_trying_omission</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">permit_trying_omission</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">int</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">p2</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">permit_nonconstant_action_parameters</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">permit_nonconstant_action_parameters</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">FALSE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-function-syntax">&lt;s-condition-uncached&gt;</span><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">W</span><span class="Preform-plain-syntax">)) </span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax"> = </span><span class="Preform-function-syntax">&lt;&lt;rp&gt;&gt;</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">permit_trying_omission</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">p</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">permit_nonconstant_action_parameters</span><span class="Preform-plain-syntax"> = </span><span class="Preform-identifier-syntax">p2</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">) {</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><a href="14-rv.html#SP20" class="function-link"><span class="Preform-function-syntax">Rvalues::is_CONSTANT_of_kind</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">, </span><span class="Preform-identifier-syntax">K_stored_action</span><span class="Preform-plain-syntax">)) {</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> } </span><span class="Preform-reserved-syntax">else</span><span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">if</span><span class="Preform-plain-syntax"> (</span><a href="14-cn.html#SP10" class="function-link"><span class="Preform-function-syntax">Conditions::is_TEST_ACTION</span></a><span class="Preform-plain-syntax">(</span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">)) {</span>
<span class="Preform-plain-syntax"> ==&gt; { -, </span><span class="Preform-identifier-syntax">S</span><span class="Preform-plain-syntax">-&gt;</span><span class="Preform-element-syntax">down</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> </span><span class="Preform-reserved-syntax">return</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">TRUE</span><span class="Preform-plain-syntax">;</span>
<span class="Preform-plain-syntax"> } </span><span class="Preform-reserved-syntax">else</span><span class="Preform-plain-syntax"> {</span>
<span class="Preform-plain-syntax"> ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax"> }</span>
<span class="Preform-plain-syntax"> }</span>
<span class="Preform-plain-syntax"> #</span><span class="Preform-identifier-syntax">endif</span>
<span class="Preform-plain-syntax"> ==&gt; { </span><span class="Preform-identifier-syntax">fail</span><span class="Preform-plain-syntax"> </span><span class="Preform-identifier-syntax">nonterminal</span><span class="Preform-plain-syntax"> };</span>
<span class="Preform-plain-syntax">}</span>
</pre>
<ul class="endnotetexts"><li>This is <a href="../words-module/4-ap.html" class="internal">Preform grammar</a>, not regular C code.</li></ul>
<p class="commentary firstcommentary"><a id="SP11" class="paragraph-anchor"></a><b>&#167;11. The cache. </b>The above nonterminals are called pretty frequently on overlapping or
coinciding runs of text. Inform runs substantially faster if the results of
parsing the most recent expressions are cached; so, for instance, if Inform
parses the text in words 507 to 511 once, it need not do so again in the same
context.
</p>
<p class="commentary firstcommentary"><a id="SP12" class="paragraph-anchor"></a><b>&#167;12. </b>The cache takes the form of a modest ring buffer for each of the contexts:
</p>
<pre class="definitions code-font"><span class="definition-keyword">define</span> <span class="Preform-constant-syntax">MAXIMUM_CACHE_SIZE</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">20</span><span class="Preform-plain-syntax"> </span><span class="Preform-comment-syntax"> a Goldilocks value: too high slows us down, too low doesn't cache enough</span>
<span class="definition-keyword">define</span> <span class="Preform-constant-syntax">NUMBER_OF_CACHED_NONTERMINALS</span><span class="Preform-plain-syntax"> </span><span class="Preform-constant-syntax">5</span>
</pre>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">expression_cache</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">expression_cache_entry</span><span class="plain-syntax"> </span><span class="identifier-syntax">pe_cache</span><span class="plain-syntax">[</span><span class="constant-syntax">MAXIMUM_CACHE_SIZE</span><span class="plain-syntax">];</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">pe_cache_size</span><span class="plain-syntax">; </span><span class="comment-syntax"> number of entries used, 0 to </span><span class="extract"><span class="extract-syntax">MAXIMUM_CACHE_SIZE</span></span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">pe_cache_posn</span><span class="plain-syntax">; </span><span class="comment-syntax"> next write position, 0 to </span><span class="extract"><span class="extract-syntax">pe_cache_size</span></span><span class="comment-syntax"> minus 1</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">expression_cache</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">typedef</span><span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="reserved-syntax">expression_cache_entry</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">wording</span><span class="plain-syntax"> </span><span class="identifier-syntax">cached_query</span><span class="plain-syntax">; </span><span class="comment-syntax"> the word range whose parsing this is</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">struct</span><span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">cached_result</span><span class="plain-syntax">; </span><span class="comment-syntax"> and the result (quite possibly </span><span class="extract"><span class="extract-syntax">UNKNOWN_NT</span></span><span class="comment-syntax">)</span>
<span class="plain-syntax">} </span><span class="reserved-syntax">expression_cache_entry</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">expression_cache_has_been_used</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="reserved-syntax">expression_cache</span><span class="plain-syntax"> </span><span class="identifier-syntax">contextual_cache</span><span class="plain-syntax">[</span><span class="constant-syntax">NUMBER_OF_CACHED_NONTERMINALS</span><span class="plain-syntax">];</span>
</pre>
<ul class="endnotetexts"><li>The structure expression_cache is private to this section.</li><li>The structure expression_cache_entry is private to this section.</li></ul>
<p class="commentary firstcommentary"><a id="SP13" class="paragraph-anchor"></a><b>&#167;13. </b></p>
<pre class="displayed-code all-displayed-code code-font">
<span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="function-syntax">ExParser::parse_with_cache</span><button class="popup" onclick="togglePopup('usagePopup1')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup1">Usage of <span class="code-font"><span class="function-syntax">ExParser::parse_with_cache</span></span>:<br/><a href="10-aots.html#SP3">&#167;3</a>, <a href="10-aots.html#SP4">&#167;4</a>, <a href="10-aots.html#SP5">&#167;5</a>, <a href="10-aots.html#SP6">&#167;6</a>, <a href="10-aots.html#SP7">&#167;7</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">wording</span><span class="plain-syntax"> </span><span class="identifier-syntax">W</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">context</span><span class="plain-syntax">, </span><span class="identifier-syntax">nonterminal</span><span class="plain-syntax"> *</span><span class="identifier-syntax">nt</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Wordings::empty</span><span class="plain-syntax">(</span><span class="identifier-syntax">W</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><a href="14-sp.html#SP10" class="function-link"><span class="function-syntax">Specifications::new_UNKNOWN</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">W</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">context</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">0</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">context</span><span class="plain-syntax"> &gt;= </span><span class="constant-syntax">NUMBER_OF_CACHED_NONTERMINALS</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax"> (</span><span class="string-syntax">"bad expression parsing context"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="10-aots.html#SP13_1" class="named-paragraph-link"><span class="named-paragraph">Check the expression cache to see if we already know the answer</span><span class="named-paragraph-number">13.1</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">unwanted</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">; </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">spec</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">plm</span><span class="plain-syntax"> = </span><span class="identifier-syntax">preform_lookahead_mode</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">preform_lookahead_mode</span><span class="plain-syntax"> = </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Preform::parse_nt_against_word_range</span><span class="plain-syntax">(</span><span class="identifier-syntax">nt</span><span class="plain-syntax">, </span><span class="identifier-syntax">W</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">unwanted</span><span class="plain-syntax">, (</span><span class="reserved-syntax">void</span><span class="plain-syntax"> **) &amp;</span><span class="identifier-syntax">spec</span><span class="plain-syntax">)) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Wordings::empty</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">spec</span><span class="plain-syntax">))) </span><span class="identifier-syntax">Node::set_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">spec</span><span class="plain-syntax">, </span><span class="identifier-syntax">W</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> } </span><span class="reserved-syntax">else</span><span class="plain-syntax"> </span><span class="identifier-syntax">spec</span><span class="plain-syntax"> = </span><a href="14-sp.html#SP10" class="function-link"><span class="function-syntax">Specifications::new_UNKNOWN</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">W</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">preform_lookahead_mode</span><span class="plain-syntax"> = </span><span class="identifier-syntax">plm</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="named-paragraph-container code-font"><a href="10-aots.html#SP13_2" class="named-paragraph-link"><span class="named-paragraph">Write the newly discovered specification to the cache for future use</span><span class="named-paragraph-number">13.2</span></a></span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">VerifyTree::verify_structure_from</span><span class="plain-syntax">(</span><span class="identifier-syntax">spec</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">spec</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP13_1" class="paragraph-anchor"></a><b>&#167;13.1. </b>The following seeks a previously cached answer:
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Check the expression cache to see if we already know the answer</span><span class="named-paragraph-number">13.1</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">expression_cache</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ec</span><span class="plain-syntax"> = &amp;(</span><span class="identifier-syntax">contextual_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">context</span><span class="plain-syntax">]);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">expression_cache_has_been_used</span><span class="plain-syntax"> == </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="10-aots.html#SP14" class="function-link"><span class="function-syntax">ExParser::warn_expression_cache</span></a><span class="plain-syntax">(); </span><span class="comment-syntax"> this empties all the caches</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">expression_cache_has_been_used</span><span class="plain-syntax"> = </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="function-syntax">&lt;ec-&gt;</span><span class="element-syntax">pe_cache_size</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++)</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Wordings::eq</span><span class="plain-syntax">(</span><span class="identifier-syntax">W</span><span class="plain-syntax">, </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">cached_query</span><span class="plain-syntax">))</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">cached_result</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="10-aots.html#SP13">&#167;13</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP13_2" class="paragraph-anchor"></a><b>&#167;13.2. </b>The cache expands until it reaches <span class="extract"><span class="extract-syntax">MAXIMUM_CACHE_SIZE</span></span>; after that,
entries are written in a position cycling through the ring. In either case
it takes <span class="extract"><span class="extract-syntax">MAXIMUM_CACHE_SIZE</span></span> further parses (not found in the cache) to
overwrite the one we put down now.
</p>
<p class="commentary"><span class="named-paragraph-container code-font"><span class="named-paragraph-defn">Write the newly discovered specification to the cache for future use</span><span class="named-paragraph-number">13.2</span></span><span class="comment-syntax"> =</span>
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="plain-syntax"> </span><span class="reserved-syntax">expression_cache</span><span class="plain-syntax"> *</span><span class="identifier-syntax">ec</span><span class="plain-syntax"> = &amp;(</span><span class="identifier-syntax">contextual_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">context</span><span class="plain-syntax">]);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_posn</span><span class="plain-syntax">].</span><span class="element-syntax">cached_query</span><span class="plain-syntax"> = </span><span class="identifier-syntax">W</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_posn</span><span class="plain-syntax">].</span><span class="element-syntax">cached_result</span><span class="plain-syntax"> = </span><span class="identifier-syntax">spec</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_posn</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_size</span><span class="plain-syntax"> &lt; </span><span class="constant-syntax">MAXIMUM_CACHE_SIZE</span><span class="plain-syntax">) </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_size</span><span class="plain-syntax">++;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_posn</span><span class="plain-syntax"> == </span><span class="constant-syntax">MAXIMUM_CACHE_SIZE</span><span class="plain-syntax">) </span><span class="identifier-syntax">ec</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">pe_cache_posn</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
</pre>
<ul class="endnotetexts"><li>This code is used in <a href="10-aots.html#SP13">&#167;13</a>.</li></ul>
<p class="commentary firstcommentary"><a id="SP14" class="paragraph-anchor"></a><b>&#167;14. </b>As with all caches, we have to be careful that the information does not fall
out of date. There are two things which can go wrong: the S-node in the cache
might be altered, perhaps as a result of the type-checker trying to force a
round peg into a square hole; or the stock of Inform's defined names might
change, so that the same text now has to be read differently.
</p>
<p class="commentary">The first problem can't be fixed here. It's tempting to try something like
flagging S-nodes which have been altered, and then ensuring that the
cache never serves up an altered result. But that fails for timing reasons &mdash;
by the time the S-node might be altered, pointers to it may exist
in multiple data structures already, because the cache might have served
it more than once by that time. (Not just a theoretical possibility &mdash; tests
show that this does, albeit rarely, happen.) The brute force solution is to
serve a copy of the cache entry, and thus never send out the same pointer
twice. But this more than doubles the memory required to store S-nodes,
which is unacceptable, and also slows Inform down, because allocating memory
for all those copies is laborious. We therefore just have to be very careful
about modifying S-nodes which have arisen from parsing.
</p>
<p class="commentary">The second problem is easier. We require other parts of Inform which make
or unmake name definitions to warn us, by calling this routine. Definitions
are made and unmade relatively rarely, so the performance hit is small.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ExParser::warn_expression_cache</span><button class="popup" onclick="togglePopup('usagePopup2')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup2">Usage of <span class="code-font"><span class="function-syntax">ExParser::warn_expression_cache</span></span>:<br/><a href="10-aots.html#SP13_1">&#167;13.1</a><br/>Local Variables - <a href="24-lv.html#SP6">&#167;6</a>, <a href="24-lv.html#SP40">&#167;40</a><br/>Parse Invocations - <a href="25-pi.html#SP5">&#167;5</a><br/>Compile Phrases - <a href="25-cp.html#SP2_2">&#167;2.2</a></span></button><span class="plain-syntax">(</span><span class="reserved-syntax">void</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">for</span><span class="plain-syntax"> (</span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">i</span><span class="plain-syntax">=0; </span><span class="identifier-syntax">i</span><span class="plain-syntax">&lt;</span><span class="constant-syntax">NUMBER_OF_CACHED_NONTERMINALS</span><span class="plain-syntax">; </span><span class="identifier-syntax">i</span><span class="plain-syntax">++) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">contextual_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">pe_cache_size</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">contextual_cache</span><span class="plain-syntax">[</span><span class="identifier-syntax">i</span><span class="plain-syntax">].</span><span class="element-syntax">pe_cache_posn</span><span class="plain-syntax"> = </span><span class="constant-syntax">0</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">}</span>
</pre>
<p class="commentary firstcommentary"><a id="SP15" class="paragraph-anchor"></a><b>&#167;15. Void phrases. </b>The S-parser is also used by the main code compiler to turn phrases into
S-nodes, using &lt;s-command&gt; and &lt;s-say-command&gt;. These however need a
wrapper: instead of turning text into an S-node, we take text from an
existing node (in the structural parse tree for a routine), turn that
into a new S-node with an invocation list below it, then glue the list
back into the original tree but throw away the S-node head.
</p>
<pre class="displayed-code all-displayed-code code-font">
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ExParser::parse_void_phrase</span><button class="popup" onclick="togglePopup('usagePopup3')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup3">Usage of <span class="code-font"><span class="function-syntax">ExParser::parse_void_phrase</span></span>:<br/>Compile Phrases - <a href="25-cp.html#SP5">&#167;5</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">p</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="10-aots.html#SP15" class="function-link"><span class="function-syntax">ExParser::parse_phrase_inner</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">, </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ExParser::parse_say_term</span><button class="popup" onclick="togglePopup('usagePopup4')"><span class="comment-syntax">?</span><span class="popuptext" id="usagePopup4">Usage of <span class="code-font"><span class="function-syntax">ExParser::parse_say_term</span></span>:<br/>Compile Phrases - <a href="25-cp.html#SP4_2_1">&#167;4.2.1</a></span></button><span class="plain-syntax">(</span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">p</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><a href="10-aots.html#SP15" class="function-link"><span class="function-syntax">ExParser::parse_phrase_inner</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">, </span><span class="identifier-syntax">TRUE</span><span class="plain-syntax">);</span>
<span class="plain-syntax">}</span>
<span class="reserved-syntax">void</span><span class="plain-syntax"> </span><span class="function-syntax">ExParser::parse_phrase_inner</span><span class="plain-syntax">(</span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">p</span><span class="plain-syntax">, </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">as_say_term</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">p</span><span class="plain-syntax"> == </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">) </span><span class="identifier-syntax">internal_error</span><span class="plain-syntax">(</span><span class="string-syntax">"no node to parse"</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">p</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">down</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">Wordings::nonempty</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">))) {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">parse_node</span><span class="plain-syntax"> *</span><span class="identifier-syntax">results</span><span class="plain-syntax"> = </span><span class="identifier-syntax">NULL</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">as_say_term</span><span class="plain-syntax"> == </span><span class="identifier-syntax">FALSE</span><span class="plain-syntax">) &amp;&amp; (</span><span class="function-syntax">&lt;s-command&gt;</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">)))) </span><span class="identifier-syntax">results</span><span class="plain-syntax"> = </span><span class="function-syntax">&lt;&lt;rp&gt;&gt;</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">as_say_term</span><span class="plain-syntax">) &amp;&amp; (</span><span class="function-syntax">&lt;s-say-command&gt;</span><span class="plain-syntax">(</span><span class="identifier-syntax">Node::get_text</span><span class="plain-syntax">(</span><span class="identifier-syntax">p</span><span class="plain-syntax">)))) </span><span class="identifier-syntax">results</span><span class="plain-syntax"> = </span><span class="function-syntax">&lt;&lt;rp&gt;&gt;</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">results</span><span class="plain-syntax">) &amp;&amp; (</span><span class="identifier-syntax">results</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">down</span><span class="plain-syntax">)) </span><span class="identifier-syntax">p</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">down</span><span class="plain-syntax"> = </span><span class="identifier-syntax">results</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">down</span><span class="plain-syntax">-&gt;</span><span class="element-syntax">down</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax">}</span>
</pre>
<nav role="progress"><div class="progresscontainer">
<ul class="progressbar"><li class="progressprev"><a href="10-its.html">&#10094;</a></li><li class="progresschapter"><a href="P-wtmd.html">P</a></li><li class="progresschapter"><a href="1-cm.html">1</a></li><li class="progresschapter"><a href="2-up.html">2</a></li><li class="progresschapter"><a href="3-bv.html">3</a></li><li class="progresschapter"><a href="4-dlr.html">4</a></li><li class="progresschapter"><a href="5-rpt.html">5</a></li><li class="progresschapter"><a href="6-lp.html">6</a></li><li class="progresschapter"><a href="7-am.html">7</a></li><li class="progresschapter"><a href="8-ptu.html">8</a></li><li class="progresschapter"><a href="9-ef.html">9</a></li><li class="progresscurrentchapter">10</li><li class="progresssection"><a href="10-its.html">its</a></li><li class="progresscurrent">aots</li><li class="progresssection"><a href="10-pl.html">pl</a></li><li class="progresssection"><a href="10-cad.html">cad</a></li><li class="progresssection"><a href="10-teav.html">teav</a></li><li class="progresssection"><a href="10-varc.html">varc</a></li><li class="progresssection"><a href="10-cap.html">cap</a></li><li class="progresschapter"></li><li class="progresschapter"><a href="12-terr.html">12</a></li><li class="progresschapter"><a href="13-kak.html">13</a></li><li class="progresschapter"><a href="14-sp.html">14</a></li><li class="progresschapter"><a href="15-pr.html">15</a></li><li class="progresschapter"><a href="16-is.html">16</a></li><li class="progresschapter"><a href="17-tl.html">17</a></li><li class="progresschapter"><a href="18-lc.html">18</a></li><li class="progresschapter"><a href="19-tc.html">19</a></li><li class="progresschapter"><a href="20-eq.html">20</a></li><li class="progresschapter"><a href="21-rl.html">21</a></li><li class="progresschapter"><a href="22-itp.html">22</a></li><li class="progresschapter"><a href="23-ad.html">23</a></li><li class="progresschapter"><a href="24-lv.html">24</a></li><li class="progresschapter"><a href="25-in.html">25</a></li><li class="progresschapter"><a href="26-fc.html">26</a></li><li class="progresschapter"><a href="27-hr.html">27</a></li><li class="progressnext"><a href="10-pl.html">&#10095;</a></li></ul></div>
</nav><!--End of weave-->
</main>
</body>
</html>