mirror of
https://github.com/ganelson/inform.git
synced 2024-07-08 18:14:21 +03:00
449 lines
40 KiB
HTML
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">★</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">§1. Definitions</a></li><li><a href="#SP3">§3. Pushing, popping</a></li><li><a href="#SP8">§8. Activation and deactivation</a></li><li><a href="#SP10">§10. The life of a block</a></li><li><a href="#SP15">§15. Bodies</a></li><li><a href="#SP17">§17. Breakage</a></li><li><a href="#SP18">§18. Blocks and scope</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. Definitions. </b></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. </b>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 —
|
|
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>§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>§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">§8</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5"></a><b>§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"> = &(</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">§10</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP6"></a><b>§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">§12</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP7"></a><b>§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"> > 0)</span>
|
|
<span class="identifier">block_being_compiled</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">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">§9</a>, <a href="#SP10">§10</a>, <a href="#SP14">§14</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP8"></a><b>§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">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9"></a><b>§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">>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">§4</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10"></a><b>§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>
|
|
<<span class="cwebmacro">Construct the next phrase block</span> <span class="cwebmacronumber">10.1</span>><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">§5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10_1"></a><b>§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">
|
|
<<span class="cwebmacrodefn">Construct the next phrase block</span> <span class="cwebmacronumber">10.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">block_being_opened</span><span class="plain">-</span><span class="element">>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">>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">>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">>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">>label_following</span><span class="plain"> = -1;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP10">§10</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP11"></a><b>§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">>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">>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">>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">§1.4</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP12"></a><b>§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">§5.3.4</a>, <a href="25-cp.html#SP5_3_5">§5.3.5</a>, <a href="25-cp.html#SP5_4_5">§5.4.5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13"></a><b>§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">§5.3.4</a>, <a href="25-cp.html#SP5_3_5">§5.3.5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP14"></a><b>§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">>label_following</span><span class="plain"> >= 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">>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">>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">(&</span><span class="identifier">VH</span><span class="plain">,</span>
|
|
<span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">>tail_schema</span><span class="plain">, &(</span><span class="identifier">block_being_compiled</span><span class="plain">-</span><span class="element">>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">§5.3.4</a>, <a href="25-cp.html#SP5_3_5">§5.3.5</a>, <a href="25-cp.html#SP5_4_5">§5.4.5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP15"></a><b>§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"> >= 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">§11.9.1.1.9</a>), 25/cii (<a href="25-cii.html#SP3_5_3">§3.5.3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP16"></a><b>§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">>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">>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">>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">§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">§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">§5.3.5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17"></a><b>§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"> >= 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">§3.7</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP18"></a><b>§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">§1.2.1</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP19"></a><b>§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">§23</a>, <a href="12-dtd.html#SP27">§27</a>), 25/cii (<a href="25-cii.html#SP1_2_1">§1.2.1</a>, <a href="25-cii.html#SP3_5_1_1">§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>
|
|
|