mirror of
https://github.com/ganelson/inform.git
synced 2024-07-08 18:14:21 +03:00
3078 lines
372 KiB
HTML
3078 lines
372 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>19/lr</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 '20/eq' generated by 7-->
|
|
<ul class="crumbs"><li><a href="../webs.html">★</a></li><li><a href="index.html">core</a></li><li><a href="index.html#20">Chapter 20: Equations</a></li><li><b>Equations</b></li></ul><p class="purpose">To manage and compile equations, which relate numerical quantities.</p>
|
|
|
|
<ul class="toc"><li><a href="#SP1">§1. Definitions</a></li><li><a href="#SP9">§9. Traversing for equations</a></li><li><a href="#SP12">§12. Parsing equations</a></li><li><a href="#SP14">§14. Declaring symbols</a></li><li><a href="#SP25">§25. Equation nodes</a></li><li><a href="#SP28">§28. Tokenising equations</a></li><li><a href="#SP31">§31. The shift-reduce parser</a></li><li><a href="#SP39">§39. Typechecking equations</a></li><li><a href="#SP42">§42. Flotation</a></li><li><a href="#SP43">§43. Compiling</a></li><li><a href="#SP45">§45. Solving</a></li><li><a href="#SP50">§50. Rearrangement</a></li><li><a href="#SP52">§52. Internal test case</a></li><li><a href="#SP53">§53. Indexing and logging</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. Definitions. </b></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. </b>As with tables, equations are detected early on in Inform's run but not
|
|
parsed for their contents until later, so we store several word ranges.
|
|
Also as with tables, each can have a number, a name or both.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation</span><span class="plain"> {</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">equation_text</span><span class="plain">; </span> <span class="comment">the text of the actual equation</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">equation_no_text</span><span class="plain">; </span> <span class="comment">the equation number (if any)</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">equation_name_text</span><span class="plain">; </span> <span class="comment">the equation name (if any)</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">where_text</span><span class="plain">; </span> <span class="comment">declaration of symbols</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">usage_text</span><span class="plain">; </span> <span class="comment">usage notes</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">equation_created_at</span><span class="plain">; </span> <span class="comment">where created in source</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">examined_already</span><span class="plain">;</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">parsed_equation</span><span class="plain">; </span> <span class="comment">and the equation itself (when eventually parsed)</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">eqn_iname</span><span class="plain">; </span> <span class="comment">used at run-time to identify this</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">symbol_list</span><span class="plain">; </span> <span class="comment">the symbols used</span>
|
|
<span class="identifier">MEMORY_MANAGEMENT</span>
|
|
<span class="plain">} </span><span class="reserved">equation</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The structure equation is accessed in 2/si and here.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. </b>Each equation is allowed to use one or more symbols. Some may correspond
|
|
to local variables in surrounding code from time to time, but others will
|
|
be constants, and it's better to think of these as placeholders in the
|
|
syntax of the equation, not as storage objects like variables. For instance,
|
|
in
|
|
E = mc^2
|
|
we have three symbols: E, m and c. (The 2 does not count.) There
|
|
might be symbols called m in any number of other equations; if so each
|
|
instance has its own <code class="display"><span class="extract">equation_symbol</span></code> structure.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_symbol</span><span class="plain"> {</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">name</span><span class="plain">; </span> <span class="comment">always just one word, in fact</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">var_kind</span><span class="plain">; </span> <span class="comment">if a variable — must be quasinumerical</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">function_notated</span><span class="plain">; </span> <span class="comment">if a phrase QN to QN</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">var_const</span><span class="plain">; </span> <span class="comment">if a symbol for a constant value</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">temp_constant</span><span class="plain">; </span> <span class="comment">is this constant a substitution for one usage only?</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">next</span><span class="plain">; </span> <span class="comment">in the list belonging to the equation</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">local_variable</span><span class="plain"> *</span><span class="identifier">local_map</span><span class="plain">; </span> <span class="comment">when being solved in a given stack frame</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">promote_local_to_real</span><span class="plain">; </span> <span class="comment">from integer, if necessary</span>
|
|
<span class="identifier">MEMORY_MANAGEMENT</span>
|
|
<span class="plain">} </span><span class="reserved">equation_symbol</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The structure equation_symbol is accessed in 2/sq, 2/si, 3/pd, 5/lp, 5/ut, 5/un, 5/ins, 5/nv, 6/rlt, 6/nv, 7/ss, 7/hdn, 7/ns, 7/oaf, 7/rs, 8/ie, 8/ec, 8/ed, 8/ed2, 9/tfa, 9/tbath, 9/rpt, 9/tc, 9/ma, 9/pk, 9/rk, 9/ass, 9/imp, 9/pd, 10/teav, 10/cap, 11/ap, 11/pr, 11/bas, 11/tc, 11/sm, 12/dtd, 12/cdp, 14/rv, 14/lv, 14/cn, 14/ds, 14/ds2, 15/pr, 15/ep, 15/vp, 15/cp, 15/spr, 16/is, 16/in, 16/cmw, 17/rs, 19/tc, 19/tb, 19/rsft, 19/tod, 21/rl, 21/rl2, 21/fao, 21/rps, 21/sv, 21/ac, 22/ph, 22/pu, 22/dptd, 22/po, 22/pav, 22/tp, 22/tp2, 23/ad, 24/lv, 24/sf, 25/in, 25/pi, 25/cii, 25/cp, 26/uo, 26/tti, 26/pc, 26/ts, 27/cm and here.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. </b>In addition, there are some standing symbols used by all equations: the
|
|
constant "pi", for example. They're stored in this linked list:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">standard_equation_symbols</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5"></a><b>§5. </b>When parsed, the equation is stored as a tree of <code class="display"><span class="extract">equation_node</span></code> structures.
|
|
As usual, the leaves represent symbols or else constants not given symbol
|
|
status (such as the 2 in E = mc^2); the non-leaf nodes represent operations,
|
|
identified with the same codes as used in "Dimensions". Note
|
|
that the equals sign <code class="display"><span class="extract">=</span></code> is itself considered an operation here.Thus:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">OPERATION_EQN =</span>
|
|
<span class="plain"> SYMBOL_EQN E</span>
|
|
<span class="plain"> OPERATION_EQN *</span>
|
|
<span class="plain"> SYMBOL_EQN m</span>
|
|
<span class="plain"> OPERATION_EQN ^</span>
|
|
<span class="plain"> SYMBOL_EQN c</span>
|
|
<span class="plain"> CONSTANT_EQN 2</span>
|
|
|
|
<span class="definitionkeyword">define</span> <span class="constant">CONSTANT_EQN</span><span class="plain"> 1 </span> <span class="comment">a leaf, representing a quasinumerical constant not given a symbol</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">SYMBOL_EQN</span><span class="plain"> 2 </span> <span class="comment">a leaf, representing a symbol</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">OPERATION_EQN</span><span class="plain"> 3 </span> <span class="comment">a non-leaf, representing an operation</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP6"></a><b>§6. </b>However, because of the algorithm used to parse the text of the equation into
|
|
this tree, we also need certain other kinds of node to exist during parsing
|
|
only. They are syntactic gimmicks, and are forbidden in the final tree.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">OPEN_BRACKET_EQN</span><span class="plain"> 4</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">CLOSE_BRACKET_EQN</span><span class="plain"> 5</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">END_EQN</span><span class="plain"> 6 </span> <span class="comment">the end (left or right edge, really) of the equation</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP7"></a><b>§7. </b>Another temporary trick in parsing is to distinguish between explicit
|
|
multiplication, where the source text uses an asterisk <code class="display"><span class="extract">*</span></code>, and implicit,
|
|
as between m and c^2 in E = mc^2. We distinguish these so that they
|
|
can bind with different tightnesses, but both are represented just as
|
|
<code class="display"><span class="extract">TIMES_OPERATION</span></code> nodes in the eventual tree.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Implicit function application is similarly used to represent the unwritten
|
|
operation in <code class="display"><span class="extract">log pi</span></code> — where the function <code class="display"><span class="extract">log</span></code> is being applied to the
|
|
value <code class="display"><span class="extract">pi</span></code>.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">IMPLICIT_TIMES_OPERATION</span><span class="plain"> 100</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain"> 101</span>
|
|
</pre>
|
|
<p class="inwebparagraph"><a id="SP8"></a><b>§8. </b>And now the equation node structure:
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">MAX_EQN_ARITY</span><span class="plain"> 2 </span> <span class="comment">at present all operations are at most binary</span>
|
|
</pre>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_node</span><span class="plain"> {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">eqn_type</span><span class="plain">; </span> <span class="comment">one of the <code class="display"><span class="extract">*_EQN</span></code> values</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">eqn_operation</span><span class="plain">; </span> <span class="comment">one of the <code class="display"><span class="extract">*_OPERATION</span></code> values (see "Dimensions.w")</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">enode_arity</span><span class="plain">; </span> <span class="comment">0 for a leaf</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">enode_operands</span><span class="plain">[</span><span class="constant">MAX_EQN_ARITY</span><span class="plain">]; </span> <span class="comment">the operands</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">leaf_constant</span><span class="plain">; </span> <span class="comment">if e.g. "21"</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">leaf_symbol</span><span class="plain">; </span> <span class="comment">if e.g. "G"</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">generalised_kind</span><span class="plain"> </span><span class="identifier">gK_before</span><span class="plain">; </span> <span class="comment">result of the node as it is</span>
|
|
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">generalised_kind</span><span class="plain"> </span><span class="identifier">gK_after</span><span class="plain">; </span> <span class="comment">result of the node as we need it to be</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">enode_promotion</span><span class="plain">; </span> <span class="comment">promote this from an integer to a real number?</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rational_n</span><span class="plain">; </span> <span class="comment">represents the rational number <code class="display"><span class="extract">n/m</span></code>...</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rational_m</span><span class="plain">; </span> <span class="comment">...unless <code class="display"><span class="extract">m</span></code> is zero</span>
|
|
<span class="identifier">MEMORY_MANAGEMENT</span>
|
|
<span class="plain">} </span><span class="reserved">equation_node</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The structure equation_node is accessed in 13/ca and here.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9"></a><b>§9. Traversing for equations. </b>Early in Inform's run, the following takes place:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">sentence_handler</span><span class="plain"> </span><span class="identifier">EQUATION_SH_handler</span><span class="plain"> = { </span><span class="constant">EQUATION_NT</span><span class="plain">, -1, 0, </span><span class="identifier">NULL</span><span class="plain"> };</span>
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::traverse_to_create</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="identifier">ParseTree::traverse</span><span class="plain">(</span><span class="functiontext">Equations::visit_to_create</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::visit_to_create</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="reserved">if</span><span class="plain"> (</span><span class="identifier">ParseTree::get_type</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">) == </span><span class="constant">EQUATION_NT</span><span class="plain">)</span>
|
|
<span class="functiontext">Equations::new</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">), </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::traverse_to_create is used in 1/mr (<a href="1-mr.html#SP4_9">§4.9</a>).</p>
|
|
|
|
<p class="endnote">The function Equations::visit_to_create appears nowhere else.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10"></a><b>§10. </b>Equation names follow the same conventions as table names.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">> ::=</span>
|
|
<span class="reserved">equation</span><span class="plain"> {<</span><span class="identifier">cardinal</span><span class="plain">-</span><span class="identifier">number</span><span class="plain">>} - ... | ==> 3</span>
|
|
<span class="reserved">equation</span><span class="plain"> {<</span><span class="identifier">cardinal</span><span class="plain">-</span><span class="identifier">number</span><span class="plain">>} | ==> 1</span>
|
|
<span class="reserved">equation</span><span class="plain"> - ... | ==> 2</span>
|
|
<span class="reserved">equation</span><span class="plain"> *** ==> </span><<span class="cwebmacro">Issue PM_EquationMisnumbered problem</span> <span class="cwebmacronumber">10.3</span>>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_1"></a><b>§10.1. </b>The above catches all of the named expressions written out in the
|
|
source text, but not the ones written "inline", in phrases like
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>let F be given by F = ma;</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">Those equations are created by calling <code class="display"><span class="extract">Equations::new</span></code> direct from the
|
|
S-parser: such equations are called "anonymous", as they have no name. But in
|
|
either case, an equation begins here:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation</span><span class="plain"> *</span><span class="functiontext">Equations::new</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">int</span><span class="plain"> </span><span class="identifier">anonymous</span><span class="plain">) {</span>
|
|
<span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_created_at</span><span class="plain"> == </span><span class="identifier">current_sentence</span><span class="plain">)</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">eqn</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">eqn</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain">);</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_created_at</span><span class="plain"> = </span><span class="identifier">current_sentence</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>where_text</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>usage_text</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>examined_already</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">package_request</span><span class="plain"> *</span><span class="identifier">PR</span><span class="plain"> = </span><span class="functiontext">Hierarchy::local_package</span><span class="plain">(</span><span class="constant">EQUATIONS_HAP</span><span class="plain">);</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>eqn_iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::make_iname_in</span><span class="plain">(</span><span class="constant">SOLVE_FN_HL</span><span class="plain">, </span><span class="identifier">PR</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">NO</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">, </span><span class="identifier">NA</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">anonymous</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
|
|
<<span class="cwebmacro">Parse the equation's number and/or name</span> <span class="cwebmacronumber">10.1.1</span>><span class="character">;</span>
|
|
<<span class="cwebmacro">Register any names for this equation</span> <span class="cwebmacronumber">10.1.3</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">>(</span><span class="identifier">W</span><span class="plain">)) {</span>
|
|
<span class="identifier">W</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">>, 1);</span>
|
|
<span class="functiontext">Equations::set_wherewithal</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">>, 2));</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_no_text</span><span class="plain"> = </span><span class="identifier">NO</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_name_text</span><span class="plain"> = </span><span class="identifier">NA</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (<</span><span class="identifier">text</span><span class="plain">-</span><span class="identifier">ending</span><span class="plain">-</span><span class="identifier">in</span><span class="plain">-</span><span class="identifier">comma</span><span class="plain">>(</span><span class="identifier">W</span><span class="plain">)) </span><span class="identifier">W</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="identifier">text</span><span class="plain">-</span><span class="identifier">ending</span><span class="plain">-</span><span class="identifier">in</span><span class="plain">-</span><span class="identifier">comma</span><span class="plain">>, 1);</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</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">eqn</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::new is used in <a href="#SP9">§9</a>, <a href="#SP52">§52</a>, 10/teav (<a href="10-teav.html#SP12_1">§12.1</a>, <a href="10-teav.html#SP12_3">§12.3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_2"></a><b>§10.2. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain"><</span><span class="identifier">text</span><span class="plain">-</span><span class="identifier">ending</span><span class="plain">-</span><span class="identifier">in</span><span class="plain">-</span><span class="identifier">comma</span><span class="plain">> ::=</span>
|
|
<span class="plain">... ,</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_3"></a><b>§10.3. </b>We take the word range (w_1, w_2) and shave off the first line, that is,
|
|
all the words up to the first line break occurring between words. (Compare
|
|
the syntax for a table declaration.) This becomes the word range (tw_1, tw_2).
|
|
We know that this begins with the word "equation", or we wouldn't be here
|
|
(because the sentence would not have been classed an <code class="display"><span class="extract">EQUATION_NT</span></code>).
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Issue PM_EquationMisnumbered problem</span> <span class="cwebmacronumber">10.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = 0;</span>
|
|
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationMisnumbered</span><span class="plain">),</span>
|
|
<span class="string">"the top line of this equation declaration seems not to be a "</span>
|
|
<span class="string">"legal equation number or name"</span><span class="plain">,</span>
|
|
<span class="string">"and should read something like 'Equation 6', or 'Equation - "</span>
|
|
<span class="string">"Newton's Second Law', or 'Equation 41 - Coulomb's Law'."</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP10">§10</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_1_1"></a><b>§10.1.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Parse the equation's number and/or name</span> <span class="cwebmacronumber">10.1.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain"> = </span><span class="identifier">Wordings::last_word_of_formatted_text</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">TW</span><span class="plain"> = </span><span class="identifier">Wordings::up_to</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">);</span>
|
|
<span class="identifier">W</span><span class="plain"> = </span><span class="identifier">Wordings::from</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">+1);</span>
|
|
<span class="reserved">if</span><span class="plain"> (<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">>(</span><span class="identifier">TW</span><span class="plain">)) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (<<</span><span class="identifier">r</span><span class="plain">>>) {</span>
|
|
<span class="reserved">case</span><span class="plain"> 0: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> 1: </span><span class="identifier">NO</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">>, 1); </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> 2: </span><span class="identifier">NA</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">>, 1); </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> 3: </span><span class="identifier">NO</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">>, 1);</span>
|
|
<span class="identifier">NA</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">name</span><span class="plain">>, 2); </span><span class="reserved">break</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">internal_error</span><span class="plain">(</span><span class="string">"malformed equation sentence"</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP10_1">§10.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_1_2"></a><b>§10.1.2. </b>An equation can be referred to by its number, or by its name. Thus
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>Equation 64 - Distribution of Cheese</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">could be referred to elsewhere in the text by any of three names:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>equation 64, Distribution of Cheese, Distribution of Cheese equation</p>
|
|
|
|
</blockquote>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">names</span><span class="plain">-</span><span class="identifier">construction</span><span class="plain">> ::=</span>
|
|
<span class="reserved">equation</span><span class="plain"> ... |</span>
|
|
<span class="plain">... </span><span class="reserved">equation</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_1_3"></a><b>§10.1.3. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Register any names for this equation</span> <span class="cwebmacronumber">10.1.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">NO</span><span class="plain">)) {</span>
|
|
<span class="identifier">word_assemblage</span><span class="plain"> </span><span class="identifier">wa</span><span class="plain"> = </span><span class="identifier">Preform::Nonparsing::merge</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">names</span><span class="plain">-</span><span class="identifier">construction</span><span class="plain">>, 0,</span>
|
|
<span class="identifier">WordAssemblages::from_wording</span><span class="plain">(</span><span class="identifier">NO</span><span class="plain">));</span>
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">AW</span><span class="plain"> = </span><span class="identifier">WordAssemblages::to_wording</span><span class="plain">(&</span><span class="identifier">wa</span><span class="plain">);</span>
|
|
<span class="identifier">Nouns::new_proper_noun</span><span class="plain">(</span><span class="identifier">AW</span><span class="plain">, </span><span class="identifier">NEUTER_GENDER</span><span class="plain">,</span>
|
|
<span class="identifier">REGISTER_SINGULAR_NTOPT</span><span class="plain"> + </span><span class="identifier">PARSE_EXACTLY_NTOPT</span><span class="plain">,</span>
|
|
<span class="constant">EQUATION_MC</span><span class="plain">, </span><span class="functiontext">Rvalues::from_equation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">));</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">NA</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (<</span><span class="identifier">s</span><span class="plain">-</span><span class="identifier">type</span><span class="plain">-</span><span class="identifier">expression</span><span class="plain">-</span><span class="identifier">or</span><span class="plain">-</span><span class="identifier">value</span><span class="plain">>(</span><span class="identifier">NA</span><span class="plain">)) {</span>
|
|
<span class="identifier">Problems::quote_wording_as_source</span><span class="plain">(1, </span><span class="identifier">NA</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationMisnamed</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"The equation name %1 will have to be disallowed as it is text "</span>
|
|
<span class="string">"which already has a meaning to Inform. For instance, creating "</span>
|
|
<span class="string">"an equation called 'Equation - 2 + 2' would be disallowed "</span>
|
|
<span class="string">"because Inform would read '2 + 2' as arithmetic, not a name."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">Nouns::new_proper_noun</span><span class="plain">(</span><span class="identifier">NA</span><span class="plain">, </span><span class="identifier">NEUTER_GENDER</span><span class="plain">,</span>
|
|
<span class="identifier">REGISTER_SINGULAR_NTOPT</span><span class="plain"> + </span><span class="identifier">PARSE_EXACTLY_NTOPT</span><span class="plain">,</span>
|
|
<span class="constant">EQUATION_MC</span><span class="plain">, </span><span class="functiontext">Rvalues::from_equation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">));</span>
|
|
<span class="identifier">word_assemblage</span><span class="plain"> </span><span class="identifier">wa</span><span class="plain"> =</span>
|
|
<span class="identifier">Preform::Nonparsing::merge</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">names</span><span class="plain">-</span><span class="identifier">construction</span><span class="plain">>, 0,</span>
|
|
<span class="identifier">WordAssemblages::from_wording</span><span class="plain">(</span><span class="identifier">NA</span><span class="plain">));</span>
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">AW</span><span class="plain"> = </span><span class="identifier">WordAssemblages::to_wording</span><span class="plain">(&</span><span class="identifier">wa</span><span class="plain">);</span>
|
|
<span class="identifier">Nouns::new_proper_noun</span><span class="plain">(</span><span class="identifier">AW</span><span class="plain">, </span><span class="identifier">NEUTER_GENDER</span><span class="plain">,</span>
|
|
<span class="identifier">REGISTER_SINGULAR_NTOPT</span><span class="plain"> + </span><span class="identifier">PARSE_EXACTLY_NTOPT</span><span class="plain">,</span>
|
|
<span class="constant">EQUATION_MC</span><span class="plain">, </span><span class="functiontext">Rvalues::from_equation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">));</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP10_1">§10.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP11"></a><b>§11. </b>A "where" clause following an equation defines its symbols, as we shall
|
|
see. That can be detected in the above parsing process where the equation
|
|
is displayed, but for anonymous equations occurring inline, the S-parser
|
|
has to discover it; and the S-parser then calls this routine:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::set_wherewithal</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">eqn</span><span class="plain">-</span><span class="element">>where_text</span><span class="plain"> = </span><span class="identifier">W</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::set_wherewithal is used in <a href="#SP10_1">§10.1</a>, <a href="#SP52">§52</a>, 10/teav (<a href="10-teav.html#SP12_1">§12.1</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP12"></a><b>§12. Parsing equations. </b>So now it's later on. We can run through all the equations displayed in the
|
|
source text:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::traverse_to_stock</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation</span><span class="plain">) {</span>
|
|
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_created_at</span><span class="plain">;</span>
|
|
<span class="functiontext">Equations::examine</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::traverse_to_stock is used in 1/mr (<a href="1-mr.html#SP4_13">§4.13</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13"></a><b>§13. </b>And, as with creation, <code class="display"><span class="extract">Equations::examine</span></code> is called explicitly in the meaning
|
|
list converter when an equation is found inline. So in all cases, we call the
|
|
following before we need to use the equation, which runs a three-stage process:
|
|
parsing the "where..." clause to declare the symbols, then parsing the equation,
|
|
then type-checking it.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::examine</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>examined_already</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>examined_already</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::eqn_declare_symbols</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="functiontext">Equations::eqn_declare_standard_symbols</span><span class="plain">();</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain"> = </span><span class="functiontext">Equations::eqn_parse</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::eqn_typecheck</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::examine is used in <a href="#SP12">§12</a>, <a href="#SP52">§52</a>, 10/teav (<a href="10-teav.html#SP12_1">§12.1</a>, <a href="10-teav.html#SP12_2">§12.2</a>, <a href="10-teav.html#SP12_3">§12.3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP14"></a><b>§14. Declaring symbols. </b>Equations are allowed to end with a "where..." clause, explaining what
|
|
the symbols in it mean. For example:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>where F is a force, a = 9.801 m/ss, m1 and m2 are masses;</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">At the earlier stages of parsing, we simply split the "where" text away
|
|
using this:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">> ::=</span>
|
|
<span class="plain">... </span><span class="identifier">where</span><span class="plain"> ...</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP15"></a><b>§15. </b>For a displayed equation, the following parses the "where..." text, which
|
|
is expected to declare every symbol occurring in it.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::eqn_declare_symbols</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::empty</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>where_text</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="reserved">int</span><span class="plain"> </span><span class="identifier">result</span><span class="plain"> = </span><span class="functiontext">Equations::eqn_declare_variables_inner</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>where_text</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">changed</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">changed</span><span class="plain">) {</span>
|
|
<span class="identifier">changed</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</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">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">),</span>
|
|
<span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>where_text</span><span class="plain">,</span>
|
|
<span class="string">"each symbol in a equation has to be declared with a kind of "</span>
|
|
<span class="string">"value or else an actual value. So '...where N = 1701.' or "</span>
|
|
<span class="string">"'...where N, M are numbers.' would be fine."</span><span class="plain">);</span>
|
|
<span class="identifier">result</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain">;</span>
|
|
<span class="identifier">changed</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">result</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_declare_symbols is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP16"></a><b>§16. </b>But the following routine is also used with the "where" text supplied in
|
|
a phrase like so:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>let F be given by Newton's Second Law, where m = 101kg;</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">In this context the "where" text sets explicit values for symbols occurring
|
|
in the equation; these are temporary settings only and will not change the
|
|
equation's behaviour elsewhere.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">So the following is called in either permanent mode, when it declares symbols
|
|
for an equation, or temporary mode, when it gives them temporary assignments.
|
|
It returns <code class="display"><span class="extract">TRUE</span></code> if all went well, or <code class="display"><span class="extract">FALSE</span></code> if problem messages had to be
|
|
issued.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">equation_being_declared</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">equation_declared_temporarily</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">eq_symbol_wn</span><span class="plain"> = -1;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17"></a><b>§17. </b>The following grammar is later used to parse the text after "where". For
|
|
example:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>F is a force, a = 9.801 m/ss, m1 and m2 are masses</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">This is split into four clauses, of which the trickiest is the third, reading
|
|
just "m1". This abbreviated form is allowed only in permanent declarations
|
|
(i.e., not in equations defined inside "let" phrases) and gives the symbol
|
|
the same definition as the one following it — so m1 becomes defined as a
|
|
mass, too.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">> ::=</span>
|
|
<span class="plain">... | ==> 0; </span><span class="identifier">eq_symbol_wn</span><span class="plain"> = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); </span><span class="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"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">setting</span><span class="plain">-</span><span class="identifier">entry</span><span class="plain">> <</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">> | ==> 0</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">setting</span><span class="plain">-</span><span class="identifier">entry</span><span class="plain">> ==> 0</span>
|
|
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">tail</span><span class="plain">> ::=</span>
|
|
<span class="plain">, </span><span class="identifier">_and</span><span class="plain"> <</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">> | ==> 0</span>
|
|
<span class="identifier">_</span><span class="plain">,/</span><span class="identifier">and</span><span class="plain"> <</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">list</span><span class="plain">> ==> 0</span>
|
|
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">setting</span><span class="plain">-</span><span class="identifier">entry</span><span class="plain">> ::=</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">setting</span><span class="plain">> ==> 0; </span><span class="reserved">if</span><span class="plain"> (!</span><span class="identifier">preform_lookahead_mode</span><span class="plain">) </span><span class="functiontext">Equations::eqn_dec_var</span><span class="plain">(</span><span class="identifier">equation_being_declared</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">eq_symbol_wn</span><span class="plain">), </span><span class="identifier">R</span><span class="plain">[1], </span><span class="identifier">RP</span><span class="plain">[1]);</span>
|
|
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">setting</span><span class="plain">> ::=</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> </span><span class="identifier">is</span><span class="plain">/</span><span class="identifier">are</span><span class="plain"> <</span><span class="identifier">k</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">> | ==> </span><span class="constant">EQW_IDENTIFIES_KIND</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="identifier">eq_symbol_wn</span><span class="plain"> = </span><span class="identifier">R</span><span class="plain">[1];</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> </span><span class="identifier">is</span><span class="plain">/</span><span class="identifier">are</span><span class="plain"> <</span><span class="identifier">s</span><span class="plain">-</span><span class="identifier">value</span><span class="plain">> | ==> </span><span class="constant">EQW_IDENTIFIES_VALUE</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="identifier">eq_symbol_wn</span><span class="plain"> = </span><span class="identifier">R</span><span class="plain">[1];</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> </span><span class="identifier">is</span><span class="plain">/</span><span class="identifier">are</span><span class="plain"> ... | ==> </span><<span class="cwebmacro">Issue PM_EquationSymbolNonValue problem</span> <span class="cwebmacronumber">17.1</span>>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> = <</span><span class="identifier">k</span><span class="plain">-</span><span class="identifier">kind</span><span class="plain">> | ==> </span><<span class="cwebmacro">Issue PM_EquationSymbolEqualsKOV problem</span> <span class="cwebmacronumber">17.2</span>>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> = <</span><span class="identifier">s</span><span class="plain">-</span><span class="identifier">value</span><span class="plain">> | ==> </span><span class="constant">EQW_IDENTIFIES_VALUE</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="identifier">eq_symbol_wn</span><span class="plain"> = </span><span class="identifier">R</span><span class="plain">[1];</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> = ... | ==> </span><<span class="cwebmacro">Issue PM_EquationSymbolNonValue problem</span> <span class="cwebmacronumber">17.1</span>>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> ==> </span><span class="constant">EQW_IDENTIFIES_NOTHING</span><span class="plain">; </span><span class="identifier">eq_symbol_wn</span><span class="plain"> = </span><span class="identifier">R</span><span class="plain">[1];</span>
|
|
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> ::=</span>
|
|
<span class="plain"><</span><span class="identifier">valid</span><span class="plain">-</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> | ==> </span><span class="identifier">R</span><span class="plain">[1]</span>
|
|
<span class="plain">### | ==> </span><<span class="cwebmacro">Issue PM_EquationSymbolMalformed problem</span> <span class="cwebmacronumber">17.3</span>>
|
|
<span class="plain">... ==> </span><<span class="cwebmacro">Issue PM_EquationSymbolMisdeclared problem</span> <span class="cwebmacronumber">17.4</span>>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17_1"></a><b>§17.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue PM_EquationSymbolNonValue problem</span> <span class="cwebmacronumber">17.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = </span><span class="constant">EQW_IDENTIFIES_PROBLEM</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="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolNonValue</span><span class="plain">),</span>
|
|
<span class="identifier">equation_being_declared</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[1]),</span>
|
|
<span class="string">"this has neither a kind of value nor an actual value."</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP17">§17</a> (twice).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17_2"></a><b>§17.2. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue PM_EquationSymbolEqualsKOV problem</span> <span class="cwebmacronumber">17.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = </span><span class="constant">EQW_IDENTIFIES_PROBLEM</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="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolEqualsKOV</span><span class="plain">),</span>
|
|
<span class="identifier">equation_being_declared</span><span class="plain">, </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">[1]),</span>
|
|
<span class="string">"'is' should be used, not '=', for a kind of value rather "</span>
|
|
<span class="string">"than an actual value."</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP17">§17</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17_3"></a><b>§17.3. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue PM_EquationSymbolMalformed problem</span> <span class="cwebmacronumber">17.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = -1;</span>
|
|
<span class="reserved">if</span><span class="plain"> (!</span><span class="identifier">preform_lookahead_mode</span><span class="plain">)</span>
|
|
<span class="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolMalformed</span><span class="plain">),</span>
|
|
<span class="identifier">equation_being_declared</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">,</span>
|
|
<span class="string">"a symbol in a equation has to be a sequence of one to ten "</span>
|
|
<span class="string">"letters optionally followed by a number from 0 to 99, so "</span>
|
|
<span class="string">"'G', 'm', 'pi' and 'KE1' are all legal symbol names. But "</span>
|
|
<span class="string">"this one is not."</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP17">§17</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17_4"></a><b>§17.4. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue PM_EquationSymbolMisdeclared problem</span> <span class="cwebmacronumber">17.4</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="plain">*</span><span class="identifier">X</span><span class="plain"> = -1;</span>
|
|
<span class="reserved">if</span><span class="plain"> (!</span><span class="identifier">preform_lookahead_mode</span><span class="plain">)</span>
|
|
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolMisdeclared</span><span class="plain">),</span>
|
|
<span class="string">"the symbols here are not declared properly"</span><span class="plain">,</span>
|
|
<span class="string">"and should each be declared with a kind of value or else an "</span>
|
|
<span class="string">"actual value."</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP17">§17</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP18"></a><b>§18. </b></p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">EQW_IDENTIFIES_KIND</span><span class="plain"> 1</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">EQW_IDENTIFIES_VALUE</span><span class="plain"> 2</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">EQW_IDENTIFIES_NOTHING</span><span class="plain"> 3</span>
|
|
<span class="definitionkeyword">define</span> <span class="constant">EQW_IDENTIFIES_PROBLEM</span><span class="plain"> 4</span>
|
|
</pre>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::eqn_declare_variables_inner</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">int</span><span class="plain"> </span><span class="identifier">temp</span><span class="plain">) {</span>
|
|
<span class="identifier">equation_being_declared</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">;</span>
|
|
<span class="identifier">equation_declared_temporarily</span><span class="plain"> = </span><span class="identifier">temp</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">pc</span><span class="plain"> = </span><span class="identifier">problem_count</span><span class="plain">;</span>
|
|
<span class="plain"><</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">-</span><span class="identifier">list</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">problem_count</span><span class="plain"> > </span><span class="identifier">pc</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::eqn_dec_var</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">int</span><span class="plain"> </span><span class="identifier">X</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">XP</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="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">temp</span><span class="plain"> = </span><span class="identifier">equation_declared_temporarily</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">X</span><span class="plain"> == </span><span class="constant">EQW_IDENTIFIES_PROBLEM</span><span class="plain">) || (</span><span class="identifier">Wordings::empty</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">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">X</span><span class="plain"> != </span><span class="constant">EQW_IDENTIFIES_NOTHING</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Find the actual value, or kind of value, which the symbol is to match</span> <span class="cwebmacronumber">18.1</span>><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">temp</span><span class="plain">) </span><<span class="cwebmacro">Assign the given value to this symbol on a temporary basis</span> <span class="cwebmacronumber">18.2</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">Equations::eqn_add_symbol</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">spec</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>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_declare_variables_inner is used in <a href="#SP15">§15</a>, <a href="#SP46">§46</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::eqn_dec_var is used in <a href="#SP17">§17</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP18_1"></a><b>§18.1. </b>Symbols are allowed to be set equal to kinds of value, but only quasinumerical
|
|
ones; or to quasinumerical constants; or to global variables which contain
|
|
quasinumerical values. The latter are included to make it easier for extensions
|
|
to set up sets of equations for, say, gravity, defining
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>The acceleration due to gravity is an acceleration that varies.</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">and thus letting the extension's user decide how strong gravity is, but
|
|
still using it in equations:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>let F be given by Newton's Second Law, where a = the acceleration due to gravity;</p>
|
|
|
|
</blockquote>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Find the actual value, or kind of value, which the symbol is to match</span> <span class="cwebmacronumber">18.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<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">X</span><span class="plain"> == </span><span class="constant">EQW_IDENTIFIES_KIND</span><span class="plain">) {</span>
|
|
<span class="identifier">K</span><span class="plain"> = </span><span class="identifier">XP</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">temp</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolVague</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">,</span>
|
|
<span class="string">"when an equation is named for use in a 'let' "</span>
|
|
<span class="string">"phrase, any variables listed under 'where...' have "</span>
|
|
<span class="string">"to be given definite values, not just vaguely said "</span>
|
|
<span class="string">"to have particular kinds. Otherwise, I can't do any "</span>
|
|
<span class="string">"calculation with them."</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="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">X</span><span class="plain"> == </span><span class="constant">EQW_IDENTIFIES_VALUE</span><span class="plain">) {</span>
|
|
<span class="identifier">spec</span><span class="plain"> = </span><span class="identifier">XP</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="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">K</span><span class="plain">) && (</span><span class="identifier">Kinds::Behaviour::is_quasinumerical</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolNonNumeric</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">,</span>
|
|
<span class="string">"this has a kind of value on which arithmetic cannot be done, "</span>
|
|
<span class="string">"so it can have no place in an equation."</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>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP18">§18</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP18_2"></a><b>§18.2. </b>At this point we know the user means the variable named at word <code class="display"><span class="extract">wn</span></code>
|
|
to have the temporary value <code class="display"><span class="extract">spec</span></code>, and we have to identify that as one
|
|
of the symbols:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Assign the given value to this symbol on a temporary basis</span> <span class="cwebmacronumber">18.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::match_cs</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolBadSub</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">,</span>
|
|
<span class="string">"you're using 'where' to substitute something into this "</span>
|
|
<span class="string">"symbol which has the wrong kind of value."</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>temp_constant</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain"> = </span><span class="identifier">spec</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="functiontext">Problems::Issue::equation_symbol_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolSpurious</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">,</span>
|
|
<span class="string">"when 'where' is used to supply values to plug into a "</span>
|
|
<span class="string">"named equation as part of a 'let' phrase, you can only "</span>
|
|
<span class="string">"supply values for symbols actually used in that equation. "</span>
|
|
<span class="string">"This one doesn't seem to occur there."</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP18">§18</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP19"></a><b>§19. </b>We won't want those temporary assignments hanging around, so once the
|
|
hurly-burly is done, the following is called:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::eqn_remove_temp_variables</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>temp_constant</span><span class="plain">) {</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>temp_constant</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_remove_temp_variables is used in <a href="#SP46">§46</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP20"></a><b>§20. </b>As we saw, permanent symbol declarations cause <code class="display"><span class="extract">Equations::eqn_add_symbol</span></code> to be called.
|
|
But what about the symbols for an inline equation, like this one?
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>let F be given by F = ma;</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">These are not explicitly declared. What happens is that any local variable
|
|
on the current stack frame, whose name could plausibly be that of a symbol,
|
|
is made into one. Sometimes the locals won't be symbols in the equation at all,
|
|
but will just have short names and coincidentally hold quasinumeric values;
|
|
that doesn't matter, because if they're not in the equation, they'll never
|
|
be used.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::declare_local_variables</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="functiontext">LocalVariables::make_available_to_equation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="comment">which calls the following for each current local variable in turn:</span>
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::declare_local</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Equations::equation_symbol_legal</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) && (</span><span class="identifier">Kinds::Behaviour::is_quasinumerical</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">)))</span>
|
|
<span class="functiontext">Equations::eqn_add_symbol</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::declare_local_variables is used in 10/teav (<a href="10-teav.html#SP12_1">§12.1</a>, <a href="10-teav.html#SP12_2">§12.2</a>, <a href="10-teav.html#SP12_3">§12.3</a>).</p>
|
|
|
|
<p class="endnote">The function Equations::declare_local is used in 24/lv (<a href="24-lv.html#SP30">§30</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP21"></a><b>§21. </b>Next we add "e" and "pi". These are added last, so that any local
|
|
declarations will trump them.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::eqn_declare_standard_symbols</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">standard_equation_symbols</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">TCW</span><span class="plain"> = </span><span class="identifier">Feeds::feed_text</span><span class="plain">(</span><span class="identifier">L</span><span class="string">"e pi"</span><span class="plain">);</span>
|
|
<span class="identifier">LOOP_THROUGH_WORDING</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">, </span><span class="identifier">TCW</span><span class="plain">) {</span>
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">V</span><span class="plain"> = </span><span class="identifier">Wordings::one_word</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (<</span><span class="identifier">s</span><span class="plain">-</span><span class="identifier">type</span><span class="plain">-</span><span class="identifier">expression</span><span class="plain">>(</span><span class="identifier">V</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">rp</span><span class="plain">>>;</span>
|
|
<span class="functiontext">Equations::eqn_add_symbol</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">K_real_number</span><span class="plain">, </span><span class="identifier">spec</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">ph</span><span class="plain">, </span><span class="reserved">phrase</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="functiontext">Phrases::Usage::get_equation_form</span><span class="plain">(&(</span><span class="identifier">ph</span><span class="plain">-</span><span class="element">>usage_data</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) {</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain"> = </span><span class="functiontext">Equations::eqn_add_symbol</span><span class="plain">(</span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">K_real_number</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">);</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain"> = </span><span class="identifier">ph</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_declare_standard_symbols is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP22"></a><b>§22. </b>And that about wraps up symbol declaration, except for the routine which
|
|
actually declares symbols:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="functiontext">Equations::eqn_add_symbol</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">kind</span><span class="plain"> *</span><span class="identifier">K</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">W</span><span class="plain"> = </span><span class="identifier">Wordings::first_word</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">);</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> **</span><span class="identifier">list_head</span><span class="plain"> = &</span><span class="identifier">standard_equation_symbols</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">eqn</span><span class="plain">) </span><span class="identifier">list_head</span><span class="plain"> = &(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">);</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain"> = *</span><span class="identifier">list_head</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::match_cs</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">))</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">equation_symbol</span><span class="plain">);</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain"> = </span><span class="identifier">K</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain"> = </span><span class="identifier">spec</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (*</span><span class="identifier">list_head</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) *</span><span class="identifier">list_head</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">f</span><span class="plain"> = *</span><span class="identifier">list_head</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">f</span><span class="plain">) && (</span><span class="identifier">f</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)) </span><span class="identifier">f</span><span class="plain"> = </span><span class="identifier">f</span><span class="plain">-</span><span class="element">>next</span><span class="plain">;</span>
|
|
<span class="identifier">f</span><span class="plain">-</span><span class="element">>next</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain"> = </span><span class="identifier">W</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>temp_constant</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_add_symbol is used in <a href="#SP18">§18</a>, <a href="#SP20">§20</a>, <a href="#SP21">§21</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP23"></a><b>§23. </b>This is where the criterion for being a valid symbol name is expressed:
|
|
it matches only a single word, and only if the lettering matches the regular
|
|
expression <code class="display"><span class="extract">[A-Za-z]?{1,8}\d?{0,2}</span></code>.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain"><</span><span class="identifier">valid</span><span class="plain">-</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">symbol</span><span class="plain">> </span><span class="identifier">internal</span><span class="plain"> {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::equation_symbol_legal</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) { *</span><span class="identifier">X</span><span class="plain"> = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">); </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">; }</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP24"></a><b>§24. </b>Using:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::equation_symbol_legal</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">Wordings::length</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">) == 1) {</span>
|
|
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">Lexer::word_raw_text</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">));</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain">, </span><span class="identifier">letters</span><span class="plain"> = 0, </span><span class="identifier">digits</span><span class="plain"> = 0, </span><span class="identifier">name_legal</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">j</span><span class="plain">=0; </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">]; </span><span class="identifier">j</span><span class="plain">++) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">j</span><span class="plain">];</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">)) </span><span class="identifier">digits</span><span class="plain">++;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::isalpha</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">)) { </span><span class="identifier">letters</span><span class="plain">++; </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">digits</span><span class="plain"> > 0) </span><span class="identifier">name_legal</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; }</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">name_legal</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">j</span><span class="plain"> >= 13) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">letters</span><span class="plain"> > 10) || (</span><span class="identifier">digits</span><span class="plain"> > 2)) </span><span class="identifier">name_legal</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">name_legal</span><span class="plain">;</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>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::equation_symbol_legal is used in <a href="#SP20">§20</a>, <a href="#SP23">§23</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP25"></a><b>§25. Equation nodes. </b>The parsed equation is a tree full of nodes, so we need routines to make
|
|
and examine them.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="functiontext">Equations::enode_new</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="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">enode</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain">);</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> = </span><span class="identifier">t</span><span class="plain">;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = -1;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 0;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>leaf_constant</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">); </span> <span class="comment">unknown for now</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">); </span> <span class="comment">unknown for now</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>enode_promotion</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>rational_n</span><span class="plain"> = 0;</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>rational_m</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">enode</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_new is used in <a href="#SP26">§26</a>, <a href="#SP28">§28</a>, <a href="#SP28_1_3">§28.1.3</a>, <a href="#SP32">§32</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP26"></a><b>§26. </b>This is how we make the three kinds of enode permitted in the final compiled
|
|
equation. (The other kinds can be created using <code class="display"><span class="extract">Equations::enode_new</span></code> directly.)
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">op</span><span class="plain">) {</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">enode</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">OPERATION_EQN</span><span class="plain">);</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">op</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">enode</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="functiontext">Equations::enode_new_symbol</span><span class="plain">(</span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain">) {</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">enode</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">SYMBOL_EQN</span><span class="plain">);</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">enode</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="functiontext">Equations::enode_new_constant</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">equation_node</span><span class="plain"> *</span><span class="identifier">enode</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">CONSTANT_EQN</span><span class="plain">);</span>
|
|
<span class="identifier">enode</span><span class="plain">-</span><span class="element">>leaf_constant</span><span class="plain"> = </span><span class="identifier">spec</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">enode</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_new_op is used in <a href="#SP28_1_3">§28.1.3</a>, <a href="#SP28_2">§28.2</a>, <a href="#SP50_3_1">§50.3.1</a>, <a href="#SP50_4">§50.4</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::enode_new_symbol is used in <a href="#SP28_1_1_1">§28.1.1.1</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::enode_new_constant is used in <a href="#SP28_1_2">§28.1.2</a>, <a href="#SP50_3_1">§50.3.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP27"></a><b>§27. </b>Being able to log nodes is useful, if only because it's always pretty to
|
|
watch shift-reduce parsers in action.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="functiontext">Equations::log_equation_node_inner</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">, 0);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::log_equation_node_inner</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">d</span><span class="plain">) {</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">d</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">+1<</span><span class="identifier">d</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">" "</span><span class="plain">); </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"+---"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<NULL>\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">OPERATION_EQN</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">PLUS_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<add>"</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="identifier">MINUS_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<subtract>"</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="identifier">DIVIDE_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<divide>"</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="identifier">TIMES_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<multiply>"</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">IMPLICIT_TIMES_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<implicitly multiply>"</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">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<apply function>"</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="identifier">EQUALS_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<set equal>"</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="identifier">ROOT_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<square root>"</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="identifier">REALROOT_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<real square root>"</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="identifier">CUBEROOT_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<cube root>"</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="identifier">POWER_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<to the power>"</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="identifier">UNARY_MINUS_OPERATION</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<unary subtraction>"</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<op-%d>"</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</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">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">SYMBOL_EQN</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<symbol-%W>"</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>name</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">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">CONSTANT_EQN</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<constant-$P>"</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_constant</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">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">OPEN_BRACKET_EQN</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<open-bracket>"</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">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">CLOSE_BRACKET_EQN</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<close-bracket>"</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">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">END_EQN</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<end>"</span><span class="plain">);</span>
|
|
<span class="reserved">else</span><span class="plain"> { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<bad-eqn>\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">" : "</span><span class="plain">);</span>
|
|
<span class="identifier">Kinds::FloatingPoint::log_gk</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain">);</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">", "</span><span class="plain">);</span>
|
|
<span class="identifier">Kinds::FloatingPoint::log_gk</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">OPERATION_EQN</span><span class="plain">)</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
|
|
<span class="functiontext">Equations::log_equation_node_inner</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">d</span><span class="plain">+1);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::log_equation_node is used in <a href="#SP13">§13</a>, <a href="#SP31">§31</a>, <a href="#SP41_4">§41.4</a>, <a href="#SP50_3_2">§50.3.2</a>, <a href="#SP53">§53</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::log_equation_node_inner appears nowhere else.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28"></a><b>§28. Tokenising equations. </b>We break up the word range (w_1, w_2) into tokens of equation matter. Word
|
|
boundaries divide tokens, but so do operators like <code class="display"><span class="extract">+</span></code>, and boundaries can
|
|
also occur in runs of alphanumerics if we spot symbol names: thus <code class="display"><span class="extract">mv^21</span></code>
|
|
will be divided into tokens <code class="display"><span class="extract">m</span></code>, <code class="display"><span class="extract">v</span></code>, <code class="display"><span class="extract">^</span></code>, <code class="display"><span class="extract">21</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">The following routine sends each token in turn to the shift/reduce parser
|
|
below, encoding each token as an enode. We return <code class="display"><span class="extract">NULL</span></code> if a problem message
|
|
has to be issued, or else a pointer to the parsed tree if we succeed.
|
|
</p>
|
|
|
|
|
|
<pre class="definitions">
|
|
<span class="definitionkeyword">define</span> <span class="constant">MAX_ENODES_IN_EXPRESSION</span><span class="plain"> 100</span>
|
|
</pre>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="functiontext">Equations::eqn_parse</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">;</span>
|
|
<span class="functiontext">Equations::enode_sr_start</span><span class="plain">(); </span> <span class="comment">start the shift-reduce parser</span>
|
|
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">previous_token</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">enode_count</span><span class="plain"> = 0; </span> <span class="comment">number of tokens shipped so far</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">bl</span><span class="plain"> = 0; </span> <span class="comment">bracket nesting level</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">wn</span><span class="plain"> = </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">), </span><span class="identifier">i</span><span class="plain"> = 0; </span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">wn</span><span class="plain"> <= </span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">)) || (</span><span class="identifier">p</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">i</span><span class="plain"> = 0; </span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">Lexer::word_raw_text</span><span class="plain">(</span><span class="identifier">wn</span><span class="plain">++); }</span>
|
|
<span class="comment">we are now at character <code class="display"><span class="extract">i</span></code> in string <code class="display"><span class="extract">p</span></code>, while <code class="display"><span class="extract">wn</span></code> is the next word</span>
|
|
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">token</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<<span class="cwebmacro">Break off a token from the current position</span> <span class="cwebmacronumber">28.1</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Issue the token to the shift-reduce parser</span> <span class="cwebmacronumber">28.2</span>><span class="plain">;</span>
|
|
|
|
<span class="identifier">previous_token</span><span class="plain"> = </span><span class="identifier">token</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] == 0) </span><span class="identifier">p</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_sr_token</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">END_EQN</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Equation fails in the shift-reduce parser</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">result</span><span class="plain"> = </span><span class="functiontext">Equations::enode_sr_result</span><span class="plain">();</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">bl</span><span class="plain"> != 0) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this seems to use brackets in a mismatched way, since there "</span>
|
|
<span class="string">"are different numbers of left and right brackets '(' and ')'."</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">result</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_parse is used in <a href="#SP13">§13</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1"></a><b>§28.1. </b>Note that symbol names can't begin with a digit.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Break off a token from the current position</span> <span class="cwebmacronumber">28.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">];</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::isalpha</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">)) </span><<span class="cwebmacro">Break off a symbol name as a token</span> <span class="cwebmacronumber">28.1.1</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">)) </span><<span class="cwebmacro">Break off a numeric constant as a token</span> <span class="cwebmacronumber">28.1.2</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><<span class="cwebmacro">Break off an operator or a piece of punctuation as a token</span> <span class="cwebmacronumber">28.1.3</span>><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28">§28</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1_1"></a><b>§28.1.1. </b>Note that symbols are identified by recognition: without knowing the identities
|
|
of the symbols, the syntax alone wouldn't tell us how to break them. We can only
|
|
break <code class="display"><span class="extract">mc^2</span></code> as <code class="display"><span class="extract">m</span></code> followed by <code class="display"><span class="extract">c^2</span></code> if we know that <code class="display"><span class="extract">m</span></code> and <code class="display"><span class="extract">c</span></code> are symbols,
|
|
rather than <code class="display"><span class="extract">mc</span></code>. (This is one reason why most programming languages don't
|
|
allow implicit multiplication.)
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Break off a symbol name as a token</span> <span class="cwebmacronumber">28.1.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">text_of_symbol</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain">; </span> <span class="comment">the length of the symbol name we try to break off</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">j</span><span class="plain">=0; (</span><span class="identifier">j</span><span class="plain"><14) && (</span><span class="identifier">Characters::isalnum</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">j</span><span class="plain">])) && (</span><span class="identifier">token</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">); </span><span class="identifier">j</span><span class="plain">++)</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_symbol</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">j</span><span class="plain">]);</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">standard_equation_symbols</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Look for this symbol name</span> <span class="cwebmacronumber">28.1.1.1</span>><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">token</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">j</span><span class="plain">=1; (</span><span class="identifier">j</span><span class="plain"><15) && (</span><span class="identifier">Characters::isalnum</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">j</span><span class="plain">-1])) && (</span><span class="identifier">token</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">); </span><span class="identifier">j</span><span class="plain">++) {</span>
|
|
<span class="comment">copy the first <code class="display"><span class="extract">j</span></code> characters into a C string:</span>
|
|
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">text_of_symbol</span><span class="plain">);</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">k</span><span class="plain">=0; </span><span class="identifier">k</span><span class="plain"><</span><span class="identifier">j</span><span class="plain">; </span><span class="identifier">k</span><span class="plain">++) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_symbol</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+</span><span class="identifier">k</span><span class="plain">]);</span>
|
|
<span class="comment">try to identify this as one of the declared symbols:</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Look for this symbol name</span> <span class="cwebmacronumber">28.1.1.1</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">token</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem_S</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationTokenUnrecognised</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">text_of_symbol</span><span class="plain">,</span>
|
|
<span class="string">"the symbol '%3' is one that I don't recognise. It doesn't "</span>
|
|
<span class="string">"seem to be declared after the equation - for instance, "</span>
|
|
<span class="string">"by adding 'where %3 is a number'."</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">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">text_of_symbol</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28_1">§28.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1_1_1"></a><b>§28.1.1.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Look for this symbol name</span> <span class="cwebmacronumber">28.1.1.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::eq_wide_string</span><span class="plain">(</span><span class="identifier">text_of_symbol</span><span class="plain">, </span><span class="identifier">Lexer::word_raw_text</span><span class="plain">(</span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">)))) {</span>
|
|
<span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_symbol</span><span class="plain">(</span><span class="identifier">ev</span><span class="plain">);</span>
|
|
<span class="identifier">i</span><span class="plain"> += </span><span class="identifier">j</span><span class="plain">;</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28_1_1">§28.1.1</a> (twice).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1_2"></a><b>§28.1.2. </b>The following is reliable because a string of digits not starting with a
|
|
0 is always a valid number to Inform unless it overflows the virtual machine's
|
|
capacity; and so is the number 0 itself.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Break off a numeric constant as a token</span> <span class="cwebmacronumber">28.1.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] == </span><span class="character">'0'</span><span class="plain">) && (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+1]))) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationLeadingZero</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"a number in an equation isn't allowed to begin with a "</span>
|
|
<span class="string">"'0' digit, so an equation like 'M = 007+Q' is against the rules."</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">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">);</span>
|
|
<<span class="cwebmacro">Copy the literal number into a C string, flanked by spaces</span> <span class="cwebmacronumber">28.1.2.1</span>><span class="plain">;</span>
|
|
<span class="comment">now sneakily add this to the word stream, and let the S-parser read it:</span>
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">NW</span><span class="plain"> = </span><span class="identifier">Feeds::feed_stream</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">);</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">text_of_number</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">s</span><span class="plain">-</span><span class="identifier">type</span><span class="plain">-</span><span class="identifier">expression</span><span class="plain">>(</span><span class="identifier">NW</span><span class="plain">)) </span><span class="identifier">spec</span><span class="plain"> = <<</span><span class="identifier">rp</span><span class="plain">>>;</span>
|
|
<span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"there's a literal number in that equation which doesn't make "</span>
|
|
<span class="string">"sense to me."</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="comment">this can only go wrong if there was an overflow, and a problem will have been issued for that:</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">CONSTANT_NT</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_constant</span><span class="plain">(</span><span class="identifier">spec</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28_1">§28.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1_2_1"></a><b>§28.1.2.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Copy the literal number into a C string, flanked by spaces</span> <span class="cwebmacronumber">28.1.2.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">])) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] == </span><span class="character">'.'</span><span class="plain">) {</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">])) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Literals::ismultiplicationsign</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">])) && (</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+1] == </span><span class="character">'1'</span><span class="plain">) && (</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+2] == </span><span class="character">'0'</span><span class="plain">) && (</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">+3] == </span><span class="character">'^'</span><span class="plain">)) {</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">])) </span><span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="identifier">p</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">++]);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">text_of_number</span><span class="plain">, </span><span class="character">' '</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28_1_2">§28.1.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_1_3"></a><b>§28.1.3. </b>Which leaves just the easiest case:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Break off an operator or a piece of punctuation as a token</span> <span class="cwebmacronumber">28.1.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="character">'='</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">EQUALS_OPERATION</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="character">'+'</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">PLUS_OPERATION</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="character">'-'</span><span class="plain">:</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">previous_token</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) ||</span>
|
|
<span class="plain">(</span><span class="identifier">previous_token</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">OPERATION_EQN</span><span class="plain">) ||</span>
|
|
<span class="plain">(</span><span class="identifier">previous_token</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">OPEN_BRACKET_EQN</span><span class="plain">))</span>
|
|
<span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">UNARY_MINUS_OPERATION</span><span class="plain">);</span>
|
|
<span class="reserved">else</span>
|
|
<span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">MINUS_OPERATION</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="character">'/'</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">DIVIDE_OPERATION</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="character">'*'</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">TIMES_OPERATION</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="character">'^'</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">POWER_OPERATION</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="character">'('</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">OPEN_BRACKET_EQN</span><span class="plain">); </span><span class="identifier">bl</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="character">')'</span><span class="plain">: </span><span class="identifier">token</span><span class="plain"> = </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">CLOSE_BRACKET_EQN</span><span class="plain">); </span><span class="identifier">bl</span><span class="plain">--; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">: {</span>
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">symbol</span><span class="plain">);</span>
|
|
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">symbol</span><span class="plain">, </span><span class="identifier">c</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem_S</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationOperatorUnrecognised</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">symbol</span><span class="plain">,</span>
|
|
<span class="string">"the symbol '%3' is one that I don't recognise. I was "</span>
|
|
<span class="string">"expecting an arithmetic sign, '+', '-', '*','/', or '^', "</span>
|
|
<span class="string">"or else '=' or a bracket '(' or ')'."</span><span class="plain">);</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Bad operator '%S'\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">symbol</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">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">symbol</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">i</span><span class="plain">++;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28_1">§28.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_2"></a><b>§28.2. </b>So now we have our next token, and are ready to ship it. But if we
|
|
detect an implicit multiplication, for instance between <code class="display"><span class="extract">m</span></code> and <code class="display"><span class="extract">c^2</span></code>
|
|
in <code class="display"><span class="extract">E=mc^2</span></code>, we issue that as an <code class="display"><span class="extract">IMPLICIT_TIMES_OPERATION</span></code> enode in
|
|
between; and in <code class="display"><span class="extract">log pi</span></code> we issue an <code class="display"><span class="extract">IMPLICIT_APPLICATION_OPERATION</span></code>.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Issue the token to the shift-reduce parser</span> <span class="cwebmacronumber">28.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::application_is_implied</span><span class="plain">(</span><span class="identifier">previous_token</span><span class="plain">, </span><span class="identifier">token</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_sr_token</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Equation fails in the shift-reduce parser</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="identifier">enode_count</span><span class="plain">++;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::multiplication_is_implied</span><span class="plain">(</span><span class="identifier">previous_token</span><span class="plain">, </span><span class="identifier">token</span><span class="plain">)) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_sr_token</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="constant">IMPLICIT_TIMES_OPERATION</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Equation fails in the shift-reduce parser</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="identifier">enode_count</span><span class="plain">++;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_sr_token</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">token</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Equation fails in the shift-reduce parser</span> <span class="cwebmacronumber">28.3</span>><span class="plain">;</span>
|
|
<span class="identifier">enode_count</span><span class="plain">++;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">enode_count</span><span class="plain"> >= </span><span class="constant">MAX_ENODES_IN_EXPRESSION</span><span class="plain"> - 2) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationTooComplex</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this is too long and complex an equation."</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>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28">§28</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP28_3"></a><b>§28.3. </b>In case any of the enode insertions fail. It's tricky to generate good error
|
|
messages and recover well when an operator-precedence grammar fails to match in
|
|
a parser like this, so we'll fall back on this:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Equation fails in the shift-reduce parser</span> <span class="cwebmacronumber">28.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationMispunctuated</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this seems to be wrongly punctuated, and doesn't make sense as a "</span>
|
|
<span class="string">"mathematical formula."</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP28">§28</a>, <a href="#SP28_2">§28.2</a> (three times).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP29"></a><b>§29. </b>Lastly, here is when multiplication is implied:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::multiplication_is_implied</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">previous_token</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">token</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lt</span><span class="plain">, </span><span class="identifier">rt</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">token</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">previous_token</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="identifier">lt</span><span class="plain"> = </span><span class="identifier">previous_token</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">; </span><span class="identifier">rt</span><span class="plain"> = </span><span class="identifier">token</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (((</span><span class="identifier">lt</span><span class="plain"> == </span><span class="constant">SYMBOL_EQN</span><span class="plain">) || (</span><span class="identifier">lt</span><span class="plain"> == </span><span class="constant">CONSTANT_EQN</span><span class="plain">) || (</span><span class="identifier">lt</span><span class="plain"> == </span><span class="constant">CLOSE_BRACKET_EQN</span><span class="plain">)) &&</span>
|
|
<span class="plain">((</span><span class="identifier">rt</span><span class="plain"> == </span><span class="constant">SYMBOL_EQN</span><span class="plain">) || (</span><span class="identifier">rt</span><span class="plain"> == </span><span class="constant">CONSTANT_EQN</span><span class="plain">) || (</span><span class="identifier">rt</span><span class="plain"> == </span><span class="constant">OPEN_BRACKET_EQN</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="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::multiplication_is_implied is used in <a href="#SP28_2">§28.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP30"></a><b>§30. </b>And when function application is implied:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::application_is_implied</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">previous_token</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">token</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lt</span><span class="plain">, </span><span class="identifier">rt</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">token</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) || (</span><span class="identifier">previous_token</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="identifier">lt</span><span class="plain"> = </span><span class="identifier">previous_token</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">; </span><span class="identifier">rt</span><span class="plain"> = </span><span class="identifier">token</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lt</span><span class="plain"> == </span><span class="constant">SYMBOL_EQN</span><span class="plain">) && (</span><span class="identifier">previous_token</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</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="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::application_is_implied is used in <a href="#SP28_2">§28.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP31"></a><b>§31. The shift-reduce parser. </b>This is a classic algorithm for expression-evaluator grammars; see for
|
|
instance Aho, Sethi and Ullman, "Compilers", section 4.6 in the second edition.
|
|
We use a pair of stacks. The SR stack holds possible attempts to understand
|
|
what we have so far, given the tokens that have arrived; the emitter stack
|
|
holds nodes which form pieces of the output tree as it is assembled. Nodes
|
|
flow from our input, are usually "shifted" onto the SR stack for a while,
|
|
are eventually "reduced" in clumps taken off this stack and "emitted",
|
|
then go onto the emitter stack, and are finally removed as they are made
|
|
into trees.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">The flow is therefore always forwards; tokens can't slosh back and forth
|
|
between the stacks. On each iteration, at least one token makes progress,
|
|
so if there are N tokens of input (including both end marker tokens) then we
|
|
take at worst 2N steps to finish. Each stack can't need more than N
|
|
entries, and N is bounded above by <code class="display"><span class="extract">MAX_ENODES_IN_EXPRESSION</span></code> plus 2
|
|
(allowing for the end markers). So:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">SR_sp</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="constant">MAX_ENODES_IN_EXPRESSION</span><span class="plain">+2];</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">emitter_sp</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">emitter_stack</span><span class="plain">[</span><span class="constant">MAX_ENODES_IN_EXPRESSION</span><span class="plain">+2];</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::log_sr_stacks</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"SR: "</span><span class="plain">);</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">SR_sp</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">" %d: "</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">); </span><span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]); }</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"EMITTER: "</span><span class="plain">);</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">emitter_sp</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) { </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">" %d: "</span><span class="plain">, </span><span class="identifier">i</span><span class="plain">); </span><span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="identifier">emitter_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]); }</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::log_sr_stacks appears nowhere else.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP32"></a><b>§32. </b>The start and finish are as follows. At the start, the emitter stack is
|
|
empty and the SR stack contains an <code class="display"><span class="extract">END_EQN</span></code> token, which represents the
|
|
left-hand end of the expression. (Another such token, this time representing the
|
|
right-hand end, will be sent by the routines above at the end of the stream. So
|
|
there will be two <code class="display"><span class="extract">END_EQN</span></code> tokens in play.)
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::enode_sr_start</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="identifier">SR_stack</span><span class="plain">[0] = </span><span class="functiontext">Equations::enode_new</span><span class="plain">(</span><span class="constant">END_EQN</span><span class="plain">);</span>
|
|
<span class="identifier">SR_sp</span><span class="plain"> = 1;</span>
|
|
<span class="identifier">emitter_sp</span><span class="plain"> = 0;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_sr_start is used in <a href="#SP28">§28</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP33"></a><b>§33. </b>If we have succeeded, the end state of the emitter stack contains a single
|
|
node: the head of the tree we have grown to represent the expression.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="functiontext">Equations::enode_sr_result</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">emitter_stack</span><span class="plain">[0];</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_sr_result is used in <a href="#SP28">§28</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP34"></a><b>§34. </b>So the following is the routine which iteratively deals with tokens as
|
|
they arrive. As noted above, the loop however ominous always terminates.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">For proofs and explanations see ASU, but the idea is simple enough: as we
|
|
see the expression a little at a time, we collect possibilities of how to
|
|
read it on the SR-stack, until we reach a point where it's possible to tell
|
|
what was meant; we then reduce the SR-stack by taking the winning possibility
|
|
off the top and moving it to the emitter stack. For instance, if we have
|
|
read <code class="display"><span class="extract">4 + 5</span></code> then we don't know yet whether the <code class="display"><span class="extract">+</span></code> will add the 4 to the 5;
|
|
if the next token is <code class="display"><span class="extract">+</span></code> or <code class="display"><span class="extract">END_EQN</span></code> then it will, but if the next token
|
|
is <code class="display"><span class="extract">*</span></code> then it won't, because we're looking at something like <code class="display"><span class="extract">4 + 5 * 6</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">If the next token is of lower precedence than <code class="display"><span class="extract">+</span></code> then we "reduce" —
|
|
telling the emitter about the addition, which we now understand — but if
|
|
it's higher, as with <code class="display"><span class="extract">*</span></code>, then we "shift", meaning, we postpone worrying
|
|
about the addition and start worrying about the multiplication instead;
|
|
our new problem, working out what <code class="display"><span class="extract">*</span></code> applies to, sits on top of the
|
|
addition problem on the SR-stack.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_sr_token</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">safety_cutout</span><span class="plain"> = 3*</span><span class="constant">MAX_ENODES_IN_EXPRESSION</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">TRUE</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">SR_sp</span><span class="plain"> <= 0) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"SR stack empty"</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">-1]-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">END_EQN</span><span class="plain">) && (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">END_EQN</span><span class="plain">)) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">Equations::enode_lt</span><span class="plain">(</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">-1], </span><span class="identifier">tok</span><span class="plain">)) || (</span><span class="functiontext">Equations::enode_eq</span><span class="plain">(</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">-1], </span><span class="identifier">tok</span><span class="plain">)))</span>
|
|
<<span class="cwebmacro">Shift an enode onto the SR-stack</span> <span class="cwebmacronumber">34.1</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_gt</span><span class="plain">(</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">-1], </span><span class="identifier">tok</span><span class="plain">))</span>
|
|
<<span class="cwebmacro">Reduce some enodes from the SR-stack to the emitter stack</span> <span class="cwebmacronumber">34.2</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">safety_cutout</span><span class="plain">-- < 0) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"SR parser deadlocked"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">emitter_sp</span><span class="plain"> != 1) || (</span><span class="identifier">SR_sp</span><span class="plain"> != 1)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_sr_token is used in <a href="#SP28">§28</a>, <a href="#SP28_2">§28.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP34_1"></a><b>§34.1. </b>After shifting, we return a signal of success, which asks for the next
|
|
token to be sent.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Shift an enode onto the SR-stack</span> <span class="cwebmacronumber">34.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">++] = </span><span class="identifier">tok</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP34">§34</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP34_2"></a><b>§34.2. </b>The ASU book is a little vague about what happens if there is an underflow
|
|
here, I think because it's possible to set up the grammar such that an
|
|
underflow cannot occur. But I can see no obvious proof that it will never
|
|
occur for us given syntactically incorrect input, so we will return <code class="display"><span class="extract">FALSE</span></code>
|
|
on an underflow to be safe.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Note that we can never emit the bottom-most token on the SR stack: that's the
|
|
left-hand end marker, so can never be validly part of any arithmetic. So
|
|
an underflow occurs if that's all that's left, i.e., when the SR stack pointer
|
|
is 1, not 0.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Reduce some enodes from the SR-stack to the emitter stack</span> <span class="cwebmacronumber">34.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">do</span><span class="plain"> { </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">SR_sp</span><span class="plain"> <= 1) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_emit</span><span class="plain">(</span><span class="identifier">SR_stack</span><span class="plain">[--</span><span class="identifier">SR_sp</span><span class="plain">]) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">SR_sp</span><span class="plain"> >= 1) && (</span><span class="functiontext">Equations::enode_lt</span><span class="plain">(</span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">-1], </span><span class="identifier">SR_stack</span><span class="plain">[</span><span class="identifier">SR_sp</span><span class="plain">]) == </span><span class="identifier">FALSE</span><span class="plain">));</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP34">§34</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP35"></a><b>§35. </b>The key point is that if nodes arrive at the SR parser in their
|
|
ordinary order of mathematical writing, then they "reduce" off the
|
|
SR stack and onto the emitter stack in reverse Polish notation order.
|
|
Thus the sequence <code class="display"><span class="extract">4 + 2 * 7</span></code> is emitted as <code class="display"><span class="extract">4 2 7 * +</span></code>. RPN has no
|
|
need of brackets to clarify the sequence of operation, and it's very
|
|
easy to build a tree from.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_emit</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SYMBOL_EQN</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="constant">CONSTANT_EQN</span><span class="plain">:</span>
|
|
<span class="identifier">emitter_stack</span><span class="plain">[</span><span class="identifier">emitter_sp</span><span class="plain">++] = </span><span class="identifier">tok</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">OPERATION_EQN</span><span class="plain">:</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> == </span><span class="constant">IMPLICIT_TIMES_OPERATION</span><span class="plain">)</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">TIMES_OPERATION</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> == </span><span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">)</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 2;</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Dimensions::arithmetic_op_is_unary</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">))</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 1;</span>
|
|
<span class="reserved">else</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 2;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> - 1; </span><span class="identifier">i</span><span class="plain"> >= 0; </span><span class="identifier">i</span><span class="plain">--) {</span>
|
|
<span class="identifier">emitter_sp</span><span class="plain">--;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">emitter_sp</span><span class="plain"> < 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="identifier">emitter_stack</span><span class="plain">[</span><span class="identifier">emitter_sp</span><span class="plain">];</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">emitter_stack</span><span class="plain">[</span><span class="identifier">emitter_sp</span><span class="plain">++] = </span><span class="identifier">tok</span><span class="plain">;</span>
|
|
<span class="reserved">break</span><span class="plain">;</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>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_emit is used in <a href="#SP34_2">§34.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP36"></a><b>§36. </b>All we need now is to decide the order of precedence of our tokens,
|
|
though this isn't as simple as it looks, because they are not all
|
|
symmetrical left-right. That's obviously true of things like an open
|
|
bracket <code class="display"><span class="extract">(</span></code>, which affects the stuff to the left very differently from
|
|
the stuff to the right. But it is also true of operators. <code class="display"><span class="extract">+</span></code> may be
|
|
associative mathematically, but in computing there's a difference
|
|
between evaluating <code class="display"><span class="extract">a + (b+c)</span></code> and <code class="display"><span class="extract">(a+b) + c</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">All of this means there's no simple order relationship on the tokens,
|
|
where T<S if and only if S>T. We order them using a numerical score,
|
|
but they get one score f(T) if they appear on the left and another
|
|
score g(T) if they appear on the right:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_lt</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok1</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok2</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">f_left</span><span class="plain"> = </span><span class="functiontext">Equations::f_function</span><span class="plain">(</span><span class="identifier">tok1</span><span class="plain">), </span><span class="identifier">g_right</span><span class="plain"> = </span><span class="functiontext">Equations::g_function</span><span class="plain">(</span><span class="identifier">tok2</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">f_left</span><span class="plain"> < </span><span class="identifier">g_right</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="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_eq</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok1</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok2</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">f_left</span><span class="plain"> = </span><span class="functiontext">Equations::f_function</span><span class="plain">(</span><span class="identifier">tok1</span><span class="plain">), </span><span class="identifier">g_right</span><span class="plain"> = </span><span class="functiontext">Equations::g_function</span><span class="plain">(</span><span class="identifier">tok2</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">f_left</span><span class="plain"> == </span><span class="identifier">g_right</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="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_gt</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok1</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok2</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">f_left</span><span class="plain"> = </span><span class="functiontext">Equations::f_function</span><span class="plain">(</span><span class="identifier">tok1</span><span class="plain">), </span><span class="identifier">g_right</span><span class="plain"> = </span><span class="functiontext">Equations::g_function</span><span class="plain">(</span><span class="identifier">tok2</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">f_left</span><span class="plain"> > </span><span class="identifier">g_right</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="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_lt is used in <a href="#SP34">§34</a>, <a href="#SP34_2">§34.2</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::enode_eq is used in <a href="#SP34">§34</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::enode_gt is used in <a href="#SP34">§34</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP37"></a><b>§37. </b>And here are those scorings. Note that for the binary operators, f
|
|
scores are usually slightly higher than g scores: that's what makes
|
|
them left associative, that is, a+b+c is read as (a+b)+c. The
|
|
exception to this is raising to powers: <code class="display"><span class="extract">a^2^3</span></code> evaluates a^8, not
|
|
a^6, because it is read as <code class="display"><span class="extract">a^(2^3)</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Implicit multiplication has higher precedence than explicit. This is
|
|
actually to give it higher precedence than division (which has to have
|
|
the same precedence as explicit multiplication), and is so that
|
|
<code class="display"><span class="extract">ab/cd</span></code> evaluates (ab)/(cd) rather than a. (b/c). d.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::f_function</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SYMBOL_EQN</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="constant">CONSTANT_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 16;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPERATION_EQN</span><span class="plain">:</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">EQUALS_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 2;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">PLUS_OPERATION</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="identifier">MINUS_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 4;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">TIMES_OPERATION</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="identifier">DIVIDE_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 6;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">IMPLICIT_TIMES_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 8;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">POWER_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 9;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 5;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">UNARY_MINUS_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 1;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unknown operator precedence"</span><span class="plain">);</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPEN_BRACKET_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 0;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CLOSE_BRACKET_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 16;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">END_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 0;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unknown f-value"</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 Equations::f_function is used in <a href="#SP36">§36</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP38"></a><b>§38. </b>And symmetrically:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::g_function</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SYMBOL_EQN</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="constant">CONSTANT_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 15;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPERATION_EQN</span><span class="plain">:</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">) </span><span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">EQUALS_OPERATION</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="identifier">PLUS_OPERATION</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="identifier">MINUS_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 3;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">TIMES_OPERATION</span><span class="plain">: </span><span class="reserved">case</span><span class="plain"> </span><span class="identifier">DIVIDE_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 5;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">IMPLICIT_TIMES_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 7;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">POWER_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 10;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 14;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">UNARY_MINUS_OPERATION</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 12;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unknown operator precedence"</span><span class="plain">);</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPEN_BRACKET_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 15;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CLOSE_BRACKET_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 0;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">END_EQN</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> 0;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unknown g-value"</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 Equations::g_function is used in <a href="#SP36">§36</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP39"></a><b>§39. Typechecking equations. </b>The SR parser can generate trees for any syntactically valid equation, but
|
|
it may be something using <code class="display"><span class="extract">=</span></code> inappropriately or not at all. We rule that
|
|
out first: we want the top node in the tree to be the unique <code class="display"><span class="extract">=</span></code> operator.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::eqn_typecheck</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="functiontext">Equations::enode_count_equals</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">)) {</span>
|
|
<span class="reserved">case</span><span class="plain"> 0:</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationDoesntEquate</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this equation doesn't seem to contain an equals sign, and "</span>
|
|
<span class="string">"without '=' there is no equating anything with anything."</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> 1:</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_is_equals</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationEquatesBadly</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"the equals sign '=' here seems to be buried inside the "</span>
|
|
<span class="string">"formula, not at the surface. For instance, 'F = ma' is "</span>
|
|
<span class="string">"fine, but 'F(m=a)' would not make sense - the '=' would "</span>
|
|
<span class="string">"be inside brackets."</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="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">:</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationEquatesMultiply</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this equation seems to contain more than one equals "</span>
|
|
<span class="string">"sign '='."</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="reserved">return</span><span class="plain"> </span><span class="functiontext">Equations::enode_typecheck</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_typecheck is used in <a href="#SP13">§13</a>, <a href="#SP47_2">§47.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP40"></a><b>§40. </b>A recursive count of instances down the tree from <code class="display"><span class="extract">tok</span></code>:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_count_equals</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0, </span><span class="identifier">i</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_is_equals</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">)) </span><span class="identifier">c</span><span class="plain">++;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
|
|
<span class="identifier">c</span><span class="plain"> += </span><span class="functiontext">Equations::enode_count_equals</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_is_equals</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</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="reserved">if</span><span class="plain"> ((</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">OPERATION_EQN</span><span class="plain">) && (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> == </span><span class="identifier">EQUALS_OPERATION</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="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_count_equals is used in <a href="#SP39">§39</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::enode_is_equals is used in <a href="#SP39">§39</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41"></a><b>§41. </b>Now we come to the real typechecking. The following is called, depth-first,
|
|
at each node in the equation; it has to assign a kind at every node, in such
|
|
a way that all operations are dimensionally valid. We return <code class="display"><span class="extract">FALSE</span></code> if we
|
|
are obliged to issue a problem message.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">float_terminal_nodes</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_typecheck</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">result</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</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">result</span><span class="plain">;</span>
|
|
<span class="identifier">LOG_INDENT</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_typecheck</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
|
|
<span class="identifier">result</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">result</span><span class="plain">) {</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SYMBOL_EQN</span><span class="plain">:</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>var_kind</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">CONSTANT_EQN</span><span class="plain">:</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span>
|
|
<span class="identifier">ParseTree::get_kind_of_value</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_constant</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_promotion</span><span class="plain">) && (</span><span class="functiontext">VirtualMachines::supports</span><span class="plain">(</span><span class="identifier">K_real_number</span><span class="plain">)))</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::to_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</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">OPERATION_EQN</span><span class="plain">:</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> == </span><span class="identifier">EQUALS_OPERATION</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Typecheck the set-equals node at the top level</span> <span class="cwebmacronumber">41.1</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> == </span><span class="identifier">POWER_OPERATION</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Typecheck a raise-to-integer-power node</span> <span class="cwebmacronumber">41.2</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> == </span><span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Typecheck a function application node</span> <span class="cwebmacronumber">41.3</span>>
|
|
<span class="reserved">else</span>
|
|
<<span class="cwebmacro">Typecheck a general operation node</span> <span class="cwebmacronumber">41.4</span>><span class="plain">;</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">: </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"forbidden enode found in parsed equation"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">float_terminal_nodes</span><span class="plain">) && (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">))</span>
|
|
<span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="identifier">LOG_OUTDENT</span><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">result</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_typecheck is used in <a href="#SP39">§39</a>, <a href="#SP42">§42</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_1"></a><b>§41.1. </b>If we know that we need a real rather than integer answer, that has to
|
|
propagate downwards from the equality into the trees on either side, casting
|
|
integers to reals.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Typecheck the set-equals node at the top level</span> <span class="cwebmacronumber">41.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="identifier">L</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::integer_equivalent</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">);</span>
|
|
<span class="identifier">R</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::integer_equivalent</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
|
|
<span class="identifier">result</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Tried to equate $u and $u\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationIncomparable</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this equation tries to set two values equal which have "</span>
|
|
<span class="string">"different kinds from each other."</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lf</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">) && (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1], </span><span class="identifier">TRUE</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) && (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">)) </span><span class="functiontext">Equations::demote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]);</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41">§41</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_2"></a><b>§41.2. </b>The restriction on powers is needed to make it possible to know the
|
|
dimensions of the result. If h is a length, h^2 is an area but h^3 is
|
|
a volume; so if all we have is h^n, and we don't know the value of n,
|
|
we're unable to see what equations h^n can appear in.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Typecheck a raise-to-integer-power node</span> <span class="cwebmacronumber">41.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">base</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">power</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1];</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Dimensions::dimensionless</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">base</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">))) {</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> = </span><span class="identifier">base</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">;</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain"> = </span><span class="identifier">base</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><<span class="cwebmacro">Take the dimensional power of the kind of the base</span> <span class="cwebmacronumber">41.2.1</span>><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lf</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">) && (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1], </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) && (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">)) </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0], </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) && ((</span><span class="identifier">lf</span><span class="plain">) || (</span><span class="identifier">rf</span><span class="plain">))) {</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::to_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41">§41</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_3"></a><b>§41.3. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Typecheck a function application node</span> <span class="cwebmacronumber">41.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">fn</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">fn</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">SYMBOL_EQN</span><span class="plain">) && (</span><span class="identifier">fn</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain">)) {</span>
|
|
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">ph</span><span class="plain"> = </span><span class="identifier">fn</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain">;</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">RK</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Phrases::TypeData::arithmetic_operation</span><span class="plain">(</span><span class="identifier">ph</span><span class="plain">) == </span><span class="identifier">REALROOT_OPERATION</span><span class="plain">) {</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">OPK</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="identifier">RK</span><span class="plain"> = </span><span class="identifier">Kinds::Dimensions::arithmetic_on_kinds</span><span class="plain">(</span><span class="identifier">OPK</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">REALROOT_OPERATION</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">RK</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationCantRoot</span><span class="plain">-</span><span class="identifier">G</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"the square root function 'root' can only be used on quantities "</span>
|
|
<span class="string">"whose dimensions are themselves a square - for example, the "</span>
|
|
<span class="string">"root of the area 100 sq m makes sense (it's 10m), but the root "</span>
|
|
<span class="string">"of 4m doesn't make sense, because what's a square root of a meter?"</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="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">RK</span><span class="plain"> = </span><span class="functiontext">Phrases::TypeData::get_return_kind</span><span class="plain">(&(</span><span class="identifier">ph</span><span class="plain">-</span><span class="element">>type_data</span><span class="plain">));</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::to_real</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">RK</span><span class="plain">));</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1], </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41">§41</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_2_1"></a><b>§41.2.1. </b>To work out the kind of b^n, we use repeated multiplication or division
|
|
of dimensions; if n=0 then we have a dimensionless value, and choose
|
|
"number" as the simplest possibility.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Take the dimensional power of the kind of the base</span> <span class="cwebmacronumber">41.2.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::integer_equivalent</span><span class="plain">(</span>
|
|
<span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span>
|
|
<span class="identifier">base</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">));</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">real</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">base</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">)) </span><span class="identifier">real</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain"> = -1, </span><span class="identifier">m</span><span class="plain"> = 1;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">power</span><span class="plain">-</span><span class="element">>rational_m</span><span class="plain"> != 0) {</span>
|
|
<span class="identifier">n</span><span class="plain"> = </span><span class="identifier">power</span><span class="plain">-</span><span class="element">>rational_n</span><span class="plain">; </span><span class="identifier">m</span><span class="plain"> = </span><span class="identifier">power</span><span class="plain">-</span><span class="element">>rational_m</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">m</span><span class="plain"> > 1) && (</span><span class="identifier">real</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) {</span>
|
|
<span class="identifier">result</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationCantPower2</span><span class="plain">-</span><span class="identifier">G</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"except for the special cases of squaring and cubing, the '^' "</span>
|
|
<span class="string">"raise-to-power symbol can only be used to power a value using "</span>
|
|
<span class="string">"real rather than integer arithmetic."</span><span class="plain">);</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">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">power</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">), </span><span class="identifier">K_number</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) ||</span>
|
|
<span class="plain">(</span><span class="identifier">power</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> != </span><span class="constant">CONSTANT_EQN</span><span class="plain">)) {</span>
|
|
<span class="identifier">result</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationDimensionPower</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"the '^' raise-to-power symbol can only be used to raise a value "</span>
|
|
<span class="string">"with dimensions to a specific number. So 'mv^2' is fine, but not "</span>
|
|
<span class="string">"'mv^n' or 'mv^(1+n)'. (This is because I would need to work out what "</span>
|
|
<span class="string">"kind of value 'v^n' would be, and the answer would depend on 'n', "</span>
|
|
<span class="string">"but I wouldn't know what 'n' is.)"</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">n</span><span class="plain"> = </span><span class="functiontext">Rvalues::to_int</span><span class="plain">(</span><span class="identifier">power</span><span class="plain">-</span><span class="element">>leaf_constant</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">n</span><span class="plain"> >= 1) {</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">Kinds::Dimensions::to_rational_power</span><span class="plain">(</span><span class="identifier">F</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">, </span><span class="identifier">m</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">NULL</span><span class="plain">) {</span>
|
|
<span class="functiontext">Problems::Issue::equation_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">), </span><span class="identifier">eqn</span><span class="plain">, </span><span class="string">""</span><span class="plain">,</span>
|
|
<span class="string">"this would involve taking a fractional power of an amount whose "</span>
|
|
<span class="string">"dimensions are not of that power form - for example, the square "</span>
|
|
<span class="string">"root of the area 100 sq m makes sense (it's 10m), but the square "</span>
|
|
<span class="string">"root of 4m doesn't make sense, because what's a square root of "</span>
|
|
<span class="string">"a meter?"</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="reserved">if</span><span class="plain"> (</span><span class="identifier">real</span><span class="plain">)</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::to_real</span><span class="plain">(</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">));</span>
|
|
<span class="reserved">else</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41_2">§41.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_4"></a><b>§41.4. </b>The following is easy because it was the content of the whole "Dimensions.w"
|
|
section:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Typecheck a general operation node</span> <span class="cwebmacronumber">41.4</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">O1</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::integer_equivalent</span><span class="plain">(</span>
|
|
<span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">));</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">real</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">))</span>
|
|
<span class="identifier">real</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Dimensions::arithmetic_op_is_unary</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">))</span>
|
|
<span class="identifier">K</span><span class="plain"> = </span><span class="identifier">Kinds::Dimensions::arithmetic_on_kinds</span><span class="plain">(</span><span class="identifier">O1</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">);</span>
|
|
<span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">O2</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::integer_equivalent</span><span class="plain">(</span>
|
|
<span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">))</span>
|
|
<span class="identifier">real</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="identifier">K</span><span class="plain"> = </span><span class="identifier">Kinds::Dimensions::arithmetic_on_kinds</span><span class="plain">(</span><span class="identifier">O1</span><span class="plain">, </span><span class="identifier">O2</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rf</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lf</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">) && (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">)) </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1], </span><span class="identifier">FALSE</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lf</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) && (</span><span class="identifier">rf</span><span class="plain"> == </span><span class="identifier">TRUE</span><span class="plain">)) </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0], </span><span class="identifier">FALSE</span><span class="plain">);</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">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">result</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_value</span><span class="plain">);</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Failed at operation:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">); </span><span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Dimensions::arithmetic_op_is_unary</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">))</span>
|
|
<<span class="cwebmacro">Issue unary equation typechecking problem message</span> <span class="cwebmacronumber">41.4.1</span>>
|
|
<span class="reserved">else</span>
|
|
<<span class="cwebmacro">Issue binary equation typechecking problem message</span> <span class="cwebmacronumber">41.4.2</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">real</span><span class="plain">)</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::to_real</span><span class="plain">(</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">));</span>
|
|
<span class="reserved">else</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41">§41</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_4_1"></a><b>§41.4.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue unary equation typechecking problem message</span> <span class="cwebmacronumber">41.4.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::quote_kind</span><span class="plain">(4,</span>
|
|
<span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">));</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">UNARY_MINUS_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"negating"</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="identifier">ROOT_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"taking the square root of"</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="identifier">REALROOT_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"taking the (real-valued) square root of"</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="identifier">CUBEROOT_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"taking the cube root of"</span><span class="plain">);</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">BelievedImpossible</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"You wrote %1, but that equation seems to involve %6 %4, which is not "</span>
|
|
<span class="string">"good arithmetic."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41_4">§41.4</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP41_4_2"></a><b>§41.4.2. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue binary equation typechecking problem message</span> <span class="cwebmacronumber">41.4.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::quote_kind</span><span class="plain">(4, </span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_after</span><span class="plain">));</span>
|
|
<span class="functiontext">Problems::quote_kind</span><span class="plain">(5, </span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain">));</span>
|
|
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">PLUS_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"adding"</span><span class="plain">); </span><span class="identifier">Problems::quote_text</span><span class="plain">(7, </span><span class="string">"to"</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="identifier">MINUS_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"subtracting"</span><span class="plain">); </span><span class="identifier">Problems::quote_text</span><span class="plain">(7, </span><span class="string">"from"</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="identifier">TIMES_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"multiplying"</span><span class="plain">); </span><span class="identifier">Problems::quote_text</span><span class="plain">(7, </span><span class="string">"by"</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="identifier">DIVIDE_OPERATION</span><span class="plain">:</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">REMAINDER_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"dividing"</span><span class="plain">); </span><span class="identifier">Problems::quote_text</span><span class="plain">(7, </span><span class="string">"by"</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="identifier">POWER_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"raising"</span><span class="plain">); </span><span class="identifier">Problems::quote_text</span><span class="plain">(7, </span><span class="string">"to the power of"</span><span class="plain">);</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">:</span>
|
|
<span class="identifier">Problems::quote_text</span><span class="plain">(6, </span><span class="string">"combining"</span><span class="plain">); </span><span class="identifier">Problems::quote_text</span><span class="plain">(7, </span><span class="string">"with"</span><span class="plain">);</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationBadArithmetic</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"You wrote %1, but that equation seems to involve "</span>
|
|
<span class="string">"%6 %4 %7 %5, which is not good arithmetic."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP41_4">§41.4</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP42"></a><b>§42. Flotation. </b></p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::promote_subequation</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">deeply</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">deeply</span><span class="plain">) {</span>
|
|
<span class="identifier">float_terminal_nodes</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="functiontext">Equations::enode_typecheck</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">tok</span><span class="plain">);</span>
|
|
<span class="identifier">float_terminal_nodes</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::to_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::demote_subequation</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</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">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::to_integer</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::promote_subequation is used in <a href="#SP41">§41</a>, <a href="#SP41_1">§41.1</a>, <a href="#SP41_2">§41.2</a>, <a href="#SP41_3">§41.3</a>, <a href="#SP41_4">§41.4</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::demote_subequation is used in <a href="#SP41_1">§41.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP43"></a><b>§43. Compiling. </b>We want each equation to have a distinct value at runtime. The following
|
|
routines do nothing (for now, anyway) except to give the I6 identifiers
|
|
for equations a value; they are never called.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::compile</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
|
|
<span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation</span><span class="plain">) {</span>
|
|
<span class="identifier">packaging_state</span><span class="plain"> </span><span class="identifier">save</span><span class="plain"> = </span><span class="functiontext">Routines::begin</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>eqn_iname</span><span class="plain">);</span>
|
|
<span class="identifier">Produce::rfalse</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
|
|
<span class="functiontext">Routines::end</span><span class="plain">(</span><span class="identifier">save</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::compile is used in 1/mr (<a href="1-mr.html#SP4_14">§4.14</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP44"></a><b>§44. </b>These identifiers are used to compile equation names as values, so:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="functiontext">Equations::identifier</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>eqn_iname</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::identifier is used in 14/rv (<a href="14-rv.html#SP24_3">§24.3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP45"></a><b>§45. Solving. </b>So we can finally turn to putting equations to use. Firstly, when a named
|
|
equation is used, a "where..." clause is sometimes given to make temporary
|
|
assignments (see above); what happens is that the S-parser temporarily sets
|
|
the usage words of the equation to the relevant text...
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::set_usage_notes</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</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">eqn</span><span class="plain">-</span><span class="element">>usage_text</span><span class="plain"> = </span><span class="identifier">W</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::set_usage_notes is used in 10/teav (<a href="10-teav.html#SP12_2">§12.2</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP46"></a><b>§46. </b>...so that, when we come to solve the equation (i.e., later on in the
|
|
invocation compiler), we know where to find these temporary assignments.
|
|
They are wiped out once this compilation is over.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::emit_solution</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">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::nonempty</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>usage_text</span><span class="plain">))</span>
|
|
<span class="functiontext">Equations::eqn_declare_variables_inner</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>usage_text</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
|
|
<span class="functiontext">Equations::emit_solution_inner</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="functiontext">Equations::eqn_remove_temp_variables</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>usage_text</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::emit_solution is used in 25/cii (<a href="25-cii.html#SP3_7_3">§3.7.3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP47"></a><b>§47. </b>With that dance out of the way, we can concentrate on the actual task.
|
|
We have to compile code which assigns the correct value to the symbol
|
|
specified by (w_1, w_2), according to the equation <code class="display"><span class="extract">eqn</span></code>.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::emit_solution_inner</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">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">to_solve</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
|
|
<<span class="cwebmacro">Identify which symbol in the equation we are solving for</span> <span class="cwebmacronumber">47.1</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Rearrange the equation so that this symbol is the entire LHS</span> <span class="cwebmacronumber">47.2</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Identify the symbols in the equation with local variables</span> <span class="cwebmacronumber">47.3</span>><span class="plain">;</span>
|
|
|
|
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">);</span>
|
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">, </span><span class="string">"Solving %n for '$w'"</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>eqn_iname</span><span class="plain">, </span><span class="identifier">to_solve</span><span class="plain">-</span><span class="element">>name</span><span class="plain">);</span>
|
|
<span class="functiontext">Emit::code_comment</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">);</span>
|
|
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">C</span><span class="plain">);</span>
|
|
<span class="functiontext">Equations::enode_compile_by_emission</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::emit_solution_inner is used in <a href="#SP46">§46</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP47_1"></a><b>§47.1. </b>Note the case sensitivity here.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Identify which symbol in the equation we are solving for</span> <span class="cwebmacronumber">47.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::length</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">) == 1)</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::match_cs</span><span class="plain">(</span><span class="identifier">W</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">))</span>
|
|
<span class="identifier">to_solve</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_solve</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">W</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationBadTarget</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"In %1, you asked to let %2 be given by the equation '%3', "</span>
|
|
<span class="string">"but '%2' isn't a symbol in that equation."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">to_solve</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain">) {</span>
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">W</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::quote_spec</span><span class="plain">(4, </span><span class="identifier">to_solve</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationConstantTarget</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"In %1, you asked to let %2 be given by the equation '%3', "</span>
|
|
<span class="string">"but '%2' isn't something which can vary freely in that equation - "</span>
|
|
<span class="string">"it's been set equal to %4."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP47">§47</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP47_2"></a><b>§47.2. </b>This step is not easy, but is delegated to <code class="display"><span class="extract">Equations::eqn_rearrange</span></code> below, so it
|
|
looks easy here. The surprising thing is the fresh round of typechecking:
|
|
why do we do that? The answer is not that we doubt whether the equation is
|
|
still valid — the rearranged equation should pass if and only if the original
|
|
did, if we've implemented all of this correctly — but because the alterations
|
|
made to the tree mean that the assignments of kinds at each node are now
|
|
potentially incorrect. Re-typechecking will recalculate these.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Rearrange the equation so that this symbol is the entire LHS</span> <span class="cwebmacronumber">47.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::eqn_rearrange</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">to_solve</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">W</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationInsoluble</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"In %1, you asked to let %2 be given by the equation '%3', "</span>
|
|
<span class="string">"but I am unable to rearrange the equation in any simple way "</span>
|
|
<span class="string">"so that it sets '%2' equal to something else. Maybe you could "</span>
|
|
<span class="string">"write a more explicit equation? (You're certainly better at "</span>
|
|
<span class="string">"maths than I am; I can only make easy deductions.)"</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::eqn_typecheck</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP47">§47</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP47_3"></a><b>§47.3. </b>Suppose we read a phrase such as
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>let PE be given by PE = mgh, where g = 9.801 m/ss;</p>
|
|
|
|
</blockquote>
|
|
|
|
<p class="inwebparagraph">We can only compile code to do this if we can identify values for the symbols.
|
|
"g" is not a problem because a temporary assignment supplies this. For each
|
|
symbol <code class="display"><span class="extract">ev</span></code> which isn't a constant, we must set <code class="display"><span class="extract">ev->local_map</span></code> to the
|
|
corresponding local variable.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Identify the symbols in the equation with local variables</span> <span class="cwebmacronumber">47.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_const</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>local_map</span><span class="plain"> = </span><span class="functiontext">LocalVariables::parse</span><span class="plain">(</span><span class="functiontext">Frames::current_stack_frame</span><span class="plain">(), </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">);</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>promote_local_to_real</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>local_map</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Can't find an unset symbol among the local variables</span> <span class="cwebmacronumber">47.3.1</span>>
|
|
<span class="reserved">else</span>
|
|
<<span class="cwebmacro">Check that the kind of the local variable matches that of the symbol</span> <span class="cwebmacronumber">47.3.2</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP47">§47</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP47_3_1"></a><b>§47.3.1. </b>In the above example, finding "PE" should not be a problem: this
|
|
is the <code class="display"><span class="extract">to_solve</span></code> symbol, and it must be a current local variable name
|
|
since the "let" will have created it as such if it didn't already
|
|
exist. But things can certainly go wrong with "m" and "h", which
|
|
need to exist as local variables in the current stack frame.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Can't find an unset symbol among the local variables</span> <span class="cwebmacronumber">47.3.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain"> == </span><span class="identifier">to_solve</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"can't find 'let' variable to assign"</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">W</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(4, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolMissing</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"In %1, you asked to let %2 be given by the equation '%3', "</span>
|
|
<span class="string">"but I can't see what to use for '%4'. The usual idea is "</span>
|
|
<span class="string">"to set the other variables in the equation using 'let': "</span>
|
|
<span class="string">"so adding 'let %4 be ...' before trying to find '%2' "</span>
|
|
<span class="string">"should work."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP47_3">§47.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP47_3_2"></a><b>§47.3.2. </b>In the case of the symbol we are setting, the local variable might be one
|
|
which has only just been created and thus has no value yet — not having
|
|
set it, Inform hasn't given it a kind more explicit than "value".
|
|
We can improve that by giving it the kind of the symbol it is to match.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">In all other cases, the local variable already exists and has a fixed kind.
|
|
This must exactly match that of the symbol. (Again, if we ever need implicit
|
|
casting between quasinumerical kinds, we'll have to return to this.)
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Check that the kind of the local variable matches that of the symbol</span> <span class="cwebmacronumber">47.3.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">K</span><span class="plain"> = </span><span class="functiontext">LocalVariables::kind</span><span class="plain">(</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>local_map</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">K_value</span><span class="plain">)) {</span>
|
|
<span class="identifier">K</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain">;</span>
|
|
<span class="functiontext">LocalVariables::set_kind</span><span class="plain">(</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>local_map</span><span class="plain">, </span><span class="identifier">K</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">K_number</span><span class="plain">)) &&</span>
|
|
<span class="plain">(</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain">, </span><span class="identifier">K_real_number</span><span class="plain">))) {</span>
|
|
<span class="identifier">K</span><span class="plain"> = </span><span class="identifier">K_real_number</span><span class="plain">;</span>
|
|
<span class="identifier">ev</span><span class="plain">-</span><span class="element">>promote_local_to_real</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::Compare::eq</span><span class="plain">(</span><span class="identifier">K</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">W</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(3, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(4, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::quote_kind</span><span class="plain">(5, </span><span class="identifier">K</span><span class="plain">);</span>
|
|
<span class="functiontext">Problems::quote_kind</span><span class="plain">(6, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>var_kind</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_EquationSymbolWrongKOV</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"In %1, you asked to let %2 be given by the equation '%3', "</span>
|
|
<span class="string">"but in that equation '%4' is supposedly %6 - whereas right "</span>
|
|
<span class="string">"here, it seems to be %5. Perhaps two different quantities have "</span>
|
|
<span class="string">"ended up with the same symbol in the source text?"</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP47_3">§47.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP48"></a><b>§48. </b>Actual compilation is simple, since the tree is set up for it.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::enode_compile_by_emission</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">a</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain">)) </span><span class="identifier">a</span><span class="plain"> = 1;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">b</span><span class="plain"> = 0;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">)) </span><span class="identifier">b</span><span class="plain"> = 1;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">f</span><span class="plain"> = </span><span class="identifier">b</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">f</span><span class="plain"> == 1) </span><span class="identifier">Kinds::FloatingPoint::begin_flotation_emit</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</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">f</span><span class="plain"> == -1) </span><span class="identifier">Kinds::FloatingPoint::begin_deflotation_emit</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain">));</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">SYMBOL_EQN</span><span class="plain">:</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>var_const</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">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>var_const</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">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>local_map</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>promote_local_to_real</span><span class="plain">) {</span>
|
|
<span class="identifier">Produce::inv_call_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">NUMBER_TY_TO_REAL_NUMBER_TY_HL</span><span class="plain">));</span>
|
|
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">inter_symbol</span><span class="plain"> *</span><span class="identifier">tok_s</span><span class="plain"> = </span><span class="functiontext">LocalVariables::declare_this</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>local_map</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">tok_s</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>promote_local_to_real</span><span class="plain">)</span>
|
|
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain">) {</span>
|
|
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">RS</span><span class="plain"> = </span><span class="functiontext">Routines::ToPhrases::make_iname</span><span class="plain">(</span>
|
|
<span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain">,</span>
|
|
<span class="functiontext">Phrases::TypeData::kind</span><span class="plain">(</span>
|
|
<span class="plain">&(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain">-</span><span class="element">>type_data</span><span class="plain">)));</span>
|
|
<span class="identifier">Produce::val_iname</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_value</span><span class="plain">, </span><span class="identifier">RS</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"uncompilable equation node"</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">CONSTANT_EQN</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">tok</span><span class="plain">-</span><span class="element">>leaf_constant</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">OPERATION_EQN</span><span class="plain">: </span><<span class="cwebmacro">Emit a single operation</span> <span class="cwebmacronumber">48.1</span>><span class="plain">; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">: </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"forbidden enode found in parsed equation"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">f</span><span class="plain"> == 1) </span><span class="identifier">Kinds::FloatingPoint::end_flotation_emit</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</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">f</span><span class="plain"> == -1) </span><span class="identifier">Kinds::FloatingPoint::end_deflotation_emit</span><span class="plain">(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>gK_before</span><span class="plain">));</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_compile_by_emission is used in <a href="#SP47">§47</a>, 13/ca (<a href="13-ca.html#SP1_2_1">§1.2.1</a>, <a href="13-ca.html#SP1_2_2">§1.2.2</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP48_1"></a><b>§48.1. </b>And here we handle operation nodes:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Emit a single operation</span> <span class="cwebmacronumber">48.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">X</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">KX</span><span class="plain"> = </span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">X</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">);</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">Y</span><span class="plain"> = </span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1];</span>
|
|
<span class="identifier">kind</span><span class="plain"> *</span><span class="identifier">KY</span><span class="plain"> = (</span><span class="identifier">Y</span><span class="plain">)?(</span><span class="identifier">Kinds::FloatingPoint::underlying</span><span class="plain">(</span><span class="identifier">Y</span><span class="plain">-</span><span class="element">>gK_after</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">Kinds::FloatingPoint::is_real</span><span class="plain">(</span><span class="identifier">X</span><span class="plain">-</span><span class="element">>gK_after</span><span class="plain">)) {</span>
|
|
<span class="identifier">KX</span><span class="plain"> = </span><span class="identifier">K_real_number</span><span class="plain">; </span><span class="identifier">KY</span><span class="plain"> = </span><span class="identifier">K_real_number</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="functiontext">Kinds::Compile::perform_arithmetic_emit</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">X</span><span class="plain">, </span><span class="identifier">KX</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">Y</span><span class="plain">, </span><span class="identifier">KY</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP48">§48</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP49"></a><b>§49. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::enode_compilation_error</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">) {</span>
|
|
<span class="identifier">Problems::quote_source</span><span class="plain">(1, </span><span class="identifier">current_sentence</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::quote_wording</span><span class="plain">(2, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::Issue::handmade_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_HardIntegerRoot</span><span class="plain">));</span>
|
|
<span class="identifier">Problems::issue_problem_segment</span><span class="plain">(</span>
|
|
<span class="string">"In %1, you asked me to solve the equation '%2', but that would have "</span>
|
|
<span class="string">"involved taking a tricky root of a whole number. Using real numbers "</span>
|
|
<span class="string">"that would be easy, but with whole numbers I'm unable to get there."</span><span class="plain">);</span>
|
|
<span class="identifier">Problems::issue_problem_end</span><span class="plain">();</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_compilation_error is used in 13/ca (<a href="13-ca.html#SP1_12">§1.12</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50"></a><b>§50. Rearrangement. </b>We carry out only the simplest of operations, but it's surprising how often that's
|
|
good enough: if it isn't, we simply return <code class="display"><span class="extract">FALSE</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Everything we do will be reversible, which is important since we are
|
|
changing the <code class="display"><span class="extract">parsed_equation</span></code> tree, and we don't want to be changing our
|
|
view of what the equation means in the process. One thing that never changes
|
|
is that the top node of the equation is always the unique "equal to" node
|
|
in the tree.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Suppose we are solving for <code class="display"><span class="extract">v</span></code>, which occurs in just one place in the equation.
|
|
Either it's at the top level under the <code class="display"><span class="extract">=</span></code>, in which case we now have an
|
|
explicit formula for <code class="display"><span class="extract">v</span></code>, or it's stuck underneath some operation node. We
|
|
rearrange the tree to move this operation over to the other side, which
|
|
allows <code class="display"><span class="extract">v</span></code> to make progress — see below for a proof that this terminates.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::eqn_rearrange</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">to_solve</span><span class="plain">) {</span>
|
|
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">TRUE</span><span class="plain">) {</span>
|
|
<<span class="cwebmacro">Swap the two sides if necessary so that v occurs only once and on the left</span> <span class="cwebmacronumber">50.1</span>><span class="plain">;</span>
|
|
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">old_LHS</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">old_RHS</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1];</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> != </span><span class="constant">OPERATION_EQN</span><span class="plain">) </span><span class="reserved">break</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> == 2)</span>
|
|
<<span class="cwebmacro">Rearrange to move v upwards through this binary operator</span> <span class="cwebmacronumber">50.3</span>>
|
|
<span class="reserved">else</span>
|
|
<<span class="cwebmacro">Rearrange to move v upwards through this unary operator</span> <span class="cwebmacronumber">50.4</span>><span class="plain">;</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>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::eqn_rearrange is used in <a href="#SP47_2">§47.2</a>, <a href="#SP52">§52</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50_1"></a><b>§50.1. </b>We have no ability to gather terms, so the variable <code class="display"><span class="extract">v</span></code> we are solving for can only
|
|
occur once in the formula. In Inform's idea of equations, <code class="display"><span class="extract">A = B</span></code> and <code class="display"><span class="extract">B = A</span></code>
|
|
have the same meaning, so we'll place <code class="display"><span class="extract">v</span></code> on the left.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Swap the two sides if necessary so that v occurs only once and on the left</span> <span class="cwebmacronumber">50.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lc</span><span class="plain"> = </span><span class="functiontext">Equations::enode_count_var</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0], </span><span class="identifier">to_solve</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rc</span><span class="plain"> = </span><span class="functiontext">Equations::enode_count_var</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1], </span><span class="identifier">to_solve</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">lc</span><span class="plain"> + </span><span class="identifier">rc</span><span class="plain"> != 1) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">lc</span><span class="plain"> == 0) {</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">swap</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">swap</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP50">§50</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50_2"></a><b>§50.2. </b>The main loop above terminates because on each iteration, either
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<ul class="items"><li>(i) the tree depth of <code class="display"><span class="extract">v</span></code> below <code class="display"><span class="extract">=</span></code> decreases by 1, or
|
|
</li><li>(ii) the tree depth of <code class="display"><span class="extract">v</span></code> remains the same but the number of <code class="display"><span class="extract">MINUS_OPERATION</span></code> or
|
|
<code class="display"><span class="extract">DIVIDE_OPERATION</span></code> nodes in the tree decreases by 1.
|
|
</li></ul>
|
|
<p class="inwebparagraph">Since at any given time there are a finite number of <code class="display"><span class="extract">MINUS_OPERATION</span></code> or
|
|
<code class="display"><span class="extract">DIVIDE_OPERATION</span></code> nodes, case (ii) cannot repeat indefinitely, and we must
|
|
therefore eventually fall into case (i); and then subsequently do so again,
|
|
and so on; and so the tree depth of <code class="display"><span class="extract">v</span></code> will ultimately fall to 1, at which
|
|
point it is at the top level as required and we break out of the loop.
|
|
</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50_3"></a><b>§50.3. </b>So the rearrangement moves have to make sure the "(i) or (ii)" property
|
|
always holds. The simplest case to understand is <code class="display"><span class="extract">+</span></code>. Suppose we have:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> +</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> E</span>
|
|
<span class="plain"> R</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">representing (V+E) = R, where V is the sub-equation containing
|
|
v. (E is an arbitrary sub-equation, and R is the right hand
|
|
side.) One of the two operands of <code class="display"><span class="extract">+</span></code> will be "promoted", moving
|
|
upwards in the tree, and since we can choose to promote either V or
|
|
E, we'll choose V, thus obtaining:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> -</span>
|
|
<span class="plain"> R</span>
|
|
<span class="plain"> E</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">that is, V = (R - E). Since V has moved upwards, so has the unique instance
|
|
of v, and therefore the tree depth of v has decreased by 1 — property (i).
|
|
Multiplication is similar, but turns into division on the right hand side.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">But now consider <code class="display"><span class="extract">-</span></code>. When we rearrange:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> -</span>
|
|
<span class="plain"> E</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> R</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">representing (E-V) = R we no longer have a choice of which operand of <code class="display"><span class="extract">-</span></code>
|
|
to promote: we have to promote the right operand, and that produces E = (R+V).
|
|
The tree depth of v is not improved, and it's now over on the right hand
|
|
side. The next iteration of the main loop will swap sides again so that we
|
|
have (R+V) = E. But a tricky node (subtraction or division) has been
|
|
exchanged out of the tree for an easy one (addition or multiplication), so
|
|
we fail property (i) but achieve property (ii).
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Rearrange to move v upwards through this binary operator</span> <span class="cwebmacronumber">50.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="comment">rearrange to move this operator</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">op</span><span class="plain"> = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">op</span><span class="plain"> == </span><span class="identifier">POWER_OPERATION</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Rearrange to remove a power</span> <span class="cwebmacronumber">50.3.1</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">op</span><span class="plain"> == </span><span class="constant">IMPLICIT_APPLICATION_OPERATION</span><span class="plain">)</span>
|
|
<<span class="cwebmacro">Rearrange using the inverse of function</span> <span class="cwebmacronumber">50.3.2</span>>
|
|
<span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">promote</span><span class="plain"> = 0, </span><span class="identifier">new_op</span><span class="plain"> = </span><span class="identifier">PLUS_OPERATION</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::enode_count_var</span><span class="plain">(</span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1], </span><span class="identifier">to_solve</span><span class="plain">) > 0) </span><span class="identifier">promote</span><span class="plain"> = 1;</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">op</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">PLUS_OPERATION</span><span class="plain">: </span><span class="identifier">new_op</span><span class="plain"> = </span><span class="identifier">MINUS_OPERATION</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="identifier">MINUS_OPERATION</span><span class="plain">: </span><span class="identifier">new_op</span><span class="plain"> = </span><span class="identifier">PLUS_OPERATION</span><span class="plain">; </span><span class="identifier">promote</span><span class="plain"> = 0; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">TIMES_OPERATION</span><span class="plain">: </span><span class="identifier">new_op</span><span class="plain"> = </span><span class="identifier">DIVIDE_OPERATION</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="identifier">DIVIDE_OPERATION</span><span class="plain">: </span><span class="identifier">new_op</span><span class="plain"> = </span><span class="identifier">TIMES_OPERATION</span><span class="plain">; </span><span class="identifier">promote</span><span class="plain"> = 0; </span><span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">: </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"%d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">op</span><span class="plain">); </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"strange operator in rearrangement"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">E</span><span class="plain"> = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1 - </span><span class="identifier">promote</span><span class="plain">];</span>
|
|
<span class="comment">the new LHS is the promoted operand:</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[</span><span class="identifier">promote</span><span class="plain">];</span>
|
|
<span class="comment">the new RHS is the operator which used to be the LHS...</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="comment">...the former RHS being the operand replacing the promoted one...</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">E</span><span class="plain">;</span>
|
|
<span class="comment">...except that the operator reverses in "sense"</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">new_op</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP50">§50</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50_3_1"></a><b>§50.3.1. </b>Solving x^v = y for v requires logs, which are not in our scheme; and
|
|
solving v^n = y for non-constant n is no better. So in either case we
|
|
surrender by returning <code class="display"><span class="extract">FALSE</span></code>.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">In fact, the only cases we can solve at present are V^2 = y and V^3 = y.
|
|
It would be easy to add solutions for V^4 = y, V^6 = y and in general for
|
|
V^k = y where the only prime factors of k are 2 and 3, but this is not
|
|
something people are likely to need very much. The taking of 4th or higher roots
|
|
hardly ever occurs in physical equations, and anyone wanting this will have
|
|
to write more explicit source text.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Anyway, rearrangement for our easy cases is indeed easy:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> ^</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> 2</span>
|
|
<span class="plain"> R</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">becomes
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> square-root</span>
|
|
<span class="plain"> R</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">and V is always promoted, so we achieve property (i); and similarly for
|
|
cube roots.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Rearrange to remove a power</span> <span class="cwebmacronumber">50.3.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">p</span><span class="plain"> = </span><span class="functiontext">Rvalues::to_int</span><span class="plain">(</span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>leaf_constant</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain"> == 2) {</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">ROOT_OPERATION</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 1;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</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">p</span><span class="plain"> == 3) {</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">CUBEROOT_OPERATION</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 1;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">POWER_OPERATION</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 2;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">the_power</span><span class="plain"> = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1];</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">DIVIDE_OPERATION</span><span class="plain">);</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_arity</span><span class="plain"> = 2;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="functiontext">Equations::enode_new_constant</span><span class="plain">(</span>
|
|
<span class="functiontext">Rvalues::from_int</span><span class="plain">(1, </span><span class="identifier">EMPTY_WORDING</span><span class="plain">));</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_number</span><span class="plain">);</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[0]-</span><span class="element">>enode_promotion</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">the_power</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_number</span><span class="plain">);</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_promotion</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_before</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_real_number</span><span class="plain">);</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>gK_after</span><span class="plain"> =</span>
|
|
<span class="identifier">Kinds::FloatingPoint::new_gk</span><span class="plain">(</span><span class="identifier">K_real_number</span><span class="plain">);</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>rational_n</span><span class="plain"> = 1;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>rational_m</span><span class="plain"> = </span><span class="identifier">p</span><span class="plain">;</span>
|
|
<span class="functiontext">Kinds::RunTime::notify_of_use</span><span class="plain">(</span><span class="identifier">K_real_number</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP50_3">§50.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50_3_2"></a><b>§50.3.2. </b>Here we have something like <code class="display"><span class="extract">log x = y</span></code> and want to rewrite as <code class="display"><span class="extract">x = exp y</span></code>,
|
|
which is only possible if we have an inverse available for our function —
|
|
in this case, <code class="display"><span class="extract">exp</span></code> being the inverse of <code class="display"><span class="extract">log</span></code>. Thus:
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> apply</span>
|
|
<span class="plain"> function</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> R</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">must become
|
|
</p>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">=</span>
|
|
<span class="plain"> V</span>
|
|
<span class="plain"> apply</span>
|
|
<span class="plain"> inverse-of-function</span>
|
|
<span class="plain"> R</span>
|
|
|
|
<<span class="cwebmacrodefn">Rearrange using the inverse of function</span> <span class="cwebmacronumber">50.3.2</span>> =
|
|
<span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">fnode</span><span class="plain"> = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">fnode</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) ||</span>
|
|
<span class="plain">(</span><span class="identifier">fnode</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) {</span>
|
|
<span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="identifier">fnode</span><span class="plain">);</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"not a function being applied"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">f</span><span class="plain"> = </span><span class="identifier">fnode</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain">;</span>
|
|
<span class="reserved">phrase</span><span class="plain"> *</span><span class="identifier">finv</span><span class="plain"> = </span><span class="functiontext">Phrases::Usage::get_equation_inverse</span><span class="plain">(&(</span><span class="identifier">f</span><span class="plain">-</span><span class="element">>usage_data</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">finv</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="comment">no known inverse for this function</span>
|
|
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain">, *</span><span class="identifier">ev_inverse</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">ev</span><span class="plain"> = </span><span class="identifier">standard_equation_symbols</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">)</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>function_notated</span><span class="plain"> == </span><span class="identifier">finv</span><span class="plain">)</span>
|
|
<span class="identifier">ev_inverse</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">;</span>
|
|
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ev_inverse</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="comment">inverse can't be used in equations</span>
|
|
|
|
<span class="identifier">fnode</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain"> = </span><span class="identifier">ev_inverse</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP50_3">§50.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP50_4"></a><b>§50.4. </b>The unary operations are easy in a similar way — they only have one operand,
|
|
so we always promote V and achieve property (i). A square root is rearranged
|
|
as a square, and a cube root as a cube. (It's important that everything we do
|
|
is reversible — we generate exactly those powers which we are able to undo
|
|
again if necessary.) Unary minus is easier still — we need only move it to
|
|
the other side; thus -V = R becomes V=-R, and <code class="display"><span class="extract">v</span></code> again rises.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Rearrange to move v upwards through this unary operator</span> <span class="cwebmacronumber">50.4</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">op</span><span class="plain"> = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain">;</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">op</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">UNARY_MINUS_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</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="identifier">ROOT_OPERATION</span><span class="plain">:</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="identifier">REALROOT_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">TIMES_OPERATION</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 2;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_RHS</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="identifier">CUBEROOT_OPERATION</span><span class="plain">:</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0];</span>
|
|
<span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_LHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>eqn_operation</span><span class="plain"> = </span><span class="identifier">TIMES_OPERATION</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain"> = 2;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="functiontext">Equations::enode_new_op</span><span class="plain">(</span><span class="identifier">TIMES_OPERATION</span><span class="plain">);</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[0] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="identifier">old_LHS</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[1]-</span><span class="element">>enode_operands</span><span class="plain">[1] = </span><span class="identifier">old_RHS</span><span class="plain">;</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="reserved">default</span><span class="plain">: </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"unanticipated operator in rearrangement"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP50">§50</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP51"></a><b>§51. </b>And that's the whole rearranger, except for the utility routine which
|
|
counts instances of the magic variable <code class="display"><span class="extract">v</span></code> at or below a given point in the
|
|
equation tree.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Equations::enode_count_var</span><span class="plain">(</span><span class="reserved">equation_node</span><span class="plain"> *</span><span class="identifier">tok</span><span class="plain">, </span><span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">to_solve</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0, </span><span class="identifier">i</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">tok</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">c</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>eqn_type</span><span class="plain"> == </span><span class="constant">SYMBOL_EQN</span><span class="plain">) && (</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>leaf_symbol</span><span class="plain"> == </span><span class="identifier">to_solve</span><span class="plain">))</span>
|
|
<span class="reserved">return</span><span class="plain"> 1;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain"><</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_arity</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++)</span>
|
|
<span class="identifier">c</span><span class="plain"> += </span><span class="functiontext">Equations::enode_count_var</span><span class="plain">(</span><span class="identifier">tok</span><span class="plain">-</span><span class="element">>enode_operands</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">], </span><span class="identifier">to_solve</span><span class="plain">);</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::enode_count_var is used in <a href="#SP50_1">§50.1</a>, <a href="#SP50_3">§50.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP52"></a><b>§52. Internal test case. </b>This is a little like those "advise all parties" law exam questions: we
|
|
parse the equation, then rearrange to solve it for each variable in turn.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::internal_test</span><span class="plain">(</span><span class="identifier">wording</span><span class="plain"> </span><span class="identifier">E</span><span class="plain">) {</span>
|
|
<span class="identifier">wording</span><span class="plain"> </span><span class="identifier">WH</span><span class="plain"> = </span><span class="identifier">EMPTY_WORDING</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">>(</span><span class="identifier">E</span><span class="plain">)) {</span>
|
|
<span class="identifier">E</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">>, 1);</span>
|
|
<span class="identifier">WH</span><span class="plain"> = </span><span class="identifier">GET_RW</span><span class="plain">(<</span><span class="reserved">equation</span><span class="plain">-</span><span class="identifier">where</span><span class="plain">>, 2);</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain"> = </span><span class="functiontext">Equations::new</span><span class="plain">(</span><span class="identifier">E</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
|
|
<span class="functiontext">Equations::set_wherewithal</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">WH</span><span class="plain">);</span>
|
|
<span class="functiontext">Equations::examine</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="functiontext">PL::Parsing::TestScripts::begin_internal_reporting</span><span class="plain">();</span>
|
|
<span class="functiontext">Equations::log_equation_parsed</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="reserved">equation_symbol</span><span class="plain"> *</span><span class="identifier">ev</span><span class="plain">;</span>
|
|
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>symbol_list</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain">; </span><span class="identifier">ev</span><span class="plain"> = </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>next</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Equations::eqn_rearrange</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Too hard to rearrange to solve for %W\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">);</span>
|
|
<span class="reserved">else</span><span class="plain"> {</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"Rearranged to solve for %W:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">ev</span><span class="plain">-</span><span class="element">>name</span><span class="plain">);</span>
|
|
<span class="functiontext">Equations::log_equation_parsed</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="functiontext">PL::Parsing::TestScripts::end_internal_reporting</span><span class="plain">();</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::internal_test is used in 26/ts (<a href="26-ts.html#SP11">§11</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP53"></a><b>§53. Indexing and logging. </b>And finally:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::log</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="identifier">LOG</span><span class="plain">(</span><span class="string">"{%W}"</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::log_equation_parsed</span><span class="plain">(</span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">eqn</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">LOG</span><span class="plain">(</span><span class="string">"<null>\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">Equations::log_equation_node</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>parsed_equation</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Equations::index</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">ec</span><span class="plain"> = 0; </span><span class="reserved">equation</span><span class="plain"> *</span><span class="identifier">eqn</span><span class="plain">;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation</span><span class="plain">) { </span><span class="identifier">ec</span><span class="plain">++; }</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ec</span><span class="plain"> == 0) </span><span class="reserved">return</span><span class="plain">;</span>
|
|
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"<b>List of Named or Numbered Equations</b> (<i>About equations</i>"</span><span class="plain">);</span>
|
|
<span class="identifier">Index::DocReferences::link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"EQUATIONS"</span><span class="plain">); </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">")"</span><span class="plain">);</span>
|
|
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
|
|
<span class="identifier">HTML_OPEN</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain"> = 0;</span>
|
|
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">, </span><span class="reserved">equation</span><span class="plain">) {</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">mw</span><span class="plain"> = </span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_no_text</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_name_text</span><span class="plain">) > </span><span class="identifier">mw</span><span class="plain">)</span>
|
|
<span class="identifier">mw</span><span class="plain"> = </span><span class="identifier">Wordings::last_wn</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_name_text</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">mw</span><span class="plain"> >= 0) {</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%+W"</span><span class="plain">, </span><span class="identifier">Wordings::up_to</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_created_at</span><span class="plain">), </span><span class="identifier">mw</span><span class="plain">));</span>
|
|
<span class="identifier">Index::link</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">Wordings::first_wn</span><span class="plain">(</span><span class="identifier">ParseTree::get_text</span><span class="plain">(</span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_created_at</span><span class="plain">)));</span>
|
|
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" (%+W)"</span><span class="plain">, </span><span class="identifier">eqn</span><span class="plain">-</span><span class="element">>equation_text</span><span class="plain">);</span>
|
|
<span class="identifier">HTML_TAG</span><span class="plain">(</span><span class="string">"br"</span><span class="plain">);</span>
|
|
<span class="identifier">N</span><span class="plain">++;</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">N</span><span class="plain"> == 0) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"<i>None</i>.\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
|
|
<span class="identifier">HTML_CLOSE</span><span class="plain">(</span><span class="string">"p"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">The function Equations::log is used in 1/cm (<a href="1-cm.html#SP5">§5</a>, <a href="1-cm.html#SP6_6">§6.6</a>).</p>
|
|
|
|
<p class="endnote">The function Equations::log_equation_parsed is used in <a href="#SP52">§52</a>.</p>
|
|
|
|
<p class="endnote">The function Equations::index appears nowhere else.</p>
|
|
|
|
<hr class="tocbar">
|
|
<ul class="toc"><li><i>(This section begins Chapter 20: Equations.)</i></li><li><i>(This section ends Chapter 20: Equations.)</i></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
</body>
|
|
</html>
|
|
|