mirror of
https://github.com/ganelson/inform.git
synced 2024-07-05 16:44:21 +03:00
328 lines
39 KiB
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">★</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>§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">§34.2</a>, <a href="4-am.html#SP43">§43</a>), 5/lp (<a href="5-lp.html#SP27">§27</a>), 5/nv (<a href="5-nv.html#SP16">§16</a>), 6/bp (<a href="6-bp.html#SP33">§33</a>), 6/rlt (<a href="6-rlt.html#SP15">§15</a>, <a href="6-rlt.html#SP15_2">§15.2</a>, <a href="6-rlt.html#SP17">§17</a>, <a href="6-rlt.html#SP29_1">§29.1</a>, <a href="6-rlt.html#SP29_2">§29.2</a>, <a href="6-rlt.html#SP29_3">§29.3</a>, <a href="6-rlt.html#SP29_4">§29.4</a>, <a href="6-rlt.html#SP29_5">§29.5</a>, <a href="6-rlt.html#SP29_6">§29.6</a>, <a href="6-rlt.html#SP30">§30</a>), 6/nv (<a href="6-nv.html#SP18_1">§18.1</a>, <a href="6-nv.html#SP18_2">§18.2</a>), 8/ef (<a href="8-ef.html#SP19">§19</a>), 12/cdp (<a href="12-cdp.html#SP2_1">§2.1</a>), 13/rsfk (<a href="13-rsfk.html#SP16_3">§16.3</a>, <a href="13-rsfk.html#SP24_1">§24.1</a>, <a href="13-rsfk.html#SP24_2">§24.2</a>, <a href="13-rsfk.html#SP24_3">§24.3</a>, <a href="13-rsfk.html#SP24_4">§24.4</a>, <a href="13-rsfk.html#SP24_5">§24.5</a>, <a href="13-rsfk.html#SP24_6_1">§24.6.1</a>, <a href="13-rsfk.html#SP24_6_2">§24.6.2</a>, <a href="13-rsfk.html#SP24_6_3">§24.6.3</a>, <a href="13-rsfk.html#SP24_6_4">§24.6.4</a>, <a href="13-rsfk.html#SP24_6_5">§24.6.5</a>, <a href="13-rsfk.html#SP24_6_6">§24.6.6</a>, <a href="13-rsfk.html#SP25">§25</a>), 15/ma (<a href="15-ma.html#SP13">§13</a>), 17/tl (<a href="17-tl.html#SP14_2">§14.2</a>), 17/ts (<a href="17-ts.html#SP11">§11</a>), 17/rs (<a href="17-rs.html#SP6_1">§6.1</a>, <a href="17-rs.html#SP6_2">§6.2</a>, <a href="17-rs.html#SP7_2">§7.2</a>), 19/tc (<a href="19-tc.html#SP8">§8</a>), 19/rsft (<a href="19-rsft.html#SP2">§2</a>), 20/eq (<a href="20-eq.html#SP43">§43</a>), 21/rl (<a href="21-rl.html#SP20">§20</a>, <a href="21-rl.html#SP22_1">§22.1</a>), 21/rb (<a href="21-rb.html#SP23">§23</a>, <a href="21-rb.html#SP24_1_1">§24.1.1</a>), 21/rl2 (<a href="21-rl2.html#SP14_1">§14.1</a>), 21/fao (<a href="21-fao.html#SP10">§10</a>), 21/sv (<a href="21-sv.html#SP3">§3</a>), 22/ph (<a href="22-ph.html#SP13">§13</a>), 22/pav (<a href="22-pav.html#SP9_2">§9.2</a>), 24/ch (<a href="24-ch.html#SP6">§6</a>, <a href="24-ch.html#SP7">§7</a>), 26/uo (<a href="26-uo.html#SP21_1">§21.1</a>, <a href="26-uo.html#SP21_2">§21.2</a>), 26/lt (<a href="26-lt.html#SP4_1">§4.1</a>), 26/ts (<a href="26-ts.html#SP10">§10</a>, <a href="26-ts.html#SP11">§11</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§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>§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>
|
|
|
|
<<span class="cwebmacro">Prepare a suitable stack frame</span> <span class="cwebmacronumber">3.1</span>><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">(), &</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">§1</a>, 25/cp (<a href="25-cp.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_1"></a><b>§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">
|
|
<<span class="cwebmacrodefn">Prepare a suitable stack frame</span> <span class="cwebmacronumber">3.1</span>> =
|
|
</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">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§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">>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">>no_formal_parameters_needed</span><span class="plain"> > 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>
|
|
<<span class="cwebmacro">Issue a problem for too many locals</span> <span class="cwebmacronumber">4.2</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">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><<span class="cwebmacro">Compile an outer shell routine with the public-facing name</span> <span class="cwebmacronumber">4.1</span>><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">§34.2</a>, <a href="4-am.html#SP43">§43</a>), 5/lp (<a href="5-lp.html#SP27">§27</a>), 5/nv (<a href="5-nv.html#SP16">§16</a>), 6/bp (<a href="6-bp.html#SP33">§33</a>), 6/rlt (<a href="6-rlt.html#SP15">§15</a>, <a href="6-rlt.html#SP15_2">§15.2</a>, <a href="6-rlt.html#SP17">§17</a>, <a href="6-rlt.html#SP29_1">§29.1</a>, <a href="6-rlt.html#SP29_2">§29.2</a>, <a href="6-rlt.html#SP29_3">§29.3</a>, <a href="6-rlt.html#SP29_4">§29.4</a>, <a href="6-rlt.html#SP29_5">§29.5</a>, <a href="6-rlt.html#SP29_6">§29.6</a>, <a href="6-rlt.html#SP30">§30</a>), 6/nv (<a href="6-nv.html#SP18_1">§18.1</a>, <a href="6-nv.html#SP18_2">§18.2</a>), 8/ef (<a href="8-ef.html#SP19">§19</a>), 12/cdp (<a href="12-cdp.html#SP2_1">§2.1</a>), 13/rsfk (<a href="13-rsfk.html#SP16_3">§16.3</a>, <a href="13-rsfk.html#SP24_1">§24.1</a>, <a href="13-rsfk.html#SP24_2">§24.2</a>, <a href="13-rsfk.html#SP24_3">§24.3</a>, <a href="13-rsfk.html#SP24_4">§24.4</a>, <a href="13-rsfk.html#SP24_5">§24.5</a>, <a href="13-rsfk.html#SP24_6_1">§24.6.1</a>, <a href="13-rsfk.html#SP24_6_2">§24.6.2</a>, <a href="13-rsfk.html#SP24_6_3">§24.6.3</a>, <a href="13-rsfk.html#SP24_6_4">§24.6.4</a>, <a href="13-rsfk.html#SP24_6_5">§24.6.5</a>, <a href="13-rsfk.html#SP24_6_6">§24.6.6</a>, <a href="13-rsfk.html#SP25">§25</a>), 15/ma (<a href="15-ma.html#SP13">§13</a>), 17/tl (<a href="17-tl.html#SP14_2">§14.2</a>), 17/ts (<a href="17-ts.html#SP11">§11</a>), 17/rs (<a href="17-rs.html#SP6_1">§6.1</a>, <a href="17-rs.html#SP6_2">§6.2</a>, <a href="17-rs.html#SP7_2">§7.2</a>), 19/tc (<a href="19-tc.html#SP8">§8</a>), 19/rsft (<a href="19-rsft.html#SP2">§2</a>), 20/eq (<a href="20-eq.html#SP43">§43</a>), 21/rl (<a href="21-rl.html#SP20">§20</a>, <a href="21-rl.html#SP22_1">§22.1</a>), 21/rb (<a href="21-rb.html#SP23">§23</a>, <a href="21-rb.html#SP24_1_5">§24.1.5</a>), 21/rl2 (<a href="21-rl2.html#SP14_1">§14.1</a>), 21/fao (<a href="21-fao.html#SP10">§10</a>), 21/sv (<a href="21-sv.html#SP3">§3</a>), 22/ph (<a href="22-ph.html#SP13">§13</a>), 22/pav (<a href="22-pav.html#SP9_2">§9.2</a>), 24/ch (<a href="24-ch.html#SP6">§6</a>, <a href="24-ch.html#SP7">§7</a>), 25/cp (<a href="25-cp.html#SP3">§3</a>), 26/uo (<a href="26-uo.html#SP21_1">§21.1</a>, <a href="26-uo.html#SP21_2">§21.2</a>), 26/lt (<a href="26-lt.html#SP4_1">§4.1</a>), 26/ts (<a href="26-ts.html#SP10">§10</a>, <a href="26-ts.html#SP11">§11</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_1"></a><b>§4.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Compile an outer shell routine with the public-facing name</span> <span class="cwebmacronumber">4.1</span>> =
|
|
</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">>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>
|
|
<<span class="cwebmacro">Compile I6 locals for the outer shell</span> <span class="cwebmacronumber">4.1.1</span>><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">NBV</span><span class="plain"> = 0;</span>
|
|
<<span class="cwebmacro">Compile some setup code to make ready for the kernel</span> <span class="cwebmacronumber">4.1.2</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Compile a call to the kernel</span> <span class="cwebmacronumber">4.1.3</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Compile some teardown code now that the kernel has finished</span> <span class="cwebmacronumber">4.1.4</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Compile a return from the outer shell</span> <span class="cwebmacronumber">4.1.5</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">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">§4</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_1_1"></a><b>§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">
|
|
<<span class="cwebmacrodefn">Compile I6 locals for the outer shell</span> <span class="cwebmacronumber">4.1.1</span>> =
|
|
</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">§4.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_1_2"></a><b>§4.1.2. </b>We allocate memory for each pointer value used in the stack frame:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Compile some setup code to make ready for the kernel</span> <span class="cwebmacronumber">4.1.2</span>> =
|
|
</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">>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">>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">>offset_past</span><span class="plain"> > </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">>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">>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">>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">>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"><</span><span class="identifier">currently_compiling_in_frame</span><span class="plain">-</span><span class="element">>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">§4.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_1_3"></a><b>§4.1.3. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Compile a call to the kernel</span> <span class="cwebmacronumber">4.1.3</span>> =
|
|
</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">§4.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_1_4"></a><b>§4.1.4. </b>Here we deallocate all the memory allocated earlier.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Compile some teardown code now that the kernel has finished</span> <span class="cwebmacronumber">4.1.4</span>> =
|
|
</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">>no_formal_parameters_needed</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="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">>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">>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">>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">§4.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_1_5"></a><b>§4.1.5. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Compile a return from the outer shell</span> <span class="cwebmacronumber">4.1.5</span>> =
|
|
</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">§4.1</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4_2"></a><b>§4.2. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Issue a problem for too many locals</span> <span class="cwebmacronumber">4.2</span>> =
|
|
</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">§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>
|
|
|