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/26-iti.html
2019-09-17 12:55:51 +01:00

924 lines
100 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>26/tti</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 '26/iti' 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#26">Chapter 26: Compilation Utilities</a></li><li><b>I6 Template Interpreter</b></li></ul><p class="purpose">Inform 6 meta-language is the language used by template files (with extension |.i6t|). It is not itself I6 code, but a list of instructions for making I6 code: most of the content is to be copied over verbatim, but certain escape sequences cause Inform to insert more elaborate material, or to do something active. The entire top-level logic of Inform is carried out by interpreting the |Main.i6t| file in this way.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP3">&#167;3. Syntax of I6T files</a></li><li><a href="#SP7_8">&#167;7.8. Acting on I6T commands</a></li><li><a href="#SP7_8_2">&#167;7.8.2. Indexing commands</a></li><li><a href="#SP7_8_3">&#167;7.8.3. Commands accessing Inform internals</a></li><li><a href="#SP8">&#167;8. Template errors</a></li><li><a href="#SP9">&#167;9. I7 expression evaluation</a></li><li><a href="#SP10">&#167;10. The build constant</a></li><li><a href="#SP11">&#167;11. Registration of sentence handlers</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Definitions. </b></p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>The following flag is set by the <code class="display"><span class="extract">-noindex</span></code> command line option.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">do_not_generate_index</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. Syntax of I6T files. </b>The syntax of these files has been designed so that a valid I6T file is
also a valid Inweb section file. This means that no tangling is required to
make the I6T files: they can be, and indeed are, simply copied verbatim
from Appendix B of the source web.
</p>
<p class="inwebparagraph">Formally, an I6T file consists of a preamble followed by one or more parts.
The preamble takes the form:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">B/name: Longer Form of Name.</span>
<span class="plain"> </span>
<span class="plain">@Purpose: ...</span>
<span class="plain"> </span>
<span class="plain">@-------------------------------------------------------------------------------</span>
</pre>
<p class="inwebparagraph">(for some number of dashes). Each part begins with a heading line in the form
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">@p Title.</span>
</pre>
<p class="inwebparagraph">At some point during the part, a heading line
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">@c</span>
</pre>
<p class="inwebparagraph">introduces the code of the part. When Inform interprets an I6T file, it ignores
the preamble and the material in every part before the <code class="display"><span class="extract">@c</span></code> heading: these
are commentary.
</p>
<p class="inwebparagraph">It actually doesn't matter if a template file contains lines longer than
this, so long as they do not occur inside <code class="display"><span class="extract">{-lines:...}</span></code> and <code class="display"><span class="extract">{-endlines}</span></code>,
and so long as no individual braced command <code class="display"><span class="extract">{-...}</span></code> exceeds this length.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MAX_I6T_LINE_LENGTH</span><span class="plain"> 1024</span>
</pre>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>We can regard the whole Inform program as basically a filter: it copies its
input, the <code class="display"><span class="extract">Main.i6t</span></code> template file, directly into its output, but making
certain replacements along the way.
</p>
<p class="inwebparagraph">The code portions of <code class="display"><span class="extract">.i6t</span></code> files are basically written in I6, but with a
special escape syntax:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">{-command:argument}</span>
</pre>
<p class="inwebparagraph">tells Inform to act immediately on the I6T command given, with the
argument supplied. One of these commands is special:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">{-lines:commandname}</span>
</pre>
<p class="inwebparagraph">tells Inform that all subsequent lines in the I6T file, up to the next
<code class="display"><span class="extract">{-endlines}</span></code>, are to be read as a series of arguments for the
<code class="display"><span class="extract">commandname</span></code> command. Thus,
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">{-lines:admire}</span>
<span class="plain">Jackson Pollock</span>
<span class="plain">Paul Klee</span>
<span class="plain">Wassily Kandinsky</span>
<span class="plain">{-endlines}</span>
</pre>
<p class="inwebparagraph">is a shorthand form for:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">{-admire:Jackson Pollock}{-admire:Paul Klee}{-admire:Wassily Kandinsky}</span>
</pre>
<p class="inwebparagraph">The following comment syntax is useful mainly for commenting out commands:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">{-! Something very clever happens next.}</span>
</pre>
<p class="inwebparagraph">The commands all either instruct Inform to do something (say, traverse the
parse tree and convert its assertions to inferences) but output nothing,
or else to compile some I6 code to the output. There are no control structures,
no variables: I6T commands do not amount to a programming language.
</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>I7 expressions can be included in I6T code exactly as in inline invocation
definitions: thus
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">Constant FROG_CLASS = (+ pond-dwelling amphibian +);</span>
</pre>
<p class="inwebparagraph">will expand "pond-dwelling amphibian" into the I6 translation of the kind
of object with this name. Because of this syntax, one has to watch out for
I6 code like so:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">if (++counter_of_some_kind &gt; 0) ...</span>
</pre>
<p class="inwebparagraph">which can trigger an unwanted <code class="display"><span class="extract">(+</span></code>.
</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>It is not quite true that the following routine acts as a filter from
input to output, because:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(i) It skips the preamble and the commentary portion of each part in the input.
</li></ul>
<ul class="items"><li>(ii) It has an <code class="display"><span class="extract">active</span></code> mode, outside of which it ignores most commands and
copies no output &mdash; it begins in active mode and leaves it only when Inform
issues problem messages, so that subsequent commands almost certainly
cannot safely be used. In a successful compilation run, the interpreter
remains in active mode throughout. Otherwise, generally speaking, it goes
into passive mode as soon as an I6T command has resulted in Problem messages,
and then in stays in passive mode until the output file is closed again;
then it goes back into active mode to carry out some shutting-down-gracefully
steps.
</li></ul>
<ul class="items"><li>(iii) The output stream is not always open. In fact, it starts unopened (and
with <code class="display"><span class="extract">OUT</span></code> set to null); two of the I6T commands open and close it. When
the file isn't open, no output can be written, but I6T commands telling Inform
to do something can still take effect: in fact, the <code class="display"><span class="extract">Main.i6t</span></code> file begins
with dozens of I6T commands before the output file is opened, and concludes
with a couple of dozen more after it has been closed.
</li></ul>
<ul class="items"><li>(iv) It can abort, cleanly exiting Inform when it does so, if a global flag
is set as a result of work done by one of its commands. In fact, this is
used only to exit Inform early after performing an extension census when called
with the command line option <code class="display"><span class="extract">-census</span></code>, and can never happen on a compilation
run, whatever problems or disasters may occur.
</li></ul>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>The I6T interpreter is a single routine which implements the description
above:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">TemplateFiles::interpret</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">sf</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">segment_name</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">N_escape</span><span class="plain">) {</span>
<span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">Input_File</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">default_command</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">heading_name</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">active</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">, </span><span class="identifier">indexing</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">skip_part</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">comment</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">col</span><span class="plain"> = 1, </span><span class="identifier">cr</span><span class="plain">, </span><span class="identifier">sfp</span><span class="plain"> = 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">segment_name</span><span class="plain">) &gt; 0) {</span>
&lt;<span class="cwebmacro">Open the I6 template file</span> <span class="cwebmacronumber">7.1</span>&gt;<span class="plain">;</span>
<span class="identifier">comment</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">comment</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">);</span>
<span class="reserved">do</span><span class="plain"> {</span>
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">);</span>
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="identifier">NewCharacter</span><span class="plain">: </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="identifier">EOF</span><span class="plain">) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'@'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">col</span><span class="plain"> == 1)) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">inweb_syntax</span><span class="plain"> = -1;</span>
&lt;<span class="cwebmacro">Read the rest of line as an at-heading</span> <span class="cwebmacronumber">7.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Act on the at-heading, going in or out of comment mode as appropriate</span> <span class="cwebmacronumber">7.4</span>&gt;<span class="plain">;</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">comment</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">default_command</span><span class="plain">) &gt; 0) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == 10) || (</span><span class="identifier">cr</span><span class="plain"> == 13)) </span><span class="reserved">continue</span><span class="plain">; </span> <span class="comment">skip blank lines here</span>
&lt;<span class="cwebmacro">Set the command to the default, and read rest of line as argument</span> <span class="cwebmacronumber">7.5</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Str::get_first_char</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">) == </span><span class="character">'!'</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">Str::get_first_char</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">) == 0)) </span><span class="reserved">continue</span><span class="plain">; </span> <span class="comment">skip blanks and comments</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"{-endlines}"</span><span class="plain">)) </span><span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">default_command</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span>&lt;<span class="cwebmacro">Act on I6T command and argument</span> <span class="cwebmacronumber">7.8</span>&gt;<span class="plain">;</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'{'</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'-'</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read up to the next close brace as an I6T command and argument</span> <span class="cwebmacronumber">7.6</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::get_first_char</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">) == </span><span class="character">'!'</span><span class="plain">) </span><span class="reserved">continue</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Act on I6T command and argument</span> <span class="cwebmacronumber">7.8</span>&gt;<span class="plain">;</span>
<span class="reserved">continue</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">cr</span><span class="plain"> == </span><span class="character">'N'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">N_escape</span><span class="plain"> &gt;= 0)) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'}'</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d"</span><span class="plain">, </span><span class="identifier">N_escape</span><span class="plain">);</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">OUT</span><span class="plain">) &amp;&amp; (</span><span class="identifier">active</span><span class="plain">)) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"{N"</span><span class="plain">);</span>
<span class="reserved">goto</span><span class="plain"> </span><span class="identifier">NewCharacter</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> { </span> <span class="comment">otherwise the open brace was a literal</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">OUT</span><span class="plain">) &amp;&amp; (</span><span class="identifier">active</span><span class="plain">)) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="character">'{'</span><span class="plain">);</span>
<span class="reserved">goto</span><span class="plain"> </span><span class="identifier">NewCharacter</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'('</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'+'</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read up to the next plus close-bracket as an I7 expression</span> <span class="cwebmacronumber">7.7</span>&gt;<span class="plain">;</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> { </span> <span class="comment">otherwise the open bracket was a literal</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">OUT</span><span class="plain">) &amp;&amp; (</span><span class="identifier">active</span><span class="plain">)) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="character">'('</span><span class="plain">);</span>
<span class="reserved">goto</span><span class="plain"> </span><span class="identifier">NewCharacter</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">OUT</span><span class="plain">) &amp;&amp; (</span><span class="identifier">active</span><span class="plain">)) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">} </span><span class="reserved">while</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> != </span><span class="identifier">EOF</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Input_File</span><span class="plain">) { </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">DL</span><span class="plain">) </span><span class="identifier">STREAM_FLUSH</span><span class="plain">(</span><span class="identifier">DL</span><span class="plain">); </span><span class="identifier">fclose</span><span class="plain">(</span><span class="identifier">Input_File</span><span class="plain">); }</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">default_command</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">heading_name</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function TemplateFiles::interpret is used in 1/mr (<a href="1-mr.html#SP4_16">&#167;4.16</a>), 26/i6i (<a href="26-i6i.html#SP7">&#167;7</a>, <a href="26-i6i.html#SP8">&#167;8</a>), 26/uo (<a href="26-uo.html#SP17">&#167;17</a>), 26/pl (<a href="26-pl.html#SP13">&#167;13</a>).</p>
<p class="inwebparagraph"><a id="SP7_1"></a><b>&#167;7.1. </b>We look for the <code class="display"><span class="extract">.i6t</span></code> files first in the materials folder, then in the
installed area and lastly (but almost always) in the built-in resources.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Open the I6 template file</span> <span class="cwebmacronumber">7.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Input_File</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">area</span><span class="plain">=0; </span><span class="identifier">area</span><span class="plain">&lt;</span><span class="constant">NO_FS_AREAS</span><span class="plain">; </span><span class="identifier">area</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Input_File</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)</span>
<span class="identifier">Input_File</span><span class="plain"> = </span><span class="identifier">Filenames::fopen</span><span class="plain">(</span>
<span class="identifier">Filenames::in_folder</span><span class="plain">(</span><span class="identifier">pathname_of_i6t_files</span><span class="plain">[</span><span class="identifier">area</span><span class="plain">], </span><span class="identifier">segment_name</span><span class="plain">), </span><span class="string">"r"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Input_File</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">STDERR</span><span class="plain">, </span><span class="string">"inform: Unable to open segment &lt;%S&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">segment_name</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::unlocated_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">), </span> <span class="comment">or anyway not usefully testable</span>
<span class="string">"I couldn't open a requested I6T segment: see the console "</span>
<span class="string">"output for details."</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_2"></a><b>&#167;7.2. </b>I6 template files are encoded as ISO Latin-1, not as Unicode UTF-8, so
ordinary <code class="display"><span class="extract">fgetc</span></code> is used, and no BOM marker is parsed. Lines are assumed
to be terminated with either <code class="display"><span class="extract">0x0a</span></code> or <code class="display"><span class="extract">0x0d</span></code>. (Since blank lines are
harmless, we take no trouble over <code class="display"><span class="extract">0a0d</span></code> or <code class="display"><span class="extract">0d0a</span></code> combinations.) The
built-in template files, almost always the only ones used, are line
terminated <code class="display"><span class="extract">0x0a</span></code> in Unix fashion.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Input_File</span><span class="plain">) </span><span class="identifier">cr</span><span class="plain"> = </span><span class="identifier">fgetc</span><span class="plain">(</span><span class="identifier">Input_File</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">sf</span><span class="plain">) {</span>
<span class="identifier">cr</span><span class="plain"> = </span><span class="identifier">sf</span><span class="plain">[</span><span class="identifier">sfp</span><span class="plain">]; </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == 0) </span><span class="identifier">cr</span><span class="plain"> = </span><span class="identifier">EOF</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">sfp</span><span class="plain">++;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">cr</span><span class="plain"> = </span><span class="identifier">EOF</span><span class="plain">;</span>
<span class="identifier">col</span><span class="plain">++; </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == 10) || (</span><span class="identifier">cr</span><span class="plain"> == 13)) </span><span class="identifier">col</span><span class="plain"> = 0;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a> (four times), <a href="#SP7_3">&#167;7.3</a>, <a href="#SP7_5">&#167;7.5</a>, <a href="#SP7_6">&#167;7.6</a>, <a href="#SP7_7">&#167;7.7</a>.</p>
<p class="inwebparagraph"><a id="SP7_3"></a><b>&#167;7.3. </b>Anything following an at-character in the first column is looked at to see if
it's a heading, that is, an Inweb syntax:
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">INWEB_PARAGRAPH_SYNTAX</span><span class="plain"> 1</span>
<span class="definitionkeyword">define</span> <span class="constant">INWEB_CODE_SYNTAX</span><span class="plain"> 2</span>
<span class="definitionkeyword">define</span> <span class="constant">INWEB_DASH_SYNTAX</span><span class="plain"> 3</span>
<span class="definitionkeyword">define</span> <span class="constant">INWEB_PURPOSE_SYNTAX</span><span class="plain"> 4</span>
</pre>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Read the rest of line as an at-heading</span> <span class="cwebmacronumber">7.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = 0, </span><span class="identifier">committed</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">unacceptable_character</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">MAX_I6T_LINE_LENGTH</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">committed</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp; ((</span><span class="identifier">cr</span><span class="plain"> == 10) || (</span><span class="identifier">cr</span><span class="plain"> == 13) || (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">' '</span><span class="plain">))) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"p"</span><span class="plain">)) </span><span class="identifier">inweb_syntax</span><span class="plain"> = </span><span class="constant">INWEB_PARAGRAPH_SYNTAX</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">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"c"</span><span class="plain">)) </span><span class="identifier">inweb_syntax</span><span class="plain"> = </span><span class="constant">INWEB_CODE_SYNTAX</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">Str::get_first_char</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">) == </span><span class="character">'-'</span><span class="plain">) </span><span class="identifier">inweb_syntax</span><span class="plain"> = </span><span class="constant">INWEB_DASH_SYNTAX</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">Str::begins_with_wide_string</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"Purpose:"</span><span class="plain">)) </span><span class="identifier">inweb_syntax</span><span class="plain"> = </span><span class="constant">INWEB_PURPOSE_SYNTAX</span><span class="plain">;</span>
<span class="identifier">committed</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">inweb_syntax</span><span class="plain"> == -1) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">unacceptable_character</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">OUT</span><span class="plain">) &amp;&amp; (</span><span class="identifier">active</span><span class="plain">)) {</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="character">'@'</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="string">"%S"</span><span class="plain">, </span><span class="identifier">I6T_buffer</span><span class="plain">);</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"heading begins: &lt;%S&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">I6T_buffer</span><span class="plain">);</span>
<span class="identifier">Problems::quote_stream</span><span class="plain">(1, </span><span class="identifier">I6T_buffer</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::unlocated_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_BadTemplateAtSign</span><span class="plain">),</span>
<span class="string">"An unknown '@...' marker has been found at column 0 in "</span>
<span class="string">"raw Inform 6 template material: specifically, '@%1'. ('@' "</span>
<span class="string">"has a special meaning in this first column, and this "</span>
<span class="string">"might clash with its use to introduce an assembly-language "</span>
<span class="string">"opcode in Inform 6: if that's a problem, you can avoid it "</span>
<span class="string">"simply by putting one or more spaces or tabs in front of "</span>
<span class="string">"the opcode(s) to keep them clear of the left margin.)"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (!(((</span><span class="identifier">cr</span><span class="plain"> &gt;= </span><span class="character">'A'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">cr</span><span class="plain"> &lt;= </span><span class="character">'Z'</span><span class="plain">)) || ((</span><span class="identifier">cr</span><span class="plain"> &gt;= </span><span class="character">'a'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">cr</span><span class="plain"> &lt;= </span><span class="character">'z'</span><span class="plain">))</span>
<span class="plain">|| ((</span><span class="identifier">cr</span><span class="plain"> &gt;= </span><span class="character">'0'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">cr</span><span class="plain"> &lt;= </span><span class="character">'9'</span><span class="plain">))</span>
<span class="plain">|| (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'-'</span><span class="plain">) || (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'&gt;'</span><span class="plain">) || (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">':'</span><span class="plain">) || (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'_'</span><span class="plain">)))</span>
<span class="identifier">unacceptable_character</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">cr</span><span class="plain"> == 10) || (</span><span class="identifier">cr</span><span class="plain"> == 13)) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">Str::copy</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">I6T_buffer</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">I6T_buffer</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_4"></a><b>&#167;7.4. </b>As can be seen, only a small minority of Inweb syntaxes are allowed:
in particular, no <code class="display"><span class="extract">@d</span></code> or angle-bracketed macros. This interpreter is not
a full-fledged tangler.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on the at-heading, going in or out of comment mode as appropriate</span> <span class="cwebmacronumber">7.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">inweb_syntax</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">INWEB_PARAGRAPH_SYNTAX</span><span class="plain">: {</span>
<span class="identifier">Str::copy_tail</span><span class="plain">(</span><span class="identifier">heading_name</span><span class="plain">, </span><span class="identifier">command</span><span class="plain">, 2);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (((</span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">Str::get_last_char</span><span class="plain">(</span><span class="identifier">heading_name</span><span class="plain">)) != 0) &amp;&amp;</span>
<span class="plain">((</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">' '</span><span class="plain">) || (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'\</span><span class="plain">t</span><span class="character">'</span><span class="plain">) || (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'.'</span><span class="plain">)))</span>
<span class="identifier">Str::delete_last_character</span><span class="plain">(</span><span class="identifier">heading_name</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">heading_name</span><span class="plain">) == 0)</span>
<span class="functiontext">TemplateFiles::error</span><span class="plain">(</span><span class="string">"Empty heading name in I6 template file"</span><span class="plain">);</span>
<span class="identifier">comment</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="identifier">skip_part</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="reserved">case</span><span class="plain"> </span><span class="constant">INWEB_CODE_SYNTAX</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">skip_part</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="identifier">comment</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">INWEB_DASH_SYNTAX</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">INWEB_PURPOSE_SYNTAX</span><span class="plain">: </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_5"></a><b>&#167;7.5. </b>Here we are in <code class="display"><span class="extract">{-lines:...}</span></code> mode, so that the entire line of the file
is to be read as an argument. Note that initial and trailing white space on
the line is deleted: this makes it easier to lay out I6T template files
tidily.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Set the command to the default, and read rest of line as argument</span> <span class="cwebmacronumber">7.5</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Str::copy</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">default_command</span><span class="plain">);</span>
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::is_space_or_tab</span><span class="plain">(</span><span class="identifier">cr</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">at_start</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">TRUE</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == 10) || (</span><span class="identifier">cr</span><span class="plain"> == 13)) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">at_start</span><span class="plain">) &amp;&amp; (</span><span class="identifier">Characters::is_space_or_tab</span><span class="plain">(</span><span class="identifier">cr</span><span class="plain">))) </span><span class="reserved">continue</span><span class="plain">;</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">); </span><span class="identifier">at_start</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">Characters::is_space_or_tab</span><span class="plain">(</span><span class="identifier">Str::get_last_char</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">)))</span>
<span class="identifier">Str::delete_last_character</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_6"></a><b>&#167;7.6. </b>And here we read a normal command. The command name must not include <code class="display"><span class="extract">}</span></code>
or <code class="display"><span class="extract">:</span></code>. If there is no <code class="display"><span class="extract">:</span></code> then the argument is left unset (so that it will
be the empty string: see above). The argument must not include <code class="display"><span class="extract">}</span></code>.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Read up to the next close brace as an I6T command and argument</span> <span class="cwebmacronumber">7.6</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">);</span>
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">com_mode</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">TRUE</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">'}'</span><span class="plain">) || (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="identifier">EOF</span><span class="plain">)) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">':'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">com_mode</span><span class="plain">)) { </span><span class="identifier">com_mode</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span><span class="reserved">continue</span><span class="plain">; }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">com_mode</span><span class="plain">) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_7"></a><b>&#167;7.7. </b>And similarly, for the <code class="display"><span class="extract">(+</span></code> ... <code class="display"><span class="extract">+)</span></code> notation used to mark I7 material
within I6:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Read up to the next plus close-bracket as an I7 expression</span> <span class="cwebmacronumber">7.7</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">i7_exp</span><span class="plain">);</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">TRUE</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Read next character from I6T stream</span> <span class="cwebmacronumber">7.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cr</span><span class="plain"> == </span><span class="identifier">EOF</span><span class="plain">) </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">cr</span><span class="plain"> == </span><span class="character">')'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">Str::get_last_char</span><span class="plain">(</span><span class="identifier">i7_exp</span><span class="plain">) == </span><span class="character">'+'</span><span class="plain">)) {</span>
<span class="identifier">Str::delete_last_character</span><span class="plain">(</span><span class="identifier">i7_exp</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">; }</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">i7_exp</span><span class="plain">, </span><span class="identifier">cr</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="functiontext">TemplateFiles::compile_I7_from_I6</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">i7_exp</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">i7_exp</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a>.</p>
<p class="inwebparagraph"><a id="SP7_8"></a><b>&#167;7.8. Acting on I6T commands. </b>Only a few commands work even in passive mode, but they include file-handling
because the close-file command needs to be able to get out of passive mode
and back into active (and besides, because the file still needs to be closed).
</p>
<p class="inwebparagraph">The <code class="display"><span class="extract">{-type:...}</span></code> command hands over the argument to a more specific
interpreter, one which constructs kinds.
</p>
<p class="inwebparagraph">The <code class="display"><span class="extract">{-segment:...}</span></code> command recursively calls the I6T interpreter on the
supplied I6T filename, which means it acts rather like <code class="display"><span class="extract">#include</span></code> in C.
Note that because we pass the current output file handle <code class="display"><span class="extract">of</span></code> through to
this new invocation, it will have the file open if we do, and closed if
we do. It will run in active mode, but that's fine, because we're in active
mode too. It won't run in indexing mode, so <code class="display"><span class="extract">{-segment:...}</span></code> can't be used
safely between <code class="display"><span class="extract">{-open-index}</span></code> and <code class="display"><span class="extract">{-close-index}</span></code>.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on I6T command and argument</span> <span class="cwebmacronumber">7.8</span>&gt; =
</code></p>
<pre class="displaydefn">
&lt;<span class="cwebmacro">Act on the I6T lines command</span> <span class="cwebmacronumber">7.8.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">active</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">continue</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"type"</span><span class="plain">)) { </span><span class="identifier">Kinds::Interpreter::despatch_kind_command</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">); </span><span class="reserved">continue</span><span class="plain">; }</span>
&lt;<span class="cwebmacro">Act on the I6T counter command</span> <span class="cwebmacronumber">7.8.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Act on an I6T indexing command</span> <span class="cwebmacronumber">7.8.2</span>&gt;<span class="plain">;</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"command: &lt;%S&gt; argument: &lt;%S&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">argument</span><span class="plain">);</span>
<span class="identifier">Problems::quote_stream</span><span class="plain">(1, </span><span class="identifier">command</span><span class="plain">);</span>
<span class="identifier">Problems::Issue::unlocated_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_TemplateError</span><span class="plain">),</span>
<span class="string">"In an explicit Inform 6 code insertion, I recognise a few special "</span>
<span class="string">"notations in the form '{-command}'. This time, though, the unknown notation "</span>
<span class="string">"{-%1} has been used, and this is an error. (It seems very unlikely indeed "</span>
<span class="string">"that this could be legal Inform 6 which I'm misreading, but if so, try "</span>
<span class="string">"adjusting the spacing to make this problem message go away.)"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a> (twice).</p>
<p class="inwebparagraph"><a id="SP7_8_1"></a><b>&#167;7.8.1. </b>There is no corresponding code here to act on <code class="display"><span class="extract">{-endlines}</span></code> because it is
not valid as a free-standing command: it can only occur at the end of a
<code class="display"><span class="extract">{-lines:...}</span></code> block, and is acted upon above.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on the I6T lines command</span> <span class="cwebmacronumber">7.8.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"lines"</span><span class="plain">)) {</span>
<span class="identifier">Str::copy</span><span class="plain">(</span><span class="identifier">default_command</span><span class="plain">, </span><span class="identifier">argument</span><span class="plain">);</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_8">&#167;7.8</a>.</p>
<p class="inwebparagraph"><a id="SP7_8_2"></a><b>&#167;7.8.2. Indexing commands. </b>Commands in between <code class="display"><span class="extract">{-open-index}</span></code> and <code class="display"><span class="extract">{-close-index}</span></code> are skipped when
Inform has been called with a command-line switch to disable the index. (As is
done by <code class="display"><span class="extract">intest</span></code>, to save time.) <code class="display"><span class="extract">{-index:name}</span></code> opens the index file
called <code class="display"><span class="extract">name</span></code>.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on an I6T indexing command</span> <span class="cwebmacronumber">7.8.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"open-index"</span><span class="plain">)) { </span><span class="identifier">indexing</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">continue</span><span class="plain">; }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"close-index"</span><span class="plain">)) { </span><span class="identifier">indexing</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span><span class="reserved">continue</span><span class="plain">; }</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">indexing</span><span class="plain">) &amp;&amp; (</span><span class="identifier">do_not_generate_index</span><span class="plain">)) </span><span class="reserved">continue</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"index-complete"</span><span class="plain">)) { </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">indexing</span><span class="plain">) </span><span class="identifier">Index::complete</span><span class="plain">(); </span><span class="reserved">continue</span><span class="plain">; }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"index-page"</span><span class="plain">)) {</span>
<span class="identifier">match_results</span><span class="plain"> </span><span class="identifier">mr</span><span class="plain"> = </span><span class="identifier">Regexp::create_mr</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Regexp::match</span><span class="plain">(&amp;</span><span class="identifier">mr</span><span class="plain">, </span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"(%c+?)=(%c+?)=(%c+)"</span><span class="plain">)) {</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">col</span><span class="plain"> = </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[0];</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">titling</span><span class="plain"> = </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[1];</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">explanation</span><span class="plain"> = </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[2];</span>
<span class="identifier">match_results</span><span class="plain"> </span><span class="identifier">mr2</span><span class="plain"> = </span><span class="identifier">Regexp::create_mr</span><span class="plain">();</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">leafname</span><span class="plain"> = </span><span class="identifier">titling</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Regexp::match</span><span class="plain">(&amp;</span><span class="identifier">mr2</span><span class="plain">, </span><span class="identifier">titling</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"(%C+?) (%c+)"</span><span class="plain">)) </span><span class="identifier">leafname</span><span class="plain"> = </span><span class="identifier">mr2</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[0];</span>
<span class="identifier">Index::new_page</span><span class="plain">(</span><span class="identifier">col</span><span class="plain">, </span><span class="identifier">titling</span><span class="plain">, </span><span class="identifier">explanation</span><span class="plain">, </span><span class="identifier">leafname</span><span class="plain">);</span>
<span class="identifier">Regexp::dispose_of</span><span class="plain">(&amp;</span><span class="identifier">mr2</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"bad index-page format"</span><span class="plain">);</span>
<span class="identifier">Regexp::dispose_of</span><span class="plain">(&amp;</span><span class="identifier">mr</span><span class="plain">);</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"index-element"</span><span class="plain">)) {</span>
<span class="identifier">match_results</span><span class="plain"> </span><span class="identifier">mr</span><span class="plain"> = </span><span class="identifier">Regexp::create_mr</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Regexp::match</span><span class="plain">(&amp;</span><span class="identifier">mr</span><span class="plain">, </span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"(%C+) (%c+?)=(%c+)"</span><span class="plain">))</span>
<span class="identifier">Index::new_segment</span><span class="plain">(</span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[0], </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[1], </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[2]);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"bad index-element format"</span><span class="plain">);</span>
<span class="identifier">Regexp::dispose_of</span><span class="plain">(&amp;</span><span class="identifier">mr</span><span class="plain">);</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"index"</span><span class="plain">)) {</span>
<span class="identifier">match_results</span><span class="plain"> </span><span class="identifier">mr</span><span class="plain"> = </span><span class="identifier">Regexp::create_mr</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Regexp::match</span><span class="plain">(&amp;</span><span class="identifier">mr</span><span class="plain">, </span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"(%c+?)=(%c+)"</span><span class="plain">)) {</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">titling</span><span class="plain"> = </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[0];</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">explanation</span><span class="plain"> = </span><span class="identifier">mr</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[1];</span>
<span class="identifier">match_results</span><span class="plain"> </span><span class="identifier">mr2</span><span class="plain"> = </span><span class="identifier">Regexp::create_mr</span><span class="plain">();</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">);</span>
<span class="identifier">Str::copy</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">, </span><span class="identifier">titling</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Regexp::match</span><span class="plain">(&amp;</span><span class="identifier">mr2</span><span class="plain">, </span><span class="identifier">leafname</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"(%C+?) (%c+)"</span><span class="plain">)) </span><span class="identifier">Str::copy</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">, </span><span class="identifier">mr2</span><span class="plain">.</span><span class="identifier">exp</span><span class="plain">[0]);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">, </span><span class="string">".html"</span><span class="plain">);</span>
<span class="identifier">Index::open_file</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">, </span><span class="identifier">titling</span><span class="plain">, -1, </span><span class="identifier">explanation</span><span class="plain">);</span>
<span class="identifier">Regexp::dispose_of</span><span class="plain">(&amp;</span><span class="identifier">mr2</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"bad index format"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">Regexp::dispose_of</span><span class="plain">(&amp;</span><span class="identifier">mr</span><span class="plain">);</span>
<span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_8">&#167;7.8</a>.</p>
<p class="inwebparagraph"><a id="SP7_8_3"></a><b>&#167;7.8.3. Commands accessing Inform internals. </b>The following expands to the number of labels produced for a given label namespace.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Act on the I6T counter command</span> <span class="cwebmacronumber">7.8.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">command</span><span class="plain">, </span><span class="identifier">L</span><span class="string">"counter"</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">OUT</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">continue</span><span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d"</span><span class="plain">, </span><span class="functiontext">JumpLabels::read_counter</span><span class="plain">(</span><span class="identifier">argument</span><span class="plain">, </span><span class="identifier">NOT_APPLICABLE</span><span class="plain">)); </span><span class="reserved">continue</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7_8">&#167;7.8</a>.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. Template errors. </b>Errors here used to be basically failed assertions, but inevitably people
reported this as a bug (0001596). It was never intended that I6T coding
be part of the outside-facing language, but for a handful of people
using template-hacking there are a handful of cases that can't be avoided, so...
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">TemplateFiles::error</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">message</span><span class="plain">) {</span>
<span class="identifier">Problems::quote_text</span><span class="plain">(1, </span><span class="identifier">message</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">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"I ran into a mistake in a template file command: %1. The I6 "</span>
<span class="string">"template files (or .i6t files) are a very low-level part of Inform, "</span>
<span class="string">"and errors like this will only occur if the standard installation "</span>
<span class="string">"has been amended or damaged. One possibility is that you're using "</span>
<span class="string">"an extension which does some 'template hacking', as it's called, "</span>
<span class="string">"but made a mistake doing so."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function TemplateFiles::error is used in <a href="#SP7_4">&#167;7.4</a>.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. I7 expression evaluation. </b>This is not quite like regular expression evaluation, because we want
"room" and "lighted" to be evaluated as the I6 translation of the
relevant class or property, rather than as code to test the predicate
"X is a room" or "X is lighted", and similarly for bare names
of defined adjectives. So:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">TemplateFiles::compile_I7_from_I6</span><span class="plain">(</span><span class="identifier">value_holster</span><span class="plain"> *</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">VH</span><span class="plain">) &amp;&amp; (</span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_wanted</span><span class="plain"> == </span><span class="identifier">INTER_VOID_VHMODE</span><span class="plain">)) {</span>
<span class="identifier">Produce::evaluation</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="functiontext">TemplateFiles::compile_I7_from_I6_inner</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">VH</span><span class="plain">) &amp;&amp; (</span><span class="identifier">VH</span><span class="plain">-&gt;</span><span class="identifier">vhmode_wanted</span><span class="plain"> == </span><span class="identifier">INTER_VOID_VHMODE</span><span class="plain">)) {</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">TemplateFiles::compile_I7_from_I6_inner</span><span class="plain">(</span><span class="identifier">value_holster</span><span class="plain"> *</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">text_stream</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">LW</span><span class="plain"> = </span><span class="identifier">Feeds::feed_stream</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="reserved">property</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">&gt;(</span><span class="identifier">LW</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VH</span><span class="plain">)</span>
<span class="identifier">Produce::val_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Properties::iname</span><span class="plain">(&lt;&lt;</span><span class="identifier">rp</span><span class="plain">&gt;&gt;));</span>
<span class="reserved">else</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="string">"%n"</span><span class="plain">, </span><span class="functiontext">Properties::iname</span><span class="plain">(&lt;&lt;</span><span class="identifier">rp</span><span class="plain">&gt;&gt;));</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">k</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">&gt;(</span><span class="identifier">LW</span><span class="plain">)) {</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = &lt;&lt;</span><span class="identifier">rp</span><span class="plain">&gt;&gt;;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::lt</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">K_object</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VH</span><span class="plain">)</span>
<span class="identifier">Produce::val_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Kinds::RunTime::I6_classname</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">));</span>
<span class="reserved">else</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="string">"%n"</span><span class="plain">, </span><span class="functiontext">Kinds::RunTime::I6_classname</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">));</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">instance</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain"> = </span><span class="functiontext">Instances::parse_object</span><span class="plain">(</span><span class="identifier">LW</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">I</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VH</span><span class="plain">)</span>
<span class="identifier">Produce::val_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="functiontext">Instances::iname</span><span class="plain">(&lt;&lt;</span><span class="identifier">rp</span><span class="plain">&gt;&gt;));</span>
<span class="reserved">else</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="string">"%~I"</span><span class="plain">, </span><span class="identifier">I</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">adjectival_phrase</span><span class="plain"> *</span><span class="identifier">aph</span><span class="plain"> = </span><span class="identifier">Adjectives::parse</span><span class="plain">(</span><span class="identifier">LW</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">aph</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Adjectives::Meanings::write_adjective_test_routine</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">aph</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="identifier">Problems::Issue::unlocated_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">),</span>
<span class="string">"You tried to use '(+' and '+)' to expand to the Inform 6 routine "</span>
<span class="string">"address of an adjective, but it was an adjective with no meaning."</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">initial_problem_count</span><span class="plain"> = </span><span class="identifier">problem_count</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">s</span><span class="plain">-</span><span class="identifier">value</span><span class="plain">&gt;(</span><span class="identifier">LW</span><span class="plain">)) </span><span class="identifier">spec</span><span class="plain"> = &lt;&lt;</span><span class="identifier">rp</span><span class="plain">&gt;&gt;;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain"> = </span><span class="functiontext">Specifications::new_UNKNOWN</span><span class="plain">(</span><span class="identifier">LW</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">ifndef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, 0);</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">initial_problem_count</span><span class="plain"> &lt; </span><span class="identifier">problem_count</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="functiontext">Dash::check_value</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">initial_problem_count</span><span class="plain"> &lt; </span><span class="identifier">problem_count</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="constant">BEGIN_COMPILATION_MODE</span><span class="plain">;</span>
<span class="identifier">COMPILATION_MODE_EXIT</span><span class="plain">(</span><span class="constant">DEREFERENCE_POINTERS_CMODE</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">VH</span><span class="plain">)</span>
<span class="functiontext">Specifications::Compiler::emit_as_val</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">spec</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain"> = </span><span class="functiontext">NonlocalVariables::parse</span><span class="plain">(</span><span class="identifier">LW</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">nlv</span><span class="plain">) {</span>
<span class="identifier">PUT</span><span class="plain">(</span><span class="identifier">URL_SYMBOL_CHAR</span><span class="plain">);</span>
<span class="identifier">Inter::SymbolsTables::symbol_to_url_name</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">InterNames::to_symbol</span><span class="plain">(</span><span class="functiontext">NonlocalVariables::iname</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">)));</span>
<span class="identifier">PUT</span><span class="plain">(</span><span class="identifier">URL_SYMBOL_CHAR</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">value_holster</span><span class="plain"> </span><span class="identifier">VH2</span><span class="plain"> = </span><span class="identifier">Holsters::new</span><span class="plain">(</span><span class="identifier">INTER_DATA_VHMODE</span><span class="plain">);</span>
<span class="functiontext">Specifications::Compiler::compile_inner</span><span class="plain">(&amp;</span><span class="identifier">VH2</span><span class="plain">, </span><span class="identifier">spec</span><span class="plain">);</span>
<span class="identifier">inter_t</span><span class="plain"> </span><span class="identifier">v1</span><span class="plain"> = 0, </span><span class="identifier">v2</span><span class="plain"> = 0;</span>
<span class="identifier">Holsters::unholster_pair</span><span class="plain">(&amp;</span><span class="identifier">VH2</span><span class="plain">, &amp;</span><span class="identifier">v1</span><span class="plain">, &amp;</span><span class="identifier">v2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">v1</span><span class="plain"> == </span><span class="identifier">ALIAS_IVAL</span><span class="plain">) {</span>
<span class="identifier">PUT</span><span class="plain">(</span><span class="identifier">URL_SYMBOL_CHAR</span><span class="plain">);</span>
<span class="identifier">inter_symbols_table</span><span class="plain"> *</span><span class="identifier">T</span><span class="plain"> = </span><span class="identifier">Inter::Packages::scope</span><span class="plain">(</span><span class="functiontext">Emit::current_enclosure</span><span class="plain">()-&gt;</span><span class="identifier">actual_package</span><span class="plain">);</span>
<span class="identifier">inter_symbol</span><span class="plain"> *</span><span class="identifier">S</span><span class="plain"> = </span><span class="identifier">Inter::SymbolsTables::symbol_from_id</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">, </span><span class="identifier">v2</span><span class="plain">);</span>
<span class="identifier">Inter::SymbolsTables::symbol_to_url_name</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">S</span><span class="plain">);</span>
<span class="identifier">PUT</span><span class="plain">(</span><span class="identifier">URL_SYMBOL_CHAR</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">CodeGen::FC::val_from</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">Packaging::at</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">()), </span><span class="identifier">v1</span><span class="plain">, </span><span class="identifier">v2</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="constant">END_COMPILATION_MODE</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function TemplateFiles::compile_I7_from_I6 is used in <a href="#SP7_7">&#167;7.7</a>, 25/cii (<a href="25-cii.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function TemplateFiles::compile_I7_from_I6_inner appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. The build constant. </b>That was the end of the template interpreter. Now, since this version-numbering
constant belongs nowhere else, we provide a single I6T command in this section
of Inform: the following routine performs <code class="display"><span class="extract">{-callv:TemplateFiles::compile_build_number}</span></code>.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">TemplateFiles::compile_build_number</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">build</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">build</span><span class="plain">, </span><span class="string">"%B"</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">NI_BUILD_COUNT_HL</span><span class="plain">);</span>
<span class="functiontext">Emit::named_string_constant</span><span class="plain">(</span><span class="identifier">iname</span><span class="plain">, </span><span class="identifier">build</span><span class="plain">);</span>
<span class="functiontext">Hierarchy::make_available</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">build</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function TemplateFiles::compile_build_number is used in 1/mr (<a href="1-mr.html#SP4_14">&#167;4.14</a>).</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Registration of sentence handlers. </b>The following routine is placed here, right at the end of the Inform code,
because at this point all of the sentence handlers &mdash; with names like
<code class="display"><span class="extract">TABLE_SH_handler</span></code> &mdash; have now been created.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">TemplateFiles::register_sentence_handlers</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Add sentence handlers for the top-level node types</span> <span class="cwebmacronumber">11.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Add sentence handlers for the SENTENCE/VERB node types</span> <span class="cwebmacronumber">11.2</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function TemplateFiles::register_sentence_handlers is used in 9/tfa (<a href="9-tfa.html#SP7_3">&#167;7.3</a>).</p>
<p class="inwebparagraph"><a id="SP11_1"></a><b>&#167;11.1. </b>This is all of the node types still present at the top level of the tree
at the end of sentence-breaking.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Add sentence handlers for the top-level node types</span> <span class="cwebmacronumber">11.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">TRACE_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">BEGINHERE_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">ENDHERE_SH</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">BIBLIOGRAPHIC_SH</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">INFORM6CODE_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">COMMAND_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">ROUTINE_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">TABLE_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">EQUATION_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">HEADING_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">SENTENCE_SH</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP11">&#167;11</a>.</p>
<p class="inwebparagraph"><a id="SP11_2"></a><b>&#167;11.2. </b>And here are all of the verb types found in <code class="display"><span class="extract">AVERB_NT</span></code> nodes which are
first children of <code class="display"><span class="extract">SENTENCE_NT</span></code> nodes.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Add sentence handlers for the SENTENCE/VERB node types</span> <span class="cwebmacronumber">11.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">ASSERT_SH</span><span class="plain">);</span>
<span class="identifier">REGISTER_SENTENCE_HANDLER</span><span class="plain">(</span><span class="identifier">SPECIAL_MEANING_SH</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP11">&#167;11</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="26-tti.html">Back to 'Translate to Identifiers'</a></li><li><a href="26-pl.html">Continue with 'Plugins'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>