1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 10:04:21 +03:00
inform7/docs/core-module/24-pb.html
2020-04-15 23:49:59 +01:00

442 lines
45 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Phrase Blocks</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<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>
<nav role="navigation">
<h1><a href="../index.html">
<img src="../docs-src/Figures/Inform.png" height=72">
</a></h1>
<ul><li><a href="../compiler.html">compiler tools</a></li>
<li><a href="../other.html">other tools</a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul><h2>Compiler Webs</h2><ul>
<li><a href="../inbuild/index.html">inbuild</a></li>
<li><a href="../inform7/index.html">inform7</a></li>
<li><a href="../inter/index.html">inter</a></li>
</ul><h2>Inbuild Modules</h2><ul>
<li><a href="../supervisor-module/index.html">supervisor</a></li>
</ul><h2>Inform7 Modules</h2><ul>
<li><a href="index.html"><span class="selectedlink">core</span></a></li>
<li><a href="../inflections-module/index.html">inflections</a></li>
<li><a href="../linguistics-module/index.html">linguistics</a></li>
<li><a href="../kinds-module/index.html">kinds</a></li>
<li><a href="../if-module/index.html">if</a></li>
<li><a href="../multimedia-module/index.html">multimedia</a></li>
<li><a href="../problems-module/index.html">problems</a></li>
<li><a href="../index-module/index.html">index</a></li>
</ul><h2>Inter Modules</h2><ul>
<li><a href="../bytecode-module/index.html">bytecode</a></li>
<li><a href="../building-module/index.html">building</a></li>
<li><a href="../codegen-module/index.html">codegen</a></li>
</ul><h2>Shared Modules</h2><ul>
<li><a href="../arch-module/index.html">arch</a></li>
<li><a href="../syntax-module/index.html">syntax</a></li>
<li><a href="../words-module/index.html">words</a></li>
<li><a href="../html-module/index.html">html</a></li>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of 'Phrase Blocks' generated by 7-->
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="../compiler.html">Inform7 Modules</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="24-pb.html#SP1">&#167;1. Definitions</a></li><li><a href="24-pb.html#SP3">&#167;3. Pushing, popping</a></li><li><a href="24-pb.html#SP8">&#167;8. Activation and deactivation</a></li><li><a href="24-pb.html#SP10">&#167;10. The life of a block</a></li><li><a href="24-pb.html#SP15">&#167;15. Bodies</a></li><li><a href="24-pb.html#SP17">&#167;17. Breakage</a></li><li><a href="24-pb.html#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"> </span><span class="constant">50</span><span class="plain"> </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="identifier">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<button class="popup" onclick="togglePopup('usagePopup1920')">...<span class="popuptext" id="usagePopup1920">Usage of <b>Frames::Blocks::empty_stack</b>:<br><a href="24-pb.html#SP8">&#167;8</a></span></button></span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain"> = </span><span class="constant">0</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">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="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<button class="popup" onclick="togglePopup('usagePopup1921')">...<span class="popuptext" id="usagePopup1921">Usage of <b>Frames::Blocks::prepush_stack</b>:<br><a href="24-pb.html#SP10">&#167;10</a></span></button></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="plain">.</span><span class="element">pb_stack</span><span class="plain">[</span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain">]);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1922')">...<span class="popuptext" id="usagePopup1922">Usage of <b>Frames::Blocks::push_stack</b>:<br><a href="24-pb.html#SP12">&#167;12</a></span></button></span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">current_block_stack</span><span class="plain">.</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="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<button class="popup" onclick="togglePopup('usagePopup1923')">...<span class="popuptext" id="usagePopup1923">Usage of <b>Frames::Blocks::pop_stack</b>:<br><a href="24-pb.html#SP9">&#167;9</a>, <a href="24-pb.html#SP10">&#167;10</a>, <a href="24-pb.html#SP14">&#167;14</a></span></button></span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="identifier">current_block_stack</span><span class="plain">.</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="plain">.</span><span class="element">pb_sp</span><span class="plain"> &gt; </span><span class="constant">0</span><span class="plain">)</span>
<span class="identifier">block_being_compiled</span><span class="plain"> = &amp;(</span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_stack</span><span class="plain">[</span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain"> - </span><span class="constant">1</span><span class="plain">]);</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="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<button class="popup" onclick="togglePopup('usagePopup1924')">...<span class="popuptext" id="usagePopup1924">Usage of <b>Frames::Blocks::begin_code_blocks</b>:<br>Routines - <a href="26-rt.html#SP3">&#167;3</a></span></button></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"><a href="24-sf.html#SP8">Frames::current_stack_frame</a></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"><a href="24-pb.html#SP4">Frames::Blocks::empty_stack</a></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\n"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1925')">...<span class="popuptext" id="usagePopup1925">Usage of <b>Frames::Blocks::end_code_blocks</b>:<br>Routines - <a href="26-rt.html#SP4">&#167;4</a></span></button></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">-&gt;</span><span class="element">block_location</span><span class="plain">;</span>
<span class="functiontext"><a href="24-pb.html#SP7">Frames::Blocks::pop_stack</a></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\n"</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1926')">...<span class="popuptext" id="usagePopup1926">Usage of <b>Frames::Blocks::beginning_block_phrase</b>:<br>Compile Phrases - <a href="25-cp.html#SP5">&#167;5</a></span></button></span><span class="plain">(</span><span class="identifier">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="plain">.</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"> == </span><span class="constant">0</span><span class="plain">) </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"><a href="24-pb.html#SP7">Frames::Blocks::pop_stack</a></span><span class="plain">();</span>
<span class="plain">}</span>
<span class="functiontext"><a href="24-pb.html#SP5">Frames::Blocks::prepush_stack</a></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="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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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="24-pb.html#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<button class="popup" onclick="togglePopup('usagePopup1927')">...<span class="popuptext" id="usagePopup1927">Usage of <b>Frames::Blocks::supply_val_and_stream</b>:<br>Compile Invocations Inline - <a href="25-cii.html#SP1_4">&#167;1.4</a></span></button></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">-&gt;</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">-&gt;</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">-&gt;</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="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<button class="popup" onclick="togglePopup('usagePopup1928')">...<span class="popuptext" id="usagePopup1928">Usage of <b>Frames::Blocks::open_code_block</b>:<br>Compile Phrases - <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></span></button></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="plain">.</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"><a href="24-pb.html#SP6">Frames::Blocks::push_stack</a></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\n"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1929')">...<span class="popuptext" id="usagePopup1929">Usage of <b>Frames::Blocks::divide_code_block</b>:<br>Compile Phrases - <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></span></button></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\n"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain">);</span>
<span class="functiontext"><a href="24-lv.html#SP41">LocalVariables::end_scope</a></span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1930')">...<span class="popuptext" id="usagePopup1930">Usage of <b>Frames::Blocks::close_code_block</b>:<br>Compile Phrases - <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></span></button></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">-&gt;</span><span class="element">label_following</span><span class="plain"> &gt;= </span><span class="constant">0</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">block_being_compiled</span><span class="plain">-&gt;</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"><a href="27-em.html#SP2">Emit::tree</a></span><span class="plain">(), </span><span class="identifier">Produce::reserve_label</span><span class="plain">(</span><span class="functiontext"><a href="27-em.html#SP2">Emit::tree</a></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\n"</span><span class="plain">, </span><span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain">);</span>
<span class="functiontext"><a href="24-lv.html#SP41">LocalVariables::end_scope</a></span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="plain">.</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">-&gt;</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"><a href="25-cii.html#SP2">Invocations::Inline::csi_inline_inner</a></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">-&gt;</span><span class="element">tail_schema</span><span class="plain">, &amp;(</span><span class="identifier">block_being_compiled</span><span class="plain">-&gt;</span><span class="element">compilation_state</span><span class="plain">));</span>
<span class="plain">}</span>
<span class="functiontext"><a href="24-pb.html#SP7">Frames::Blocks::pop_stack</a></span><span class="plain">();</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1931')">...<span class="popuptext" id="usagePopup1931">Usage of <b>Frames::Blocks::inside_a_loop_body</b>:<br>Dash - <a href="14-ds2.html#SP11_9_1_1_9">&#167;11.9.1.1.9</a><br>Compile Invocations Inline - <a href="25-cii.html#SP3_5_3">&#167;3.5.3</a></span></button></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="plain">.</span><span class="element">pb_sp</span><span class="plain">-1; </span><span class="identifier">i</span><span class="plain"> &gt;= </span><span class="constant">0</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">--)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ControlStructures::is_a_loop</span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="plain">.</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="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<button class="popup" onclick="togglePopup('usagePopup1932')">...<span class="popuptext" id="usagePopup1932">Usage of <b>Frames::Blocks::current_block_level</b>:<br>Local Variables - <a href="24-lv.html#SP42">&#167;42</a></span></button></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="plain">.</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<button class="popup" onclick="togglePopup('usagePopup1933')">...<span class="popuptext" id="usagePopup1933">Usage of <b>Frames::Blocks::name_of_current_block</b>:<br>Dash - <a href="14-ds2.html#SP11_9_1_1_9">&#167;11.9.1.1.9</a></span></button></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">ControlStructures::incipit</span><span class="plain">(</span><span class="identifier">block_being_compiled</span><span class="plain">-&gt;</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<button class="popup" onclick="togglePopup('usagePopup1934')">...<span class="popuptext" id="usagePopup1934">Usage of <b>Frames::Blocks::start_of_current_block</b>:<br>none</span></button></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">-&gt;</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<button class="popup" onclick="togglePopup('usagePopup1935')">...<span class="popuptext" id="usagePopup1935">Usage of <b>Frames::Blocks::switch_value</b>:<br>Compile Phrases - <a href="25-cp.html#SP5_3_5">&#167;5.3.5</a></span></button></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">-&gt;</span><span class="element">switch_val</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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"> = </span><span class="constant">0</span><span class="plain">;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Frames::Blocks::emit_break<button class="popup" onclick="togglePopup('usagePopup1936')">...<span class="popuptext" id="usagePopup1936">Usage of <b>Frames::Blocks::emit_break</b>:<br>Compile Invocations Inline - <a href="25-cii.html#SP3_7">&#167;3.7</a></span></button></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="plain">.</span><span class="identifier">pb_sp</span><span class="plain">-1; </span><span class="identifier">i</span><span class="plain"> &gt;= </span><span class="constant">0</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">--)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ControlStructures::permits_break</span><span class="plain">(</span><span class="identifier">current_block_stack</span><span class="plain">.</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="plain">.</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="plain">.</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"><a href="27-em.html#SP2">Emit::tree</a></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"><a href="27-em.html#SP2">Emit::tree</a></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="plain">.</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"><a href="27-em.html#SP2">Emit::tree</a></span><span class="plain">(), </span><span class="identifier">Produce::reserve_label</span><span class="plain">(</span><span class="functiontext"><a href="27-em.html#SP2">Emit::tree</a></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"><a href="27-em.html#SP2">Emit::tree</a></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="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<button class="popup" onclick="togglePopup('usagePopup1937')">...<span class="popuptext" id="usagePopup1937">Usage of <b>Frames::Blocks::set_variable_scope</b>:<br>Compile Invocations Inline - <a href="25-cii.html#SP1_2_1">&#167;1.2.1</a></span></button></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"><a href="24-sf.html#SP8">Frames::current_stack_frame</a></span><span class="plain">())</span>
<span class="functiontext"><a href="24-lv.html#SP40">LocalVariables::set_scope_to</a></span><span class="plain">(</span><span class="identifier">lvar</span><span class="plain">,</span>
<span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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<button class="popup" onclick="togglePopup('usagePopup1938')">...<span class="popuptext" id="usagePopup1938">Usage of <b>Frames::Blocks::set_scope_to_block_about_to_open</b>:<br>Deciding to Defer - <a href="12-dtd.html#SP23">&#167;23</a>, <a href="12-dtd.html#SP27">&#167;27</a><br>Compile Invocations Inline - <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></span></button></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"><a href="24-sf.html#SP8">Frames::current_stack_frame</a></span><span class="plain">())</span>
<span class="functiontext"><a href="24-lv.html#SP40">LocalVariables::set_scope_to</a></span><span class="plain">(</span><span class="identifier">lvar</span><span class="plain">,</span>
<span class="identifier">current_block_stack</span><span class="plain">.</span><span class="element">pb_sp</span><span class="plain"> + </span><span class="constant">1</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></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-->
<script>
function togglePopup(material_id) {
var popup = document.getElementById(material_id);
popup.classList.toggle("show");
}
</script>
<link href="Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
</main>
</body>
</html>