1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 16:44:21 +03:00
inform7/docs/linguistics-module/5-np.html
2020-04-07 01:06:09 +01:00

714 lines
76 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>5/vm</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<nav role="navigation">
<h1><a href="../webs.html">Sources</a></h1>
<ul>
<li><a href="../compiler.html"><b>compiler tools</b></a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul>
<h2>Compiler Webs</h2>
<ul>
<li><a href="../inbuild/index.html">inbuild</a></li>
<li><a href="../inform7/index.html">inform7</a></li>
<li><a href="../inter/index.html">inter</a></li>
</ul>
<h2>Inbuild Modules</h2>
<ul>
<li><a href="../inbuild-module/index.html">inbuild</a></li>
<li><a href="../arch-module/index.html">arch</a></li>
<li><a href="../words-module/index.html">words</a></li>
<li><a href="../syntax-module/index.html">syntax</a></li>
<li><a href="../html-module/index.html">html</a></li>
</ul>
<h2>Inform7 Modules</h2>
<ul>
<li><a href="../core-module/index.html">core</a></li>
<li><a href="../problems-module/index.html">problems</a></li>
<li><a href="../inflections-module/index.html">inflections</a></li>
<li><a href="../linguistics-module/index.html">linguistics</a></li>
<li><a href="../kinds-module/index.html">kinds</a></li>
<li><a href="../if-module/index.html">if</a></li>
<li><a href="../multimedia-module/index.html">multimedia</a></li>
<li><a href="../index-module/index.html">index</a></li>
</ul>
<h2>Inter Modules</h2>
<ul>
<li><a href="../inter-module/index.html">inter</a></li>
<li><a href="../building-module/index.html">building</a></li>
<li><a href="../codegen-module/index.html">codegen</a></li>
</ul>
<h2>Foundation</h2>
<ul>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of '5/np' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../compiler.html">Compiler Modules</a></li><li><a href="index.html">linguistics</a></li><li><a href="index.html#5">Chapter 5: Diagramming Sentences</a></li><li><b>Noun Phrases</b></li></ul><p class="purpose">To construct noun-phrase subtrees for assertion sentences found in the parse tree.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Hierarchy of noun phrases</a></li><li><a href="#SP2">&#167;2. Creation</a></li><li><a href="#SP4">&#167;4. Raw nounphrases (NP1)</a></li><li><a href="#SP5">&#167;5. Articled nounphrases (NP2)</a></li><li><a href="#SP7">&#167;7. Balanced variants</a></li><li><a href="#SP8">&#167;8. List-divided nounphrases (NP3)</a></li><li><a href="#SP11">&#167;11. Worldly nounphrases (NP4)</a></li><li><a href="#SP18">&#167;18. Relationship nodes</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Hierarchy of noun phrases. </b>Noun phrase nodes are built at four levels of elaboration, which we take in
turn:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><ul class="items"><li>(NP1) Raw: where the text is entirely untouched and unannotated.
</li><li>(NP2) Articled: where any initial English article is converted to an annotation.
</li><li>(NP3) List-divided: where, in addition, a list is broken up into individual items.
</li><li>(NP4) Worldly: where, in addition, pronouns, relative phrases establishing
relationships and properties (and other grammar meaningful only for references
to physical objects and kinds) are parsed.
</li></ul>
</li></ul>
<p class="inwebparagraph">At levels (NP1) and (NP2), a NP produces a single <code class="display"><span class="extract">PROPER_NOUN_NT</span></code> node; at
level (NP3), the result is a subtree contining <code class="display"><span class="extract">PROPER_NOUN_NT</span></code> and <code class="display"><span class="extract">AND_NT</span></code>
nodes; but at level (NP4) this subtree may include any of <code class="display"><span class="extract">RELATIONSHIP_NT</span></code>,
<code class="display"><span class="extract">CALLED_NT</span></code>, <code class="display"><span class="extract">WITH_NT</span></code>, <code class="display"><span class="extract">AND_NT</span></code>, <code class="display"><span class="extract">KIND_NT</span></code> or <code class="display"><span class="extract">PROPER_NOUN_NT</span></code>.
</p>
<p class="inwebparagraph">Because a small proportion of noun phrase subtrees is thrown away, due to
backtracking on mistaken guesses at parsing of sentences, it is important
that creating an (NP) should have no side-effects beyond the construction
of the tree itself (and, of course, the memory used up, but we won't worry
about that: the proportion thrown away really is small).
</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. Creation. </b>The following macro is useful in the grammar below:
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">GENERATE_RAW_NP</span>
<span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = (</span><span class="identifier">preform_lookahead_mode</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)?(</span><span class="functiontext">NounPhrases::new_raw</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)):</span><span class="identifier">NULL</span>
</pre>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">NounPhrases::new_raw</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">parse_node</span><span class="plain"> *</span><span class="identifier">PN</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">PROPER_NOUN_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">nounphrase_article_ANNOT</span><span class="plain">, </span><span class="constant">NO_ART</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">PN</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="identifier">PN</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function NounPhrases::new_raw is used in <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>Other node types are generated as follows. Note that these make nothing in
lookahead mode; this prevents needless memory allocation.
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">NounPhrases::PN_void</span><span class="plain">(</span><span class="identifier">node_type_t</span><span class="plain"> </span><span class="identifier">t</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">if</span><span class="plain"> (</span><span class="identifier">preform_lookahead_mode</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">parse_node</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">P</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="identifier">P</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">NounPhrases::PN_single</span><span class="plain">(</span><span class="identifier">node_type_t</span><span class="plain"> </span><span class="identifier">t</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">parse_node</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">preform_lookahead_mode</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">parse_node</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
<span class="identifier">P</span><span class="plain">-&gt;</span><span class="identifier">down</span><span class="plain"> = </span><span class="identifier">A</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">P</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="identifier">node_type_t</span><span class="plain"> </span><span class="identifier">t</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">parse_node</span><span class="plain"> *</span><span class="identifier">A</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">B</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">preform_lookahead_mode</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">parse_node</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
<span class="identifier">P</span><span class="plain">-&gt;</span><span class="identifier">down</span><span class="plain"> = </span><span class="identifier">A</span><span class="plain">; </span><span class="identifier">P</span><span class="plain">-&gt;</span><span class="identifier">down</span><span class="plain">-&gt;</span><span class="identifier">next</span><span class="plain"> = </span><span class="identifier">B</span><span class="plain">;</span>
<span class="reserved">return</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 NounPhrases::PN_void is used in <a href="#SP15">&#167;15</a>, <a href="#SP17">&#167;17</a>.</p>
<p class="endnote">The function NounPhrases::PN_single is used in <a href="#SP17">&#167;17</a>.</p>
<p class="endnote">The function NounPhrases::PN_pair is used in <a href="#SP8">&#167;8</a>, <a href="#SP10">&#167;10</a>, <a href="#SP14">&#167;14</a>, <a href="#SP15">&#167;15</a>.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. Raw nounphrases (NP1). </b>A raw noun phrase can in principle be any nonempty wording:
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; ::=</span>
<span class="plain">... ==&gt; </span><span class="constant">GENERATE_RAW_NP</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Articled nounphrases (NP2). </b>Although, again, any text is acceptable, now we now take note of the definite
or indefinite article, and also of whether it's used in the singular or the
plural.
</p>
<p class="inwebparagraph">Note that unexpectedly upper-case articles are left well alone: this is why
</p>
<blockquote>
<p>On the table is a thing called A Town Called Alice.</p>
</blockquote>
<p class="inwebparagraph">creates an object called "A Town Called Alice", not an indefinitely-articled
one called "Town Called Alice". Articles are not removed if that would
leave the text empty.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">definite</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">definite</span><span class="plain">-</span><span class="identifier">article</span><span class="plain">&gt; &lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[2]</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">&gt; ::=</span>
<span class="plain">... | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</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">preform_lookahead_mode</span><span class="plain">; </span><span class="comment">match only when looking ahead</span>
<span class="plain">&lt;</span><span class="reserved">if</span><span class="plain">-</span><span class="identifier">not</span><span class="plain">-</span><span class="identifier">deliberately</span><span class="plain">-</span><span class="identifier">capitalised</span><span class="plain">&gt; &lt;</span><span class="identifier">indefinite</span><span class="plain">-</span><span class="identifier">article</span><span class="plain">&gt; &lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[3]; </span>&lt;<span class="cwebmacro">Annotate node by article</span> <span class="cwebmacronumber">5.1</span>&gt;<span class="plain">;</span>
<span class="plain">&lt;</span><span class="reserved">if</span><span class="plain">-</span><span class="identifier">not</span><span class="plain">-</span><span class="identifier">deliberately</span><span class="plain">-</span><span class="identifier">capitalised</span><span class="plain">&gt; &lt;</span><span class="identifier">definite</span><span class="plain">-</span><span class="identifier">article</span><span class="plain">&gt; &lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[3]; </span>&lt;<span class="cwebmacro">Annotate node by definite article</span> <span class="cwebmacronumber">5.2</span>&gt;<span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP5_1"></a><b>&#167;5.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Annotate node by article</span> <span class="cwebmacronumber">5.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">nounphrase_article_ANNOT</span><span class="plain">, </span><span class="constant">INDEF_ART</span><span class="plain">);</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">plural_reference_ANNOT</span><span class="plain">, (</span><span class="identifier">R</span><span class="plain">[2] &gt;= </span><span class="constant">3</span><span class="plain">)?</span><span class="identifier">TRUE:FALSE</span><span class="plain">);</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">gender_reference_ANNOT</span><span class="plain">, (</span><span class="identifier">R</span><span class="plain">[2] % </span><span class="constant">3</span><span class="plain">) + </span><span class="constant">1</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP5">&#167;5</a>.</p>
<p class="inwebparagraph"><a id="SP5_2"></a><b>&#167;5.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Annotate node by definite article</span> <span class="cwebmacronumber">5.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">nounphrase_article_ANNOT</span><span class="plain">, </span><span class="constant">DEF_ART</span><span class="plain">);</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">plural_reference_ANNOT</span><span class="plain">, (</span><span class="identifier">R</span><span class="plain">[2] &gt;= </span><span class="constant">3</span><span class="plain">)?</span><span class="identifier">TRUE:FALSE</span><span class="plain">);</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">gender_reference_ANNOT</span><span class="plain">, (</span><span class="identifier">R</span><span class="plain">[2] % </span><span class="constant">3</span><span class="plain">) + </span><span class="constant">1</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP5">&#167;5</a>.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>Sometimes we want to look at the article (if any) used in a raw NP, and
absorb that into annotations, removing it from the wording. For instance, in
</p>
<blockquote>
<p>On the table is a thing called a part of the broken box.</p>
</blockquote>
<p class="inwebparagraph">we want to remove the initial article from the calling-name to produce
"part of the broken box". (If we handled this NP as other than raw, we might
spuriously make a subtree with <code class="display"><span class="extract">RELATIONSHIP_NT</span></code> in thanks to the apparent
"part of" clause.)
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">NounPhrases::annotate_by_articles</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">RAW_NP</span><span class="plain">) {</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">&gt;(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">RAW_NP</span><span class="plain">));</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">MODEL</span><span class="plain"> = &lt;&lt;</span><span class="identifier">rp</span><span class="plain">&gt;&gt;;</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">RAW_NP</span><span class="plain">, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">MODEL</span><span class="plain">));</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">RAW_NP</span><span class="plain">, </span><span class="constant">nounphrase_article_ANNOT</span><span class="plain">,</span>
<span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">MODEL</span><span class="plain">, </span><span class="constant">nounphrase_article_ANNOT</span><span class="plain">));</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">RAW_NP</span><span class="plain">, </span><span class="constant">plural_reference_ANNOT</span><span class="plain">,</span>
<span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">MODEL</span><span class="plain">, </span><span class="constant">plural_reference_ANNOT</span><span class="plain">));</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">RAW_NP</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function NounPhrases::annotate_by_articles appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Balanced variants. </b>The balanced versions match any text in which brackets and braces are used in
a correctly paired way; otherwise they are the same.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">balanced</span><span class="plain">&gt; ::=</span>
<span class="plain">^&lt;</span><span class="identifier">balanced</span><span class="plain">-</span><span class="identifier">text</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">balanced</span><span class="plain">&gt; ::=</span>
<span class="plain">^&lt;</span><span class="identifier">balanced</span><span class="plain">-</span><span class="identifier">text</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. List-divided nounphrases (NP3). </b>An "articled list" matches text like
</p>
<blockquote>
<p>the lion, a witch, and some wardrobes</p>
</blockquote>
<p class="inwebparagraph">as a list of three articled noun phrases.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ::=</span>
<span class="plain">... | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</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">preform_lookahead_mode</span><span class="plain">; </span><span class="comment">match only when looking ahead</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">balanced</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="constant">AND_NT</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[2]), </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[2])</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; ::=</span>
<span class="plain">, {</span><span class="identifier">_and</span><span class="plain">} &lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">{</span><span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain">} &lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b>That builds into a lopsided binary tree: thus "the lion, a witch,
and some wardrobes" becomes
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">AND_NT ","</span>
<span class="plain"> PROPERTY_LIST_NT "lion" article:definite</span>
<span class="plain"> AND_NT ", and"</span>
<span class="plain"> PROPERTY_LIST_NT "witch" article:indefinite</span>
<span class="plain"> PROPERTY_LIST_NT "wardrobe" article:indefinite pluralreference:true</span>
</pre>
<p class="inwebparagraph">The binary structure is chosen since it allows us to use a simple recursion
to run through possibilities, and also to preserve each connective of the text
in the <code class="display"><span class="extract">AND_NT</span></code> nodes.
</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>Alternative lists divide up at "or". Thus
</p>
<blockquote>
<p>voluminous, middling big or poky</p>
</blockquote>
<p class="inwebparagraph">becomes a tree of three (raw) noun phrases.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">alternative</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ::=</span>
<span class="plain">... | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</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">preform_lookahead_mode</span><span class="plain">; </span><span class="comment">match only when looking ahead</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">balanced</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">alternative</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="constant">AND_NT</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[2]), </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[2])</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">alternative</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; ::=</span>
<span class="plain">, {</span><span class="identifier">_or</span><span class="plain">} &lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">alternative</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">{</span><span class="identifier">_</span><span class="plain">,/</span><span class="identifier">or</span><span class="plain">} &lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">alternative</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Worldly nounphrases (NP4). </b>That just leaves the big one. It comes in two versions, for the object and
subject NPs of a regular sentence, but they are almost exactly the same. They
differ slightly, as we'll see, in the handling of relative phrases; when
parsing a sentence such as
</p>
<blockquote>
<p>X is Y</p>
</blockquote>
<p class="inwebparagraph">Inform uses &lt;nounphrase-as-subject&gt; on X and &lt;nounphrase-as-object&gt; on Y. Both
of these make use of the recursive &lt;np-inner&gt; grammar, and the difference
in effect is that at the topmost level of recursion the as-subject version
allows only limited RPs, not unlimited ones. (In languages other than English,
we might want bigger differences, with X read in the nominative and Y in the
accusative.)
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">as</span><span class="plain">-</span><span class="identifier">object</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">as</span><span class="plain">-</span><span class="identifier">subject</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="reserved">if</span><span class="plain">-</span><span class="identifier">not</span><span class="plain">-</span><span class="identifier">deliberately</span><span class="plain">-</span><span class="identifier">capitalised</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">limited</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[2]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">-</span><span class="identifier">without</span><span class="plain">-</span><span class="identifier">rp</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">nounphrase</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="reserved">if</span><span class="plain">-</span><span class="identifier">not</span><span class="plain">-</span><span class="identifier">deliberately</span><span class="plain">-</span><span class="identifier">capitalised</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">unlimited</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[2]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">-</span><span class="identifier">without</span><span class="plain">-</span><span class="identifier">rp</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b>So here we go with relative phrases. We've already seen that our two general
forms of NP differ only in the range of RPs allowed at the top level: here we
see, furthermore, that the only limitation is that in the subject of an
assertion sentence, a RP can't be introduced with what seems to be a participle.
</p>
<p class="inwebparagraph">It might seem grammatically odd to be parsing RPs as the subject side of a
sentence, when they surely ought to belong to the VP rather than either of the
NPs. But English is, in fact, odd this way: it allows indicative statements,
but no other sentences, to use "subject-verb inversion". An assertion such as
</p>
<blockquote>
<p>In the Garden is a tortoise.</p>
</blockquote>
<p class="inwebparagraph">is impossible to parse with a naive grammar for relative phrases, because
the "in" is miles away from its governing verb "is". (This quirk is called an
inversion since the sentence is equivalent to the easier to construe
"A tortoise is in the Garden".) This is why we want to parse subject NPs
and object NPs symmetrically, and allow either one to be an RP instead.
</p>
<p class="inwebparagraph">And yet subject-verb inversion can't be allowed in all cases, though; we might
pedantically argue that the Yoda-like utterance
</p>
<blockquote>
<p>Holding the light sabre is the young Jedi.</p>
</blockquote>
<p class="inwebparagraph">is grammatically correct, but if so then we have to read
</p>
<blockquote>
<p>Holding Area is a room.</p>
</blockquote>
<p class="inwebparagraph">as a statement that a room is holding something called "Area", which then
causes Inform to throw problem messages about confusion between people and
rooms (since only people can hold things). So we forbid subject-verb inversion
in the case of a participle like "holding".
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">limited</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">implicit</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">probable</span><span class="plain">-</span><span class="identifier">participle</span><span class="plain">&gt; *** | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">explicit</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">unlimited</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">implicit</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">explicit</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>Finally, we define what we mean by implicit and explicit relative phrases.
As examples, the right-hand sides of:
</p>
<blockquote>
<p>The lawnmower is in the Garden.</p>
</blockquote>
<blockquote>
<p>The giraffe is here.</p>
</blockquote>
<p class="inwebparagraph">are explicit and implicit respectively. Implicit RPs are those where the
relationship is with something unstated. For instance, "here" generally means
a containment by the room currently being discussed; "carried" implies that
the player does the carrying.
</p>
<p class="inwebparagraph">Note that we throw out a relative phrase if the noun phrase within it would
begin with "and" or a comma; this enables us to parse sentences concerning
directions, in particular, a little better.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">relative</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">explicit</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">permitted</span><span class="plain">-</span><span class="identifier">preposition</span><span class="plain">&gt; </span><span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain"> ... | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">permitted</span><span class="plain">-</span><span class="identifier">preposition</span><span class="plain">&gt; </span><span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain"> | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain">;</span>
<span class="plain">&lt;</span><span class="identifier">permitted</span><span class="plain">-</span><span class="identifier">preposition</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">-</span><span class="identifier">without</span><span class="plain">-</span><span class="identifier">rp</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; </span>&lt;<span class="cwebmacro">Work out a meaning</span> <span class="cwebmacronumber">13.1</span>&gt;<span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP13_1"></a><b>&#167;13.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Work out a meaning</span> <span class="cwebmacronumber">13.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="constant">VERB_MEANING_TYPE</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VerbMeanings::get_relational_meaning</span><span class="plain">(</span>
<span class="functiontext">Verbs::regular_meaning</span><span class="plain">(</span><span class="identifier">permitted_verb_identity</span><span class="plain">, </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">NULL</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R</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">FALSE</span><span class="plain">;</span>
<span class="plain">*</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_rel</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="functiontext">VerbMeanings::reverse_VMT</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">), -1, </span><span class="identifier">RP</span><span class="plain">[2]);</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. </b>Now the heart of it. There are basically seven constructions which can make
complex NPs from simple ones: we've already seen one of these, the relative
phrase. The sequence of checking these is very important, because it decides
which clauses are represented higher in the parse tree when multiple structures
are present within the NP. For instance, we want to turn
</p>
<blockquote>
<p>[A] in a container called the flask and cap with flange</p>
</blockquote>
<p class="inwebparagraph">into the subtree:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">RELATIONSHIP_NT "in" = containment</span>
<span class="plain"> CALLED_NT "called"</span>
<span class="plain"> PROPER_NOUN_NT "container" article:indefinite</span>
<span class="plain"> PROPER_NOUN_NT "flask and cap with flange" article:definite</span>
</pre>
<p class="inwebparagraph">but we also want:
</p>
<blockquote>
<p>[B] in a container with carrying capacity 10 and diameter 12</p>
</blockquote>
<pre class="display">
<span class="plain">RELATIONSHIP_NT "in" = containment</span>
<span class="plain"> WITH_NT "with"</span>
<span class="plain"> PROPER_NOUN_NT "container" article:indefinite</span>
<span class="plain"> AND_NT "and"</span>
<span class="plain"> PROPERTY_LIST_NT "carrying capacity 10"</span>
<span class="plain"> PROPERTY_LIST_NT "diameter 12"</span>
</pre>
<p class="inwebparagraph">These two cases together force our conventions: from sentence [A] we see
that initial relative clauses (in) must beat callings ("called") which
must beat property clauses ("with"), while from [B] we see that property
clauses must beat lists ("and"). These all have to beat "of" and
"from", which seem to be about linguistically equal, because these
constructions must be easily reversible, as we shall see, and the best way
to ensure that is to make sure they can only appear right down close to
leaves in the tree. This dictates
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">RELATIONSHIP_NT &gt; CALLED_NT &gt; WITH_NT &gt; AND_NT</span>
</pre>
<p class="inwebparagraph">in the sense that a subtree construction higher in this chain will take
precedence over (and therefore be higher up in the tree than) one that is
lower. That leaves just the seventh construction: "kind of ...". To
avoid misreading this as an "of", and to protect "called", we need
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">CALLED_NT &gt; KIND_NT</span>
</pre>
<p class="inwebparagraph">but otherwise we are fairly free where to put it (though the resulting trees
will take different shapes in some cases if we move it around, we could
write code which handled any of the outcomes about equally well). In fact,
we choose to make it lowest possible, so the final precedence order is:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">RELATIONSHIP_NT &gt; CALLED_NT &gt; WITH_NT &gt; AND_NT &gt; KIND_NT</span>
</pre>
<p class="inwebparagraph">Once all possible constructions have been recursively exhausted, every leaf we
end up at is treated as a balanced articled NP. (Thus &lt;np-inner&gt; fails on
source text where brackets aren't balanced, such as "smile X-)". This is why
&lt;nounphrase-as-object&gt; above resorts to using &lt;nounphrase-articled&gt; if
&lt;np-inner&gt; should fail. The reason we want &lt;np-inner&gt; to require balance is
that otherwise "called" clauses can be misread: "frog (called toad)" can be
misread as saying that "frog (" is called "toad )".)
</p>
<p class="inwebparagraph">Two technicalities to note about the following nonterminal. Production (a)
exists to accept arbitrary text quickly and without allocating memory to hold
parse nodes when the Preform parser is simply performing a lookahead (to see
where it will eventually parse). This is a very important economy: without it,
parsing a list of n items will have running time and space requirements of
order 2^n. But during regular parsing, production (a) has no effect, and can
be ignored. Secondly, note the ampersand notation: recall that
<code class="display"><span class="extract">&amp;whatever</span></code> at the start of production means "only try this production if the
word <code class="display"><span class="extract">whatever</span></code> is somewhere in the text we're looking at". Again, it's a
speed optimisation, and doesn't affect the language's definition.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">-</span><span class="identifier">without</span><span class="plain">-</span><span class="identifier">rp</span><span class="plain">&gt; ::=</span>
<span class="plain">... | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</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">preform_lookahead_mode</span><span class="plain">; </span><span class="comment">match only when looking ahead</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; {</span><span class="identifier">called</span><span class="plain">} &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">balanced</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="constant">CALLED_NT</span><span class="plain">, </span><span class="identifier">WR</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[2])</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">with</span><span class="plain">-</span><span class="identifier">or</span><span class="plain">-</span><span class="identifier">having</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="constant">WITH_NT</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[2]), </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[2])</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">and</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="constant">AND_NT</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[2]), </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[2])</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">nominative</span><span class="plain">-</span><span class="identifier">pronoun</span><span class="plain">&gt; | ==&gt; </span><span class="constant">GENERATE_RAW_NP</span><span class="plain">; </span><span class="identifier">ParseTree::annotate_int</span><span class="plain">(*</span><span class="identifier">XP</span><span class="plain">, </span><span class="constant">nounphrase_article_ANNOT</span><span class="plain">, </span><span class="constant">IT_ART</span><span class="plain">);</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">articled</span><span class="plain">-</span><span class="identifier">balanced</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. </b>The tail of with-or-having parses for instance "with carrying capacity 5"
in the NP
</p>
<blockquote>
<p>a container with carrying capacity 5</p>
</blockquote>
<p class="inwebparagraph">This makes use of a nifty feature of Preform: when Preform scans to see how to
divide the text, it tries &lt;np-with-or-having-tail&gt; in each possible position.
The reply can be yes, no, or no and move on a little. So if we spot "it with
action", the answer is no, and move on three words: that jumps over a "with"
which we don't want to recognise. (Because if we did, then "the locking it
with action" would be parsed as a property list, "action", attaching to a
bogus object called "locking it".)
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">with</span><span class="plain">-</span><span class="identifier">or</span><span class="plain">-</span><span class="identifier">having</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; ::=</span>
<span class="identifier">it</span><span class="plain"> </span><span class="identifier">with</span><span class="plain"> </span><span class="identifier">action</span><span class="plain"> *** | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain"> + </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]) - </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="plain">{</span><span class="identifier">with</span><span class="plain">/</span><span class="identifier">having</span><span class="plain">} (/) *** | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain"> + </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]) - </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="plain">{</span><span class="identifier">with</span><span class="plain">/</span><span class="identifier">having</span><span class="plain">} ... ( &lt;</span><span class="identifier">response</span><span class="plain">-</span><span class="identifier">letter</span><span class="plain">&gt; ) | ==&gt; </span><span class="constant">0</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FAIL_NONTERMINAL</span><span class="plain"> + </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]) - </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="plain">{</span><span class="identifier">with</span><span class="plain">/</span><span class="identifier">having</span><span class="plain">} &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">WR</span><span class="plain">[1]); *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ::=</span>
<span class="plain">... | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</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">preform_lookahead_mode</span><span class="plain">; </span><span class="comment">match only when looking ahead</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_pair</span><span class="plain">(</span><span class="constant">AND_NT</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[2]), </span><span class="identifier">RP</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[2])</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1];</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">&gt; ::=</span>
<span class="plain">... ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_void</span><span class="plain">(</span><span class="constant">PROPERTY_LIST_NT</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; ::=</span>
<span class="plain">, {</span><span class="identifier">_and</span><span class="plain">} &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">{</span><span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain">} &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">new</span><span class="plain">-</span><span class="identifier">property</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">&gt; ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b>The "and" tail is much easier:
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">and</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">&gt; ::=</span>
<span class="plain">, {</span><span class="identifier">_and</span><span class="plain">} &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; | ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">{</span><span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain">} &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; ==&gt; </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); *</span><span class="identifier">XP</span><span class="plain">= </span><span class="identifier">RP</span><span class="plain">[1]</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. </b>Kind phrases are easier:
</p>
<blockquote>
<p>A sedan chair is a kind of vehicle. A weather pattern is a kind.</p>
</blockquote>
<p class="inwebparagraph">Note that indefinite articles are permitted before the word "kind(s)",
but definite articles are not.
</p>
<pre class="display">
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">&gt; ::=</span>
<span class="plain">&lt;</span><span class="identifier">indefinite</span><span class="plain">-</span><span class="identifier">article</span><span class="plain">&gt; &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">unarticled</span><span class="plain">&gt; | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[2]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">unarticled</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="identifier">RP</span><span class="plain">[1]</span>
<span class="plain">&lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">-</span><span class="identifier">phrase</span><span class="plain">-</span><span class="identifier">unarticled</span><span class="plain">&gt; ::=</span>
<span class="identifier">kind</span><span class="plain">/</span><span class="identifier">kinds</span><span class="plain"> | ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_void</span><span class="plain">(</span><span class="constant">KIND_NT</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">)</span>
<span class="identifier">kind</span><span class="plain">/</span><span class="identifier">kinds</span><span class="plain"> </span><span class="identifier">of</span><span class="plain"> &lt;</span><span class="identifier">np</span><span class="plain">-</span><span class="identifier">inner</span><span class="plain">&gt; ==&gt; </span><span class="constant">0</span><span class="plain">; *</span><span class="identifier">XP</span><span class="plain"> = </span><span class="functiontext">NounPhrases::PN_single</span><span class="plain">(</span><span class="constant">KIND_NT</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">RP</span><span class="plain">[1])</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. Relationship nodes. </b>A modest utility routine to construct and annotation RELATIONSHIP nodes.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">STANDARD_RELN</span><span class="plain"> </span><span class="constant">0</span><span class="plain"> </span><span class="comment">the default annotation value: never explicitly set</span>
<span class="definitionkeyword">define</span> <span class="constant">PARENTAGE_HERE_RELN</span><span class="plain"> </span><span class="constant">1</span><span class="plain"> </span><span class="comment">only ever set by the Spatial plugin</span>
<span class="definitionkeyword">define</span> <span class="constant">DIRECTION_RELN</span><span class="plain"> </span><span class="constant">2</span>
</pre>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">NounPhrases::PN_rel</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="constant">VERB_MEANING_TYPE</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">reln_type</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">referent</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">preform_lookahead_mode</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">parse_node</span><span class="plain"> *</span><span class="identifier">P</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">RELATIONSHIP_NT</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">CORE_MODULE</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R</span><span class="plain">) </span><span class="identifier">ParseTree::set_relationship</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">reln_type</span><span class="plain"> &gt;= </span><span class="constant">0</span><span class="plain">)</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">P</span><span class="plain">, </span><span class="constant">relationship_node_type_ANNOT</span><span class="plain">, </span><span class="identifier">reln_type</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"undefined relationship node"</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">referent</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">referent</span><span class="plain"> = </span><span class="functiontext">NounPhrases::new_raw</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">referent</span><span class="plain">, </span><span class="constant">implicitly_refers_to_ANNOT</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">P</span><span class="plain">-&gt;</span><span class="identifier">down</span><span class="plain"> = </span><span class="identifier">referent</span><span class="plain">;</span>
<span class="reserved">return</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 NounPhrases::PN_rel is used in <a href="#SP13_1">&#167;13.1</a>, 5/vp (<a href="5-vp.html#SP9_1">&#167;9.1</a>).</p>
<hr class="tocbar">
<ul class="toc"><li><a href="5-vm.html">Back to 'Verb Meanings'</a></li><li><a href="5-vp.html">Continue with 'Verb Phrases'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>
</html>