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/14-cn.html
2019-08-31 13:56:36 +01:00

507 lines
57 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>14/lv</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 '14/cn' 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#14">Chapter 14: Specifications</a></li><li><b>Conditions</b></li></ul><p class="purpose">Utility functions for condition nodes.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Creation</a></li><li><a href="#SP12">&#167;12. Pretty-printing</a></li><li><a href="#SP14">&#167;14. Specificity</a></li><li><a href="#SP16">&#167;16. Compiling</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Creation. </b>In Inform, conditions are not values, nor can values be used directly as
conditions: we therefore need to provide the logical operations of AND, OR,
and NOT structurally via the SP rather than implementing them as phrases
like the arithmetic operators. (Conditions and values are kept separate
even though it does complicate the type system because this provides
cleaner resolution of ambiguities, and I don't repent of this, because the
mixture of the two is sometimes unclear enough even in C: in natural
language, it tends to look very odd indeed.)
</p>
<p class="inwebparagraph">So <code class="display"><span class="extract">LOGICAL_AND_NT</span></code> and <code class="display"><span class="extract">LOGICAL_OR_NT</span></code> imitate the effect of logical
operators. They have two arguments which must themselves be CONDITIONs;
and similarly for the unary <code class="display"><span class="extract">LOGICAL_NOT_NT</span></code>. A unique feature of Inform
among programming languages is that it has a fourth: <code class="display"><span class="extract">LOGICAL_TENSE_NT</span></code>,
which expresses that a condition holds at a different time from the present.
</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b><code class="display"><span class="extract">TEST_PROPOSITION_NT</span></code> contains a predicate calculus sentence in the
<code class="display"><span class="extract">proposition</span></code> field of its SP: there are no arguments.
</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b><code class="display"><span class="extract">TEST_PHRASE_OPTION_NT</span></code> tests the use of a phrase option, and is the
actual SP parsed for the second usage of the word "thoroughly" in
the following example:
</p>
<blockquote>
<p>To prognosticate, swiftly or thoroughly: ...; if thoroughly, ...</p>
</blockquote>
<p class="inwebparagraph">It uses the SP's data field to refer to the option in question: its value is the
bitmap value of the option, which will usually be 2^n where the option
is the n-th in the list for this phrase, counting upwards from 0.
</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b><code class="display"><span class="extract">TEST_VALUE_NT</span></code> tests the value beneath it in a condition context. For
truth state values, this does the obvious thing: <code class="display"><span class="extract">true</span></code> passes and
<code class="display"><span class="extract">false</span></code> fails. For stored actions or descriptions of actions, the current
action is tested to see if it matches.
</p>
<p class="inwebparagraph">For constant descriptions, whatever is currently being discussed (the I6 value
<code class="display"><span class="extract">self</span></code>, generally speaking) is tested to see if it matches. But in order to
make definitions like this one work, we also need to treat descriptions as
values:
</p>
<blockquote>
<p>To decide which number is total (P - property) of (D - description):</p>
</blockquote>
<p class="inwebparagraph">The way this is done is that type-checking a description (say, "closed doors
in lighted rooms") against the expectation of finding the kind constructor
"description of K" forces Inform to convert it to a constant of that type,
compiling it as an iterator routine in I6 capable of (among other things)
supplying the members in turn, and then using the address of this routine as
the actual I6 value. (Constants with the kind "description of K" cannot arise
in any other way.)
</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>Now some creator routines.
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new</span><span class="plain">(</span><span class="identifier">time_period</span><span class="plain"> *</span><span class="identifier">tp</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">TEST_PROPOSITION_NT</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Occurrence::get_tense</span><span class="plain">(</span><span class="identifier">tp</span><span class="plain">) != </span><span class="identifier">IS_TENSE</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tense improperly applied"</span><span class="plain">);</span>
<span class="functiontext">Conditions::attach_historic_requirement</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="identifier">tp</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::new appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>So, some more specific creators. The operators are easy:
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new_LOGICAL_AND</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec1</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec2</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">LOGICAL_AND_NT</span><span class="plain">);</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="identifier">spec1</span><span class="plain">;</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain"> = </span><span class="identifier">spec2</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new_LOGICAL_OR</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec1</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec2</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">LOGICAL_OR_NT</span><span class="plain">);</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="identifier">spec1</span><span class="plain">;</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain"> = </span><span class="identifier">spec2</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::new_LOGICAL_AND is used in 10/cap (<a href="10-cap.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function Conditions::new_LOGICAL_OR is used in 10/cap (<a href="10-cap.html#SP2">&#167;2</a>).</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b></p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::negate</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">cond</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">, </span><span class="constant">LOGICAL_NOT_NT</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">cond</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new_with_words</span><span class="plain">(</span><span class="constant">LOGICAL_NOT_NT</span><span class="plain">, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">));</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::negate is used in 10/varc (<a href="10-varc.html#SP13_3">&#167;13.3</a>), 10/cap (<a href="10-cap.html#SP4">&#167;4</a>, <a href="10-cap.html#SP5">&#167;5</a>).</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>Testing propositions is also straightforward. There's no creator for
<code class="display"><span class="extract">NOW_PREPOSITION_VNT</span></code>, since this is formed only by coercion of one of these.
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new_TEST_PROPOSITION</span><span class="plain">(</span><span class="reserved">pcalc_prop</span><span class="plain"> *</span><span class="identifier">prop</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">TEST_PROPOSITION_NT</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_proposition</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="identifier">prop</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::new_TEST_PROPOSITION is used in 10/varc (<a href="10-varc.html#SP13_3">&#167;13.3</a>).</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b>The option number here is actually 2^i, where 0&lt;= i&lt;15. This is just
exactly feasible, since the specification data field is 16 bits wide.
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new_TEST_PHRASE_OPTION</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">opt_num</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new</span><span class="plain">(</span><span class="constant">TEST_PHRASE_OPTION_NT</span><span class="plain">);</span>
<span class="identifier">ParseTree::annotate_int</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="constant">phrase_option_ANNOT</span><span class="plain">, </span><span class="identifier">opt_num</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::new_TEST_PHRASE_OPTION is used in 10/cap (<a href="10-cap.html#SP6">&#167;6</a>).</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b></p>
<pre class="display">
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new_TEST_ACTION</span><span class="plain">(</span><span class="identifier">action_pattern</span><span class="plain"> *</span><span class="identifier">ap</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">ap</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">"null action pattern"</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new_with_words</span><span class="plain">(</span><span class="constant">TEST_VALUE_NT</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">);</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="functiontext">Rvalues::from_action_pattern</span><span class="plain">(</span><span class="identifier">ap</span><span class="plain">);</span>
<span class="identifier">ParseTree::set_text</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</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">spec</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="plain">#</span><span class="identifier">ifndef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::new_TEST_ACTION</span><span class="plain">(</span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">ap</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">internal_error</span><span class="plain">(</span><span class="string">"can't make test action without IF module"</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="plain">#</span><span class="identifier">endif</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Conditions::is_TEST_ACTION</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain">) {</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="constant">TEST_VALUE_NT</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">Rvalues::to_action_pattern</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</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="identifier">endif</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">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::action_tested</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain">) {</span>
<span class="plain">#</span><span class="identifier">ifdef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Conditions::is_TEST_ACTION</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"action improperly extracted"</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="plain">#</span><span class="identifier">ifndef</span><span class="plain"> </span><span class="identifier">IF_MODULE</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"can't perform action_tested without IF module"</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="identifier">endif</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::new_TEST_ACTION is used in 10/teav (<a href="10-teav.html#SP23">&#167;23</a>), 10/cap (<a href="10-cap.html#SP3">&#167;3</a>, <a href="10-cap.html#SP7">&#167;7</a>, <a href="10-cap.html#SP8_1">&#167;8.1</a>), 25/pi (<a href="25-pi.html#SP5_1">&#167;5.1</a>).</p>
<p class="endnote">The function Conditions::new_TEST_ACTION is used in 10/teav (<a href="10-teav.html#SP23">&#167;23</a>), 10/cap (<a href="10-cap.html#SP3">&#167;3</a>, <a href="10-cap.html#SP7">&#167;7</a>, <a href="10-cap.html#SP8_1">&#167;8.1</a>), 25/pi (<a href="25-pi.html#SP5_1">&#167;5.1</a>).</p>
<p class="endnote">The function Conditions::is_TEST_ACTION is used in <a href="#SP16">&#167;16</a>, 10/aots (<a href="10-aots.html#SP10">&#167;10</a>), 11/sm (<a href="11-sm.html#SP16">&#167;16</a>), 14/ds2 (<a href="14-ds2.html#SP19_5_1">&#167;19.5.1</a>), 18/lc (<a href="18-lc.html#SP8">&#167;8</a>).</p>
<p class="endnote">The function Conditions::action_tested is used in <a href="#SP16">&#167;16</a>, 11/sm (<a href="11-sm.html#SP16">&#167;16</a>).</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b>Since, in principle, any condition might also have a time period attached
to it, we need a follow-up routine to attach this as necessary to a newly
created condition:
</p>
<pre class="display">
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::attach_tense</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">cond</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">t</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">, </span><span class="constant">LOGICAL_TENSE_NT</span><span class="plain">)) {</span>
<span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">;</span>
<span class="identifier">Occurrence::set_tense</span><span class="plain">(</span><span class="identifier">ParseTree::get_condition_tense</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">), </span><span class="identifier">t</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new_with_words</span><span class="plain">(</span><span class="constant">LOGICAL_TENSE_NT</span><span class="plain">, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">));</span>
<span class="identifier">ParseTree::set_condition_tense</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="identifier">Occurrence::store</span><span class="plain">(</span><span class="identifier">Occurrence::new_tense_marker</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">)));</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Conditions::attach_historic_requirement</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">cond</span><span class="plain">, </span><span class="identifier">time_period</span><span class="plain"> *</span><span class="identifier">tp</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">, </span><span class="identifier">AMBIGUITY_NT</span><span class="plain">)) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">amb</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">cond</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">; </span><span class="identifier">cond</span><span class="plain">; </span><span class="identifier">cond</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">-&gt;</span><span class="identifier">next_alternative</span><span class="plain">) {</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">reading</span><span class="plain"> = </span><span class="identifier">ParseTree::duplicate</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">);</span>
<span class="identifier">reading</span><span class="plain">-&gt;</span><span class="identifier">next_alternative</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">reading</span><span class="plain"> = </span><span class="functiontext">Conditions::attach_historic_requirement</span><span class="plain">(</span><span class="identifier">reading</span><span class="plain">, </span><span class="identifier">tp</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">reading</span><span class="plain">, </span><span class="constant">UNKNOWN_NT</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="identifier">amb</span><span class="plain"> = </span><span class="identifier">ParseTree::add_possible_reading</span><span class="plain">(</span><span class="identifier">amb</span><span class="plain">,</span>
<span class="identifier">reading</span><span class="plain">, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">amb</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">t</span><span class="plain"> = </span><span class="identifier">IS_TENSE</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">, </span><span class="constant">LOGICAL_TENSE_NT</span><span class="plain">)) {</span>
<span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">;</span>
<span class="identifier">t</span><span class="plain"> = </span><span class="identifier">Occurrence::get_tense</span><span class="plain">(</span><span class="identifier">ParseTree::get_condition_tense</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">));</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">ParseTree::new_with_words</span><span class="plain">(</span><span class="constant">LOGICAL_TENSE_NT</span><span class="plain">, </span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">cond</span><span class="plain">));</span>
<span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain"> = </span><span class="identifier">cond</span><span class="plain">;</span>
<span class="identifier">t</span><span class="plain"> = </span><span class="identifier">IS_TENSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">ParseTree::set_condition_tense</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="identifier">tp</span><span class="plain">);</span>
<span class="identifier">Occurrence::set_tense</span><span class="plain">(</span><span class="identifier">ParseTree::get_condition_tense</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">), </span><span class="identifier">t</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">spec</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::attach_tense is used in 10/varc (<a href="10-varc.html#SP13_3">&#167;13.3</a>), 10/cap (<a href="10-cap.html#SP8_1">&#167;8.1</a>).</p>
<p class="endnote">The function Conditions::attach_historic_requirement is used in <a href="#SP5">&#167;5</a>, 10/cap (<a href="10-cap.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. Pretty-printing. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Conditions::write_out_in_English</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Specifications::is_description</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">)) {</span>
<span class="functiontext">Descriptions::write_out_in_English</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">spec</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="constant">TEST_VALUE_NT</span><span class="plain">)) &amp;&amp; (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">, </span><span class="constant">CONSTANT_NT</span><span class="plain">))) {</span>
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="functiontext">Specifications::to_kind</span><span class="plain">(</span><span class="identifier">spec</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">K</span><span class="plain">) {</span>
<span class="identifier">Kinds::Textual::write_articled</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">K</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"a condition"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::write_out_in_English is used in 14/sp (<a href="14-sp.html#SP6">&#167;6</a>).</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>And the log:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Conditions::log</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_condition_tense</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">))</span>
<span class="identifier">Occurrence::log</span><span class="plain">(</span><span class="identifier">DL</span><span class="plain">, </span><span class="identifier">ParseTree::get_condition_tense</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">, </span><span class="constant">TEST_PROPOSITION_NT</span><span class="plain">))</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"(test: $D)"</span><span class="plain">, </span><span class="functiontext">Specifications::to_proposition</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">));</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Specifications::is_description</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">)) {</span>
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"(st: $D)"</span><span class="plain">, </span><span class="functiontext">Descriptions::to_proposition</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::log is used in 7/ptu (<a href="7-ptu.html#SP17_1">&#167;17.1</a>).</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. Specificity. </b>We will need a way of determining which of two conditions is more complex,
so that action-based rules with "when..." clauses tacked on can be sorted:
the following is used to compare such "when..." conditions.
</p>
<p class="inwebparagraph">This is essentially a counting argument. Long conditions, with many clauses,
beat shorter ones.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Conditions::compare_specificity_of_CONDITIONs</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec1</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">spec1</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) &amp;&amp; (</span><span class="identifier">spec2</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">count1</span><span class="plain"> = </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">spec1</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">count2</span><span class="plain"> = </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">spec2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">count1</span><span class="plain"> &gt; </span><span class="identifier">count2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 1;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">count1</span><span class="plain"> &lt; </span><span class="identifier">count2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> -1;</span>
<span class="reserved">return</span><span class="plain"> 0;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::compare_specificity_of_CONDITIONs appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. </b>The only justification for the following complexity score is that it does
seem to accord well with what people expect. (There's clearly no theoretically
perfect way to define complexity of conditions in a language as complex as
Inform; this bit of scruffy, rather than neat, logic will have to do.)
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">spec</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">ParseTreeUsage::is_condition</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 1;</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">)) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">LOGICAL_AND_NT</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">)</span>
<span class="plain">+ </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain">);</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">LOGICAL_OR_NT</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> -1;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">LOGICAL_NOT_NT</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">);</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">LOGICAL_TENSE_NT</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Conditions::count</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">);</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">TEST_PROPOSITION_NT</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Calculus::Propositions::length</span><span class="plain">(</span><span class="functiontext">Specifications::to_proposition</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">));</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">TEST_PHRASE_OPTION_NT</span><span class="plain">:</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">TEST_VALUE_NT</span><span class="plain">:</span>
<span class="reserved">return</span><span class="plain"> 1;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> 0;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::count is used in <a href="#SP14">&#167;14</a>, 21/ac (<a href="21-ac.html#SP9">&#167;9</a>).</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. Compiling. </b>We clear two oddball cases out of the way, and then for the most part we
delegate to potent routines elsewhere. Note that in some situations a valid
I6 condition must be enclosed in round brackets, and that a redundant pair
of brackets never does any harm; so we always compile one.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Conditions::compile</span><span class="plain">(</span><span class="identifier">value_holster</span><span class="plain"> *</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">spec_found</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">)) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">TEST_PROPOSITION_NT</span><span class="plain">:</span>
<span class="functiontext">Calculus::Deferrals::emit_test_of_proposition</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">,</span>
<span class="functiontext">Specifications::to_proposition</span><span class="plain">(</span><span class="identifier">spec_found</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">LOGICAL_TENSE_NT</span><span class="plain">:</span>
<span class="functiontext">Chronology::compile_past_tense_condition</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">, </span><span class="identifier">spec_found</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">LOGICAL_NOT_NT</span><span class="plain">: </span>&lt;<span class="cwebmacro">Compile a logical negation</span> <span class="cwebmacronumber">16.1</span>&gt;<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">LOGICAL_AND_NT</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="constant">LOGICAL_OR_NT</span><span class="plain">: </span>&lt;<span class="cwebmacro">Compile a logical operator</span> <span class="cwebmacronumber">16.2</span>&gt;<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">TEST_VALUE_NT</span><span class="plain">: {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Conditions::is_TEST_ACTION</span><span class="plain">(</span><span class="identifier">spec_found</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">action_pattern</span><span class="plain"> *</span><span class="identifier">ap</span><span class="plain"> = </span><span class="functiontext">Rvalues::to_action_pattern</span><span class="plain">(</span>
<span class="functiontext">Conditions::action_tested</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">));</span>
<span class="identifier">PL::Actions::Patterns::compile_pattern_match</span><span class="plain">(</span><span class="identifier">VH</span><span class="plain">, *</span><span class="identifier">ap</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
<span class="plain">#</span><span class="identifier">endif</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">Specifications::is_description</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">)) {</span>
<span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, 1); </span> <span class="comment">purely for problem recovery</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="functiontext">Specifications::Compiler::emit_as_val</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">spec_found</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">TEST_PHRASE_OPTION_NT</span><span class="plain">: </span>&lt;<span class="cwebmacro">Compile a phrase option test</span> <span class="cwebmacronumber">16.3</span>&gt;<span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Conditions::compile is used in 14/cfs (<a href="14-cfs.html#SP7">&#167;7</a>).</p>
<p class="inwebparagraph"><a id="SP16_1"></a><b>&#167;16.1. </b>An easy case, running straight out to I6 operators:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile a logical negation</span> <span class="cwebmacronumber">16.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::no_children</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">) != 1)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"Compiled malformed LOGICAL_NOT_NT"</span><span class="plain">);</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">NOT_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="functiontext">Specifications::Compiler::emit_as_val</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">spec_found</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">);</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP16">&#167;16</a>.</p>
<p class="inwebparagraph"><a id="SP16_2"></a><b>&#167;16.2. </b>An easy case, running straight out to I6 operators:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile a logical operator</span> <span class="cwebmacronumber">16.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::no_children</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">) != 2)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"Compiled malformed logical operator"</span><span class="plain">);</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">left_operand</span><span class="plain"> = </span><span class="identifier">spec_found</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">;</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">right_operand</span><span class="plain"> = </span><span class="identifier">spec_found</span><span class="plain">-</span><span class="element">&gt;down</span><span class="plain">-</span><span class="element">&gt;next</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">left_operand</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">right_operand</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">"Compiled CONDITION/AND with LHS operands"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">, </span><span class="constant">LOGICAL_AND_NT</span><span class="plain">)) </span><span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">AND_BIP</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::is</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">, </span><span class="constant">LOGICAL_OR_NT</span><span class="plain">)) </span><span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">OR_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="functiontext">Specifications::Compiler::emit_as_val</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">left_operand</span><span class="plain">);</span>
<span class="functiontext">Specifications::Compiler::emit_as_val</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">right_operand</span><span class="plain">);</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP16">&#167;16</a>.</p>
<p class="inwebparagraph"><a id="SP16_3"></a><b>&#167;16.3. </b>Phrase options are stored as bits in a 16-bit map, so that each individual
option is a power of two from 2^0 to 2^15. We test if this is valid by
performing logical-and against the I6 local variable <code class="display"><span class="extract">phrase_options</span></code>, which
exists if and only if the enclosing I6 routine takes phrase options. The
type-checker won't allow these specifications to be compiled anywhere else.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile a phrase option test</span> <span class="cwebmacronumber">16.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">BITWISEAND_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="reserved">local_variable</span><span class="plain"> *</span><span class="identifier">po</span><span class="plain"> = </span><span class="functiontext">LocalVariables::phrase_options</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">po</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">"no phrase options exist in this frame"</span><span class="plain">);</span>
<span class="identifier">inter_symbol</span><span class="plain"> *</span><span class="identifier">po_s</span><span class="plain"> = </span><span class="functiontext">LocalVariables::declare_this</span><span class="plain">(</span><span class="identifier">po</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">, 8);</span>
<span class="identifier">Produce::val_symbol</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">po_s</span><span class="plain">);</span>
<span class="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, (</span><span class="identifier">inter_t</span><span class="plain">) </span><span class="identifier">ParseTree::int_annotation</span><span class="plain">(</span><span class="identifier">spec_found</span><span class="plain">, </span><span class="constant">phrase_option_ANNOT</span><span class="plain">));</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP16">&#167;16</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="14-lv.html">Back to 'Lvalues'</a></li><li><a href="14-ds.html">Continue with 'Descriptions'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>