1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 16:44:21 +03:00
inform7/docs/core-module/26-rt.html

328 lines
39 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>26/ct</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '26/rt' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">core</a></li><li><a href="index.html#26">Chapter 26: Compilation Utilities</a></li><li><b>Routines</b></li></ul><p class="purpose">To compile the bones of functions, and their local variable declarations.</p>
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. </b>The code following is used throughout Inform, whenever we want to compile
a function. Sometimes that's in order to define a phrase, but often not.
</p>
<p class="inwebparagraph">There are two ways to begin a function: specifying a stack frame which has
already been set up, or not. Here's not:
</p>
<pre class="display">
<span class="identifier">packaging_state</span><span class="plain"> </span><span class="functiontext">Routines::begin</span><span class="plain">(</span><span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Routines::begin_framed</span><span class="plain">(</span><span class="identifier">name</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 Routines::begin is used in 4/am (<a href="4-am.html#SP34_2">&#167;34.2</a>, <a href="4-am.html#SP43">&#167;43</a>), 5/lp (<a href="5-lp.html#SP27">&#167;27</a>), 5/nv (<a href="5-nv.html#SP16">&#167;16</a>), 6/bp (<a href="6-bp.html#SP33">&#167;33</a>), 6/rlt (<a href="6-rlt.html#SP15">&#167;15</a>, <a href="6-rlt.html#SP15_2">&#167;15.2</a>, <a href="6-rlt.html#SP17">&#167;17</a>, <a href="6-rlt.html#SP29_1">&#167;29.1</a>, <a href="6-rlt.html#SP29_2">&#167;29.2</a>, <a href="6-rlt.html#SP29_3">&#167;29.3</a>, <a href="6-rlt.html#SP29_4">&#167;29.4</a>, <a href="6-rlt.html#SP29_5">&#167;29.5</a>, <a href="6-rlt.html#SP29_6">&#167;29.6</a>, <a href="6-rlt.html#SP30">&#167;30</a>), 6/nv (<a href="6-nv.html#SP18_1">&#167;18.1</a>, <a href="6-nv.html#SP18_2">&#167;18.2</a>), 8/ef (<a href="8-ef.html#SP19">&#167;19</a>), 12/cdp (<a href="12-cdp.html#SP2_1">&#167;2.1</a>), 13/rsfk (<a href="13-rsfk.html#SP16_3">&#167;16.3</a>, <a href="13-rsfk.html#SP24_1">&#167;24.1</a>, <a href="13-rsfk.html#SP24_2">&#167;24.2</a>, <a href="13-rsfk.html#SP24_3">&#167;24.3</a>, <a href="13-rsfk.html#SP24_4">&#167;24.4</a>, <a href="13-rsfk.html#SP24_5">&#167;24.5</a>, <a href="13-rsfk.html#SP24_6_1">&#167;24.6.1</a>, <a href="13-rsfk.html#SP24_6_2">&#167;24.6.2</a>, <a href="13-rsfk.html#SP24_6_3">&#167;24.6.3</a>, <a href="13-rsfk.html#SP24_6_4">&#167;24.6.4</a>, <a href="13-rsfk.html#SP24_6_5">&#167;24.6.5</a>, <a href="13-rsfk.html#SP24_6_6">&#167;24.6.6</a>, <a href="13-rsfk.html#SP25">&#167;25</a>), 15/ma (<a href="15-ma.html#SP13">&#167;13</a>), 17/tl (<a href="17-tl.html#SP14_2">&#167;14.2</a>), 17/ts (<a href="17-ts.html#SP11">&#167;11</a>), 17/rs (<a href="17-rs.html#SP6_1">&#167;6.1</a>, <a href="17-rs.html#SP6_2">&#167;6.2</a>, <a href="17-rs.html#SP7_2">&#167;7.2</a>), 19/tc (<a href="19-tc.html#SP8">&#167;8</a>), 19/rsft (<a href="19-rsft.html#SP2">&#167;2</a>), 20/eq (<a href="20-eq.html#SP43">&#167;43</a>), 21/rl (<a href="21-rl.html#SP20">&#167;20</a>, <a href="21-rl.html#SP22_1">&#167;22.1</a>), 21/rb (<a href="21-rb.html#SP23">&#167;23</a>, <a href="21-rb.html#SP24_1_1">&#167;24.1.1</a>), 21/rl2 (<a href="21-rl2.html#SP14_1">&#167;14.1</a>), 21/fao (<a href="21-fao.html#SP10">&#167;10</a>), 21/sv (<a href="21-sv.html#SP3">&#167;3</a>), 22/ph (<a href="22-ph.html#SP13">&#167;13</a>), 22/pav (<a href="22-pav.html#SP9_2">&#167;9.2</a>), 24/ch (<a href="24-ch.html#SP6">&#167;6</a>, <a href="24-ch.html#SP7">&#167;7</a>), 26/uo (<a href="26-uo.html#SP21_1">&#167;21.1</a>, <a href="26-uo.html#SP21_2">&#167;21.2</a>), 26/lt (<a href="26-lt.html#SP4_1">&#167;4.1</a>), 26/ts (<a href="26-ts.html#SP10">&#167;10</a>, <a href="26-ts.html#SP11">&#167;11</a>).</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>During the time when we're compiling the body of the routine,
we need to keep track of:
</p>
<pre class="display">
<span class="reserved">ph_stack_frame</span><span class="plain"> *</span><span class="identifier">currently_compiling_in_frame</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">the stack frame for this routine</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">currently_compiling_nnp</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">; </span> <span class="comment">is this a nonphrasal stack frame we made ourselves?</span>
<span class="identifier">inter_package</span><span class="plain"> *</span><span class="identifier">currently_compiling_inter_block</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">where Inter is being emitted to</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">currently_compiling_iname</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">routine we end up with</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>So here is the general version, in which <code class="display"><span class="extract">phsf</span></code> may or may not be a
pre-existing stack frame:
</p>
<pre class="display">
<span class="identifier">packaging_state</span><span class="plain"> </span><span class="functiontext">Routines::begin_framed</span><span class="plain">(</span><span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain">, </span><span class="reserved">ph_stack_frame</span><span class="plain"> *</span><span class="identifier">phsf</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">iname</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"no iname for routine"</span><span class="plain">);</span>
<span class="identifier">currently_compiling_iname</span><span class="plain"> = </span><span class="identifier">iname</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Prepare a suitable stack frame</span> <span class="cwebmacronumber">3.1</span>&gt;<span class="plain">;</span>
<span class="functiontext">Frames::Blocks::begin_code_blocks</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">Emit::unused_packaging_state</span><span class="plain">();</span>
<span class="identifier">currently_compiling_inter_block</span><span class="plain"> = </span><span class="identifier">Produce::block</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), &amp;</span><span class="identifier">save</span><span class="plain">, </span><span class="identifier">iname</span><span class="plain">);</span>
<span class="functiontext">LocalVariables::declare</span><span class="plain">(</span><span class="identifier">phsf</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">save</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Routines::begin_framed is used in <a href="#SP1">&#167;1</a>, 25/cp (<a href="25-cp.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP3_1"></a><b>&#167;3.1. </b>If the <code class="display"><span class="extract">phsf</span></code> argument is set, then we'll use that; otherwise we will
create a new nonphrasal stack frame.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Prepare a suitable stack frame</span> <span class="cwebmacronumber">3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">phsf</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
<span class="identifier">phsf</span><span class="plain"> = </span><span class="functiontext">Frames::new_nonphrasal</span><span class="plain">();</span>
<span class="identifier">currently_compiling_nnp</span><span class="plain"> = </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">currently_compiling_nnp</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">currently_compiling_in_frame</span><span class="plain"> = </span><span class="identifier">phsf</span><span class="plain">;</span>
<span class="functiontext">Frames::make_current</span><span class="plain">(</span><span class="identifier">phsf</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP3">&#167;3</a>.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>As can be seen, very much more work is involved in finishing a function
than in starting it. This is because we need to split into two cases: one
where the code we've just compiled required allocation of heap memory
(e.g. for dynamic strings or lists), and another simpler case where it
did not.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Routines::end</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="identifier">kind</span><span class="plain"> *</span><span class="identifier">R_kind</span><span class="plain"> = </span><span class="functiontext">LocalVariables::deduced_function_kind</span><span class="plain">(</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">);</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">kernel_name</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">public_name</span><span class="plain"> = </span><span class="identifier">currently_compiling_iname</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;allocated_pointers</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;no_formal_parameters_needed</span><span class="plain"> &gt; 0))</span>
<span class="identifier">kernel_name</span><span class="plain"> = </span><span class="identifier">Produce::kernel</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">public_name</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">needed</span><span class="plain"> = </span><span class="functiontext">LocalVariables::count</span><span class="plain">(</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kernel_name</span><span class="plain">) </span><span class="identifier">needed</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VirtualMachines::allow_this_many_locals</span><span class="plain">(</span><span class="identifier">needed</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
&lt;<span class="cwebmacro">Issue a problem for too many locals</span> <span class="cwebmacronumber">4.2</span>&gt;<span class="plain">;</span>
<span class="functiontext">LocalVariables::declare</span><span class="plain">(</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
<span class="identifier">Produce::end_block</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="functiontext">Emit::routine</span><span class="plain">(</span><span class="identifier">kernel_name</span><span class="plain">?</span><span class="identifier">kernel_name</span><span class="plain">:</span><span class="identifier">public_name</span><span class="plain">,</span>
<span class="identifier">R_kind</span><span class="plain">, </span><span class="identifier">currently_compiling_inter_block</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">kernel_name</span><span class="plain">) </span>&lt;<span class="cwebmacro">Compile an outer shell routine with the public-facing name</span> <span class="cwebmacronumber">4.1</span>&gt;<span class="plain">;</span>
<span class="functiontext">Frames::Blocks::end_code_blocks</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">currently_compiling_nnp</span><span class="plain">) </span><span class="functiontext">Frames::remove_nonphrase_stack_frame</span><span class="plain">();</span>
<span class="functiontext">Frames::remove_current</span><span class="plain">();</span>
<span class="identifier">Produce::end_main_block</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">save</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Routines::end is used in 4/am (<a href="4-am.html#SP34_2">&#167;34.2</a>, <a href="4-am.html#SP43">&#167;43</a>), 5/lp (<a href="5-lp.html#SP27">&#167;27</a>), 5/nv (<a href="5-nv.html#SP16">&#167;16</a>), 6/bp (<a href="6-bp.html#SP33">&#167;33</a>), 6/rlt (<a href="6-rlt.html#SP15">&#167;15</a>, <a href="6-rlt.html#SP15_2">&#167;15.2</a>, <a href="6-rlt.html#SP17">&#167;17</a>, <a href="6-rlt.html#SP29_1">&#167;29.1</a>, <a href="6-rlt.html#SP29_2">&#167;29.2</a>, <a href="6-rlt.html#SP29_3">&#167;29.3</a>, <a href="6-rlt.html#SP29_4">&#167;29.4</a>, <a href="6-rlt.html#SP29_5">&#167;29.5</a>, <a href="6-rlt.html#SP29_6">&#167;29.6</a>, <a href="6-rlt.html#SP30">&#167;30</a>), 6/nv (<a href="6-nv.html#SP18_1">&#167;18.1</a>, <a href="6-nv.html#SP18_2">&#167;18.2</a>), 8/ef (<a href="8-ef.html#SP19">&#167;19</a>), 12/cdp (<a href="12-cdp.html#SP2_1">&#167;2.1</a>), 13/rsfk (<a href="13-rsfk.html#SP16_3">&#167;16.3</a>, <a href="13-rsfk.html#SP24_1">&#167;24.1</a>, <a href="13-rsfk.html#SP24_2">&#167;24.2</a>, <a href="13-rsfk.html#SP24_3">&#167;24.3</a>, <a href="13-rsfk.html#SP24_4">&#167;24.4</a>, <a href="13-rsfk.html#SP24_5">&#167;24.5</a>, <a href="13-rsfk.html#SP24_6_1">&#167;24.6.1</a>, <a href="13-rsfk.html#SP24_6_2">&#167;24.6.2</a>, <a href="13-rsfk.html#SP24_6_3">&#167;24.6.3</a>, <a href="13-rsfk.html#SP24_6_4">&#167;24.6.4</a>, <a href="13-rsfk.html#SP24_6_5">&#167;24.6.5</a>, <a href="13-rsfk.html#SP24_6_6">&#167;24.6.6</a>, <a href="13-rsfk.html#SP25">&#167;25</a>), 15/ma (<a href="15-ma.html#SP13">&#167;13</a>), 17/tl (<a href="17-tl.html#SP14_2">&#167;14.2</a>), 17/ts (<a href="17-ts.html#SP11">&#167;11</a>), 17/rs (<a href="17-rs.html#SP6_1">&#167;6.1</a>, <a href="17-rs.html#SP6_2">&#167;6.2</a>, <a href="17-rs.html#SP7_2">&#167;7.2</a>), 19/tc (<a href="19-tc.html#SP8">&#167;8</a>), 19/rsft (<a href="19-rsft.html#SP2">&#167;2</a>), 20/eq (<a href="20-eq.html#SP43">&#167;43</a>), 21/rl (<a href="21-rl.html#SP20">&#167;20</a>, <a href="21-rl.html#SP22_1">&#167;22.1</a>), 21/rb (<a href="21-rb.html#SP23">&#167;23</a>, <a href="21-rb.html#SP24_1_5">&#167;24.1.5</a>), 21/rl2 (<a href="21-rl2.html#SP14_1">&#167;14.1</a>), 21/fao (<a href="21-fao.html#SP10">&#167;10</a>), 21/sv (<a href="21-sv.html#SP3">&#167;3</a>), 22/ph (<a href="22-ph.html#SP13">&#167;13</a>), 22/pav (<a href="22-pav.html#SP9_2">&#167;9.2</a>), 24/ch (<a href="24-ch.html#SP6">&#167;6</a>, <a href="24-ch.html#SP7">&#167;7</a>), 25/cp (<a href="25-cp.html#SP3">&#167;3</a>), 26/uo (<a href="26-uo.html#SP21_1">&#167;21.1</a>, <a href="26-uo.html#SP21_2">&#167;21.2</a>), 26/lt (<a href="26-lt.html#SP4_1">&#167;4.1</a>), 26/ts (<a href="26-ts.html#SP10">&#167;10</a>, <a href="26-ts.html#SP11">&#167;11</a>).</p>
<p class="inwebparagraph"><a id="SP4_1"></a><b>&#167;4.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile an outer shell routine with the public-facing name</span> <span class="cwebmacronumber">4.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">returns_block_value</span><span class="plain"> =</span>
<span class="identifier">Kinds::Behaviour::uses_pointer_values</span><span class="plain">(</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;kind_returned</span><span class="plain">);</span>
<span class="identifier">inter_package</span><span class="plain"> *</span><span class="identifier">block_package</span><span class="plain"> = </span><span class="identifier">Produce::block</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">public_name</span><span class="plain">);</span>
<span class="identifier">inter_symbol</span><span class="plain"> *</span><span class="identifier">I7RBLK_symbol</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Compile I6 locals for the outer shell</span> <span class="cwebmacronumber">4.1.1</span>&gt;<span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">NBV</span><span class="plain"> = 0;</span>
&lt;<span class="cwebmacro">Compile some setup code to make ready for the kernel</span> <span class="cwebmacronumber">4.1.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile a call to the kernel</span> <span class="cwebmacronumber">4.1.3</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile some teardown code now that the kernel has finished</span> <span class="cwebmacronumber">4.1.4</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Compile a return from the outer shell</span> <span class="cwebmacronumber">4.1.5</span>&gt;<span class="plain">;</span>
<span class="identifier">Produce::end_block</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="functiontext">Emit::routine</span><span class="plain">(</span><span class="identifier">public_name</span><span class="plain">, </span><span class="identifier">R_kind</span><span class="plain">, </span><span class="identifier">block_package</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4">&#167;4</a>.</p>
<p class="inwebparagraph"><a id="SP4_1_1"></a><b>&#167;4.1.1. </b>Suppose the routine has to return a list. Then the routine is compiled
with an extra first parameter (called <code class="display"><span class="extract">I7RBLK</span></code>), which is a pointer to the
block value in which to write the answer. After that come all of the call
parameters of the phrase (but none of the "let" or scratch-use locals). If,
on the other hand, the routine returns a word value, <code class="display"><span class="extract">I7RBLK</span></code> is placed
after the call parameters, and is used only as a scratch variable.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile I6 locals for the outer shell</span> <span class="cwebmacronumber">4.1.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">returns_block_value</span><span class="plain">) </span><span class="identifier">I7RBLK_symbol</span><span class="plain"> = </span><span class="functiontext">Emit::local</span><span class="plain">(</span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"I7RBLK"</span><span class="plain">, 0, </span><span class="identifier">I</span><span class="string">"pointer to return value"</span><span class="plain">);</span>
<span class="functiontext">LocalVariables::declare</span><span class="plain">(</span><span class="identifier">currently_compiling_in_frame</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">returns_block_value</span><span class="plain">) </span><span class="identifier">I7RBLK_symbol</span><span class="plain"> = </span><span class="functiontext">Emit::local</span><span class="plain">(</span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"I7RBLK"</span><span class="plain">, 0, </span><span class="identifier">I</span><span class="string">"pointer to stack frame"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4_1">&#167;4.1</a>.</p>
<p class="inwebparagraph"><a id="SP4_1_2"></a><b>&#167;4.1.2. </b>We allocate memory for each pointer value used in the stack frame:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile some setup code to make ready for the kernel</span> <span class="cwebmacronumber">4.1.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Produce::push</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">I7SFRAME_HL</span><span class="plain">));</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">pointer_allocation</span><span class="plain"> *</span><span class="identifier">pall</span><span class="plain">=</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;allocated_pointers</span><span class="plain">; </span><span class="identifier">pall</span><span class="plain">; </span><span class="identifier">pall</span><span class="plain">=</span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;next_in_frame</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;offset_past</span><span class="plain"> &gt; </span><span class="identifier">NBV</span><span class="plain">) </span><span class="identifier">NBV</span><span class="plain"> = </span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;offset_past</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">STACKFRAMECREATE_HL</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="identifier">iname</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="identifier">Produce::val</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">, </span><span class="identifier">LITERAL_IVAL</span><span class="plain">, (</span><span class="identifier">inter_t</span><span class="plain">) </span><span class="identifier">NBV</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="reserved">for</span><span class="plain"> (</span><span class="reserved">pointer_allocation</span><span class="plain"> *</span><span class="identifier">pall</span><span class="plain">=</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;allocated_pointers</span><span class="plain">; </span><span class="identifier">pall</span><span class="plain">; </span><span class="identifier">pall</span><span class="plain">=</span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;next_in_frame</span><span class="plain">)</span>
<span class="functiontext">Kinds::RunTime::emit_heap_allocation</span><span class="plain">(</span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;allocation</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">&lt;</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;no_formal_parameters_needed</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain"> = </span><span class="functiontext">NonlocalVariables::temporary_formal</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">Produce::push</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="functiontext">NonlocalVariables::iname</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">));</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4_1">&#167;4.1</a>.</p>
<p class="inwebparagraph"><a id="SP4_1_3"></a><b>&#167;4.1.3. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile a call to the kernel</span> <span class="cwebmacronumber">4.1.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">STORE_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="identifier">Produce::ref_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">I7RBLK_symbol</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">returns_block_value</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">BLKVALUECOPY_HL</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="identifier">iname</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="identifier">Produce::val_symbol</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">K_number</span><span class="plain">,</span><span class="identifier">I7RBLK_symbol</span><span class="plain">);</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="identifier">kernel_name</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="functiontext">LocalVariables::emit_parameter_list</span><span class="plain">(</span><span class="identifier">currently_compiling_in_frame</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="reserved">if</span><span class="plain"> (</span><span class="identifier">returns_block_value</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="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4_1">&#167;4.1</a>.</p>
<p class="inwebparagraph"><a id="SP4_1_4"></a><b>&#167;4.1.4. </b>Here we deallocate all the memory allocated earlier.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Compile some teardown code now that the kernel has finished</span> <span class="cwebmacronumber">4.1.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;no_formal_parameters_needed</span><span class="plain">-1; </span><span class="identifier">i</span><span class="plain">&gt;=0; </span><span class="identifier">i</span><span class="plain">--) {</span>
<span class="reserved">nonlocal_variable</span><span class="plain"> *</span><span class="identifier">nlv</span><span class="plain"> = </span><span class="functiontext">NonlocalVariables::temporary_formal</span><span class="plain">(</span><span class="identifier">i</span><span class="plain">);</span>
<span class="identifier">Produce::pull</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="functiontext">NonlocalVariables::iname</span><span class="plain">(</span><span class="identifier">nlv</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">pointer_allocation</span><span class="plain"> *</span><span class="identifier">pall</span><span class="plain">=</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">&gt;allocated_pointers</span><span class="plain">; </span><span class="identifier">pall</span><span class="plain">; </span><span class="identifier">pall</span><span class="plain">=</span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;next_in_frame</span><span class="plain">) {</span>
<span class="identifier">inter_name</span><span class="plain"> *</span><span class="identifier">iname</span><span class="plain"> = </span><span class="functiontext">Hierarchy::find</span><span class="plain">(</span><span class="constant">BLKVALUEFREEONSTACK_HL</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="identifier">iname</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="identifier">Produce::val</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">LITERAL_IVAL</span><span class="plain">, (</span><span class="identifier">inter_t</span><span class="plain">) </span><span class="identifier">pall</span><span class="plain">-</span><span class="element">&gt;offset_index</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="identifier">Produce::pull</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">I7SFRAME_HL</span><span class="plain">));</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4_1">&#167;4.1</a>.</p>
<p class="inwebparagraph"><a id="SP4_1_5"></a><b>&#167;4.1.5. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compile a return from the outer shell</span> <span class="cwebmacronumber">4.1.5</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">RETURN_BIP</span><span class="plain">);</span>
<span class="identifier">Produce::down</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
<span class="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">I7RBLK_symbol</span><span class="plain">);</span>
<span class="identifier">Produce::up</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">());</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4_1">&#167;4.1</a>.</p>
<p class="inwebparagraph"><a id="SP4_2"></a><b>&#167;4.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Issue a problem for too many locals</span> <span class="cwebmacronumber">4.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">Problems::Issue::sentence_problem</span><span class="plain">(</span><span class="identifier">_p_</span><span class="plain">(</span><span class="identifier">PM_TooManyLocals</span><span class="plain">),</span>
<span class="string">"there are too many temporarily-named values in this phrase"</span><span class="plain">,</span>
<span class="string">"which may be a sign that it is complicated enough to need breaking up "</span>
<span class="string">"into smaller phrases making use of each other. "</span>
<span class="string">"The limit is 15 at a time for a Z-machine project (see the Settings) "</span>
<span class="string">"and 256 at a time for Glulx. That has to include both values created in the "</span>
<span class="string">"declaration of a phrase (e.g. the 'N' in 'To deduct (N - a number) points: "</span>
<span class="string">"...', or the 'watcher' in 'Instead of taking something in the presence of "</span>
<span class="string">"a man (called the watcher): ...'), and also values created with 'let' or "</span>
<span class="string">"'repeat' (each 'repeat' loop claiming two such values) - not to mention "</span>
<span class="string">"one or two values occasionally needed to work with Tables. Because of all "</span>
<span class="string">"this, it's best to keep the complexity to a minimum within any single phrase."</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP4">&#167;4</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><a href="26-ct.html">Back to 'Compiled Text'</a></li><li><a href="26-tti.html">Continue with 'Translate to Identifiers'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>