1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/docs/core-module/24-pb.html
2019-08-31 13:56:36 +01:00

449 lines
40 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>24/lv</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '24/pb' 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#24">Chapter 24: Compilation Context</a></li><li><b>Phrase Blocks</b></li></ul><p class="purpose">Blocks of code are used to give conditionals and loops greater scope, as in more traditional programming languages.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Definitions</a></li><li><a href="#SP3">&#167;3. Pushing, popping</a></li><li><a href="#SP8">&#167;8. Activation and deactivation</a></li><li><a href="#SP10">&#167;10. The life of a block</a></li><li><a href="#SP15">&#167;15. Bodies</a></li><li><a href="#SP17">&#167;17. Breakage</a></li><li><a href="#SP18">&#167;18. Blocks and scope</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Definitions. </b></p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>During code compilation, we must keep track of statement blocks: those
forming the body of "if", "while" or "repeat". The phrase as a whole does
not count as a block as such, unlike in C; and, again unlike in C, an
"if... otherwise..." invocation, where there are multiple phrases in both
"..." parts, counts as a single block with what we call a "division" in &mdash;
not as two different blocks.
</p>
<p class="inwebparagraph">In principle, this information belongs to the current stack frame, since
it's within the context of a stack frame that code is compiled. But it
would be wasteful to store arrays for statement blocks inside every stack
frame structure, because in practice we only compile within one stack
frame at a time, and we finish each before beginning the next. So we
store the block stack in the only instance of a private structure.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MAX_BLOCK_NESTING</span><span class="plain"> 50 </span> <span class="comment">which frankly seems plenty</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">block_stack</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">pb_sp</span><span class="plain">; </span> <span class="comment">stack pointer for the block stack which follows:</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">phrase_block</span><span class="plain"> </span><span class="identifier">pb_stack</span><span class="plain">[</span><span class="constant">MAX_BLOCK_NESTING</span><span class="plain">+1];</span>
<span class="plain">} </span><span class="reserved">block_stack</span><span class="plain">;</span>
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">phrase_block</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">control_structure_phrase</span><span class="plain"> *</span><span class="identifier">from_structure</span><span class="plain">; </span> <span class="comment">e.g., "if" or "while"</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">block_location</span><span class="plain">; </span> <span class="comment">where block begins</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">switch_val</span><span class="plain">; </span> <span class="comment">for a switch statement</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">inter_schema</span><span class="plain"> *</span><span class="identifier">tail_schema</span><span class="plain">; </span> <span class="comment">code to add when the block closes</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">csi_state</span><span class="plain"> </span><span class="identifier">compilation_state</span><span class="plain">; </span> <span class="comment">details needed to compile that code</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">label_following</span><span class="plain">; </span> <span class="comment">or -1 if none is used</span>
<span class="plain">} </span><span class="reserved">phrase_block</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure block_stack is private to this section.</p>
<p class="endnote">The structure phrase_block is private to this section.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. Pushing, popping. </b>We need to keep track of two positions on the stack: the top (filled) entry,
and, sometimes, the one above it.
</p>
<pre class="display">
<span class="reserved">block_stack</span><span class="plain"> </span><span class="identifier">current_block_stack</span><span class="plain">;</span>
<span class="reserved">phrase_block</span><span class="plain"> *</span><span class="identifier">block_being_compiled</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">the one being compiled, if any</span>
<span class="reserved">phrase_block</span><span class="plain"> *</span><span class="identifier">block_being_opened</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">the one about to open, if any</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>We need to be careful changing any of these without keeping the others in
line, so the only code allowed to change them is here:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::empty_stack</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain"> = 0;</span>
<span class="identifier">block_being_compiled</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">block_being_opened</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 Frames::Blocks::empty_stack is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>Pushing happens in two stages. First we make a pointer to what will be, but
is not yet, the top of the stack:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::prepush_stack</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">block_being_opened</span><span class="plain"> = &amp;(</span><span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">]);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::prepush_stack is used in <a href="#SP10">&#167;10</a>.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>And then we actually increment the stack pointer:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::push_stack</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">++;</span>
<span class="identifier">block_being_compiled</span><span class="plain"> = </span><span class="identifier">block_being_opened</span><span class="plain">;</span>
<span class="identifier">block_being_opened</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 Frames::Blocks::push_stack is used in <a href="#SP12">&#167;12</a>.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>Popping is easier:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::pop_stack</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">--;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain"> &gt; 0)</span>
<span class="identifier">block_being_compiled</span><span class="plain"> = &amp;(</span><span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain"> - 1]);</span>
<span class="reserved">else</span>
<span class="identifier">block_being_compiled</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">which should be true anyway</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::pop_stack is used in <a href="#SP9">&#167;9</a>, <a href="#SP10">&#167;10</a>, <a href="#SP14">&#167;14</a>.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. Activation and deactivation. </b>If a phrase needs code blocks, Inform should call this when compilation
begins:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::begin_code_blocks</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="functiontext">Frames::current_stack_frame</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">"tried to use blocks outside stack frame"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">block_being_compiled</span><span class="plain">)</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"tried to begin block stack already in use"</span><span class="plain">);</span>
<span class="functiontext">Frames::Blocks::empty_stack</span><span class="plain">(); </span> <span class="comment">which it should be anyway</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">LOCAL_VARIABLES</span><span class="plain">, </span><span class="string">"Block stack now active\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::begin_code_blocks is used in 26/rt (<a href="26-rt.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b>And this when it ends. The stack should in fact be empty, but just in
case we are recovering from some kind of problem, we'll empty anything
somehow left on it.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::end_code_blocks</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">while</span><span class="plain"> (</span><span class="identifier">block_being_compiled</span><span class="plain">) {</span>
<span class="identifier">current_sentence</span><span class="plain"> = </span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;block_location</span><span class="plain">;</span>
<span class="functiontext">Frames::Blocks::pop_stack</span><span class="plain">();</span>
<span class="plain">}</span>
<span class="identifier">block_being_compiled</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">LOCAL_VARIABLES</span><span class="plain">, </span><span class="string">"Block stack now inactive\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::end_code_blocks is used in 26/rt (<a href="26-rt.html#SP4">&#167;4</a>).</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. The life of a block. </b>So now let's follow what happens when a block is being compiled. Suppose
we have:
</p>
<blockquote>
<p>repeat through the Table of Odds:</p>
</blockquote>
<p class="inwebparagraph">When Inform begins to compile this invocation, it observes that the phrase
being invoked is followed by a code block, and calls the following routine
to warn us. (That doesn't mean the block is opening yet: the setup code
for the loop hasn't been compiled yet.)
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::beginning_block_phrase</span><span class="plain">(</span><span class="reserved">control_structure_phrase</span><span class="plain"> *</span><span class="identifier">csp</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain"> == </span><span class="constant">MAX_BLOCK_NESTING</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">problem_count</span><span class="plain"> == 0) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"block stack overflow"</span><span class="plain">);</span>
<span class="functiontext">Frames::Blocks::pop_stack</span><span class="plain">();</span>
<span class="plain">}</span>
<span class="functiontext">Frames::Blocks::prepush_stack</span><span class="plain">();</span>
&lt;<span class="cwebmacro">Construct the next phrase block</span> <span class="cwebmacronumber">10.1</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::beginning_block_phrase is used in 25/cp (<a href="25-cp.html#SP5">&#167;5</a>).</p>
<p class="inwebparagraph"><a id="SP10_1"></a><b>&#167;10.1. </b>In the case of a repeat through a Table, we need to create two loop
variables. In addition to those, the loop we're compiling will inevitably
change the two row selection variables (always called <code class="display"><span class="extract">ct_0</span></code> and <code class="display"><span class="extract">ct_1</span></code>),
so we need to protect their contents; we push them onto the stack before
the loop begins, and pull them again when it finishes.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Construct the next phrase block</span> <span class="cwebmacronumber">10.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;switch_val</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;tail_schema</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;block_location</span><span class="plain"> = </span><span class="identifier">current_sentence</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;from_structure</span><span class="plain"> = </span><span class="identifier">csp</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;label_following</span><span class="plain"> = -1;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP10">&#167;10</a>.</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b>Slightly later on, we know these:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::supply_val_and_stream</span><span class="plain">(</span><span class="identifier">parse_node</span><span class="plain"> *</span><span class="identifier">val</span><span class="plain">, </span><span class="identifier">inter_schema</span><span class="plain"> *</span><span class="identifier">I</span><span class="plain">, </span><span class="reserved">csi_state</span><span class="plain"> </span><span class="identifier">CSIS</span><span class="plain">) {</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;switch_val</span><span class="plain"> = </span><span class="identifier">val</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;tail_schema</span><span class="plain"> = </span><span class="identifier">I</span><span class="plain">;</span>
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">&gt;compilation_state</span><span class="plain"> = </span><span class="identifier">CSIS</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::supply_val_and_stream is used in 25/cii (<a href="25-cii.html#SP1_4">&#167;1.4</a>).</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b>At this next stage, the preliminary code for the loop (if it's a loop)
has been compiled, and we're ready to open the actual block:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::open_code_block</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">current_block_stack</span><span class="element">.pb_sp</span><span class="plain"> != </span><span class="constant">MAX_BLOCK_NESTING</span><span class="plain">) </span><span class="functiontext">Frames::Blocks::push_stack</span><span class="plain">();</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">LOCAL_VARIABLES</span><span class="plain">, </span><span class="string">"Start of block level %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::open_code_block is used in 25/cp (<a href="25-cp.html#SP5_3_4">&#167;5.3.4</a>, <a href="25-cp.html#SP5_3_5">&#167;5.3.5</a>, <a href="25-cp.html#SP5_4_5">&#167;5.4.5</a>).</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b>A division in a code block occurs at the "otherwise" point of an "if",
for example, but also for cases in a switch-style "if", so there can be
many of them.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::divide_code_block</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">block_being_compiled</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="comment">for problem recovery only</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">LOCAL_VARIABLES</span><span class="plain">, </span><span class="string">"Division in block level %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">);</span>
<span class="functiontext">LocalVariables::end_scope</span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::divide_code_block is used in 25/cp (<a href="25-cp.html#SP5_3_4">&#167;5.3.4</a>, <a href="25-cp.html#SP5_3_5">&#167;5.3.5</a>).</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. </b>Whatever we pushed earlier, we now pull:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::close_code_block</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">block_being_compiled</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="comment">for problem recovery only</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;label_following</span><span class="plain"> &gt;= 0) {</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">TL</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">TL</span><span class="plain">, </span><span class="string">".loop_break_%d"</span><span class="plain">, </span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;label_following</span><span class="plain">);</span>
<span class="identifier">Produce::place_label</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">Produce::reserve_label</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">TL</span><span class="plain">));</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">TL</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">LOGIF</span><span class="plain">(</span><span class="identifier">LOCAL_VARIABLES</span><span class="plain">, </span><span class="string">"End of block level %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">);</span>
<span class="functiontext">LocalVariables::end_scope</span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;tail_schema</span><span class="plain">) {</span>
<span class="identifier">value_holster</span><span class="plain"> </span><span class="identifier">VH</span><span class="plain"> = </span><span class="identifier">Holsters::new</span><span class="plain">(</span><span class="identifier">INTER_VOID_VHMODE</span><span class="plain">);</span>
<span class="functiontext">Invocations::Inline::csi_inline_inner</span><span class="plain">(&amp;</span><span class="identifier">VH</span><span class="plain">,</span>
<span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;tail_schema</span><span class="plain">, &amp;(</span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;compilation_state</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="functiontext">Frames::Blocks::pop_stack</span><span class="plain">();</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::close_code_block is used in 25/cp (<a href="25-cp.html#SP5_3_4">&#167;5.3.4</a>, <a href="25-cp.html#SP5_3_5">&#167;5.3.5</a>, <a href="25-cp.html#SP5_4_5">&#167;5.4.5</a>).</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. Bodies. </b>Are we in the body of a loop, perhaps indirectly?
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::inside_a_loop_body</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="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain"> = </span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</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">if</span><span class="plain"> (</span><span class="functiontext">Sentences::RuleSubtrees::is_a_loop</span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.from_structure</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 Frames::Blocks::inside_a_loop_body is used in 14/ds2 (<a href="14-ds2.html#SP11_9_1_1_9">&#167;11.9.1.1.9</a>), 25/cii (<a href="25-cii.html#SP3_5_3">&#167;3.5.3</a>).</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b>What can we find about the block we are most immediately in? Note that
if there is no current block stack, we behave as if the block stack were
empty, but (as long as nobody tries to open or close any blocks) no
internal errors are issued. This allows the typechecker to run even when
there is no current block stack, which is important when typechecking an
expression whose evaluation requires the use of a phrase.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::current_block_level</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">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">wchar_t</span><span class="plain"> *</span><span class="functiontext">Frames::Blocks::name_of_current_block</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">block_being_compiled</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">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">Sentences::RuleSubtrees::incipit</span><span class="plain">(</span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;from_structure</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Frames::Blocks::start_of_current_block</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">block_being_compiled</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">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;block_location</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">parse_node</span><span class="plain"> *</span><span class="functiontext">Frames::Blocks::switch_value</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">block_being_compiled</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">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">&gt;switch_val</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::current_block_level is used in 24/lv (<a href="24-lv.html#SP42">&#167;42</a>).</p>
<p class="endnote">The function Frames::Blocks::name_of_current_block is used in 14/ds2 (<a href="14-ds2.html#SP11_9_1_1_9">&#167;11.9.1.1.9</a>).</p>
<p class="endnote">The function Frames::Blocks::start_of_current_block appears nowhere else.</p>
<p class="endnote">The function Frames::Blocks::switch_value is used in 25/cp (<a href="25-cp.html#SP5_3_5">&#167;5.3.5</a>).</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. Breakage. </b>It might seem reasonable to compile a breaking-out of the current loop
into an I6 "break" statement, but the semantics of I6 "break" are subtly
different: as in C, they will break out of a switch case in preference
to a wider loop, whereas in I7 we want always to exit the innermost loop.
So we do this by hand, jumping to a label placed just after the loop ends.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">unique_breakage_count</span><span class="plain"> = 0;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::emit_break</span><span class="plain">(</span><span class="reserved">void</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"> = </span><span class="identifier">current_block_stack</span><span class="element">.pb_sp</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">if</span><span class="plain"> (</span><span class="functiontext">Sentences::RuleSubtrees::permits_break</span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.from_structure</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.label_following</span><span class="plain"> == -1)</span>
<span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.label_following</span><span class="plain"> =</span>
<span class="identifier">unique_breakage_count</span><span class="plain">++;</span>
<span class="identifier">Produce::inv_primitive</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">JUMP_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">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">TL</span><span class="plain">);</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">TL</span><span class="plain">, </span><span class="string">".loop_break_%d"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="element">.pb_stack</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]</span><span class="element">.label_following</span><span class="plain">);</span>
<span class="identifier">Produce::lab</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">Produce::reserve_label</span><span class="plain">(</span><span class="functiontext">Emit::tree</span><span class="plain">(), </span><span class="identifier">TL</span><span class="plain">));</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">TL</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">return</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"not inside a loop block"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::emit_break is used in 25/cii (<a href="25-cii.html#SP3_7">&#167;3.7</a>).</p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. Blocks and scope. </b>When "let" creates something, this is called:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::set_variable_scope</span><span class="plain">(</span><span class="reserved">local_variable</span><span class="plain"> *</span><span class="identifier">lvar</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Frames::current_stack_frame</span><span class="plain">())</span>
<span class="functiontext">LocalVariables::set_scope_to</span><span class="plain">(</span><span class="identifier">lvar</span><span class="plain">,</span>
<span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::set_variable_scope is used in 25/cii (<a href="25-cii.html#SP1_2_1">&#167;1.2.1</a>).</p>
<p class="inwebparagraph"><a id="SP19"></a><b>&#167;19. </b>But when loops create something, this is called instead, because the loop
counter exists in one scope level inside the one holding the loop header
phrase:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::set_scope_to_block_about_to_open</span><span class="plain">(</span><span class="reserved">local_variable</span><span class="plain"> *</span><span class="identifier">lvar</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Frames::current_stack_frame</span><span class="plain">())</span>
<span class="functiontext">LocalVariables::set_scope_to</span><span class="plain">(</span><span class="identifier">lvar</span><span class="plain">,</span>
<span class="identifier">current_block_stack</span><span class="element">.pb_sp</span><span class="plain"> + 1);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Frames::Blocks::set_scope_to_block_about_to_open is used in 12/dtd (<a href="12-dtd.html#SP23">&#167;23</a>, <a href="12-dtd.html#SP27">&#167;27</a>), 25/cii (<a href="25-cii.html#SP1_2_1">&#167;1.2.1</a>, <a href="25-cii.html#SP3_5_1_1">&#167;3.5.1.1</a>).</p>
<hr class="tocbar">
<ul class="toc"><li><a href="24-lv.html">Back to 'Local Variables'</a></li><li><a href="24-sf.html">Continue with 'Stack Frames'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>