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/7-hdn.html
2019-08-24 11:21:48 +01:00

1765 lines
190 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>7/ss</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 '7/hdn' 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#7">Chapter 7: Sentences</a></li><li><b>Headings</b></li></ul><p class="purpose">To keep track of the hierarchy of headings and subheadings found in the source text.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP9">&#167;9. Declarations</a></li><li><a href="#SP10_2">&#167;10.2. Parsing heading qualifiers</a></li><li><a href="#SP12">&#167;12. The heading tree</a></li><li><a href="#SP14">&#167;14. Verifying the heading tree</a></li><li><a href="#SP15">&#167;15. Miscellaneous heading services</a></li><li><a href="#SP19">&#167;19. Headings with extension dependencies</a></li><li><a href="#SP22">&#167;22. World objects under each heading</a></li><li><a href="#SP24">&#167;24. The noun search list</a></li><li><a href="#SP30">&#167;30. Handling headings during the main traverses</a></li><li><a href="#SP31">&#167;31. Describing the heading structure, 1: to the debugging log</a></li><li><a href="#SP33">&#167;33. Describing the heading structure, 2: to the index</a></li><li><a href="#SP34">&#167;34. Describing the heading structure, 3: to a freestanding XML file</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>To take up the narrative of how Inform runs once more, we have read the
source text in from the primary source file and from the extensions it
requested: nothing more will be supplied from disc, and the whole combined
text is arranged as a string of sentence nodes, each direct children of the
root. In this section, we are concerned with HEADING nodes.
</p>
<p class="inwebparagraph">Most of these occur when the user has explicitly typed a heading such as:
</p>
<blockquote>
<p>Part VII - The Ghost of the Aragon</p>
</blockquote>
<p class="inwebparagraph">The sentence-breaker called <code class="display"><span class="extract">Sentences::Headings::declare</span></code> each time it found one of
these, but also when a new source file started, because a file boundary is
construed as beginning with a hidden "heading" of a higher rank than any
other, and the sentence-breaker made a corresponding HEADING node there
too. This is important because the doctrine is that each heading starts
afresh with a new hierarchy of lower-order headings: thus changing the Part
means we can start again with Chapter 1 if we like, and so on. Because each
source file starts with an implicit super-heading, each source file gets
its own independent hierarchy of Volume, and so on. But the convention is
also important because we need to be able to say that every word loaded
from disc ultimately falls under some heading, even if the source text as
typed by the designer does not obviously have any headings in it.
</p>
<p class="inwebparagraph">The hierarchy thus runs: File (0), Volume (1), Book (2), Part (3),
Chapter (4), Section (5). (The implementation below allows for even lower
levels of subheading, from 6 to 9, but Inform doesn't use them.) Every run
of Inform declares at least two File (0) headings, representing the start of
main text and the start of the Standard Rules, and these latter have a
couple of dozen headings themselves, so the typical number of headings
in a source text is 30 to 100.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">NO_HEADING_LEVELS</span><span class="plain"> 10</span>
</pre>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>Although it is implicit in the parse tree already, the heading structure
is not easy to deduce, and so in this section we build a much smaller tree
consisting just of the hierarchy of headings. The heading tree has nodes
made from the following structures:
</p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">heading</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">sentence_declaring</span><span class="plain">; </span> <span class="comment">if any: file starts are undeclared</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">source_location</span><span class="plain"> </span><span class="identifier">start_location</span><span class="plain">; </span> <span class="comment">first word under this heading is here</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">level</span><span class="plain">; </span> <span class="comment">0 for Volume (highest) to 5 for Section (lowest)</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">indentation</span><span class="plain">; </span> <span class="comment">in a hierarchical listing</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">index_definitions_made_under_this</span><span class="plain">; </span> <span class="comment">for instance, global variables made here?</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">for_release</span><span class="plain">; </span> <span class="comment">include this material in a release version?</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">omit_material</span><span class="plain">; </span> <span class="comment">if set, simply ignore all of this</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">use_with_or_without</span><span class="plain">; </span> <span class="comment">if TRUE, use with the extension; if FALSE, without</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">extension_identifier</span><span class="plain"> </span><span class="identifier">for_use_with</span><span class="plain">; </span> <span class="comment">e.g. "for use with ... by ..."</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">in_place_of_text</span><span class="plain">; </span> <span class="comment">e.g. "in place of ... in ... by ..."</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">heading_text</span><span class="plain">; </span> <span class="comment">once provisos have been stripped away</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">list_of_contents</span><span class="plain">; </span> <span class="comment">tagged names defined under this</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">last_in_list_of_contents</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">parent_heading</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">child_heading</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">next_heading</span><span class="plain">;</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">heading</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure heading is accessed in 27/cm and here.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>The headings and subheadings are formed into a tree in which each heading
contains its lesser-order headings. The pseudo-heading exists to be the root
of this tree; the entire text falls under it. It is not a real heading at all,
and has no "level" or "indentation" as such.
</p>
<pre class="display">
<span class="reserved">heading</span><span class="plain"> </span><span class="identifier">pseudo_heading</span><span class="plain">; </span> <span class="comment">The entire source falls under this top-level heading</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>As an example, a sequence in the primary source text of (Chapter I, Book
Two, Section 5, Chapter I, Section 1, Chapter III) would be formed up into
the heading tree:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">(the pseudo-heading) level -1, indentation -1</span>
<span class="plain"> (File: Standard Rules) level 0, indentation 0</span>
<span class="plain"> ...</span>
<span class="plain"> (File: primary source text) level 0, indentation 0</span>
<span class="plain"> Chapter I level 4, indentation 1</span>
<span class="plain"> Book Two level 2, indentation 1</span>
<span class="plain"> Section 5 level 5, indentation 2</span>
<span class="plain"> Chapter I level 4, indentation 2</span>
<span class="plain"> Section 1 level 5, indentation 3</span>
<span class="plain"> Chapter III level 4, indentation 2</span>
</pre>
<p class="inwebparagraph">Note that the level of a heading is not the same thing as its depth in this
tree, which we call the "indentation", and there is no simple relationship
between the two numbers. Clearly we want to start at the left margin. If a
new heading is subordinate to its predecessor (i.e., has higher level),
we want to indent further, but by the least amount needed &mdash; a single tap step.
Adjacent equal-level headings are on a par with each other and should have
the same indentation. But when the new heading is lower level than its
predecessor (i.e., more important) then the indentation decreases to
match the last one equally important.
</p>
<p class="inwebparagraph">We can secure the last of those properties with a formal definition as
follows. The level l_n of a heading depends only on its wording (or
source file origin), but the indentation of the nth heading, i_n,
depends on (l_1, l_2, ..., l_n), the sequence of all levels so
far:
i_n = i_m + 1 where m = max { j | 0&lt;= j &lt; n, l_j &lt; l_n }
where l_0 = i_0 = -1, so that this set always contains 0 and is
therefore not empty. We deduce that
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) i_1 = 0 and thereafter i_n &gt;= 0, since l_n is never negative again,
</li></ul>
<ul class="items"><li>(b) if l_k = l_{k+1} then i_k = i_{k+1}, since the set over which
the maximum is taken is the same,
</li></ul>
<ul class="items"><li>(c) if l_{k+1} &gt; l_k, a subheading of its predecessor, then
i_{k+1} = i_k + 1, a single tab step outward.
</li></ul>
<p class="inwebparagraph">That establishes the other properties we wanted, and shows that i_n is
indeed the number of tab steps we should be determining.
</p>
<p class="inwebparagraph">Note that to calculate i_n we do not need the whole of (l_1, ..., l_n):
we only need to remember the values of
i_{m(K)}, where m(K) = max { j | 0&lt;= j &lt; n, l_j &lt; K }
for each possible heading level K=0, 1, ..., 9. This requires much less
storage: we call it the "last indentation above level K".
</p>
<p class="inwebparagraph">This leads to the following algorithm when looking at the headings in any
individual file of source text: at the top of file,
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">for (i=0; i&lt;NO_HEADING_LEVELS; i++) last_indentation_above_level[i] = -1;</span>
</pre>
<p class="inwebparagraph">Then parse for headings (they have an easily recognised lexical form); each
time one is found, work out its <code class="display"><span class="extract">level</span></code> as 1, ..., 5 for Volume down to Section,
and call:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">int find_indentation(int level) {</span>
<span class="plain"> int i, ind = last_indentation_above_level[level] + 1;</span>
<span class="plain"> for (i=level+1; i&lt;NO_HEADING_LEVELS; i++)</span>
<span class="plain"> last_indentation_above_level[i] = ind;</span>
<span class="plain"> return ind;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph">While this algorithm is trivially equivalent to finding the depth of a
heading in the tree which we are going to build anyway, it is worth noting
here for the benefit of anyone writing a tool to (let's say) typeset an
Inform source text with a table of contents, or provide a navigation
gadget in the user interface.
</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>The primary source text, and indeed the source text in the extensions,
can make whatever headings they like: no sequence is illegal. It is not
for Inform to decide on behalf of the author that it is eccentric to place
Section C before Section B, for instance. The author might be doing so
deliberately, to put the Chariot-race before the Baths, say; and the
indexing means that it will be very apparent to the author what the heading
structure currently is, so mistakes are unlikely to last long. This is a
classic case where Inform trying to be too clever would annoy more often
than assist.
</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b></p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">name_resolution_data</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">heading_count</span><span class="plain">; </span> <span class="comment">used when tallying up objects under their headings</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">next_under_heading</span><span class="plain">; </span> <span class="comment">next in the list under that</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">search_score</span><span class="plain">; </span> <span class="comment">used when searching nametags to parse names</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">next_to_search</span><span class="plain">; </span> <span class="comment">similarly</span>
<span class="plain">} </span><span class="reserved">name_resolution_data</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure name_resolution_data is private to this section.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b></p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">contents_entry</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">heading_entered</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">contents_entry</span><span class="plain"> *</span><span class="identifier">next</span><span class="plain">;</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">contents_entry</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure contents_entry is accessed in 3/pd, 5/lp, 5/ut, 5/un, 5/ins, 6/rlt, 6/nv, 7/ss, 7/ns, 7/oaf, 7/rs, 8/ie, 8/ec, 8/ed, 9/tfa, 9/tbath, 9/rpt, 9/tc, 9/ma, 9/rk, 9/ass, 9/imp, 9/pd, 10/teav, 10/cap, 11/ap, 11/pr, 11/bas, 11/tc, 11/sm, 12/dtd, 12/cdp, 14/rv, 14/lv, 14/cn, 14/ds, 14/ds2, 15/cp, 16/is, 16/in, 19/tb, 19/rsft, 19/tod, 20/eq, 21/rl, 21/rl2, 21/fao, 21/rps, 21/sv, 21/ac, 22/ph, 22/tp, 22/tp2, 23/ad, 24/lv, 24/sf, 25/in, 25/pi, 25/cii, 25/cp, 26/uo, 26/tti, 26/pc, 26/ts, 27/cm and here.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. Declarations. </b>The heading tree is constructed all at once, after most of the sentence-breaking
is done, but since a few sentences can in principle be added later, we watch
for the remote chance of further headings being added, by keeping the following
flag:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">heading_tree_made_at_least_once</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>Now, then, the routine <code class="display"><span class="extract">Sentences::Headings::declare</span></code> is called by the sentence-breaker
each time it constructs a new HEADING node. (Note that it is not called to
create the pseudo-heading, which does not come from a node.)
</p>
<p class="inwebparagraph">A level 0 heading has text (the first sentence which happens to be in the
new source file), but this has no significance other than its location,
and cannot contain information about releasing or about virtual machines.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">last_indentation_above_level</span><span class="plain">[</span><span class="constant">NO_HEADING_LEVELS</span><span class="plain">], </span><span class="identifier">lial_made</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">extension_identifier</span><span class="plain"> *</span><span class="identifier">grammar_eid</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::declare</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain">);</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;list_of_contents</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;last_in_list_of_contents</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_release</span><span class="plain"> = </span><span class="identifier">NOT_APPLICABLE</span><span class="plain">; </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;omit_material</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;index_definitions_made_under_this</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</span><span class="plain"> = </span><span class="identifier">NOT_APPLICABLE</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">PN</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">Wordings::empty</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">))))</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"heading at textless node"</span><span class="plain">);</span>
<span class="identifier">internal_error_if_node_type_wrong</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">, </span><span class="identifier">HEADING_NT</span><span class="plain">);</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain"> = </span><span class="identifier">PN</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain"> = </span><span class="identifier">Wordings::location</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">));</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> = </span><span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">, </span><span class="identifier">heading_level_ANNOT</span><span class="plain">);</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt; 0) </span>&lt;<span class="cwebmacro">Parse heading text for release or other stipulations</span> <span class="cwebmacronumber">10.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &lt; 0) || (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt;= </span><span class="constant">NO_HEADING_LEVELS</span><span class="plain">)) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"impossible level"</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Determine the indentation from the level</span> <span class="cwebmacronumber">10.1</span>&gt;<span class="plain">;</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">HEADINGS</span><span class="plain">, </span><span class="string">"Created heading $H\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">heading_tree_made_at_least_once</span><span class="plain">) </span><span class="functiontext">Sentences::Headings::make_tree</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">h</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::declare is used in 7/ss (<a href="7-ss.html#SP3">&#167;3</a>, <a href="7-ss.html#SP8">&#167;8</a>).</p>
<p class="inwebparagraph"><a id="SP10_1"></a><b>&#167;10.1. </b>This implements the indentation algorithm described above.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Determine the indentation from the level</span> <span class="cwebmacronumber">10.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</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">lial_made</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">NO_HEADING_LEVELS</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">last_indentation_above_level</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = -1;</span>
<span class="identifier">lial_made</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain"> = </span><span class="identifier">last_indentation_above_level</span><span class="plain">[</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">] + 1;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">+1; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">NO_HEADING_LEVELS</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="identifier">last_indentation_above_level</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP10">&#167;10</a>.</p>
<p class="inwebparagraph"><a id="SP10_2"></a><b>&#167;10.2. Parsing heading qualifiers. </b></p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">PLATFORM_UNMET_HQ</span><span class="plain"> 0</span>
<span class="definitionkeyword">define</span> <span class="constant">PLATFORM_MET_HQ</span><span class="plain"> 1</span>
<span class="definitionkeyword">define</span> <span class="constant">NOT_FOR_RELEASE_HQ</span><span class="plain"> 2</span>
<span class="definitionkeyword">define</span> <span class="constant">FOR_RELEASE_ONLY_HQ</span><span class="plain"> 3</span>
<span class="definitionkeyword">define</span> <span class="constant">UNINDEXED_HQ</span><span class="plain"> 4</span>
<span class="definitionkeyword">define</span> <span class="constant">USE_WITH_HQ</span><span class="plain"> 5</span>
<span class="definitionkeyword">define</span> <span class="constant">USE_WITHOUT_HQ</span><span class="plain"> 6</span>
<span class="definitionkeyword">define</span> <span class="constant">IN_PLACE_OF_HQ</span><span class="plain"> 7</span>
</pre>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Parse heading text for release or other stipulations</span> <span class="cwebmacronumber">10.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">grammar_eid</span><span class="plain"> = &amp;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">);</span>
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">PN</span><span class="plain">;</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">PN</span><span class="plain">);</span>
<span class="reserved">while</span><span class="plain"> (&lt;</span><span class="reserved">heading</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt;(</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="reserved">switch</span><span class="plain"> (&lt;&lt;</span><span class="identifier">r</span><span class="plain">&gt;&gt;) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PLATFORM_UNMET_HQ</span><span class="plain">: </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;omit_material</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">NOT_FOR_RELEASE_HQ</span><span class="plain">: </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_release</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">FOR_RELEASE_ONLY_HQ</span><span class="plain">: </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_release</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">UNINDEXED_HQ</span><span class="plain">: </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;index_definitions_made_under_this</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">USE_WITH_HQ</span><span class="plain">: </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">USE_WITHOUT_HQ</span><span class="plain">: </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</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">IN_PLACE_OF_HQ</span><span class="plain">:</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt;, 1);</span>
<span class="functiontext">CoreMain::disable_importation</span><span class="plain">();</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">W</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="reserved">heading</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt;, 1);</span>
<span class="plain">}</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain"> = </span><span class="identifier">W</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP10">&#167;10</a>.</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b>When a heading has been found, we repeatedly try to match it against
&lt;heading-qualifier&gt; to see if it ends with text telling us what to do with
the source text it governs. For example,
</p>
<blockquote>
<p>Section 21 - Frogs (unindexed) (not for Glulx)</p>
</blockquote>
<p class="inwebparagraph">would match twice, first registering the VM requirement, then the unindexedness.
</p>
<p class="inwebparagraph">It's an unfortunate historical quirk that the unbracketed qualifiers are
allowed; they should probably be withdrawn.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="reserved">heading</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; ::=</span>
<span class="plain">... ( &lt;</span><span class="identifier">bracketed</span><span class="plain">-</span><span class="reserved">heading</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; ) | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="plain">... </span><span class="identifier">not</span><span class="plain"> </span><span class="reserved">for</span><span class="plain"> </span><span class="identifier">release</span><span class="plain"> | ==&gt; </span><span class="constant">NOT_FOR_RELEASE_HQ</span>
<span class="plain">... </span><span class="reserved">for</span><span class="plain"> </span><span class="identifier">release</span><span class="plain"> </span><span class="identifier">only</span><span class="plain"> | ==&gt; </span><span class="constant">FOR_RELEASE_ONLY_HQ</span>
<span class="plain">... </span><span class="identifier">unindexed</span><span class="plain"> ==&gt; </span><span class="constant">UNINDEXED_HQ</span>
<span class="plain">&lt;</span><span class="identifier">bracketed</span><span class="plain">-</span><span class="reserved">heading</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; ::=</span>
<span class="identifier">not</span><span class="plain"> </span><span class="reserved">for</span><span class="plain"> </span><span class="identifier">release</span><span class="plain"> | ==&gt; </span><span class="constant">NOT_FOR_RELEASE_HQ</span>
<span class="reserved">for</span><span class="plain"> </span><span class="identifier">release</span><span class="plain"> </span><span class="identifier">only</span><span class="plain"> | ==&gt; </span><span class="constant">FOR_RELEASE_ONLY_HQ</span>
<span class="identifier">unindexed</span><span class="plain"> | ==&gt; </span><span class="constant">UNINDEXED_HQ</span>
<span class="plain">&lt;</span><span class="identifier">platform</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">platform</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; ::=</span>
<span class="reserved">for</span><span class="plain"> &lt;</span><span class="identifier">platform</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; </span><span class="identifier">only</span><span class="plain"> | ==&gt; (</span><span class="identifier">R</span><span class="plain">[1])?</span><span class="constant">PLATFORM_MET_HQ</span><span class="plain">:</span><span class="constant">PLATFORM_UNMET_HQ</span>
<span class="identifier">not</span><span class="plain"> </span><span class="reserved">for</span><span class="plain"> &lt;</span><span class="identifier">platform</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; ==&gt; (</span><span class="identifier">R</span><span class="plain">[1])?</span><span class="constant">PLATFORM_UNMET_HQ</span><span class="plain">:</span><span class="constant">PLATFORM_MET_HQ</span>
<span class="plain">&lt;</span><span class="identifier">platform</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">language</span><span class="plain">-</span><span class="identifier">element</span><span class="plain">&gt; </span><span class="identifier">language</span><span class="plain"> </span><span class="identifier">element</span><span class="plain"> | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="plain">...... </span><span class="identifier">language</span><span class="plain"> </span><span class="identifier">element</span><span class="plain"> | ==&gt; </span>&lt;<span class="cwebmacro">Issue PM_UnknownLanguageElement problem</span> <span class="cwebmacronumber">11.1</span>&gt;
<span class="plain">&lt;</span><span class="identifier">virtual</span><span class="plain">-</span><span class="identifier">machine</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">R</span><span class="plain">[1]</span>
<span class="plain">...... ==&gt; </span>&lt;<span class="cwebmacro">Issue PM_UnknownVirtualMachine problem</span> <span class="cwebmacronumber">11.2</span>&gt;
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">qualifier</span><span class="plain">&gt; ::=</span>
<span class="reserved">for</span><span class="plain"> </span><span class="identifier">use</span><span class="plain"> </span><span class="identifier">with</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; | ==&gt; </span><span class="constant">USE_WITH_HQ</span>
<span class="reserved">for</span><span class="plain"> </span><span class="identifier">use</span><span class="plain"> </span><span class="identifier">without</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; | ==&gt; </span><span class="constant">USE_WITHOUT_HQ</span>
<span class="identifier">not</span><span class="plain"> </span><span class="reserved">for</span><span class="plain"> </span><span class="identifier">use</span><span class="plain"> </span><span class="identifier">with</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; | ==&gt; </span><span class="constant">USE_WITHOUT_HQ</span>
<span class="identifier">in</span><span class="plain"> </span><span class="identifier">place</span><span class="plain"> </span><span class="identifier">of</span><span class="plain"> (&lt;</span><span class="identifier">quoted</span><span class="plain">-</span><span class="identifier">text</span><span class="plain">&gt;) </span><span class="identifier">in</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; | ==&gt; </span><span class="constant">IN_PLACE_OF_HQ</span>
<span class="identifier">in</span><span class="plain"> </span><span class="identifier">place</span><span class="plain"> </span><span class="identifier">of</span><span class="plain"> ...... </span><span class="identifier">in</span><span class="plain"> &lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; ==&gt; </span><span class="constant">IN_PLACE_OF_HQ</span>
<span class="plain">&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt; ::=</span>
<span class="plain">...... </span><span class="identifier">by</span><span class="plain"> ...... ==&gt; </span>&lt;<span class="cwebmacro">Set for-use-with extension identifier</span> <span class="cwebmacronumber">11.3</span>&gt;
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP11_1"></a><b>&#167;11.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue PM_UnknownLanguageElement problem</span> <span class="cwebmacronumber">11.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_UnknownLanguageElement</span><span class="plain">),</span>
<span class="string">"this heading contains a stipulation about the current "</span>
<span class="string">"Inform language definition which I can't understand"</span><span class="plain">,</span>
<span class="string">"and should be something like '(for Glulx external files "</span>
<span class="string">"language element only)'."</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><code class="display">
&lt;<span class="cwebmacrodefn">Issue PM_UnknownVirtualMachine problem</span> <span class="cwebmacronumber">11.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_UnknownVirtualMachine</span><span class="plain">),</span>
<span class="string">"this heading contains a stipulation about the Setting "</span>
<span class="string">"for story file format which I can't understand"</span><span class="plain">,</span>
<span class="string">"and should be something like '(for Z-machine version 5 "</span>
<span class="string">"or 8 only)' or '(for Glulx only)'."</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_3"></a><b>&#167;11.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Set for-use-with extension identifier</span> <span class="cwebmacronumber">11.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = </span><span class="identifier">R</span><span class="plain">[0] + 4;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">exft</span><span class="plain">);</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">exfa</span><span class="plain">);</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">TW</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt;, 1);</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">AW</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(&lt;</span><span class="identifier">extension</span><span class="plain">-</span><span class="identifier">identifier</span><span class="plain">&gt;, 2);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">exft</span><span class="plain">, </span><span class="string">"%+W"</span><span class="plain">, </span><span class="identifier">TW</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">exfa</span><span class="plain">, </span><span class="string">"%+W"</span><span class="plain">, </span><span class="identifier">AW</span><span class="plain">);</span>
<span class="functiontext">Extensions::IDs::new</span><span class="plain">(</span><span class="identifier">grammar_eid</span><span class="plain">, </span><span class="identifier">exfa</span><span class="plain">, </span><span class="identifier">exft</span><span class="plain">, </span><span class="constant">USEWITH_EIDBC</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">exft</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">exfa</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="SP12"></a><b>&#167;12. The heading tree. </b>The headings were constructed above as freestanding nodes (except that the
pseudo-heading already existed): here, we assemble them into a tree
structure. Because we want to be able to call this more than once, perhaps
to make revisions if late news comes in of a new heading (see above), we
begin by removing any existing relationships between the heading nodes.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::make_tree</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Reduce the whole heading tree to a pile of twigs</span> <span class="cwebmacronumber">12.1</span>&gt;<span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">If h is outside the tree, make it a child of the pseudo-heading</span> <span class="cwebmacronumber">12.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Run through subsequent equal or subordinate headings to move them downward</span> <span class="cwebmacronumber">12.3</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">heading_tree_made_at_least_once</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="functiontext">Sentences::Headings::verify_heading_tree</span><span class="plain">();</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::make_tree is used in <a href="#SP10">&#167;10</a>, <a href="#SP27_3">&#167;27.3</a>, 1/mr (<a href="1-mr.html#SP4_9">&#167;4.9</a>).</p>
<p class="inwebparagraph"><a id="SP12_1"></a><b>&#167;12.1. </b>Note that the loop over headings below loops through all those which were
created by the memory manager: which is to say, all of them except for the
pseudo-heading, which was explicitly placed in static memory above.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Reduce the whole heading tree to a pile of twigs</span> <span class="cwebmacronumber">12.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
<span class="identifier">pseudo_heading</span><span class="element">.child_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">pseudo_heading</span><span class="element">.parent_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">pseudo_heading</span><span class="element">.next_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">) {</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP12_2"></a><b>&#167;12.2. </b>The idea of the heading loop is that when we place a heading, we also place
subsequent headings of lesser or equal status until we cannot do so any longer.
That means that if we reach h and find that it has no parent, it must be
subordinate to no earlier heading: thus, it must be attached to the pseudo-heading
at the top of the tree.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">If h is outside the tree, make it a child of the pseudo-heading</span> <span class="cwebmacronumber">12.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::make_child_heading</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, &amp;</span><span class="identifier">pseudo_heading</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP12_3"></a><b>&#167;12.3. </b>Note that the following could be summed up as "move subsequent headings as
deep in the tree as we can see they need to be from h's perspective alone".
This isn't always the final position. For instance, given the sequence
Volume 1, Chapter I, Section A, Chapter II, the tree is adjusted twice:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">when h = Volume 1: then when h = Chapter I:</span>
<span class="plain">Volume 1 Volume 1</span>
<span class="plain"> Chapter I Chapter I</span>
<span class="plain"> Section A Section A</span>
<span class="plain"> Chapter II Chapter II</span>
</pre>
<p class="inwebparagraph">since Section A is demoted twice, once by Volume 1, then by Chapter I.
(This algorithm would in principle be quadratic in the number of headings if
the possible depth of the tree were unbounded &mdash; every heading might have to
demote every one of its successors &mdash; but in fact because the depth is at
most 9, it runs in linear time.)
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Run through subsequent equal or subordinate headings to move them downward</span> <span class="cwebmacronumber">12.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">subseq</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">subseq</span><span class="plain"> = </span><span class="identifier">NEXT_OBJECT</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">); </span> <span class="comment">start from the next heading in source</span>
<span class="plain">(</span><span class="identifier">subseq</span><span class="plain">) &amp;&amp; (</span><span class="identifier">subseq</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt;= </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">); </span> <span class="comment">for a run with level below or equal h</span>
<span class="identifier">subseq</span><span class="plain"> = </span><span class="identifier">NEXT_OBJECT</span><span class="plain">(</span><span class="identifier">subseq</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">)) { </span> <span class="comment">in source declaration order</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">subseq</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> == </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">) { </span> <span class="comment">a heading of equal status ends the run...</span>
<span class="functiontext">Sentences::Headings::make_child_heading</span><span class="plain">(</span><span class="identifier">subseq</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">; </span> <span class="comment">...and becomes h's sibling</span>
<span class="plain">}</span>
<span class="functiontext">Sentences::Headings::make_child_heading</span><span class="plain">(</span><span class="identifier">subseq</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">); </span> <span class="comment">all lesser headings in the run become h's children</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>The above routine, then, calls <code class="display"><span class="extract">Sentences::Headings::make_child_heading</span></code> to attach a heading
to the tree as a child of a given parent:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::make_child_heading</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">ch</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">pa</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">former_pa</span><span class="plain"> = </span><span class="identifier">ch</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">former_pa</span><span class="plain"> == </span><span class="identifier">pa</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Detach ch from the heading tree if it is already there</span> <span class="cwebmacronumber">13.1</span>&gt;<span class="plain">;</span>
<span class="identifier">ch</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain"> = </span><span class="identifier">pa</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Add ch to the end of the list of children of pa</span> <span class="cwebmacronumber">13.2</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::make_child_heading is used in <a href="#SP12_2">&#167;12.2</a>, <a href="#SP12_3">&#167;12.3</a>.</p>
<p class="inwebparagraph"><a id="SP13_1"></a><b>&#167;13.1. </b>If ch is present in the tree, it must have a parent, unless it is the
pseudo-heading: but the latter can never be moved, so it isn't. Therefore
we can remove ch by striking it out from the children list of the parent.
(Any children which ch has, grandchildren so to speak, come with it.)
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Detach ch from the heading tree if it is already there</span> <span class="cwebmacronumber">13.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">former_pa</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">former_pa</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain"> == </span><span class="identifier">ch</span><span class="plain">)</span>
<span class="identifier">former_pa</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain"> = </span><span class="identifier">ch</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">sibling</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">sibling</span><span class="plain"> = </span><span class="identifier">former_pa</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">; </span><span class="identifier">sibling</span><span class="plain">; </span><span class="identifier">sibling</span><span class="plain"> = </span><span class="identifier">sibling</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sibling</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> == </span><span class="identifier">ch</span><span class="plain">) {</span>
<span class="identifier">sibling</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> = </span><span class="identifier">ch</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">;</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">ch</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP13">&#167;13</a>.</p>
<p class="inwebparagraph"><a id="SP13_2"></a><b>&#167;13.2. </b>Two cases: the new parent is initially childless, or it isn't.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Add ch to the end of the list of children of pa</span> <span class="cwebmacronumber">13.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">sibling</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">pa</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">pa</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain"> = </span><span class="identifier">ch</span><span class="plain">;</span>
<span class="reserved">else</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">sibling</span><span class="plain"> = </span><span class="identifier">pa</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">; </span><span class="identifier">sibling</span><span class="plain">; </span><span class="identifier">sibling</span><span class="plain"> = </span><span class="identifier">sibling</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sibling</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">sibling</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain"> = </span><span class="identifier">ch</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="#SP13">&#167;13</a>.</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. Verifying the heading tree. </b>We have now, in effect, computed the indentation value of each heading twice,
by two entirely different methods: first by the mathematical argument above,
then by observing that it is the depth in the heading tree. Seeing if
these two methods have given the same answer provides a convenient check on
our working.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">heading_tree_damaged</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::verify_heading_tree</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="functiontext">Sentences::Headings::verify_heading_tree_recursively</span><span class="plain">(&amp;</span><span class="identifier">pseudo_heading</span><span class="plain">, -1);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">heading_tree_damaged</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"heading tree failed to verify"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::verify_heading_tree_recursively</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain"> != &amp;</span><span class="identifier">pseudo_heading</span><span class="plain">) &amp;&amp; (</span><span class="identifier">depth</span><span class="plain"> != </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain">)) {</span>
<span class="identifier">heading_tree_damaged</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$H\</span><span class="plain">n</span><span class="string">*** indentation should be %d ***\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="functiontext">Sentences::Headings::verify_heading_tree_recursively</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1);</span>
<span class="functiontext">Sentences::Headings::verify_heading_tree_recursively</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::verify_heading_tree is used in <a href="#SP12">&#167;12</a>.</p>
<p class="endnote">The function Sentences::Headings::verify_heading_tree_recursively appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. Miscellaneous heading services. </b>The first of these we have already seen in use: the sentence-breaker calls
it to ask whether sentences falling under the current heading should be
included in the active source text. (For instance, sentences under a
heading with the disclaimer "(for Glulx only)" will not be included
if the target virtual machine on this run of Inform is the Z-machine.)
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::include_material</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_release</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">) &amp;&amp; (</span><span class="identifier">this_is_a_release_compile</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) </span><span class="reserved">return</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">h</span><span class="plain">-</span><span class="element">&gt;for_release</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) &amp;&amp; (</span><span class="identifier">this_is_a_release_compile</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">)) </span><span class="reserved">return</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">h</span><span class="plain">-</span><span class="element">&gt;omit_material</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::indexed</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">; </span> <span class="comment">definitions made nowhere are normally indexed</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;index_definitions_made_under_this</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::include_material is used in 7/ss (<a href="7-ss.html#SP3">&#167;3</a>).</p>
<p class="endnote">The function Sentences::Headings::indexed is used in 5/nv (<a href="5-nv.html#SP27_2">&#167;27.2</a>), 8/ed2 (<a href="8-ed2.html#SP3_2_1_7_3">&#167;3.2.1.7.3</a>), 22/pi (<a href="22-pi.html#SP1">&#167;1</a>).</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b>A utility to do with the file of origin:
</p>
<pre class="display">
<span class="reserved">extension_file</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::get_extension_containing</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">SourceFiles::get_extension_corresponding</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::get_extension_containing is used in <a href="#SP20">&#167;20</a>, 19/tb (<a href="19-tb.html#SP31">&#167;31</a>), 22/pi (<a href="22-pi.html#SP1">&#167;1</a>), 25/cp (<a href="25-cp.html#SP3_1">&#167;3.1</a>).</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. </b>Although File (0) headings do have text, contrary to the implication of
the routine here, this text is only what happens to be first in the file:
it isn't a heading actually typed by the user, which is all that we are
interested in for this purpose. So we send back a null word range.
</p>
<pre class="display">
<span class="identifier">wording</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::get_text</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> == 0)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::get_text is used in 5/nv (<a href="5-nv.html#SP27_2">&#167;27.2</a>), 22/pi (<a href="22-pi.html#SP1_2">&#167;1.2</a>).</p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. </b>This routine determines the (closest) heading to which a scrap of text
belongs, and is important since the parsing of noun phrases is affected by
that choice of heading (as we shall see): to Inform, headings provide something
analogous to the scope of local variables in a conventional programming
language.
</p>
<p class="inwebparagraph">Because every file has a File (0) heading registered at line 1, the loop
in the following routine is guaranteed to return a valid heading provided
the original source location is well formed (i.e., has a non-null source
file and a line number of at least 1).
</p>
<pre class="display">
<span class="reserved">heading</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::heading_of</span><span class="plain">(</span><span class="identifier">source_location</span><span class="plain"> </span><span class="identifier">sl</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sl</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">LOOP_BACKWARDS_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">sl</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain"> == </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">sl</span><span class="plain">.</span><span class="identifier">line_number</span><span class="plain"> &gt;= </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">line_number</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">h</span><span class="plain">;</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unable to determine the heading level of source material"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::of_wording</span><span class="plain">(</span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::heading_of</span><span class="plain">(</span><span class="identifier">Wordings::location</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">));</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::heading_of is used in <a href="#SP27_1">&#167;27.1</a>.</p>
<p class="endnote">The function Sentences::Headings::of_wording is used in <a href="#SP22">&#167;22</a>, 5/nv (<a href="5-nv.html#SP27_2">&#167;27.2</a>), 8/ed2 (<a href="8-ed2.html#SP3_2_1_7_3">&#167;3.2.1.7.3</a>), 19/tb (<a href="19-tb.html#SP31">&#167;31</a>), 22/pi (<a href="22-pi.html#SP1">&#167;1</a>), 25/cp (<a href="25-cp.html#SP3_1">&#167;3.1</a>).</p>
<p class="inwebparagraph"><a id="SP19"></a><b>&#167;19. Headings with extension dependencies. </b>If the content under a heading depended on the VM not in use, or was marked
not for release in a release run, we were able to exclude it just by
skipping. The same cannot be done when a heading says that it should be
used only if a given extension is, or is not, being used, because when
the heading is created we don't yet know which extensions are included.
But when the following is called, we do know that.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::satisfy_dependencies</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</span><span class="plain"> != </span><span class="identifier">NOT_APPLICABLE</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::satisfy_individual_heading_dependency</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::satisfy_dependencies is used in 1/mr (<a href="1-mr.html#SP4_9">&#167;4.9</a>).</p>
<p class="inwebparagraph"><a id="SP20"></a><b>&#167;20. </b>And now the code to check an individual heading's usage. This whole
thing is carefully timed so that we can still afford to cut up and rearrange
the parse tree on quite a large scale, and that's just what we do.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::satisfy_individual_heading_dependency</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &lt; 1) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">extension_identifier</span><span class="plain"> *</span><span class="identifier">eid</span><span class="plain"> = &amp;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">loaded</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="functiontext">Extensions::IDs::no_times_used_in_context</span><span class="plain">(</span><span class="identifier">eid</span><span class="plain">, </span><span class="constant">LOADED_EIDBC</span><span class="plain">) != 0) </span><span class="identifier">loaded</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">HEADINGS</span><span class="plain">, </span><span class="string">"SIHD on $H: loaded %d: annotation %d: %W: %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">, </span><span class="identifier">loaded</span><span class="plain">,</span>
<span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">,</span>
<span class="constant">suppress_heading_dependencies_ANNOT</span><span class="plain">),</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">)) {</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">S</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">,</span>
<span class="constant">suppress_heading_dependencies_ANNOT</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (&lt;</span><span class="identifier">quoted</span><span class="plain">-</span><span class="identifier">text</span><span class="plain">&gt;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">)) {</span>
<span class="identifier">Word::dequote</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">));</span>
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain"> = </span><span class="identifier">Lexer::word_text</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">));</span>
<span class="identifier">S</span><span class="plain"> = </span><span class="identifier">Feeds::feed_text</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h2</span><span class="plain">; </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">found</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">loaded</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span>&lt;<span class="cwebmacro">Can't replace heading in an unincluded extension</span> <span class="cwebmacronumber">20.1</span>&gt;
<span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h2</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">h2</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">Wordings::match_perhaps_quoted</span><span class="plain">(</span><span class="identifier">S</span><span class="plain">, </span><span class="identifier">h2</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Extensions::IDs::match</span><span class="plain">(</span>
<span class="functiontext">Extensions::Files::get_eid</span><span class="plain">(</span>
<span class="functiontext">Sentences::Headings::get_extension_containing</span><span class="plain">(</span><span class="identifier">h2</span><span class="plain">)), </span><span class="identifier">eid</span><span class="plain">))) {</span>
<span class="identifier">found</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">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> != </span><span class="identifier">h2</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Can't replace heading unless level matches</span> <span class="cwebmacronumber">20.3</span>&gt;<span class="character">;</span>
<span class="functiontext">Sentences::Headings::excise_material_under</span><span class="plain">(</span><span class="identifier">h2</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::excise_material_under</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="identifier">h2</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">);</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">found</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span>&lt;<span class="cwebmacro">Can't find heading in the given extension</span> <span class="cwebmacronumber">20.2</span>&gt;<span class="character">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="plain">} </span><span class="reserved">else</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;use_with_or_without</span><span class="plain"> != </span><span class="identifier">loaded</span><span class="plain">) </span><span class="functiontext">Sentences::Headings::excise_material_under</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::satisfy_individual_heading_dependency is used in <a href="#SP19">&#167;19</a>.</p>
<p class="inwebparagraph"><a id="SP20_1"></a><b>&#167;20.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Can't replace heading in an unincluded extension</span> <span class="cwebmacronumber">20.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">;</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
<span class="functiontext">Problems::quote_extension_id</span><span class="plain">(2, &amp;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_HeadingInPlaceOfUnincluded</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"In the sentence %1, it looks as if you intend to replace a section "</span>
<span class="string">"of source text from the extension '%2', but no extension of that "</span>
<span class="string">"name has been included - so it is not possible to replace any of its "</span>
<span class="string">"headings."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP20">&#167;20</a>.</p>
<p class="inwebparagraph"><a id="SP21"></a><b>&#167;21. </b>To excise, we simply prune the heading's contents from the parse tree,
though optionally grafting them to another node rather than discarding them
altogether.
</p>
<p class="inwebparagraph">Any heading which is excised is marked so that it won't have its own
dependencies checked. This clarifies several cases, and in particular ensures
that if Chapter X is excised then a subordinate Section Y cannot live on by
replacing something elsewhere (which would effectively delete the content
elsewhere).
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::excise_material_under</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">transfer_to</span><span class="plain">) {</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">HEADINGS</span><span class="plain">, </span><span class="string">"Excision under $H\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">hpn</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"stipulations on a non-sentence heading"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">)) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h2</span><span class="plain"> = </span><span class="functiontext">Sentences::Headings::find_dependent_heading</span><span class="plain">(</span><span class="identifier">hpn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h2</span><span class="plain">) </span>&lt;<span class="cwebmacro">Can't replace heading subordinate to another replaced heading</span> <span class="cwebmacronumber">21.1</span>&gt;<span class="character">;</span>
<span class="plain">}</span>
<span class="functiontext">Sentences::Headings::suppress_dependencies</span><span class="plain">(</span><span class="identifier">hpn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">transfer_to</span><span class="plain">) </span><span class="identifier">ParseTree::graft</span><span class="plain">(</span><span class="identifier">hpn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">, </span><span class="identifier">transfer_to</span><span class="plain">);</span>
<span class="identifier">hpn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::find_dependent_heading</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">pn</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">) == </span><span class="identifier">HEADING_NT</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain"> = </span><span class="identifier">ParseTree::get_embodying_heading</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain">) &amp;&amp; (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">))) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">h</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">pn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">; </span><span class="identifier">p</span><span class="plain">; </span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain"> = </span><span class="identifier">ParseTree::get_embodying_heading</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">h</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">h</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::suppress_dependencies</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">pn</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">) == </span><span class="identifier">HEADING_NT</span><span class="plain">)</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">pn</span><span class="plain">, </span><span class="constant">suppress_heading_dependencies_ANNOT</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">pn</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">; </span><span class="identifier">p</span><span class="plain">; </span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::suppress_dependencies</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::excise_material_under is used in <a href="#SP20">&#167;20</a>.</p>
<p class="endnote">The function Sentences::Headings::find_dependent_heading appears nowhere else.</p>
<p class="endnote">The function Sentences::Headings::suppress_dependencies appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP21_1"></a><b>&#167;21.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Can't replace heading subordinate to another replaced heading</span> <span class="cwebmacronumber">21.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">h2</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">;</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
<span class="functiontext">Problems::quote_extension_id</span><span class="plain">(2, &amp;(</span><span class="identifier">h2</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">));</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(3, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">);</span>
<span class="functiontext">Problems::quote_extension_id</span><span class="plain">(4, &amp;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_HeadingInPlaceOfSubordinate</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"In the sentence %1, it looks as if you intend to replace a section "</span>
<span class="string">"of source text from the extension '%2', but that doesn't really make "</span>
<span class="string">"sense because this new piece of source text is part of a superior "</span>
<span class="string">"heading ('%3') which is already being replaced spliced into '%4'."</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP21">&#167;21</a>.</p>
<p class="inwebparagraph"><a id="SP20_2"></a><b>&#167;20.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Can't find heading in the given extension</span> <span class="cwebmacronumber">20.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">;</span>
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
<span class="functiontext">Problems::quote_extension_id</span><span class="plain">(2, &amp;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">));</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;in_place_of_text</span><span class="plain">);</span>
<span class="identifier">Problems::quote_text</span><span class="plain">(4,</span>
<span class="string">"unspecified, that is, the extension didn't have a version number"</span><span class="plain">);</span>
<span class="reserved">extension_file</span><span class="plain"> *</span><span class="identifier">ef</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">, </span><span class="reserved">extension_file</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Extensions::IDs::match</span><span class="plain">(&amp;(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;for_use_with</span><span class="plain">), </span><span class="functiontext">Extensions::Files::get_eid</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">)))</span>
<span class="identifier">Problems::quote_wording</span><span class="plain">(4,</span>
<span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="functiontext">Extensions::Files::get_version_wn</span><span class="plain">(</span><span class="identifier">ef</span><span class="plain">)));</span>
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_HeadingInPlaceOfUnknown</span><span class="plain">));</span>
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
<span class="string">"In the sentence %1, it looks as if you intend to replace a section "</span>
<span class="string">"of source text from the extension '%2', but that extension does "</span>
<span class="string">"not seem to have any heading called '%3'. (The version I loaded "</span>
<span class="string">"was %4.)"</span><span class="plain">);</span>
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP20">&#167;20</a>.</p>
<p class="inwebparagraph"><a id="SP20_3"></a><b>&#167;20.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Can't replace heading unless level matches</span> <span class="cwebmacronumber">20.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">;</span>
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_UnequalHeadingInPlaceOf</span><span class="plain">),</span>
<span class="string">"these headings are not of the same level"</span><span class="plain">,</span>
<span class="string">"so it is not possible to make the replacement. (Level here means "</span>
<span class="string">"being a Volume, Book, Part, Chapter or Section: for instance, "</span>
<span class="string">"only a Chapter heading can be used 'in place of' a Chapter.)"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP20">&#167;20</a>.</p>
<p class="inwebparagraph"><a id="SP22"></a><b>&#167;22. World objects under each heading. </b>Every heading must carry with it a linked list of the nametags created in
sentences which belong to it. So when any noun is created, the following
is called to let the current sentence's heading know that it has a new
friend.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="identifier">LOOP_OVER_NOUNS_UNDER</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">)</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">nt</span><span class="plain">=</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;list_of_contents</span><span class="plain">; </span><span class="identifier">nt</span><span class="plain">; </span><span class="identifier">nt</span><span class="plain">=</span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;next_under_heading</span><span class="plain">)</span>
</pre>
<pre class="display">
<span class="reserved">name_resolution_data</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">t</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">t</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to fetch resolution data for null tag"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> &amp;(</span><span class="identifier">t</span><span class="plain">-&gt;</span><span class="identifier">name_resolution</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">no_tags_attached</span><span class="plain"> = 0;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::attach_noun</span><span class="plain">(</span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">new_tag</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_sentence</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain"> = </span><span class="functiontext">Sentences::Headings::of_wording</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">current_sentence</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="identifier">no_tags_attached</span><span class="plain">++;</span>
<span class="reserved">name_resolution_data</span><span class="plain"> *</span><span class="identifier">nrd</span><span class="plain"> = </span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">new_tag</span><span class="plain">);</span>
<span class="identifier">nrd</span><span class="plain">-</span><span class="element">&gt;next_to_search</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">h</span><span class="plain">-</span><span class="element">&gt;last_in_list_of_contents</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;list_of_contents</span><span class="plain"> = </span><span class="identifier">new_tag</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;last_in_list_of_contents</span><span class="plain">)-</span><span class="element">&gt;next_under_heading</span><span class="plain"> = </span><span class="identifier">new_tag</span><span class="plain">;</span>
<span class="identifier">nrd</span><span class="plain">-</span><span class="element">&gt;next_under_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;last_in_list_of_contents</span><span class="plain"> = </span><span class="identifier">new_tag</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::name_resolution_data is used in <a href="#SP23">&#167;23</a>, <a href="#SP25">&#167;25</a>, <a href="#SP28_1">&#167;28.1</a>, <a href="#SP29">&#167;29</a>.</p>
<p class="endnote">The function Sentences::Headings::attach_noun appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP23"></a><b>&#167;23. </b>The following verification checks that every noun is listed
in the list for exactly one heading. The point of the check is not so much
to make sure the tag lists are properly formed, as the code making those
is pretty elementary: it's really a test that the source text is well-formed
with everything placed under a heading, and no sentence having fallen
through a crack.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::verify_divisions</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt</span><span class="plain">; </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">total</span><span class="plain"> = 0, </span><span class="identifier">disaster</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">, </span><span class="identifier">noun</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;heading_count</span><span class="plain"> = 0;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">)</span>
<span class="identifier">LOOP_OVER_NOUNS_UNDER</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;heading_count</span><span class="plain">++, </span><span class="identifier">total</span><span class="plain">++;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">, </span><span class="identifier">noun</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;heading_count</span><span class="plain"> &gt; 1) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$z occurs under %d headings\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">nt</span><span class="plain">, </span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;heading_count</span><span class="plain">);</span>
<span class="identifier">disaster</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">total</span><span class="plain"> != </span><span class="identifier">no_tags_attached</span><span class="plain">) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"%d tags != %d attached\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">total</span><span class="plain">, </span><span class="identifier">no_tags_attached</span><span class="plain">);</span>
<span class="identifier">disaster</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">disaster</span><span class="plain">) </span><span class="identifier">internal_error_tree_unsafe</span><span class="plain">(</span><span class="string">"heading contents list failed verification"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::verify_divisions appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP24"></a><b>&#167;24. The noun search list. </b>Identifying noun phrases is tricky. Many plausible phrases could refer in
principle to several different instances: "east", for instance, might
mean the direction or, say, "east garden". And what if the source
mentions many chairs, and now refers simply to "the chair"? This problem
is not so acute for nouns referring to abstractions, where we can simply
forbid duplicate definitions and require an exact wording when talking
about them. But for names of IF objects &mdash; which represent the solid and often
repetitive items and places of a simulated world &mdash; it cannot be ducked.
We can hardly tell an Inform author to create at most one item whose
name contains the word "jar", for instance.
</p>
<p class="inwebparagraph">All programming languages face similar problems. In C, for instance, a local
variable named <code class="display"><span class="extract">east</span></code> will be recognised in preference to a global one of the
same name (to some extent external linking provides a third level again).
The way this is done is usually explained in terms of the "scope" of a
definition, the part of the source for which it is valid: the winner, in
cases of ambiguity, being the definition of narrowest scope which is valid
at the position in question. In our terms, a stand-alone C program has a
heading tree like so, with two semantically meaningful heading levels,
File (0) and Routine (1), and then sublevels provided by braced blocks:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">File</span>
<span class="plain"> main()</span>
<span class="plain"> routine1()</span>
<span class="plain"> interior block of a loop</span>
<span class="plain"> ...</span>
<span class="plain"> routine2()</span>
<span class="plain"> ...</span>
</pre>
<p class="inwebparagraph">The resolution of a name at a given position P is unambiguous: find the
heading H to which P belongs; if the name is defined there, accept that;
if not move H upwards and try again; if it is not defined even at File (0)
level, issue an error: the term is undefined.
</p>
<p class="inwebparagraph">Inform is different in two respects, one trivial, the other not. The trivial
difference is that an Inform name can be defined midway through the matter
(though as a result of the PM_ revision, ANSI C now also allows variables
to be created mid-block, in fact: and some C compilers even implement this).
</p>
<p class="inwebparagraph">The big difference is that in Inform, names are always visible across
headings. They can be used before being defined; Section 2 of Part II is
free to mention the elephant defined in Section 7 of Part VIII, say.
English text is like this: a typical essay has one great big namespace.
</p>
<p class="inwebparagraph">We resolve this by searching backwards through recent noun creations in
the current heading, then in the current heading level above that, and so
on up to the top conceptual level of the source. Thus a "chair" in the
current chapter will always have priority over any in previous chapters,
and so on. However, kinds are always given priority over mere instances,
in order that "door" will retain its generic meaning even if, say,
"an oak door" is created.
</p>
<p class="inwebparagraph"><a id="SP25"></a><b>&#167;25. </b>This means that, under every heading, the search sequence is different.
So for the sake of efficiency we construct a linked list of world
objects in priority order the first time we search under a new heading,
then simply use that thereafter: we also keep track of the tail of this
list. Sections other than this one cannot read the list itself, and
use the following definition to iterate through it.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="identifier">LOOP_OVER_NT_SEARCH_LIST</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">nt</span><span class="plain"> = </span><span class="identifier">nt_search_start</span><span class="plain">; </span><span class="identifier">nt</span><span class="plain">; </span><span class="identifier">nt</span><span class="plain"> = </span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;next_to_search</span><span class="plain">)</span>
</pre>
<pre class="display">
<span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt_search_start</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">nt_search_finish</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP26"></a><b>&#167;26. </b>The search sequence is, in effect, a cache storing a former computation,
and like all caches it can fall out of date if the circumstances change so
that the same computation would now produce a different outcome. That can
only happen here if a new noun is to be created: the assertion-maker
calls the following routine to let us know.
</p>
<pre class="display">
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">noun_search_list_valid_for_this_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">initially it's unbuilt</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::disturb</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">noun_search_list_valid_for_this_heading</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::disturb appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP27"></a><b>&#167;27. </b>Leaving aside the cache, then, we build a list as initially empty, then
all nametags of priority 1 as found by recursively searching headings, then all
nametags of priority 2, and so on.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::construct_noun_search_list</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Work out the heading from which we wish to search</span> <span class="cwebmacronumber">27.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">noun_search_list_valid_for_this_heading</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain">; </span> <span class="comment">rely on the cache</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">HEADINGS</span><span class="plain">, </span><span class="string">"Rebuilding noun search list from: $H\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Start the search list empty</span> <span class="cwebmacronumber">27.2</span>&gt;<span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=1; </span><span class="identifier">i</span><span class="plain">&lt;=</span><span class="identifier">MAX_NOUN_PRIORITY</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="functiontext">Sentences::Headings::build_search_list_from</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Verify that the search list indeed contains every noun just once</span> <span class="cwebmacronumber">27.3</span>&gt;<span class="plain">;</span>
<span class="identifier">noun_search_list_valid_for_this_heading</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::construct_noun_search_list appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP27_1"></a><b>&#167;27.1. </b>Basically, we calculate the search list from the point of view of the
current sentence:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Work out the heading from which we wish to search</span> <span class="cwebmacronumber">27.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">current_sentence</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">Wordings::empty</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">current_sentence</span><span class="plain">))))</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"cannot establish position P: there is no current sentence"</span><span class="plain">);</span>
<span class="identifier">source_location</span><span class="plain"> </span><span class="identifier">position_P</span><span class="plain"> = </span><span class="identifier">Wordings::location</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">current_sentence</span><span class="plain">));</span>
<span class="identifier">h</span><span class="plain"> = </span><span class="functiontext">Sentences::Headings::heading_of</span><span class="plain">(</span><span class="identifier">position_P</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP27">&#167;27</a>.</p>
<p class="inwebparagraph"><a id="SP27_2"></a><b>&#167;27.2. </b>The pseudo-heading has no list of contents because all objects are created in
source files, each certainly underneath a File (0) heading, so nothing should
ever get that far.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Start the search list empty</span> <span class="cwebmacronumber">27.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">nt_search_start</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">nt_search_finish</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">pseudo_heading</span><span class="element">.list_of_contents</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">should always be true, but just in case</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP27">&#167;27</a>.</p>
<p class="inwebparagraph"><a id="SP27_3"></a><b>&#167;27.3. </b>The potential for disaster if this algorithm should be incorrect is high,
so we perform a quick count to see if everything made it onto the list
and produce an internal error if not.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Verify that the search list indeed contains every noun just once</span> <span class="cwebmacronumber">27.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0; </span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_NT_SEARCH_LIST</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">) </span><span class="identifier">c</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> != </span><span class="identifier">no_tags_attached</span><span class="plain">) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Reordering failed from $H\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"%d tags created, %d in ordering\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">no_tags_attached</span><span class="plain">, </span><span class="identifier">c</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::log_all_headings</span><span class="plain">();</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Making fresh tree:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::make_tree</span><span class="plain">();</span>
<span class="functiontext">Sentences::Headings::log_all_headings</span><span class="plain">();</span>
<span class="identifier">internal_error_tree_unsafe</span><span class="plain">(</span><span class="string">"reordering of nametags failed"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP27">&#167;27</a>.</p>
<p class="inwebparagraph"><a id="SP28"></a><b>&#167;28. </b>The following adds all nametags under heading H to the search list, using
its own list of contents, and then recurses to add all objects under
subheadings of H other than the one which has just recursed up to H. With
that done, we recurse up to the superheading of H.
</p>
<p class="inwebparagraph">To prove that <code class="display"><span class="extract">Sentences::Headings::build_search_list_from</span></code> is called exactly once for each
heading in the tree, forget about the up/down orientation and consider it
as a graph instead. At each node we try going to every possible other node,
except the way we came (at the start of the traverse, the "way we came"
being null): clearly this ensures that all of our neighbours have been
visited. Since every heading ultimately depends from the pseudo-heading,
the graph is connected, and therefore every heading must eventually be
visited. No heading can be visited twice, because that would mean that a
cycle of nodes H_1, H_2, ..., H_i, H_1 must exist: since we have a tree
structure, there are no loops, and so H_i = H_2, H_{i-1} = H_3, and so
on &mdash; we must be walking a path and then retracing our steps in reverse.
That being so, there is a point where we turned back: we went from H_j to
H_{j+1} to H_j again. And this violates the principle that at each node
we move outwards in every direction except the way we came, a
contradiction.
</p>
<p class="inwebparagraph">The routine looks as if it may have a large recursion depth &mdash; maybe as
deep as the number of headings &mdash; but because we go downwards and then
upwards, the maximum recursion depth of the routine is less than 2L+1, where
L is the number of levels in the tree other than the pseudo-heading. This
provides an upper bound of about 21, regardless of the size of the source
text. The running time is linear in both the number of headings and the
number of nametags in the source text.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::build_search_list_from</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">within</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">way_we_came</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">p</span><span class="plain">) {</span>
<span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt</span><span class="plain">; </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">subhead</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">within</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_NOUNS_UNDER</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">, </span><span class="identifier">within</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Nouns::priority</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">) == </span><span class="identifier">p</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Add tag to the end of the search list</span> <span class="cwebmacronumber">28.1</span>&gt;<span class="plain">;</span>
<span class="comment">recurse downwards through subordinate headings, other than the way we came up</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">subhead</span><span class="plain"> = </span><span class="identifier">within</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">; </span><span class="identifier">subhead</span><span class="plain">; </span><span class="identifier">subhead</span><span class="plain"> = </span><span class="identifier">subhead</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">subhead</span><span class="plain"> != </span><span class="identifier">way_we_came</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::build_search_list_from</span><span class="plain">(</span><span class="identifier">subhead</span><span class="plain">, </span><span class="identifier">within</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
<span class="comment">recurse upwards to superior headings, unless we came here through a downward recursion</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">within</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain"> != </span><span class="identifier">way_we_came</span><span class="plain">)</span>
<span class="functiontext">Sentences::Headings::build_search_list_from</span><span class="plain">(</span><span class="identifier">within</span><span class="plain">-</span><span class="element">&gt;parent_heading</span><span class="plain">, </span><span class="identifier">within</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::build_search_list_from is used in <a href="#SP27">&#167;27</a>.</p>
<p class="inwebparagraph"><a id="SP28_1"></a><b>&#167;28.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Add tag to the end of the search list</span> <span class="cwebmacronumber">28.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">nt_search_finish</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">nt_search_start</span><span class="plain"> = </span><span class="identifier">nt</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="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt_search_finish</span><span class="plain">)-</span><span class="element">&gt;next_to_search</span><span class="plain"> != </span><span class="identifier">NULL</span><span class="plain">)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"end of tag search list has frayed somehow"</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt_search_finish</span><span class="plain">)-</span><span class="element">&gt;next_to_search</span><span class="plain"> = </span><span class="identifier">nt</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;next_to_search</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">nt_search_finish</span><span class="plain"> = </span><span class="identifier">nt</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP28">&#167;28</a>.</p>
<p class="inwebparagraph"><a id="SP29"></a><b>&#167;29. </b>The search list is used for finding best matches in a particular order, the
order being used to break tie-breaks. Note that we return <code class="display"><span class="extract">NULL</span></code> if no noun
in the search list has a positive score.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::set_noun_search_score</span><span class="plain">(</span><span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">v</span><span class="plain">) {</span>
<span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;search_score</span><span class="plain"> = </span><span class="identifier">v</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">noun</span><span class="plain"> *</span><span class="functiontext">Sentences::Headings::highest_scoring_noun_searched</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt</span><span class="plain">, *</span><span class="identifier">best_nt</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">best_score</span><span class="plain"> = 0;</span>
<span class="identifier">LOOP_OVER_NT_SEARCH_LIST</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">x</span><span class="plain"> = </span><span class="functiontext">Sentences::Headings::name_resolution_data</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">)-</span><span class="element">&gt;search_score</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">x</span><span class="plain"> &gt; </span><span class="identifier">best_score</span><span class="plain">) { </span><span class="identifier">best_nt</span><span class="plain"> = </span><span class="identifier">nt</span><span class="plain">; </span><span class="identifier">best_score</span><span class="plain"> = </span><span class="identifier">x</span><span class="plain">; }</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">best_nt</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::set_noun_search_score appears nowhere else.</p>
<p class="endnote">The function Sentences::Headings::highest_scoring_noun_searched appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP30"></a><b>&#167;30. Handling headings during the main traverses. </b>Here's what we do when we run into a heading, as we look through the
assertions in the source text: nothing, except to wipe out any meanings of
words like "it" left over from previous sentences. Headings are for
organisation, and are not directly functional in themselves.
</p>
<pre class="display">
<span class="reserved">sentence_handler</span><span class="plain"> </span><span class="identifier">HEADING_SH_handler</span><span class="plain"> =</span>
<span class="plain">{ </span><span class="identifier">HEADING_NT</span><span class="plain">, -1, 0, </span><span class="functiontext">Sentences::Headings::handle_heading</span><span class="plain"> };</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::handle_heading</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain">) {</span>
<span class="functiontext">Assertions::Traverse::new_discussion</span><span class="plain">();</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::handle_heading appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP31"></a><b>&#167;31. Describing the heading structure, 1: to the debugging log. </b>Finally, three ways to describe the run of headings: to the debugging log,
to the index of the project, and to a freestanding XML file.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::log</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">==</span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"&lt;null heading&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">==&amp;</span><span class="identifier">pseudo_heading</span><span class="plain">) { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"&lt;pseudo_heading&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"H%d "</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">)</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"&lt;%f, line %d&gt;"</span><span class="plain">,</span>
<span class="identifier">TextFromFiles::get_filename</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">),</span>
<span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">line_number</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">"&lt;nowhere&gt;"</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">" level:%d indentation:%d"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::log is used in 1/cm (<a href="1-cm.html#SP5">&#167;5</a>, <a href="1-cm.html#SP6_6">&#167;6.6</a>).</p>
<p class="inwebparagraph"><a id="SP32"></a><b>&#167;32. </b>And here we log the whole heading tree by recursing through it, and
surreptitiously check that it is correctly formed at the same time.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::log_all_headings</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$H\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::log_headings_recursively</span><span class="plain">(&amp;</span><span class="identifier">pseudo_heading</span><span class="plain">, 0);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::log_headings_recursively</span><span class="plain">(</span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">depth</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">==</span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">depth</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">" "</span><span class="plain">);</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"$H\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">depth</span><span class="plain">-1 != </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"*** indentation should be %d ***\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">-1);</span>
<span class="functiontext">Sentences::Headings::log_headings_recursively</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">+1);</span>
<span class="functiontext">Sentences::Headings::log_headings_recursively</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">, </span><span class="identifier">depth</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::log_all_headings is used in <a href="#SP27_3">&#167;27.3</a>.</p>
<p class="endnote">The function Sentences::Headings::log_headings_recursively appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP33"></a><b>&#167;33. Describing the heading structure, 2: to the index. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">headings_indexed</span><span class="plain"> = 0;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::index</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</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">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;b&gt;"</span><span class="plain">); </span><span class="identifier">PL::Bibliographic::contents_heading</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;/b&gt;"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"CONTENTS"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::index_heading_recursively</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">pseudo_heading</span><span class="element">.child_heading</span><span class="plain">);</span>
<span class="reserved">contents_entry</span><span class="plain"> *</span><span class="identifier">ce</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">min_positive_level</span><span class="plain"> = 10;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">ce</span><span class="plain">, </span><span class="reserved">contents_entry</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt; 0) &amp;&amp;</span>
<span class="plain">(</span><span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &lt; </span><span class="identifier">min_positive_level</span><span class="plain">))</span>
<span class="identifier">min_positive_level</span><span class="plain"> = </span><span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">ce</span><span class="plain">, </span><span class="reserved">contents_entry</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Index this entry in the contents</span> <span class="cwebmacronumber">33.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="reserved">contents_entry</span><span class="plain">) == 1) {</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"(This would look more like a contents page if the source text "</span>
<span class="string">"were divided up into headings."</span><span class="plain">);</span>
<span class="identifier">Index::DocReferences::link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"HEADINGS"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">")"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::index appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP33_1"></a><b>&#167;33.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Index this entry in the contents</span> <span class="cwebmacronumber">33.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain"> = </span><span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">;</span>
<span class="comment">indent to correct tab position</span>
<span class="identifier">HTML_OPEN_WITH</span><span class="plain">(</span><span class="string">"ul"</span><span class="plain">, </span><span class="string">"class=\</span><span class="plain">"</span><span class="string">leaders\</span><span class="plain">"</span><span class="string">"</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">ind_used</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> == 0) </span><span class="identifier">ind_used</span><span class="plain"> = 1;</span>
<span class="identifier">HTML_OPEN_WITH</span><span class="plain">(</span><span class="string">"li"</span><span class="plain">, </span><span class="string">"class=\</span><span class="plain">"</span><span class="string">leaded indent%d\</span><span class="plain">"</span><span class="string">"</span><span class="plain">, </span><span class="identifier">ind_used</span><span class="plain">);</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"span"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> == 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="reserved">contents_entry</span><span class="plain">) == 1)</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Source text"</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Preamble"</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="comment">write the text of the heading title</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%+W"</span><span class="plain">, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"span"</span><span class="plain">);</span>
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"span"</span><span class="plain">);</span>
<span class="reserved">contents_entry</span><span class="plain"> *</span><span class="identifier">next_ce</span><span class="plain"> = </span><span class="identifier">NEXT_OBJECT</span><span class="plain">(</span><span class="identifier">ce</span><span class="plain">, </span><span class="reserved">contents_entry</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> != 0)</span>
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">next_ce</span><span class="plain">) &amp;&amp; (</span><span class="identifier">next_ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt; </span><span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">))</span>
<span class="identifier">next_ce</span><span class="plain"> = </span><span class="identifier">NEXT_OBJECT</span><span class="plain">(</span><span class="identifier">next_ce</span><span class="plain">, </span><span class="reserved">contents_entry</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">start_word</span><span class="plain"> = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">));</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">end_word</span><span class="plain"> = (</span><span class="identifier">next_ce</span><span class="plain">)?(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">next_ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">)))</span>
<span class="plain">: (</span><span class="identifier">TextFromFiles::last_lexed_word</span><span class="plain">(</span><span class="identifier">FIRST_OBJECT</span><span class="plain">(</span><span class="identifier">source_file</span><span class="plain">)));</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain"> = 0;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = </span><span class="identifier">start_word</span><span class="plain">; </span><span class="identifier">i</span><span class="plain"> &lt; </span><span class="identifier">end_word</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="identifier">N</span><span class="plain"> += </span><span class="identifier">TextFromFiles::word_count</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">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt; </span><span class="identifier">min_positive_level</span><span class="plain">) </span><span class="identifier">HTML::begin_colour</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"808080"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d words"</span><span class="plain">, </span><span class="identifier">N</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> &gt; </span><span class="identifier">min_positive_level</span><span class="plain">) </span><span class="identifier">HTML::end_colour</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">);</span>
<span class="comment">place a link to the relevant line of the primary source text</span>
<span class="identifier">Index::link_location</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"span"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"li"</span><span class="plain">);</span>
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"ul"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
&lt;<span class="cwebmacro">List all the objects and kinds created under the given heading, one tap stop deeper</span> <span class="cwebmacronumber">33.1.2</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP33">&#167;33</a>.</p>
<p class="inwebparagraph"><a id="SP33_1_1"></a><b>&#167;33.1.1. </b>We index only headings of level 1 and up &mdash; so, not the pseudo-heading or the
File (0) ones &mdash; and which are not within any extensions &mdash; so, are in the
primary source text written by the user.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::index_heading_recursively</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">show_heading</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">next</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">next</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">next</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">next</span><span class="plain">) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">SourceFiles::get_extension_corresponding</span><span class="plain">(</span><span class="identifier">next</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">)))</span>
<span class="identifier">next</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">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain"> == 0) {</span>
<span class="identifier">show_heading</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">headings_indexed</span><span class="plain"> == 0) &amp;&amp;</span>
<span class="plain">((</span><span class="identifier">next</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">next</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">)) !=</span>
<span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;sentence_declaring</span><span class="plain">)))))</span>
<span class="identifier">show_heading</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">SourceFiles::get_extension_corresponding</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">))</span>
<span class="identifier">show_heading</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">show_heading</span><span class="plain">) {</span>
<span class="reserved">contents_entry</span><span class="plain"> *</span><span class="identifier">ce</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">contents_entry</span><span class="plain">);</span>
<span class="identifier">ce</span><span class="plain">-</span><span class="element">&gt;heading_entered</span><span class="plain"> = </span><span class="identifier">h</span><span class="plain">;</span>
<span class="identifier">headings_indexed</span><span class="plain">++;</span>
<span class="plain">}</span>
<span class="functiontext">Sentences::Headings::index_heading_recursively</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;child_heading</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::index_heading_recursively</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;next_heading</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::index_heading_recursively is used in <a href="#SP33">&#167;33</a>.</p>
<p class="inwebparagraph"><a id="SP33_1_2"></a><b>&#167;33.1.2. </b>We skip any objects or kinds without names (i.e., whose <code class="display"><span class="extract">creator</span></code> is null).
The rest appear in italic type, and without links to source text since this
in practice strews distractingly many orange berries across the page.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">List all the objects and kinds created under the given heading, one tap stop deeper</span> <span class="cwebmacronumber">33.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">noun</span><span class="plain"> *</span><span class="identifier">nt</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0;</span>
<span class="identifier">LOOP_OVER_NOUNS_UNDER</span><span class="plain">(</span><span class="identifier">nt</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">) {</span>
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Nouns::get_name</span><span class="plain">(</span><span class="identifier">nt</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">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain">++ == 0) {</span>
<span class="identifier">HTMLFiles::open_para</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">ind_used</span><span class="plain">+1, </span><span class="string">"hanging"</span><span class="plain">);</span>
<span class="identifier">HTML::begin_colour</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"808080"</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">", "</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;i&gt;%+W&lt;/i&gt;"</span><span class="plain">, </span><span class="identifier">W</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">c</span><span class="plain"> &gt; 0) { </span><span class="identifier">HTML::end_colour</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">); </span><span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">); }</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP33_1">&#167;33.1</a>.</p>
<p class="inwebparagraph"><a id="SP34"></a><b>&#167;34. Describing the heading structure, 3: to a freestanding XML file. </b>This is provided as a convenience to the application using Inform, which may want
to have a pull-down menu or similar gadget allowing the user to jump to a given
heading. This tells the interface where every heading is, thus saving it from
having to parse the source.
</p>
<p class="inwebparagraph">The property list contains a single dictionary, whose keys are the numbers
0, 1, 2, ..., n-1, where there are n headings in all. (The pseudo-heading
is not included.) A special key, the only non-numerical one, called "Application
Version", contains the Inform build number in its usual form: "4Q34", for instance.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::write_as_xml</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">text_stream</span><span class="plain"> </span><span class="identifier">xf_struct</span><span class="plain">; </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">xf</span><span class="plain"> = &amp;</span><span class="identifier">xf_struct</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">STREAM_OPEN_TO_FILE</span><span class="plain">(</span><span class="identifier">xf</span><span class="plain">, </span><span class="identifier">filename_of_headings</span><span class="plain">, </span><span class="identifier">UTF8_ENC</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">Problems::Fatal::filename_related</span><span class="plain">(</span><span class="string">"Can't open headings file"</span><span class="plain">, </span><span class="identifier">filename_of_headings</span><span class="plain">);</span>
<span class="functiontext">Sentences::Headings::write_headings_as_xml_inner</span><span class="plain">(</span><span class="identifier">xf</span><span class="plain">);</span>
<span class="identifier">STREAM_CLOSE</span><span class="plain">(</span><span class="identifier">xf</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Sentences::Headings::write_headings_as_xml_inner</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
<span class="reserved">heading</span><span class="plain"> *</span><span class="identifier">h</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Write DTD indication for XML headings file</span> <span class="cwebmacronumber">34.1</span>&gt;<span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;plist version=\</span><span class="plain">"</span><span class="string">1.0\</span><span class="plain">"</span><span class="string">&gt;&lt;dict&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">INDENT</span><span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Application Version&lt;/key&gt;&lt;string&gt;%B (build %B)&lt;/string&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">, </span><span class="reserved">heading</span><span class="plain">) {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;%d&lt;/key&gt;&lt;dict&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-&gt;</span><span class="identifier">allocation_id</span><span class="plain">);</span>
<span class="identifier">INDENT</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Write the dictionary of properties for a single heading</span> <span class="cwebmacronumber">34.2</span>&gt;<span class="plain">;</span>
<span class="identifier">OUTDENT</span><span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;/dict&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">OUTDENT</span><span class="plain">;</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;/dict&gt;&lt;/plist&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Sentences::Headings::write_as_xml is used in 1/mr (<a href="1-mr.html#SP4_9">&#167;4.9</a>).</p>
<p class="endnote">The function Sentences::Headings::write_headings_as_xml_inner appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP34_1"></a><b>&#167;34.1. </b>We use a convenient Apple DTD:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Write DTD indication for XML headings file</span> <span class="cwebmacronumber">34.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;?xml version=\</span><span class="plain">"</span><span class="string">1.0\</span><span class="plain">"</span><span class="string"> encoding=\</span><span class="plain">"</span><span class="string">UTF-8\</span><span class="plain">"</span><span class="string">?&gt;\</span><span class="plain">n</span><span class="string">"</span>
<span class="string">"&lt;!DOCTYPE plist PUBLIC \</span><span class="plain">"</span><span class="string">-//Apple Computer//DTD PLIST 1.0//EN\</span><span class="plain">"</span><span class="string"> "</span>
<span class="string">"\</span><span class="plain">"</span><span class="string">http://www.apple.com/DTDs/PropertyList-1.0.dtd\</span><span class="plain">"</span><span class="string">&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP34">&#167;34</a>.</p>
<p class="inwebparagraph"><a id="SP34_2"></a><b>&#167;34.2. </b>Note that a level of 0, and a title of <code class="display"><span class="extract">--</span></code>, signifies a File (0) level
heading: external tools can probably ignore such records. Similarly, it is
unlikely that they will ever see a record without a "Filename" key &mdash;
this would mean a heading arising from text created internally within Inform,
which will only happen if someone has done something funny with <code class="display"><span class="extract">.i6t</span></code> files &mdash;
but should this arise then the best recourse is to ignore the heading.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Write the dictionary of properties for a single heading</span> <span class="cwebmacronumber">34.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">)</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Filename&lt;/key&gt;&lt;string&gt;%f&lt;/string&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">TextFromFiles::get_filename</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">file_of_origin</span><span class="plain">));</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Line&lt;/key&gt;&lt;integer&gt;%d&lt;/integer&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;start_location</span><span class="plain">.</span><span class="identifier">line_number</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain">))</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Title&lt;/key&gt;&lt;string&gt;%+W&lt;/string&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;heading_text</span><span class="plain">);</span>
<span class="reserved">else</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Title&lt;/key&gt;&lt;string&gt;--&lt;/string&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Level&lt;/key&gt;&lt;integer&gt;%d&lt;/integer&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;level</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"&lt;key&gt;Indentation&lt;/key&gt;&lt;integer&gt;%d&lt;/integer&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">h</span><span class="plain">-</span><span class="element">&gt;indentation</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP34">&#167;34</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="7-ss.html">Back to 'Structural Sentences'</a></li><li><a href="7-ns.html">Continue with 'Nonstructural Sentences'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>