emacs.d/clones/ruslanspivak.com/index.html
2022-10-07 19:32:11 +02:00

609 lines
No EOL
36 KiB
HTML

<!DOCTYPE html>
<html lang="en"
xmlns:og="http://ogp.me/ns#"
xmlns:fb="https://www.facebook.com/2008/fbml">
<head>
<title>Ruslan's Blog</title>
<!-- Using the latest rendering mode for IE -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="canonical" href="index.html">
<meta name="author" content="Ruslan Spivak" />
<!-- Open Graph tags -->
<meta property="og:site_name" content="Ruslan's Blog" />
<meta property="og:type" content="website"/>
<meta property="og:title" content="Ruslan's Blog"/>
<meta property="og:url" content="https://ruslanspivak.com"/>
<meta property="og:description" content="Ruslan's Blog"/>
<meta name="twitter:card" content="summary">
<meta name="twitter:domain" content="https://ruslanspivak.com">
<!-- Bootstrap -->
<link rel="stylesheet" href="theme/css/bootstrap.min.css" type="text/css"/>
<link href="theme/css/font-awesome.min.css" rel="stylesheet">
<link href="theme/css/pygments/tango.css" rel="stylesheet">
<link href="theme/css/typogrify.css" rel="stylesheet">
<link rel="stylesheet" href="theme/css/style.css" type="text/css"/>
<link href="static/custom.css" rel="stylesheet">
<link href="feeds/all.atom.xml" type="application/atom+xml" rel="alternate"
title="Ruslan's Blog ATOM Feed"/>
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="index.html" class="navbar-brand">
Ruslan's Blog </a>
</div>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav">
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="pages/about.html"><i class="fa fa-question"></i><span class="icon-label">About</span></a></li>
<li><a href="archives.html"><i class="fa fa-th-list"></i><span class="icon-label">Archives</span></a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
</div> <!-- /.navbar -->
<!-- Banner -->
<!-- End Banner -->
<div class="container">
<div class="row">
<div class="col-sm-9">
<article>
<h2><a href="lsbasi-part19/index.html">Let&#8217;s Build A Simple Interpreter. Part 19: Nested Procedure&nbsp;Calls</a></h2>
<div class="well well-sm">
<footer class="post-info">
<span class="label label-default">Date</span>
<span class="published">
<i class="fa fa-calendar"></i><time datetime="2020-03-19T10:00:00-04:00"> Thu, March 19, 2020</time>
</span>
</footer><!-- /.post-info --> </div>
<div class="summary">
<blockquote>
<p><em><span class="dquo">&#8220;</span>What I cannot create, I do not understand.&#8221; &#8212; Richard&nbsp;Feynman</em></p>
</blockquote>
<p>As I promised you last time, today we&#8217;re going to expand on the material covered in the previous article and talk about executing nested procedure calls. Just like last time, we will limit our focus today to procedures that can access their parameters and local variables only. We will cover accessing non-local variables in the next&nbsp;article.</p>
<p>Here is the sample program for&nbsp;today:</p>
<div class="highlight"><pre><span></span><span class="k">program</span> <span class="n">Main</span><span class="o">;</span>
<span class="k">procedure</span> <span class="nf">Alpha</span><span class="p">(</span><span class="n">a</span> <span class="o">:</span> <span class="kt">integer</span><span class="o">;</span> <span class="n">b</span> <span class="o">:</span> <span class="kt">integer</span><span class="p">)</span><span class="o">;</span>
<span class="k">var</span> <span class="n">x</span> <span class="o">:</span> <span class="kt">integer</span><span class="o">;</span>
<span class="k">procedure</span> <span class="nf">Beta</span><span class="p">(</span><span class="n">a</span> <span class="o">:</span> <span class="kt">integer</span><span class="o">;</span> <span class="n">b</span> <span class="o">:</span> <span class="kt">integer</span><span class="p">)</span><span class="o">;</span>
<span class="k">var</span> <span class="n">x</span> <span class="o">:</span> <span class="kt">integer</span><span class="o">;</span>
<span class="k">begin</span>
<span class="n">x</span> <span class="o">:=</span> <span class="n">a</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="n">b</span> <span class="o">*</span> <span class="mi">2</span><span class="o">;</span>
<span class="k">end</span><span class="o">;</span>
<span class="k">begin</span>
<span class="n">x</span> <span class="o">:=</span> <span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="p">)</span> <span class="o">*</span> <span class="mi">2</span><span class="o">;</span>
<span class="n">Beta</span><span class="p">(</span><span class="mi">5</span><span class="o">,</span> <span class="mi">10</span><span class="p">)</span><span class="o">;</span> <span class="cm">{ procedure call }</span>
<span class="k">end</span><span class="o">;</span>
<span class="k">begin</span> <span class="cm">{ Main }</span>
<span class="n">Alpha</span><span class="p">(</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">5</span><span class="o">,</span> <span class="mi">7</span><span class="p">)</span><span class="o">;</span> <span class="cm">{ procedure call }</span>
<span class="k">end</span><span class="o">.</span> <span class="cm">{ Main }</span>
</pre></div>
<p>The nesting relationships diagram for the program looks like&nbsp;this:</p>
<p><img alt="" src="lsbasi-part19/lsbasi_part19_nestingrel.png" width="240"></p>
<p>Some things to note about the above&nbsp;program:</p>
<ul>
<li>
<p>it has two procedure declarations, <em>Alpha</em> and <em>Beta</em></p>
</li>
<li>
<p><em>Alpha</em> is declared inside the main program (the <em>global</em>&nbsp;scope)</p>
</li>
<li>
<p>the <em>Beta</em> procedure is declared inside the <em>Alpha</em>&nbsp;procedure</p>
</li>
<li>
<p>both <em>Alpha</em> and <em>Beta</em> have the same names for their formal parameters: integers <em>a</em> and <em>b</em></p>
</li>
<li>
<p>and both <em>Alpha</em> and <em>Beta</em> have the same local variable <em>x</em></p>
</li>
<li>
<p>the program has nested calls: the <em>Beta</em> procedure is called from the <em>Alpha</em> procedure, which, in turn, is called from the main&nbsp;program</p>
</li>
</ul>
<p><br>
Now, let&#8217;s do an experiment. Download the <a href="https://github.com/rspivak/lsbasi/blob/master/part19/part19.pas">part19.pas</a> file from <a href="https://github.com/rspivak/lsbasi/blob/master/part19">GitHub</a> and run the <a href="https://github.com/rspivak/lsbasi/blob/master/part18/spi.py">interpreter from the previous article</a> with the <a href="https://github.com/rspivak/lsbasi/blob/master/part19/part19.pas">part19.pas</a> file as its input to see what happens when the interpreter executes nested procedure calls (the main program calling <em>Alpha</em> calling <em>Beta</em>):</p>
<div class="highlight"><pre><span></span>$ python spi.py part19.pas --stack
ENTER: PROGRAM Main
CALL STACK
<span class="m">1</span>: PROGRAM Main
...
ENTER: PROCEDURE Beta
CALL STACK
<span class="m">2</span>: PROCEDURE Beta
a : <span class="m">5</span>
b : <span class="m">10</span>
<span class="m">2</span>: PROCEDURE Alpha
a : <span class="m">8</span>
b : <span class="m">7</span>
x : <span class="m">30</span>
<span class="m">1</span>: PROGRAM Main
LEAVE: PROCEDURE Beta
CALL STACK
<span class="m">2</span>: PROCEDURE Beta
a : <span class="m">5</span>
b : <span class="m">10</span>
x : <span class="m">70</span>
<span class="m">2</span>: PROCEDURE Alpha
a : <span class="m">8</span>
b : <span class="m">7</span>
x : <span class="m">30</span>
<span class="m">1</span>: PROGRAM Main
...
LEAVE: PROGRAM Main
CALL STACK
<span class="m">1</span>: PROGRAM Main
</pre></div>
<p><br>
It just works! There are no errors. And if you study the contents of the ARs(activation records), you can see that the values stored in the activation records for the <em>Alpha</em> and <em>Beta</em> procedure calls are correct. So, what&#8217;s the catch then? There is one small issue. If you take a look at the output where it says &#8216;<span class="caps">ENTER</span>: <span class="caps">PROCEDURE</span> Beta&#8217;, you can see that the nesting level for the <em>Beta</em> and <em>Alpha</em> procedure call is the same, it&#8217;s 2 (two). The nesting level for <em>Alpha</em> should be 2 and the nesting level for <em>Beta</em> should be 3. That&#8217;s the issue that we need to fix. Right now the <em>nesting_level</em> value in the <em>visit_ProcedureCall</em> method is hardcoded to be 2&nbsp;(two):</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">visit_ProcedureCall</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span>
<span class="n">proc_name</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">proc_name</span>
<span class="n">ar</span> <span class="o">=</span> <span class="n">ActivationRecord</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">proc_name</span><span class="p">,</span>
<span class="nb">type</span><span class="o">=</span><span class="n">ARType</span><span class="o">.</span><span class="n">PROCEDURE</span><span class="p">,</span>
<span class="n">nesting_level</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">proc_symbol</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">proc_symbol</span>
<span class="o">...</span>
</pre></div>
<p><br>
Let&#8217;s get rid of the hardcoded value. How do we determine a nesting level for a procedure call? In the method above we have a procedure symbol and it is stored in a scoped symbol table that has the right scope level that we can use as the value of the <em>nesting_level</em> parameter (see <a href="lsbasi-part14/index.html">Part 14</a> for more details about scopes and scope&nbsp;levels).</p>
<p>How do we get to the scoped symbol table&#8217;s scope level through the procedure&nbsp;symbol?</p>
<p>Let&#8217;s look at the following parts of the <em>ScopedSymbolTable</em>&nbsp;class:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ScopedSymbolTable</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scope_name</span><span class="p">,</span> <span class="n">scope_level</span><span class="p">,</span> <span class="n">enclosing_scope</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="o">...</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scope_level</span> <span class="o">=</span> <span class="n">scope_level</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">insert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">symbol</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">f</span><span class="s1">&#39;Insert: {symbol.name}&#39;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_symbols</span><span class="p">[</span><span class="n">symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">symbol</span>
</pre></div>
<p>Looking at the code above, we can see that we could assign the scope level of a scoped symbol table to a symbol when we store the symbol in the scoped symbol table (scope) inside the <em>insert</em> method. This way we will have access to the procedure symbol&#8217;s scope level in the <em>visit_Procedure</em> method during the interpretation phase. And that&#8217;s exactly what we&nbsp;need.</p>
<p>Let&#8217;s make the necessary&nbsp;changes:</p>
<ul>
<li>
<p>First, let&#8217;s add a <em>scope_level</em> member to the <em>Symbol</em> class and give it a default value of&nbsp;zero:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Symbol</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="o">...</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scope_level</span> <span class="o">=</span> <span class="mi">0</span>
</pre></div>
</li>
<li>
<p>Next, let&#8217;s assign the corresponding scope level to a symbol when storing the symbol in a scoped symbol&nbsp;table:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ScopedSymbolTable</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">insert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">symbol</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">f</span><span class="s1">&#39;Insert: {symbol.name}&#39;</span><span class="p">)</span>
<span class="n">symbol</span><span class="o">.</span><span class="n">scope_level</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">scope_level</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_symbols</span><span class="p">[</span><span class="n">symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">symbol</span>
</pre></div>
</li>
</ul>
<p><br>
Now, when creating an <span class="caps">AR</span> for a procedure call in the <em>visit_ProcedureCall</em> method, we have access to the scope level of the procedure symbol. All that&#8217;s left to do is use the scope level of the procedure symbol as the value of the <em>nesting_level</em>&nbsp;parameter:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Interpreter</span><span class="p">(</span><span class="n">NodeVisitor</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">visit_ProcedureCall</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span>
<span class="n">proc_name</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">proc_name</span>
<span class="n">proc_symbol</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">proc_symbol</span>
<span class="n">ar</span> <span class="o">=</span> <span class="n">ActivationRecord</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="n">proc_name</span><span class="p">,</span>
<span class="nb">type</span><span class="o">=</span><span class="n">ARType</span><span class="o">.</span><span class="n">PROCEDURE</span><span class="p">,</span>
<span class="n">nesting_level</span><span class="o">=</span><span class="n">proc_symbol</span><span class="o">.</span><span class="n">scope_level</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>That&#8217;s great, no more hardcoded nesting levels. One thing worth mentioning is why we put <em>proc_symbol.scope_level + 1</em> as the value of the <em>nesting_level</em> parameter and not just <em>proc_symbol.scope_level.</em> In <a href="lsbasi-part17.html">Part 17</a>, I mentioned that the nesting level of an <span class="caps">AR</span> corresponds to the scope level of the respective procedure or function declaration plus one. Let&#8217;s see&nbsp;why.</p>
<p>In our sample program for today, the <em>Alpha</em> procedure symbol - the symbol that contains information about the <em>Alpha</em> procedure declaration - is stored in the <em>global</em> scope at level 1 (one). So 1 is the value of the <em>Alpha</em> procedure symbol&#8217;s <em>scope_level</em>. But as we know from <a href="lsbasi-part14/index.html">Part14</a>, the scope level of the procedure declaration <em>Alpha</em> is one less than the level of the variables declared inside the procedure <em>Alpha</em>. So, to get the scope level of the scope where the <em>Alpha</em> procedure&#8217;s parameters and local variables are stored, we need to increment the procedure symbol&#8217;s scope level by 1. That&#8217;s the reason we use <em>proc_symbol.scope_level + 1</em> as the value of the <em>nesting_level</em> parameter when creating an <span class="caps">AR</span> for a procedure call and not simply <em>proc_symbol.scope_level</em>.</p>
<p>Let&#8217;s see the changes we&#8217;ve made so far in action. Download <a href="https://github.com/rspivak/lsbasi/blob/master/part19">the updated interpreter</a> and test it again with the <a href="https://github.com/rspivak/lsbasi/blob/master/part19">part19.pas</a> file as its&nbsp;input:</p>
<div class="highlight"><pre><span></span>$ python spi.py part19.pas --stack
ENTER: PROGRAM Main
CALL STACK
<span class="m">1</span>: PROGRAM Main
ENTER: PROCEDURE Alpha
CALL STACK
<span class="m">2</span>: PROCEDURE Alpha
a : <span class="m">8</span>
b : <span class="m">7</span>
<span class="m">1</span>: PROGRAM Main
ENTER: PROCEDURE Beta
CALL STACK
<span class="m">3</span>: PROCEDURE Beta
a : <span class="m">5</span>
b : <span class="m">10</span>
<span class="m">2</span>: PROCEDURE Alpha
a : <span class="m">8</span>
b : <span class="m">7</span>
x : <span class="m">30</span>
<span class="m">1</span>: PROGRAM Main
LEAVE: PROCEDURE Beta
CALL STACK
<span class="m">3</span>: PROCEDURE Beta
a : <span class="m">5</span>
b : <span class="m">10</span>
x : <span class="m">70</span>
<span class="m">2</span>: PROCEDURE Alpha
a : <span class="m">8</span>
b : <span class="m">7</span>
x : <span class="m">30</span>
<span class="m">1</span>: PROGRAM Main
LEAVE: PROCEDURE Alpha
CALL STACK
<span class="m">2</span>: PROCEDURE Alpha
a : <span class="m">8</span>
b : <span class="m">7</span>
x : <span class="m">30</span>
<span class="m">1</span>: PROGRAM Main
LEAVE: PROGRAM Main
CALL STACK
<span class="m">1</span>: PROGRAM Main
</pre></div>
<p>As you can see from the output above, the nesting levels of the activation records (<span class="caps">AR</span>) now have the correct&nbsp;values:</p>
<ul>
<li>
<p>The <em>Main</em> program <span class="caps">AR</span>: nesting level&nbsp;1</p>
</li>
<li>
<p>The <em>Alpha</em> procedure <span class="caps">AR</span>: nesting level&nbsp;2</p>
</li>
<li>
<p>The <em>Beta</em> procedure <span class="caps">AR</span>: nesting level&nbsp;3</p>
</li>
</ul>
<p><br>
Let&#8217;s take a look at how the scope tree (scoped symbol tables) and the call stack look visually during the execution of the program. Here is how the call stack looks right after the message &#8220;<span class="caps">LEAVE</span>: <span class="caps">PROCEDURE</span> Beta&#8221; and before the <span class="caps">AR</span> for the <em>Beta</em> procedure call is popped off the&nbsp;stack:</p>
<p><img alt="" src="lsbasi-part19/lsbasi_part19_callstack.png" width="640"></p>
<p>And if we flip the call stack (so that the top of the stack is at the &#8220;bottom&#8221;), you can see how the call stack with activation records relates to the scope tree with scopes (scoped symbol tables). In fact, we can say that activation records are run-time equivalents of scopes. Scopes are created during semantic analysis of a source program (the source program is read, parsed, and analyzed at this stage, but not executed) and the call stack with activation records is created at run-time when the interpreter executes the source&nbsp;program:</p>
<p><img alt="" src="lsbasi-part19/lsbasi_part19_scopes_callstack.png" width="640"></p>
<p>As you&#8217;ve seen in this article, we haven&#8217;t made a lot of changes to support the execution of nested procedure calls. The only real change was to make sure the nesting level in ARs was correct. The rest of the codebase stayed the same. The main reason why our code continues to work pretty much unchanged with nested procedure calls is because the <em>Alpha</em> and <em>Beta</em> procedures in the sample program access the values of local variables only (including their own parameters). And because those values are stored in the <span class="caps">AR</span> at the top of the stack, this allows us to continue to use the methods <em>visit_Assignment</em> and <em>visit_Var</em> without any change, when executing the body of the procedures. Here is the source code of the methods&nbsp;again:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">visit_Assign</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span>
<span class="n">var_name</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">left</span><span class="o">.</span><span class="n">value</span>
<span class="n">var_value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">right</span><span class="p">)</span>
<span class="n">ar</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">peek</span><span class="p">()</span>
<span class="n">ar</span><span class="p">[</span><span class="n">var_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">var_value</span>
<span class="k">def</span> <span class="nf">visit_Var</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">node</span><span class="p">):</span>
<span class="n">var_name</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">value</span>
<span class="n">ar</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">peek</span><span class="p">()</span>
<span class="n">var_value</span> <span class="o">=</span> <span class="n">ar</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">var_name</span><span class="p">)</span>
<span class="k">return</span> <span class="n">var_value</span>
</pre></div>
<p><br>
Okay, today we&#8217;ve been able to successfully execute nested procedure calls with our interpreter with very few changes. And now we&#8217;re one step closer to properly executing recursive procedure&nbsp;calls.</p>
<p>That&#8217;s it for today. In the next article, we&#8217;ll talk about how procedures can access non-local variables during&nbsp;run-time.</p>
<p><br/>
<strong>Stay safe, stay healthy, and take care of each other! See you next&nbsp;time.</strong></p>
<p><br/>
<em>Resources used in preparation for this article (links are affiliate&nbsp;links):</em></p>
<ol>
<li><a target="_blank" href="https://www.amazon.com/gp/product/193435645X/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=193435645X&linkCode=as2&tag=russblo0b-20&linkId=5d5ca8c07bff5452ea443d8319e7703d">Language Implementation Patterns: Create Your Own Domain-Specific and General Programming Languages (Pragmatic Programmers)</a><img src="https://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&amp;l=am2&amp;o=1&amp;a=193435645X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></li>
<li><a target="_blank" href="https://www.amazon.com/gp/product/0470177071/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0470177071&linkCode=as2&tag=russblo0b-20&linkId=542d1267e34a529e0f69027af20e27f3">Writing Compilers and Interpreters: A Software Engineering Approach</a><img src="https://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&amp;l=am2&amp;o=1&amp;a=0470177071" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></li>
<li><a target="_blank" href="https://www.amazon.com/gp/product/0124104096/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0124104096&linkCode=as2&tag=russblo0b-20&linkId=8db1da254b12fe6da1379957dda717fc">Programming Language Pragmatics, Fourth Edition</a><img src="https://ir-na.amazon-adsystem.com/e/ir?t=russblo0b-20&amp;l=am2&amp;o=1&amp;a=0124104096" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></li>
</ol>
<p><br/>
<p>If you want to get my newest articles in your inbox, then enter your email address below and click "Get Updates!"</p>
<!-- Begin MailChimp Signup Form -->
<link href="https://cdn-images.mailchimp.com/embedcode/classic-081711.css"
rel="stylesheet" type="text/css">
<style type="text/css">
#mc_embed_signup {
background: #f5f5f5;
clear: left;
font: 18px Helvetica,Arial,sans-serif;
}
#mc_embed_signup form {
text-align: center;
padding: 20px 0 10px 3%;
}
#mc_embed_signup .mc-field-group input {
display: inline;
width: 40%;
}
#mc_embed_signup div.response {
width: 100%;
}
</style>
<div id="mc_embed_signup">
<form
action="https://ruslanspivak.us4.list-manage.com/subscribe/post?u=7dde30eedc045f4670430c25f&amp;id=6f69f44e03"
method="post"
id="mc-embedded-subscribe-form"
name="mc-embedded-subscribe-form"
class="validate"
target="_blank" novalidate>
<div id="mc_embed_signup_scroll">
<div class="mc-field-group">
<label for="mce-NAME">Enter Your First Name *</label>
<input type="text" value="" name="NAME" class="required" id="mce-NAME">
</div>
<div class="mc-field-group">
<label for="mce-EMAIL">Enter Your Best Email *</label>
<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
</div>
<div id="mce-responses" class="clear">
<div class="response" id="mce-error-response" style="display:none"></div>
<div class="response" id="mce-success-response" style="display:none"></div>
</div>
<!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
<div style="position: absolute; left: -5000px;"><input type="text" name="b_7dde30eedc045f4670430c25f_6f69f44e03" tabindex="-1" value=""></div>
<div class="clear"><input type="submit" value="Get Updates!" name="subscribe" id="mc-embedded-subscribe" class="button" style="background-color: rgb(63, 146, 236);"></div>
</div>
</form>
</div>
<!-- <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[1]='NAME';ftypes[1]='text';fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script> -->
<!--End mc_embed_signup-->
</p>
<p><br/>
<strong>All articles in this series:</strong>
<ul>
<li>
<a href="lsbasi-part1/index.html">Let's Build A Simple Interpreter. Part 1.</a>
</li>
<li>
<a href="lsbasi-part2/index.html">Let's Build A Simple Interpreter. Part 2.</a>
</li>
<li>
<a href="lsbasi-part3/index.html">Let's Build A Simple Interpreter. Part 3.</a>
</li>
<li>
<a href="lsbasi-part4/index.html">Let's Build A Simple Interpreter. Part 4.</a>
</li>
<li>
<a href="lsbasi-part5/index.html">Let's Build A Simple Interpreter. Part 5.</a>
</li>
<li>
<a href="lsbasi-part6/index.html">Let's Build A Simple Interpreter. Part 6.</a>
</li>
<li>
<a href="lsbasi-part7/index.html">Let's Build A Simple Interpreter. Part 7: Abstract Syntax Trees</a>
</li>
<li>
<a href="lsbasi-part8/index.html">Let's Build A Simple Interpreter. Part 8.</a>
</li>
<li>
<a href="lsbasi-part9/index.html">Let's Build A Simple Interpreter. Part 9.</a>
</li>
<li>
<a href="lsbasi-part10/index.html">Let's Build A Simple Interpreter. Part 10.</a>
</li>
<li>
<a href="lsbasi-part11/index.html">Let's Build A Simple Interpreter. Part 11.</a>
</li>
<li>
<a href="lsbasi-part12/index.html">Let's Build A Simple Interpreter. Part 12.</a>
</li>
<li>
<a href="lsbasi-part13.html">Let's Build A Simple Interpreter. Part 13: Semantic Analysis</a>
</li>
<li>
<a href="lsbasi-part14/index.html">Let's Build A Simple Interpreter. Part 14: Nested Scopes and a Source-to-Source Compiler</a>
</li>
<li>
<a href="lsbasi-part15/index.html">Let's Build A Simple Interpreter. Part 15.</a>
</li>
<li>
<a href="lsbasi-part16/index.html">Let's Build A Simple Interpreter. Part 16: Recognizing Procedure Calls</a>
</li>
<li>
<a href="lsbasi-part17.html">Let's Build A Simple Interpreter. Part 17: Call Stack and Activation Records</a>
</li>
<li>
<a href="lsbasi-part18/index.html">Let's Build A Simple Interpreter. Part 18: Executing Procedure Calls</a>
</li>
<li>
<a href="lsbasi-part19/index.html">Let's Build A Simple Interpreter. Part 19: Nested Procedure Calls</a>
</li>
</ul>
</p>
<!-- <a class="btn btn-default btn-xs" href="https://ruslanspivak.com/lsbasi-part19/">more ...</a> -->
</div>
</article>
<hr/>
</div>
<div class="col-sm-3" id="sidebar">
<aside>
<section class="well well-sm">
<ul class="list-group list-group-flush">
<li class="list-group-item"><h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Social</span></h4>
<ul class="list-group" id="social">
<li class="list-group-item"><a href="https://github.com/rspivak/"><i class="fa fa-github-square fa-lg"></i> github</a></li>
<li class="list-group-item"><a href="https://twitter.com/rspivak"><i class="fa fa-twitter-square fa-lg"></i> twitter</a></li>
<li class="list-group-item"><a href="https://linkedin.com/in/ruslanspivak/"><i class="fa fa-linkedin-square fa-lg"></i> linkedin</a></li>
</ul>
</li>
<li class="list-group-item"><h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Popular posts</span></h4>
<ul class="list-group" id="popularposts">
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="lsbaws-part1/index.html">
Let's Build A Web Server. Part 1.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="lsbasi-part1/index.html">
Let's Build A Simple Interpreter. Part 1.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="lsbaws-part2/index.html">
Let's Build A Web Server. Part 2.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="lsbaws-part3/index.html">
Let's Build A Web Server. Part 3.
</a>
</li>
<li class="list-group-item"
style="font-size: 15px; word-break: normal;">
<a href="lsbasi-part2/index.html">
Let's Build A Simple Interpreter. Part 2.
</a>
</li>
</ul>
</li>
<li class="list-group-item">
<h4>
<span>Disclaimer</span>
</h4>
<p id="disclaimer-text"> Some of the links on this site
have my Amazon referral id, which provides me with a small
commission for each sale. Thank you for your support.
</p>
</li>
</ul>
</section>
</aside>
</div>
</div>
</div>
<footer>
<div class="container">
<hr>
<div class="row">
<div class="col-xs-10">&copy; 2020 Ruslan Spivak
<!-- &middot; Powered by <a href="https://github.com/DandyDev/pelican-bootstrap3" target="_blank">pelican-bootstrap3</a>, -->
<!-- <a href="http://docs.getpelican.com/" target="_blank">Pelican</a>, -->
<!-- <a href="http://getbootstrap.com" target="_blank">Bootstrap</a> -->
<!-- -->
</div>
<div class="col-xs-2"><p class="pull-right"><i class="fa fa-arrow-up"></i> <a href="index.html#">Back to top</a></p></div>
</div>
</div>
</footer>
<script src="theme/js/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="theme/js/bootstrap.min.js"></script>
<!-- Enable responsive features in IE8 with Respond.js (https://github.com/scottjehl/Respond) -->
<script src="theme/js/respond.min.js"></script>
<!-- Disqus -->
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'ruslanspivak'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function () {
var s = document.createElement('script');
s.async = true;
s.type = 'text/javascript';
s.src = '//' + disqus_shortname + '.disqus.com/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
</script>
<!-- End Disqus Code -->
<!-- Google Analytics Universal -->
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-2572871-3', 'auto');
ga('send', 'pageview');
</script>
<!-- End Google Analytics Universal Code -->
</body>
</html>