1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/docs/core-module/8-ie.html
2019-04-22 15:42:10 +01:00

765 lines
73 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>8/ef</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '8/ie' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">core</a></li><li><a href="index.html#8">Chapter 8: Extensions</a></li><li><b>Including Extensions</b></li></ul><p class="purpose">To fulfill requests to include extensions, adding their material to the parse tree as needed, and removing INCLUDE nodes.</p>
<ul class="toc"><li><a href="#SP5">&#167;5. Extension loading</a></li><li><a href="#SP6">&#167;6. Parsing extension version numbers</a></li><li><a href="#SP7">&#167;7. Checking the begins here and ends here sentences</a></li><li><a href="#SP11">&#167;11. Sentence handlers for begins here and ends here</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. </b>At this point in the narrative of a typical run of Inform, we have read in the
source text supplied by the user. The lexer automatically prefaced this with
"Include Standard Rules by Graham Nelson", and the sentence-breaker
converted all such sentences to nodes of type <code class="display"><span class="extract">INCLUDE_NT</span></code> which are
children of the parse tree root. (The eldest child, therefore, is the
Standard Rules inclusion.)
</p>
<p class="inwebparagraph">We now look through the parse tree in sentence order &mdash; something we shall
do many times, and which we call a "traverse" &mdash; and look for INCLUDE
nodes. Each is replaced with a mass of further nodes for the material in
whatever new extensions were required. This process is repeated until there
are no "Include" sentences left. In principle this could go on forever if
A includes B which includes A, or some such, but we log each extension read
in to ensure that nothing is read twice.
</p>
<p class="inwebparagraph">At the end of this routine, provided no Problems have been issued, there are
guaranteed to be no INCLUDE nodes remaining in the parse tree.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::traverse</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">includes_cleared</span><span class="plain">;</span>
<span class="reserved">do</span><span class="plain"> {</span>
<span class="identifier">includes_cleared</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> &gt; 0) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">elder</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">ParseTree::traverse_ppni</span><span class="plain">(</span><span class="functiontext">Extensions::Inclusion::visit</span><span class="plain">, &amp;</span><span class="identifier">elder</span><span class="plain">, &amp;</span><span class="identifier">includes_cleared</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">while</span><span class="plain"> (</span><span class="identifier">includes_cleared</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::visit</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">pn</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> **</span><span class="identifier">elder</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> *</span><span class="identifier">includes_cleared</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">) == </span><span class="identifier">INCLUDE_NT</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Replace INCLUDE node with sentence nodes for any extensions required</span> <span class="cwebmacronumber">1.1</span>&gt;<span class="plain">;</span>
<span class="plain">*</span><span class="identifier">includes_cleared</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">) != </span><span class="identifier">ROOT_NT</span><span class="plain">) {</span>
<span class="plain">*</span><span class="identifier">elder</span><span class="plain"> = </span><span class="identifier">pn</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::traverse is used in 1/mr (<a href="1-mr.html#SP4_9">&#167;4.9</a>).</p>
<p class="endnote">The function Extensions::Inclusion::visit appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP1_1"></a><b>&#167;1.1. </b>The INCLUDE node becomes an INCLUSION, which in turn contains the extension's code.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Replace INCLUDE node with sentence nodes for any extensions required</span> <span class="cwebmacronumber">1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">title</span><span class="plain"> = </span><span class="identifier">pn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">, *</span><span class="identifier">author</span><span class="plain"> = </span><span class="identifier">pn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">l</span><span class="plain"> = </span><span class="identifier">ParseTree::begin_inclusion</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">);</span>
<span class="functiontext">Extensions::Inclusion::fulfill_request_to_include_extension</span><span class="plain">(</span><span class="identifier">title</span><span class="plain">, </span><span class="identifier">author</span><span class="plain">);</span>
<span class="identifier">ParseTree::end_inclusion</span><span class="plain">(</span><span class="identifier">l</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP1">&#167;1</a>.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>Here we parse requests to include one or more extensions. People mostly
don't avail themselves of the opportunity, but it is legal to include
several at once, with a line like:
</p>
<blockquote>
<p>Include Carrots by Peter Rabbit and Green Lettuce by Flopsy Bunny.</p>
</blockquote>
<p class="inwebparagraph">A consequence of this convention is that "and" is not permitted in the
name of an extension. We might change this some day.
</p>
<p class="inwebparagraph">Here's how an individual title is described. The bracketed text is later
parsed by &lt;platform-qualifier&gt;.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">title</span><span class="plain">-</span><span class="identifier">and</span><span class="plain">-</span><span class="identifier">version</span><span class="plain">&gt; ::=</span>
<span class="identifier">version</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">version</span><span class="plain">&gt; </span><span class="identifier">of</span><span class="plain"> &lt;</span><span class="identifier">definite</span><span class="plain">-</span><span class="identifier">article</span><span class="plain">&gt; &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="identifier">version</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">version</span><span class="plain">&gt; </span><span class="identifier">of</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">definite</span><span class="plain">-</span><span class="identifier">article</span><span class="plain">&gt; &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">&gt; | ==&gt; -1</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">&gt; ==&gt; -1</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; ( ... ) | ==&gt; 0; &lt;&lt;</span><span class="identifier">rest1</span><span class="plain">&gt;&gt; = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]); &lt;&lt;</span><span class="identifier">rest2</span><span class="plain">&gt;&gt; = </span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1])</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; ==&gt; 0; &lt;&lt;</span><span class="identifier">rest1</span><span class="plain">&gt;&gt; = -1; &lt;&lt;</span><span class="identifier">rest2</span><span class="plain">&gt;&gt; = -1</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">unversioned</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">quoted</span><span class="plain">-</span><span class="identifier">text</span><span class="plain">&gt; *** | ==&gt; </span>&lt;<span class="cwebmacro">Issue PM_IncludeExtQuoted problem</span> <span class="cwebmacronumber">2.1</span>&gt;
<span class="plain">... ==&gt; 0; &lt;&lt;</span><span class="identifier">t1</span><span class="plain">&gt;&gt; = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); &lt;&lt;</span><span class="identifier">t2</span><span class="plain">&gt;&gt; = </span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP2_1"></a><b>&#167;2.1. </b>Quite a popular mistake, this:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Issue PM_IncludeExtQuoted problem</span> <span class="cwebmacronumber">2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="plain">&lt;&lt;</span><span class="identifier">t1</span><span class="plain">&gt;&gt; = -1; &lt;&lt;</span><span class="identifier">t2</span><span class="plain">&gt;&gt; = -1;</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_IncludeExtQuoted</span><span class="plain">),</span>
<span class="string">"the name of an included extension should be given without double "</span>
<span class="string">"quotes in an Include sentence"</span><span class="plain">,</span>
<span class="string">"so for instance 'Include Oh My God by Janice Bing.' rather than "</span>
<span class="string">"'Include \</span><span class="plain">"</span><span class="string">Oh My God\</span><span class="plain">"</span><span class="string"> by Janice Bing.')"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP2">&#167;2</a>.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>This internal parses version text such as "12/110410".
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">version</span><span class="plain">&gt; </span><span class="identifier">internal</span><span class="plain"> 1 {</span>
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); </span> <span class="comment">actually, defer parsing by returning a word number here</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::fulfill_request_to_include_extension</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">auth_p</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">) == </span><span class="identifier">AND_NT</span><span class="plain">) {</span>
<span class="functiontext">Extensions::Inclusion::fulfill_request_to_include_extension</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">, </span><span class="identifier">auth_p</span><span class="plain">);</span>
<span class="functiontext">Extensions::Inclusion::fulfill_request_to_include_extension</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain">, </span><span class="identifier">auth_p</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">&lt;&lt;</span><span class="identifier">rest1</span><span class="plain">&gt;&gt; = -1; &lt;&lt;</span><span class="identifier">rest2</span><span class="plain">&gt;&gt; = -1;</span>
<span class="plain">&lt;&lt;</span><span class="identifier">t1</span><span class="plain">&gt;&gt; = -1; &lt;&lt;</span><span class="identifier">t2</span><span class="plain">&gt;&gt; = -1;</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">title</span><span class="plain">-</span><span class="identifier">and</span><span class="plain">-</span><span class="identifier">version</span><span class="plain">&gt;(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">));</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Wordings::new</span><span class="plain">(&lt;&lt;</span><span class="identifier">t1</span><span class="plain">&gt;&gt;, &lt;&lt;</span><span class="identifier">t2</span><span class="plain">&gt;&gt;);</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">AW</span><span class="plain"> = </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">auth_p</span><span class="plain">);</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">RW</span><span class="plain"> = </span><span class="identifier">Wordings::new</span><span class="plain">(&lt;&lt;</span><span class="identifier">rest1</span><span class="plain">&gt;&gt;, &lt;&lt;</span><span class="identifier">rest2</span><span class="plain">&gt;&gt;);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">version_word</span><span class="plain"> = &lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) </span>&lt;<span class="cwebmacro">Fulfill request to include a single extension</span> <span class="cwebmacronumber">4.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::fulfill_request_to_include_extension is used in <a href="#SP1_1">&#167;1.1</a>.</p>
<p class="inwebparagraph"><a id="SP4_1"></a><b>&#167;4.1. </b>A request consists of author, name and version, the latter being optional.
We obtain the extension file structure corresponding to this: it may have
no text at all (for instance if Inform could not open the file), or it may be
one we have seen before, thanks to an earlier inclusion. Only when it
provided genuinely new text will its <code class="display"><span class="extract">body_text_unbroken</span></code> flag be set,
and then we call the sentence-breaker to ParseTree::graft the new material on to the
parse tree.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Fulfill request to include a single extension</span> <span class="cwebmacronumber">4.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">version_word</span><span class="plain"> &gt;= 0)</span>
<span class="functiontext">Extensions::Inclusion::parse_version</span><span class="plain">(</span><span class="identifier">version_word</span><span class="plain">); </span> <span class="comment">this checks the formatting of the version number</span>
<span class="reserved">extension_file</span><span class="plain"> *</span><span class="identifier">requested_extension</span><span class="plain"> =</span>
<span class="functiontext">Extensions::Inclusion::load</span><span class="plain">(</span><span class="identifier">AW</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">version_word</span><span class="plain">, </span><span class="identifier">RW</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">requested_extension</span><span class="plain">-</span><span class="element">&gt;body_text_unbroken</span><span class="plain">) {</span>
<span class="identifier">Sentences::break</span><span class="plain">(</span><span class="identifier">requested_extension</span><span class="plain">-</span><span class="element">&gt;body_text</span><span class="plain">, </span><span class="identifier">requested_extension</span><span class="plain">);</span>
<span class="identifier">requested_extension</span><span class="plain">-</span><span class="element">&gt;body_text_unbroken</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Extension loading. </b>Extensions are loaded here.
</p>
<pre class="display">
<span class="reserved">extension_file</span><span class="plain"> *</span><span class="functiontext">Extensions::Inclusion::load</span><span class="plain">(</span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">T</span><span class="plain">,</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">version_word</span><span class="plain">, </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">VMW</span><span class="plain">) {</span>
<span class="reserved">extension_file</span><span class="plain"> *</span><span class="identifier">ef</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">, </span><span class="reserved">extension_file</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Wordings::match</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;author_text</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">)) &amp;&amp; (</span><span class="identifier">Wordings::match</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;title_text</span><span class="plain">, </span><span class="identifier">T</span><span class="plain">)))</span>
&lt;<span class="cwebmacro">This is an extension already loaded, so note any version number hike and return</span> <span class="cwebmacronumber">5.1</span>&gt;<span class="plain">;</span>
<span class="identifier">ef</span><span class="plain"> = </span><span class="functiontext">Extensions::Files::new</span><span class="plain">(</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">T</span><span class="plain">, </span><span class="identifier">VMW</span><span class="plain">, </span><span class="identifier">version_word</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0)</span>
&lt;<span class="cwebmacro">Read the extension file into the lexer, and break it into body and documentation</span> <span class="cwebmacronumber">5.2</span>&gt;<span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">ef</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::load is used in <a href="#SP4_1">&#167;4.1</a>, 8/ed2 (<a href="8-ed2.html#SP3_1">&#167;3.1</a>).</p>
<p class="inwebparagraph"><a id="SP5_1"></a><b>&#167;5.1. </b>Note that we ignore a request for an extension which has already been
loaded, except if the new request ups the ante in terms of the minimum
version permitted: in which case we need to record that the requirement has
been tightened. That is, if we previously wanted version 2 of Pantomime
Sausages by Mr Punch, and loaded it, but then read the sentence
</p>
<blockquote>
<p>Include version 3 of Pantomime Sausages by Mr Punch.</p>
</blockquote>
<p class="inwebparagraph">then we need to note that the version requirement on PS has been raised to 3.
(This is why version numbers are not checked at load time: in general, we
can't know at load time what we will ultimately require.)
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">This is an extension already loaded, so note any version number hike and return</span> <span class="cwebmacronumber">5.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Extensions::Inclusion::parse_version</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;min_version_needed</span><span class="plain">) &lt;</span>
<span class="functiontext">Extensions::Inclusion::parse_version</span><span class="plain">(</span><span class="identifier">version_word</span><span class="plain">)) {</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;min_version_needed</span><span class="plain"> = </span><span class="identifier">version_word</span><span class="plain">;</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;inclusion_sentence</span><span class="plain"> = </span><span class="identifier">current_sentence</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">ef</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP5">&#167;5</a>.</p>
<p class="inwebparagraph"><a id="SP5_2"></a><b>&#167;5.2. </b>We finally make our call out of the Extensions section, down through the
trap-door into Read Source Text, to seek and open the file.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Read the extension file into the lexer, and break it into body and documentation</span> <span class="cwebmacronumber">5.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">synopsis</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Concoct a synopsis for the extension to be read</span> <span class="cwebmacronumber">5.2.1</span>&gt;<span class="plain">;</span>
<span class="identifier">feed_t</span><span class="plain"> </span><span class="identifier">id</span><span class="plain"> = </span><span class="identifier">Feeds::begin</span><span class="plain">();</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="functiontext">SourceFiles::read_extension_source_text</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">, </span><span class="identifier">synopsis</span><span class="plain">, </span><span class="identifier">census_mode</span><span class="plain">)) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">ORIGIN_WAS_MATERIALS_EXTENSIONS_AREA</span><span class="plain">:</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">ORIGIN_WAS_USER_EXTENSIONS_AREA</span><span class="plain">:</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;loaded_from_built_in_area</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">ORIGIN_WAS_BUILT_IN_EXTENSIONS_AREA</span><span class="plain">:</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;loaded_from_built_in_area</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">default</span><span class="plain">: </span> <span class="comment">which can happen if the extension file cannot be found</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;loaded_from_built_in_area</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">EXW</span><span class="plain"> = </span><span class="identifier">Feeds::end</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">EXW</span><span class="plain">)) </span>&lt;<span class="cwebmacro">Break the extension's text into body and documentation</span> <span class="cwebmacronumber">5.2.3</span>&gt;<span class="character">;</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">synopsis</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP5">&#167;5</a>.</p>
<p class="inwebparagraph"><a id="SP5_2_1"></a><b>&#167;5.2.1. </b>We concoct a textual synopsis in the form
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">"Pantomime Sausages by Mr Punch"</span>
</pre>
<p class="inwebparagraph">to be used by <code class="display"><span class="extract">SourceFiles::read_extension_source_text</span></code> for printing to <code class="display"><span class="extract">stdout</span></code>. Since
we dare not assume <code class="display"><span class="extract">stdout</span></code> can manage characters outside the basic ASCII
range, we flatten them from general ISO to plain ASCII.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Concoct a synopsis for the extension to be read</span> <span class="cwebmacronumber">5.2.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">synopsis</span><span class="plain">, </span><span class="string">"%+W by %+W"</span><span class="plain">, </span><span class="identifier">T</span><span class="plain">, </span><span class="identifier">A</span><span class="plain">);</span>
<span class="identifier">LOOP_THROUGH_TEXT</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">synopsis</span><span class="plain">)</span>
<span class="identifier">Str::put</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">,</span>
<span class="identifier">Characters::make_filename_safe</span><span class="plain">(</span><span class="identifier">Str::get</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">)));</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP5_2">&#167;5.2</a>.</p>
<p class="inwebparagraph"><a id="SP5_2_2"></a><b>&#167;5.2.2. </b>If an extension file contains the special text (outside literal mode) of
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">---- Documentation ----</span>
</pre>
<p class="inwebparagraph">then this is taken as the end of the Inform source, and the beginning of a
snippet of documentation about the extension; text from that point on is
saved until later, but not broken into sentences for the parse tree, and it
is therefore invisible to the rest of Inform. If this division line is not
present then the extension contains only body source and no documentation.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">body</span><span class="plain">&gt; ::=</span>
<span class="plain">*** ---- </span><span class="identifier">documentation</span><span class="plain"> ---- ... | ==&gt; </span><span class="identifier">TRUE</span>
<span class="plain">... ==&gt; </span><span class="identifier">FALSE</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP5_2_3"></a><b>&#167;5.2.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Break the extension's text into body and documentation</span> <span class="cwebmacronumber">5.2.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">body</span><span class="plain">&gt;(</span><span class="identifier">EXW</span><span class="plain">);</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;body_text</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">body</span><span class="plain">&gt;, 1);</span>
<span class="reserved">if</span><span class="plain"> (&lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;) </span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;documentation_text</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">body</span><span class="plain">&gt;, 2);</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;body_text_unbroken</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span> <span class="comment">mark this to be sentence-broken</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP5_2">&#167;5.2</a>.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. Parsing extension version numbers. </b>Extensions can have versions in the form N/DDDDDD, a format which was chosen
for sentimental reasons: IF enthusiasts know it well from the banner text of
the Infocom titles of the 1980s. This story file, for instance, was compiled
at the time of the Reykjavik summit between Presidents Gorbachev and Reagan:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">Moonmist</span>
<span class="plain">Infocom interactive fiction - a mystery story</span>
<span class="plain">Copyright (c) 1986 by Infocom, Inc. All rights reserved.</span>
<span class="plain">Moonmist is a trademark of Infocom, Inc.</span>
<span class="plain">Release number 9 / Serial number 861022</span>
</pre>
<p class="inwebparagraph">Story file collectors customarily abbreviate this in catalogues to <code class="display"><span class="extract">9/861022</span></code>.
</p>
<p class="inwebparagraph">In our scheme, DDDDDD can be omitted (in which case so must the slash be).
Spacing is not allowed around the slash (if present), so the version number
always occupies a single lexical word.
</p>
<p class="inwebparagraph">The following routine parses the version number at word <code class="display"><span class="extract">vwn</span></code> to give an
non-negative integer &mdash; in fact it really just construes the whole thing,
with the slash removed, as a 7-digit number &mdash; in such a way that an earlier
version always has a lower integer than a later one. It is legal for <code class="display"><span class="extract">vwn</span></code>
to be -1, which means "no version number quoted", and evaluates as
0 &mdash; corresponding to <code class="display"><span class="extract">0/000000</span></code>, lower than the lowest version number it is
legal to quote explicitly, which is <code class="display"><span class="extract">1</span></code>. (It follows that requiring no
version in particular is equivalent to requiring <code class="display"><span class="extract">0/000000</span></code> or better, since
every extension passes that test.)
</p>
<p class="inwebparagraph">In order that the numerical form of a version number should be a signed
32-bit integer which does not overflow, we require that the release number
<code class="display"><span class="extract">N</span></code> be at most 999. It could in fact rise to 2146 without incident, but
it seems cleaner to constrain the number of digits than the value.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MAX_VERSION_NUMBER_LENGTH</span><span class="plain"> 10 </span> <span class="comment">for <code class="display"><span class="extract">999/991231</span></code></span>
</pre>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::parse_version</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">vwn</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">, </span><span class="identifier">rv</span><span class="plain">, </span><span class="identifier">slashes</span><span class="plain"> = 0, </span><span class="identifier">digits</span><span class="plain"> = 0, </span><span class="identifier">slash_at</span><span class="plain"> = 0;</span>
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, *</span><span class="identifier">q</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">vwn</span><span class="plain"> == -1) </span><span class="reserved">return</span><span class="plain"> 0; </span> <span class="comment">an unspecified version equates to <code class="display"><span class="extract">0/000000</span></code></span>
<span class="identifier">p</span><span class="plain"> = </span><span class="identifier">Lexer::word_text</span><span class="plain">(</span><span class="identifier">vwn</span><span class="plain">); </span><span class="identifier">q</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] != 0; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] == </span><span class="character">'/'</span><span class="plain">) {</span>
<span class="identifier">slashes</span><span class="plain">++; </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">i</span><span class="plain"> == 0) || (</span><span class="identifier">slashes</span><span class="plain"> &gt; 1)) </span><span class="reserved">goto</span><span class="plain"> </span><span class="identifier">Malformed</span><span class="plain">;</span>
<span class="identifier">slash_at</span><span class="plain"> = </span><span class="identifier">i</span><span class="plain">; </span><span class="identifier">q</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">+</span><span class="identifier">i</span><span class="plain">+1;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (!(</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]))) </span><span class="reserved">goto</span><span class="plain"> </span><span class="identifier">Malformed</span><span class="plain">;</span>
<span class="identifier">digits</span><span class="plain">++;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">p</span><span class="plain">[0] == </span><span class="character">'0'</span><span class="plain">) || (</span><span class="identifier">digits</span><span class="plain"> == 0)) </span><span class="reserved">goto</span><span class="plain"> </span><span class="identifier">Malformed</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">slashes</span><span class="plain"> == 0) &amp;&amp; (</span><span class="identifier">digits</span><span class="plain"> &lt;= 3)) </span> <span class="comment">so that <code class="display"><span class="extract">p</span></code> points to 1 to 3 digits, not starting with <code class="display"><span class="extract">0</span></code></span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">Wide::atoi</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">)*1000000;</span>
<span class="identifier">p</span><span class="plain">[</span><span class="identifier">slash_at</span><span class="plain">] = 0; </span> <span class="comment">temporarily replace the slash with a null, making <code class="display"><span class="extract">p</span></code> and <code class="display"><span class="extract">q</span></code> distinct C strings</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wide::len</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">) &gt; 3) </span><span class="reserved">goto</span><span class="plain"> </span><span class="identifier">Malformed</span><span class="plain">; </span> <span class="comment">now <code class="display"><span class="extract">p</span></code> points to 1 to 3 digits, not starting with <code class="display"><span class="extract">0</span></code></span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wide::len</span><span class="plain">(</span><span class="identifier">q</span><span class="plain">) != 6) </span><span class="reserved">goto</span><span class="plain"> </span><span class="identifier">Malformed</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (*</span><span class="identifier">q</span><span class="plain"> == </span><span class="character">'0'</span><span class="plain">) </span><span class="identifier">q</span><span class="plain">++; </span> <span class="comment">now <code class="display"><span class="extract">q</span></code> points to 0 to 6 digits, not starting with <code class="display"><span class="extract">0</span></code></span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">q</span><span class="plain">[0] == 0) </span><span class="identifier">q</span><span class="plain">--; </span> <span class="comment">if it was 0 digits, backspace to make it a single digit <code class="display"><span class="extract">0</span></code></span>
<span class="identifier">rv</span><span class="plain"> = (</span><span class="identifier">Wide::atoi</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">)*1000000) + </span><span class="identifier">Wide::atoi</span><span class="plain">(</span><span class="identifier">q</span><span class="plain">);</span>
<span class="identifier">p</span><span class="plain">[</span><span class="identifier">slash_at</span><span class="plain">] = </span><span class="character">'/'</span><span class="plain">; </span> <span class="comment">put the slash back over the null byte temporarily dividing the string</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="identifier">Malformed</span><span class="plain">: </span>&lt;<span class="cwebmacro">Issue a problem message for a malformed version number</span> <span class="cwebmacronumber">6.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::parse_version is used in <a href="#SP4_1">&#167;4.1</a>, <a href="#SP5_1">&#167;5.1</a>, <a href="#SP9">&#167;9</a>, 8/ef (<a href="8-ef.html#SP18">&#167;18</a>).</p>
<p class="inwebparagraph"><a id="SP6_1"></a><b>&#167;6.1. </b>Because we tend to call <code class="display"><span class="extract">Extensions::Inclusion::parse_version</span></code> repeatedly on the same word, we
want to recover tidily from this problem, and not report it over and over.
We do this by altering the text to <code class="display"><span class="extract">1</span></code>, the lowest well-formed version
number text.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message for a malformed version number</span> <span class="cwebmacronumber">6.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Offending word number %d &lt;%N&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">vwn</span><span class="plain">, </span><span class="identifier">vwn</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ExtVersionMalformed</span><span class="plain">),</span>
<span class="string">"a version number must have the form N/DDDDDD"</span><span class="plain">,</span>
<span class="string">"as in the example '2/040426' for release 2 made on 26 April 2004. "</span>
<span class="string">"(The DDDDDD part is optional, so '3' is a legal version number too. "</span>
<span class="string">"N must be between 1 and 999: in particular, there is no version 0.)"</span><span class="plain">);</span>
<span class="identifier">Vocabulary::change_text_of_word</span><span class="plain">(</span><span class="identifier">vwn</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"1"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> 1000000; </span> <span class="comment">which equates to <code class="display"><span class="extract">1/000000</span></code></span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP6">&#167;6</a>.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Checking the begins here and ends here sentences. </b>When a newly loaded extension is being sentence-broken, problem messages
will be turned up unless it contains the matching pair of "begins here"
and "ends here" sentences. Assuming it does, the sentence breaker has no
objection, but it also calls the two routines below to verify that these
sentences have the correct format. (The point of this is to catch a malformed
extension at the earliest possible moment after loading it: it's easy to
mis-install extensions, especially if doing so by hand, and the resulting
problem messages could be quite inscrutable if one extension was wrongly
identified as another.)
</p>
<p class="inwebparagraph">First, we check the "begins here" sentence. We also identify where the
version number is given (if it is), and check that we are not trying to
use an extension which is marked as not working on the current VM.
</p>
<p class="inwebparagraph">It is sufficient to try parsing the version number in order to check it:
we throw away the answer, as we can't use it yet, but this will provoke
problem messages if it is malformed.
</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>This parses the subject noun-phrase in the sentence
</p>
<blockquote>
<p>Version 3 of Pantomime Sausages by Mr Punch begins here.</p>
</blockquote>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">begins</span><span class="plain">-</span><span class="identifier">here</span><span class="plain">-</span><span class="identifier">sentence</span><span class="plain">-</span><span class="identifier">subject</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">title</span><span class="plain">-</span><span class="identifier">and</span><span class="plain">-</span><span class="identifier">version</span><span class="plain">&gt; </span><span class="identifier">by</span><span class="plain"> ... | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]; &lt;&lt;</span><span class="identifier">auth1</span><span class="plain">&gt;&gt; = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]); &lt;&lt;</span><span class="identifier">auth2</span><span class="plain">&gt;&gt; = </span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]);</span>
<span class="plain">... ==&gt; </span>&lt;<span class="cwebmacro">Issue PM_ExtMiswordedBeginsHere problem</span> <span class="cwebmacronumber">8.1</span>&gt;
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP8_1"></a><b>&#167;8.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue PM_ExtMiswordedBeginsHere problem</span> <span class="cwebmacronumber">8.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="plain">&lt;&lt;</span><span class="identifier">auth1</span><span class="plain">&gt;&gt; = -1; &lt;&lt;</span><span class="identifier">auth2</span><span class="plain">&gt;&gt; = -1;</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ExtMiswordedBeginsHere</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"has a misworded 'begins here' sentence ('%2'), which contains "</span>
<span class="string">"no 'by'. Recall that every extension should begin with a "</span>
<span class="string">"sentence such as 'Quantum Mechanics by Max Planck begins "</span>
<span class="string">"here.', and end with a matching 'Quantum Mechanics ends "</span>
<span class="string">"here.', perhaps with documentation to follow."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::check_begins_here</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain">, </span><span class="reserved">extension_file</span><span class="plain"> *</span><span class="identifier">ef</span><span class="plain">) {</span>
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">PN</span><span class="plain">; </span> <span class="comment">in case problem messages need to be issued</span>
<span class="functiontext">Problems::quote_extension</span><span class="plain">(1, </span><span class="identifier">ef</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">));</span>
<span class="plain">&lt;</span><span class="identifier">begins</span><span class="plain">-</span><span class="identifier">here</span><span class="plain">-</span><span class="identifier">sentence</span><span class="plain">-</span><span class="identifier">subject</span><span class="plain">&gt;(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">));</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Wordings::new</span><span class="plain">(&lt;&lt;</span><span class="identifier">t1</span><span class="plain">&gt;&gt;, &lt;&lt;</span><span class="identifier">t2</span><span class="plain">&gt;&gt;);</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">AW</span><span class="plain"> = </span><span class="identifier">Wordings::new</span><span class="plain">(&lt;&lt;</span><span class="identifier">auth1</span><span class="plain">&gt;&gt;, &lt;&lt;</span><span class="identifier">auth2</span><span class="plain">&gt;&gt;);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::empty</span><span class="plain">(</span><span class="identifier">AW</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;version_loaded</span><span class="plain"> = &lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;;</span>
<span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;VM_restriction_text</span><span class="plain"> = </span><span class="identifier">Wordings::new</span><span class="plain">(&lt;&lt;</span><span class="identifier">rest1</span><span class="plain">&gt;&gt;, &lt;&lt;</span><span class="identifier">rest2</span><span class="plain">&gt;&gt;);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;version_loaded</span><span class="plain"> &gt;= 0) </span><span class="functiontext">Extensions::Inclusion::parse_version</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;version_loaded</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;VM_restriction_text</span><span class="plain">))</span>
&lt;<span class="cwebmacro">Check that the extension's stipulation about the virtual machine can be met</span> <span class="cwebmacronumber">9.1</span>&gt;<span class="character">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Wordings::match</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;title_text</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">Wordings::match</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;author_text</span><span class="plain">, </span><span class="identifier">AW</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">))</span>
&lt;<span class="cwebmacro">Issue a problem message pointing out that name and author do not agree with filename</span> <span class="cwebmacronumber">9.2</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::check_begins_here is used in 7/ss (<a href="7-ss.html#SP4">&#167;4</a>).</p>
<p class="inwebparagraph"><a id="SP9_1"></a><b>&#167;9.1. </b>On the other hand, we do already know what virtual machine we are compiling
for, so we can immediately object if the loaded extension cannot be used
with our VM de jour.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Check that the extension's stipulation about the virtual machine can be met</span> <span class="cwebmacronumber">9.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">platform</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt;(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;VM_restriction_text</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (&lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt; == </span><span class="constant">PLATFORM_UNMET_HQ</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Issue a problem message saying that the VM does not meet requirements</span> <span class="cwebmacronumber">9.1.2</span>&gt;<span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
&lt;<span class="cwebmacro">Issue a problem message saying that the VM requirements are malformed</span> <span class="cwebmacronumber">9.1.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP9">&#167;9</a>.</p>
<p class="inwebparagraph"><a id="SP9_2"></a><b>&#167;9.2. </b>Suppose we wanted Onion Cookery by Delia Smith. We loaded the extension
file called Onion Cookery in the Delia Smith folder of the (probably external)
extensions area: but suppose that file turns out instead to be French Cuisine
by Elizabeth David, according to its "begins here" sentence? Then the
following problem message is produced:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message pointing out that name and author do not agree with filename</span> <span class="cwebmacronumber">9.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="functiontext">Problems::quote_extension</span><span class="plain">(1, </span><span class="identifier">ef</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ExtMisidentified</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"The extension %1, which your source text makes use of, seems to be "</span>
<span class="string">"misidentified: its 'begins here' sentence declares it as '%2'. "</span>
<span class="string">"(Perhaps it was wrongly installed?)"</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP9">&#167;9</a>.</p>
<p class="inwebparagraph"><a id="SP9_1_1"></a><b>&#167;9.1.1. </b>See Virtual Machines for the grammar of what can be given as a VM
requirement.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message saying that the VM requirements are malformed</span> <span class="cwebmacronumber">9.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="functiontext">Problems::quote_extension</span><span class="plain">(1, </span><span class="identifier">ef</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;VM_restriction_text</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ExtMalformedVM</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"Your source text makes use of the extension %1: but my copy "</span>
<span class="string">"stipulates that it is '%2', which is a description of the required "</span>
<span class="string">"story file format which I can't understand, and should be "</span>
<span class="string">"something like '(for Z-machine version 5 or 8 only)'."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP9_1">&#167;9.1</a>.</p>
<p class="inwebparagraph"><a id="SP9_1_2"></a><b>&#167;9.1.2. </b>Here the problem is not that the extension is broken in some way: it's
just not what we can currently use. Therefore the correction should be a
matter of removing the inclusion, not of altering the extension, so we
report this problem at the inclusion line.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem message saying that the VM does not meet requirements</span> <span class="cwebmacronumber">9.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;inclusion_sentence</span><span class="plain">;</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;title_text</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;author_text</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(4, </span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;VM_restriction_text</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ExtInadequateVM</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"You wrote %1: but my copy of %2 by %3 stipulates that it "</span>
<span class="string">"is '%4'. That means it can only be used with certain of "</span>
<span class="string">"the possible compiled story file formats, and at the "</span>
<span class="string">"moment, we don't fit the requirements. (You can change "</span>
<span class="string">"the format used for this project on the Settings panel.)"</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP9_1">&#167;9.1</a>.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>Similarly, we check the "ends here" sentence. Here there are no
side-effects: we merely verify that the name matches the one quoted in
the "begins here". We only check this if the problem count is still 0,
since we don't want to keep on nagging somebody who has already been told
that the extension isn't the one he thinks it is.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::check_ends_here</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain">, </span><span class="reserved">extension_file</span><span class="plain"> *</span><span class="identifier">ef</span><span class="plain">) {</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Articles::remove_the</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">problem_count</span><span class="plain"> == 0) &amp;&amp; (</span><span class="identifier">Wordings::match</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">-</span><span class="element">&gt;title_text</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">PN</span><span class="plain">;</span>
<span class="functiontext">Problems::quote_extension</span><span class="plain">(1, </span><span class="identifier">ef</span><span class="plain">);</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_ExtMisidentifiedEnds</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"The extension %1, which your source text makes use of, seems to be "</span>
<span class="string">"malformed: its 'begins here' sentence correctly identifies it, but "</span>
<span class="string">"then the 'ends here' sentence calls it '%2' instead. (They need "</span>
<span class="string">"to be a matching pair except that the end does not name the "</span>
<span class="string">"author: for instance, 'Hocus Pocus by Jan Ackerman begins here.' "</span>
<span class="string">"would match with 'Hocus Pocus ends here.')"</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::check_ends_here is used in 7/ss (<a href="7-ss.html#SP4">&#167;4</a>).</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Sentence handlers for begins here and ends here. </b>The main traverses of the assertions are handled by code which calls
"sentence handler" routines on each node in turn, depending on type.
Here are the handlers for BEGINHERE and ENDHERE. As can be seen, all
we really do is start again from a clean piece of paper.
</p>
<p class="inwebparagraph">Note that, because one extension can include another, these nodes may
well be interleaved: we might find the sequence A begins, B begins,
B ends, A ends. The careful checking done so far ensures that these
will always properly nest. We don't at present make use of this, but
we might in future.
</p>
<pre class="display">
<span class="reserved">sentence_handler</span><span class="plain"> </span><span class="identifier">BEGINHERE_SH_handler</span><span class="plain"> =</span>
<span class="plain">{ </span><span class="identifier">BEGINHERE_NT</span><span class="plain">, -1, 0, </span><span class="functiontext">Extensions::Inclusion::handle_extension_begins</span><span class="plain"> };</span>
<span class="reserved">sentence_handler</span><span class="plain"> </span><span class="identifier">ENDHERE_SH_handler</span><span class="plain"> =</span>
<span class="plain">{ </span><span class="identifier">ENDHERE_NT</span><span class="plain">, -1, 0, </span><span class="functiontext">Extensions::Inclusion::handle_extension_ends</span><span class="plain"> };</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::handle_extension_begins</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain">) {</span>
<span class="functiontext">Assertions::Traverse::new_discussion</span><span class="plain">(); </span><span class="identifier">near_start_of_extension</span><span class="plain"> = 1;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Extensions::Inclusion::handle_extension_ends</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain">) {</span>
<span class="identifier">near_start_of_extension</span><span class="plain"> = 0;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Extensions::Inclusion::handle_extension_begins appears nowhere else.</p>
<p class="endnote">The function Extensions::Inclusion::handle_extension_ends appears nowhere else.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="8-ef.html">Back to 'Extension Files'</a></li><li><a href="8-ei.html">Continue with 'Extension Identifiers'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>