emacs.d/clones/ruslanspivak.com/lsbasi-part18/index.html

919 lines
70 KiB
HTML
Raw Normal View History

2022-10-07 19:32:11 +02:00
<!DOCTYPE html>
<html lang="en"
xmlns:og="http://ogp.me/ns#"
xmlns:fb="https://www.facebook.com/2008/fbml">
<head>
<title>Lets Build A Simple Interpreter. Part 18: Executing Procedure Calls - 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" />
<meta name="description" content="Do the best you can until you know better. Then when you know better, do better. ― Maya Angelou" />
<meta property="og:site_name" content="Ruslan's Blog" />
<meta property="og:type" content="article"/>
<meta property="og:title" content="Lets Build A Simple Interpreter. Part 18: Executing Procedure Calls"/>
<meta property="og:url" content="https://ruslanspivak.com/lsbasi-part18/"/>
<meta property="og:description" content="Do the best you can until you know better. Then when you know better, do better. ― Maya Angelou"/>
<meta property="article:published_time" content="2020-02-20" />
<meta property="article:section" content="blog" />
<meta property="article:author" content="Ruslan Spivak" />
<meta property="og:image"
content="https://ruslanspivak.com/lsbasi-part18/lsbasi_part18_milestones.png"/>
<meta name="twitter:card" content="summary">
<meta name="twitter:domain" content="https://ruslanspivak.com">
<meta property="twitter:image"
content="https://ruslanspivak.com/lsbasi-part18/lsbasi_part18_milestones.png"/>
<!-- 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">
<section id="content">
<article>
<header class="page-header">
<h1>
<a href="index.html"
rel="bookmark"
title="Permalink to Lets Build A Simple Interpreter. Part 18: Executing Procedure Calls">
Let&#8217;s Build A Simple Interpreter. Part 18: Executing Procedure&nbsp;Calls
</a>
</h1>
</header>
<div class="entry-content">
<div class="panel">
<div class="panel-body">
<footer class="post-info">
<span class="label label-default">Date</span>
<span class="published">
<i class="fa fa-calendar"></i><time datetime="2020-02-20T08:00:00-05:00"> Thu, February 20, 2020</time>
</span>
</footer><!-- /.post-info --> </div>
</div>
<blockquote>
<p><em><span class="dquo">&#8220;</span>Do the best you can until you know better. Then when you know better, do better.&#8221; ― Maya&nbsp;Angelou</em></p>
</blockquote>
<p>It&#8217;s a huge milestone for us today! Because today we will extend our interpreter to execute procedure calls. If that&#8217;s not exciting, I don&#8217;t know what is.&nbsp;:)</p>
<p><img alt="" src="lsbasi_part18_milestones.png" width="640"></p>
<p>Are you ready? Let&#8217;s get to&nbsp;it!</p>
<p><br/>
Here is the sample program we&#8217;ll focus on in this&nbsp;article:</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">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="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>It has one procedure declaration and one procedure call<em>.</em> We will limit our focus today to procedures that can access their parameters and local variables only. We will cover nested procedure calls and accessing non-local variables in the next two&nbsp;articles.</p>
<p><br/>
Let&#8217;s describe an algorithm that our interpreter needs to implement to be able to execute the <em>Alpha(3 + 5, 7)</em> procedure call in the program&nbsp;above.</p>
<p>Here is the algorithm for executing a procedure call, step by&nbsp;step:</p>
<ol>
<li>
<p>Create an activation&nbsp;record</p>
</li>
<li>
<p>Save procedure arguments (actual parameters) in the activation&nbsp;record</p>
</li>
<li>
<p>Push the activation record onto the call&nbsp;stack</p>
</li>
<li>
<p>Execute the body of the&nbsp;procedure</p>
</li>
<li>
<p>Pop the activation record off the&nbsp;stack</p>
</li>
</ol>
<p>Procedure calls in our interpreter are handled by the <em>visit_ProcedureCall</em> method. The method is currently&nbsp;empty:</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="k">pass</span>
</pre></div>
<p>Let&#8217;s go over each step in the algorithm and write code for the <em>visit_ProcedureCall</em> method to execute procedure&nbsp;calls.</p>
<p>Let&#8217;s get&nbsp;started!</p>
<p><br/>
<em>Step 1. Create an activation&nbsp;record</em></p>
<p>If you remember from the <a href="../lsbasi-part17.html">previous article</a>, an <em>activation record (<span class="caps">AR</span>)</em> is a dictionary-like object for maintaining information about the currently executing invocation of a procedure or function, and also the program itself. The activation record for a procedure, for example, contains the current values of its formal parameters and the current values of its local variables. So, to store the procedure&#8217;s arguments and local variables, we need to create an <span class="caps">AR</span> first. Recall that the <em>ActivationRecord</em> constructor takes 3 parameters: <em>name</em>, <em>type</em>, and <em>nesting_level</em>. And here&#8217;s what we need to pass to the constructor when creating an <span class="caps">AR</span> for a procedure&nbsp;call:</p>
<ul>
<li>
<p>We need to pass the procedure&#8217;s name as the <em>name</em> parameter to the&nbsp;constructor</p>
</li>
<li>
<p>We also need to specify <span class="caps">PROCEDURE</span> as the <em>type</em> of the <span class="caps">AR</span></p>
</li>
<li>
<p>And we need to pass 2 as the <em>nesting_level</em> for the procedure call because the program&#8217;s nesting level is set to 1 (You can see that in the <em>visit_Program</em> method of the&nbsp;interpreter)</p>
</li>
</ul>
<p>Before we extend the <em>visit_ProcedureCall</em> method to create an activation record for a procedure call, we need to add the <span class="caps">PROCEDURE</span> type to the <em>ARType</em> enumeration. Let&#8217;s do this&nbsp;first:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ARType</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">PROGRAM</span> <span class="o">=</span> <span class="s1">&#39;PROGRAM&#39;</span>
<span class="n">PROCEDURE</span> <span class="o">=</span> <span class="s1">&#39;PROCEDURE&#39;</span>
</pre></div>
<p>Now, let&#8217;s update the <em>visit_ProcedureCall</em> method to create an activation record with the appropriate arguments that we described earlier in the&nbsp;text:</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>
</pre></div>
<p>Writing code to create an activation record was easy once we figured out what to pass to the <em>ActivationRecord</em> constructor as&nbsp;arguments.</p>
<p><br/>
<em>Step 2. Save procedure arguments in the activation&nbsp;record</em></p>
<blockquote>
<p><span class="caps">ASIDE</span>: <em>Formal parameters</em> are parameters that show up in the declaration of a procedure. <em>Actual parameters</em> (also known as <em>arguments</em>) are different variables and expressions passed to the procedure in a particular procedure&nbsp;call.</p>
</blockquote>
<p>Here is a list of steps that describes the high-level actions the interpreter needs to take to save procedure arguments in the activation&nbsp;record:</p>
<ol type="a">
<li>Get a list of the procedure&#8217;s formal&nbsp;parameters</li>
<li>Get a list of the procedure&#8217;s actual parameters&nbsp;(arguments)</li>
<li>For each formal parameter, get the corresponding actual parameter and save the pair in the procedure&#8217;s activation record by using the formal parameter&#8217;s name as a key and the actual parameter (argument), after having evaluated it, as the&nbsp;value</li>
</ol>
<p>If we have the following procedure declaration and procedure&nbsp;call:</p>
<div class="highlight"><pre><span></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="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>
</pre></div>
<p>Then after the above three steps have been executed, the procedure&#8217;s <span class="caps">AR</span> contents should look like&nbsp;this:</p>
<div class="highlight"><pre><span></span><span class="mi">2</span><span class="o">:</span> <span class="n">PROCEDURE</span> <span class="n">Alpha</span>
<span class="n">a</span> <span class="o">:</span> <span class="mi">8</span>
<span class="n">b</span> <span class="o">:</span> <span class="mi">7</span>
</pre></div>
<p>Here is the code that implements the steps&nbsp;above:</p>
<div class="highlight"><pre><span></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">formal_params</span> <span class="o">=</span> <span class="n">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span>
<span class="k">for</span> <span class="n">param_symbol</span><span class="p">,</span> <span class="n">argument_node</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">formal_params</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">):</span>
<span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
</pre></div>
<p>Let&#8217;s take a closer look at the steps and the&nbsp;code.</p>
<p><br/>
a) First, we need to get a list of the procedure&#8217;s formal parameters. Where can we get them from? They are available in the respective procedure symbol created during the semantic analysis phase. To jog your memory, here is the definition of the <em>ProcedureSymbol</em>&nbsp;class:</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="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="nb">type</span>
<span class="k">class</span> <span class="nc">ProcedureSymbol</span><span class="p">(</span><span class="n">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="n">formal_params</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="c1"># a list of VarSymbol objects</span>
<span class="bp">self</span><span class="o">.</span><span class="n">formal_params</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">formal_params</span> <span class="ow">is</span> <span class="bp">None</span> <span class="k">else</span> <span class="n">formal_params</span>
</pre></div>
<p>And here&#8217;s the contents of the <em>global</em> scope (program level), which shows a string representation of the <em>Alpha</em> procedure symbol with its formal&nbsp;parameters:</p>
<div class="highlight"><pre><span></span><span class="gh">SCOPE (SCOPED SYMBOL TABLE)</span>
<span class="gh">===========================</span>
Scope name : global
Scope level : 1
Enclosing scope: None
<span class="gh">Scope (Scoped symbol table) contents</span>
<span class="gh">------------------------------------</span>
INTEGER: &lt;BuiltinTypeSymbol(name=&#39;INTEGER&#39;)&gt;
REAL: &lt;BuiltinTypeSymbol(name=&#39;REAL&#39;)&gt;
Alpha: &lt;ProcedureSymbol(name=Alpha, parameters=[<span class="nt">&lt;VarSymbol(name=&#39;a&#39;, type=&#39;INTEGER&#39;)&gt;</span>, &lt;VarSymbol(name=&#39;b&#39;, type=&#39;INTEGER&#39;)&gt;])&gt;
</pre></div>
<p>Okay, we now know where to get the formal parameters from. How do we get to the procedure symbol from the <em>ProcedureCall</em> <span class="caps">AST</span> <em>node</em> variable? Let&#8217;s take a look at the <em>visit_ProcedureCall</em> method code that we&#8217;ve written so&nbsp;far:</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>
</pre></div>
<p>We can get access to the procedure symbol by adding the following statement to the code&nbsp;above:</p>
<div class="highlight"><pre><span></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>
</pre></div>
<p>But if you look at the definition of the <em>ProcedureCall</em> class from the <a href="../lsbasi-part17.html">previous article</a>, you can see that the class doesn&#8217;t have <em>proc_symbol</em> as a&nbsp;member:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ProcedureCall</span><span class="p">(</span><span class="n">AST</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">proc_name</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">,</span> <span class="n">token</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proc_name</span> <span class="o">=</span> <span class="n">proc_name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">actual_params</span> <span class="o">=</span> <span class="n">actual_params</span> <span class="c1"># a list of AST nodes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">token</span> <span class="o">=</span> <span class="n">token</span>
</pre></div>
<p>Let&#8217;s fix that and extend the <em>ProcedureCall</em> class to have the <em>proc_symbol</em>&nbsp;field:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ProcedureCall</span><span class="p">(</span><span class="n">AST</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">proc_name</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">,</span> <span class="n">token</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proc_name</span> <span class="o">=</span> <span class="n">proc_name</span>
<span class="bp">self</span><span class="o">.</span><span class="n">actual_params</span> <span class="o">=</span> <span class="n">actual_params</span> <span class="c1"># a list of AST nodes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">token</span> <span class="o">=</span> <span class="n">token</span>
<span class="c1"># a reference to procedure declaration symbol</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proc_symbol</span> <span class="o">=</span> <span class="bp">None</span>
</pre></div>
<p>That was easy. Now, where should we set the <em>proc_symbol</em> so that it has the right value (a reference to the respective procedure symbol) for the interpretation phase? As I&#8217;ve mentioned earlier, the procedure symbol gets created during the semantic analysis phase. We can store it in the <em>ProcedureCall</em> <span class="caps">AST</span> node during the node traversal done by the semantic analyzer&#8217;s <em>visit_ProcedureCall</em>&nbsp;method.</p>
<p>Here is the original&nbsp;method:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">SemanticAnalyzer</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="k">for</span> <span class="n">param_node</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">param_node</span><span class="p">)</span>
</pre></div>
<p>Because we have access to the current scope when traversing the <span class="caps">AST</span> tree in the semantic analyzer, we can look up the procedure symbol by a procedure name and then store the procedure symbol in the <em>proc_symbol</em> variable of the <em>ProcedureCall</em> <span class="caps">AST</span> node. Let&#8217;s do&nbsp;this:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">SemanticAnalyzer</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="k">for</span> <span class="n">param_node</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">param_node</span><span class="p">)</span>
<span class="n">proc_symbol</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_scope</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">proc_name</span><span class="p">)</span>
<span class="c1"># accessed by the interpreter when executing procedure call</span>
<span class="n">node</span><span class="o">.</span><span class="n">proc_symbol</span> <span class="o">=</span> <span class="n">proc_symbol</span>
</pre></div>
<p>In the code above, we simply resolve a procedure name to its procedure symbol, which is stored in one of the scoped symbol tables (in our case in the <em>global</em> scope, to be exact), and then assign the procedure symbol to the <em>proc_symbol</em> field of the <em>ProcedureCall</em> <span class="caps">AST</span>&nbsp;node.</p>
<p>For our sample program, after the semantic analysis phase and the actions described above, the <span class="caps">AST</span> tree will have a link to the <em>Alpha</em> procedure symbol in the global&nbsp;scope:</p>
<p><img alt="" src="lsbasi_part18_astsymbollink.png" width="640"></p>
<p>As you can see in the picture above, this setup allows us to get the procedure&#8217;s formal parameters from the interpreter&#8217;s <em>visit_ProcedureCall</em> method - when evaluating a <em>ProcedureCall</em> node - by simply accessing the <em>formal_params</em> field of the <em>proc_symbol</em> variable stored in the <em>ProcedureCall</em> <span class="caps">AST</span>&nbsp;node:</p>
<div class="highlight"><pre><span></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">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span> <span class="c1"># aka parameters</span>
</pre></div>
<p><br/>
b) After we get the list of formal parameters, we need to get a list of the procedure&#8217;s actual parameters (arguments). Getting the list of arguments is easy because they are readily available from the <em>ProcedureCall</em> <span class="caps">AST</span> <em>node</em>&nbsp;itself:</p>
<div class="highlight"><pre><span></span><span class="n">node</span><span class="o">.</span><span class="n">actual_params</span> <span class="c1"># aka arguments</span>
</pre></div>
<p><br/>
c) And the last step. For each formal parameter, we need to get the corresponding actual parameter and save the pair in the procedure&#8217;s activation record by using the formal parameter&#8217;s name as the key and the actual parameter (argument), after having evaluated it, as the&nbsp;value</p>
<p>Let&#8217;s take a look at the code that does building of the key-value pairs using the Python <a href="https://docs.python.org/3/library/functions.html#zip">zip()</a>&nbsp;function:</p>
<div class="highlight"><pre><span></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">formal_params</span> <span class="o">=</span> <span class="n">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span>
<span class="k">for</span> <span class="n">param_symbol</span><span class="p">,</span> <span class="n">argument_node</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">formal_params</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">):</span>
<span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
</pre></div>
<p>Once you know how the Python <a href="https://docs.python.org/3/library/functions.html#zip">zip()</a> function works, the <em>for</em> loop above should be easy to understand. Here&#8217;s a Python shell demonstration of the <a href="https://docs.python.org/3/library/functions.html#zip">zip()</a> function in&nbsp;action:</p>
<div class="highlight"><pre><span></span>&gt;&gt;&gt; formal_params = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
&gt;&gt;&gt; actual_params = [1, 2, 3]
&gt;&gt;&gt;
&gt;&gt;&gt; zipped = zip(formal_params, actual_params)
&gt;&gt;&gt;
&gt;&gt;&gt; list(zipped)
[(&#39;a&#39;, 1), (&#39;b&#39;, 2), (&#39;c&#39;, 3)]
</pre></div>
<p>The statement to store the key-value pairs in the activation record is very&nbsp;straightforward:</p>
<div class="highlight"><pre><span></span><span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
</pre></div>
<p>The key is the name of a formal parameter, and the value is the evaluated value of the argument passed to the procedure&nbsp;call.</p>
<p>Here is the interpreter&#8217;s <em>visit_ProcedureCall</em> method with all the modifications we&#8217;ve done so&nbsp;far:</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">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="n">formal_params</span> <span class="o">=</span> <span class="n">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span>
<span class="k">for</span> <span class="n">param_symbol</span><span class="p">,</span> <span class="n">argument_node</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">formal_params</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">):</span>
<span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
</pre></div>
<p><br/>
<em>Step 3. Push the activation record onto the call&nbsp;stack</em></p>
<p>After we&#8217;ve created the <span class="caps">AR</span> and put all the procedure&#8217;s parameters into the <span class="caps">AR</span>, we need to push the <span class="caps">AR</span> onto the stack. It&#8217;s super easy to do. We need to add just one line of&nbsp;code:</p>
<div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">ar</span><span class="p">)</span>
</pre></div>
<p>Remember: an <span class="caps">AR</span> of a currently executing procedure is always at the top of the stack. This way the currently executing procedure has easy access to its parameters and local variables. Here is the updated <em>visit_ProcedureCall</em>&nbsp;method:</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="n">formal_params</span> <span class="o">=</span> <span class="n">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span>
<span class="k">for</span> <span class="n">param_symbol</span><span class="p">,</span> <span class="n">argument_node</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">formal_params</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">):</span>
<span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">ar</span><span class="p">)</span>
</pre></div>
<p><br/>
<em>Step 4. Execute the body of the&nbsp;procedure</em></p>
<p>Now that everything has been set up, let&#8217;s execute the body of the procedure. The only problem is that neither the <em>ProcedureCall</em> <span class="caps">AST</span> <em>node</em> nor the procedure symbol <em>proc_symbol</em> knows anything about the body of the respective procedure&nbsp;declaration.</p>
<p>How do we get access to the body of the procedure declaration during execution of a procedure call? In other words, when traversing the <span class="caps">AST</span> tree and visiting the <em>ProcedureCall</em> <span class="caps">AST</span> node during the interpretation phase, we need to get access to the <em>block_node</em> variable of the corresponding <em>ProcedureDecl</em> node. The <em>block_node</em> variable holds a reference to an <span class="caps">AST</span> sub-tree that represents the body of the procedure. How can we access that variable from the <em>visit_ProcedureCall</em> method of the <em>Interpreter</em> class? Let&#8217;s think about&nbsp;it.</p>
<p>We already have access to the procedure symbol that contains information about the procedure declaration, like the procedure&#8217;s formal parameters, so let&#8217;s find a way to store a reference to the <em>block_node</em> in the procedure symbol itself. The right spot to do that is the semantic analyzer&#8217;s <em>visit_ProcedureDecl</em> method. In this method we have access to both the procedure symbol and the procedure&#8217;s body, the <em>block_node</em> field of the <em>ProcedureDecl</em> <span class="caps">AST</span> node that points to the procedure body&#8217;s <span class="caps">AST</span>&nbsp;sub-tree.</p>
<p>We have a procedure symbol, and we have a <em>block_node</em>. Let&#8217;s store a pointer to the <em>block_node</em> in the <em>block_ast</em> field of the <em>proc_symbol</em>:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">SemanticAnalyzer</span><span class="p">(</span><span class="n">NodeVisitor</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">visit_ProcedureDecl</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">ProcedureSymbol</span><span class="p">(</span><span class="n">proc_name</span><span class="p">)</span>
<span class="o">...</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;LEAVE scope: {proc_name}&#39;</span><span class="p">)</span>
<span class="c1"># accessed by the interpreter when executing procedure call</span>
<span class="n">proc_symbol</span><span class="o">.</span><span class="n">block_ast</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">block_node</span>
</pre></div>
<p>And to make it explicit, let&#8217;s also extend the <em>ProcedureSymbol</em> class and add the <em>block_ast</em> field to&nbsp;it:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ProcedureSymbol</span><span class="p">(</span><span class="n">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="n">formal_params</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="o">...</span>
<span class="c1"># a reference to procedure&#39;s body (AST sub-tree)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">block_ast</span> <span class="o">=</span> <span class="bp">None</span>
</pre></div>
<p>In the picture below you can see the extended <em>ProcedureSymbol</em> instance that stores a reference to the corresponding procedure&#8217;s body (a <em>Block</em> node in the <span class="caps">AST</span>):</p>
<p><img alt="" src="lsbasi_part18_symbolastlink.png" width="640"></p>
<p>With all the above, executing the body of the procedure in the procedure call becomes as simple as visiting the procedure declaration&#8217;s <em>Block</em> <span class="caps">AST</span> node accessible through the <em>block_ast</em> field of the procedure&#8217;s <em>proc_symbol</em>:</p>
<div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">proc_symbol</span><span class="o">.</span><span class="n">block_ast</span><span class="p">)</span>
</pre></div>
<p><br/>
Here is the fully updated <em>visit_ProcedureCall</em> method of the <em>Interpreter</em>&nbsp;class:</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="n">formal_params</span> <span class="o">=</span> <span class="n">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span>
<span class="k">for</span> <span class="n">param_symbol</span><span class="p">,</span> <span class="n">argument_node</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">formal_params</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">):</span>
<span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">ar</span><span class="p">)</span>
<span class="c1"># evaluate procedure body</span>
<span class="bp">self</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">proc_symbol</span><span class="o">.</span><span class="n">block_ast</span><span class="p">)</span>
</pre></div>
<p>If you remember from the <a href="../lsbasi-part17.html">previous article</a>, the <em>visit_Assignment</em> and <em>visit_Var</em> methods use an <span class="caps">AR</span> at the top of the call stack to access and store&nbsp;variables:</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>These methods stay unchanged. When interpreting the body of a procedure, these methods will store and access values from the <span class="caps">AR</span> of the currently executing procedure, which will be at the top of the stack. We&#8217;ll see shortly how it all fits and works&nbsp;together.</p>
<p><br/>
<em>Step 5. Pop the activation record off the&nbsp;stack</em></p>
<p>After we&#8217;re done evaluating the body of the procedure, we no longer need the procedure&#8217;s <span class="caps">AR</span>, so we pop it off the call stack right before leaving the <em>visit_ProcedureCall</em> method. Remember, the top of the call stack contains an <span class="caps">AR</span> for a currently executing procedure, function, or program, so once we&#8217;re done evaluating one of those routines, we need to pop their respective <span class="caps">AR</span> off the call stack using the call stack&#8217;s <em>pop()</em>&nbsp;method:</p>
<div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
</pre></div>
<p>Let&#8217;s put it all together and also add some logging to the <em>visit_ProcedureCall</em> method to log the contents of the <em>call stack</em> right after pushing the procedure&#8217;s <span class="caps">AR</span> onto the <em>call stack</em> and right before popping it off the&nbsp;stack:</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="n">formal_params</span> <span class="o">=</span> <span class="n">proc_symbol</span><span class="o">.</span><span class="n">formal_params</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">actual_params</span>
<span class="k">for</span> <span class="n">param_symbol</span><span class="p">,</span> <span class="n">argument_node</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">formal_params</span><span class="p">,</span> <span class="n">actual_params</span><span class="p">):</span>
<span class="n">ar</span><span class="p">[</span><span class="n">param_symbol</span><span class="o">.</span><span class="n">name</span><span class="p">]</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">argument_node</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">ar</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;ENTER: PROCEDURE {proc_name}&#39;</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="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="p">))</span>
<span class="c1"># evaluate procedure body</span>
<span class="bp">self</span><span class="o">.</span><span class="n">visit</span><span class="p">(</span><span class="n">proc_symbol</span><span class="o">.</span><span class="n">block_ast</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;LEAVE: PROCEDURE {proc_name}&#39;</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="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">call_stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
</pre></div>
<p><br/>
Let&#8217;s take our modified interpreter for a ride and see how it executes procedure calls. Download the following sample program from <a href="https://github.com/rspivak/lsbasi/tree/master/part18">GitHub</a> or save it as <a href="https://github.com/rspivak/lsbasi/blob/master/part18/part18.pas">part18.pas</a>:</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">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="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>Download the interpreter file <a href="https://github.com/rspivak/lsbasi/blob/master/part18/spi.py">spi.py</a> from <a href="https://github.com/rspivak/lsbasi/tree/master/part18/">GitHub</a> and run it on the command line with the following&nbsp;arguments:</p>
<div class="highlight"><pre><span></span>$ python spi.py part18.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
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>So far, so good. Let&#8217;s take a closer look at the output and inspect the contents of the call stack during program and procedure&nbsp;execution.</p>
<p>1. The interpreter first&nbsp;prints</p>
<div class="highlight"><pre><span></span><span class="n">ENTER</span><span class="o">:</span> <span class="n">PROGRAM</span> <span class="n">Main</span>
<span class="n">CALL</span> <span class="n">STACK</span>
<span class="mi">1</span><span class="o">:</span> <span class="n">PROGRAM</span> <span class="n">Main</span>
</pre></div>
<p>when visiting the <em>Program</em> <span class="caps">AST</span> node before executing the body of the program. At this point the <em>call stack</em> has one <em>activation record.</em> This activation record is at the top of the call stack and it&#8217;s used for storing global variables. Because we don&#8217;t have any global variables in our sample program, there is nothing in the activation&nbsp;record.</p>
<p>2. Next, the interpreter&nbsp;prints</p>
<div class="highlight"><pre><span></span><span class="n">ENTER</span><span class="o">:</span> <span class="n">PROCEDURE</span> <span class="n">Alpha</span>
<span class="n">CALL</span> <span class="n">STACK</span>
<span class="mi">2</span><span class="o">:</span> <span class="n">PROCEDURE</span> <span class="n">Alpha</span>
<span class="n">a</span> <span class="o">:</span> <span class="mi">8</span>
<span class="n">b</span> <span class="o">:</span> <span class="mi">7</span>
<span class="mi">1</span><span class="o">:</span> <span class="n">PROGRAM</span> <span class="n">Main</span>
</pre></div>
<p>when it visits the <em>ProcedureCall</em> <span class="caps">AST</span> node for the <em>Alpha(3 + 5, 7)</em> procedure call. At this point the body of the <em>Alpha</em> procedure hasn&#8217;t been evaluated yet and the <em>call stack</em> has two activation records: one for the <em>Main</em> program at the bottom of the stack (nesting level 1) and one for the <em>Alpha</em> procedure call, at the top of the stack (nesting level 2). The <span class="caps">AR</span> at the top of the stack holds the values of the procedure arguments <em>a</em> and <em>b</em> only; there is no value for the local variable <em>x</em> in the <span class="caps">AR</span> because the body of the procedure hasn&#8217;t been evaluated&nbsp;yet.</p>
<p>3. Up next, the interpreter&nbsp;prints</p>
<div class="highlight"><pre><span></span><span class="n">LEAVE</span><span class="o">:</span> <span class="n">PROCEDURE</span> <span class="n">Alpha</span>
<span class="n">CALL</span> <span class="n">STACK</span>
<span class="mi">2</span><span class="o">:</span> <span class="n">PROCEDURE</span> <span class="n">Alpha</span>
<span class="n">a</span> <span class="o">:</span> <span class="mi">8</span>
<span class="n">b</span> <span class="o">:</span> <span class="mi">7</span>
<span class="n">x</span> <span class="o">:</span> <span class="mi">30</span>
<span class="mi">1</span><span class="o">:</span> <span class="n">PROGRAM</span> <span class="n">Main</span>
</pre></div>
<p>when it&#8217;s about to leave the <em>ProcedureCall</em> <span class="caps">AST</span> node for the <em>Alpha(3 + 5, 7)</em> procedure call but before popping off the <span class="caps">AR</span> for the <em>Alpha</em>&nbsp;procedure.</p>
<p>From the output above, you can see that in addition to the procedure arguments, the <span class="caps">AR</span> for the currently executing procedure <em>Alpha</em> now also contains the result of the assignment to the local variable <em>x</em>, the result of executing the <em>x := (a + b ) * 2;</em> statement in the body of the procedure. At this point the call stack visually looks like&nbsp;this:</p>
<p><img alt="" src="lsbasi_part18_callstack.png" width="260"></p>
<p>4. And finally the interpreter&nbsp;prints</p>
<div class="highlight"><pre><span></span><span class="n">LEAVE</span><span class="o">:</span> <span class="n">PROGRAM</span> <span class="n">Main</span>
<span class="n">CALL</span> <span class="n">STACK</span>
<span class="mi">1</span><span class="o">:</span> <span class="n">PROGRAM</span> <span class="n">Main</span>
</pre></div>
<p>when it leaves the <em>Program</em> <span class="caps">AST</span> node but before it pops off the <span class="caps">AR</span> for the main program. As you can see, the activation record for the main program is the only <span class="caps">AR</span> left in the stack because the <span class="caps">AR</span> for the <em>Alpha</em> procedure call got popped off the stack earlier, right before finishing executing the <em>Alpha</em> procedure&nbsp;call.</p>
<p><br/>
That&#8217;s it. Our interpreter successfully executed a procedure call. If you&#8217;ve reached this far,&nbsp;congratulations!</p>
<p><img alt="" src="lsbasi_part18_congrats.png" width="200"></p>
<p>It is a huge milestone for us. Now you know how to execute procedure calls. And if you&#8217;ve been waiting for this article for a long time, thank you for your&nbsp;patience.</p>
<p>That&#8217;s all for today. In the next article, we&#8217;ll expand on the current material and talk about executing nested procedure calls. So stay tuned and see you next&nbsp;time!</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="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>
</div>
<!-- /.entry-content -->
<hr/>
<section class="comments" id="comments">
<h2>Comments</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'ruslanspivak'; // required: replace example with your forum shortname
var disqus_identifier = 'lets-build-a-simple-interpreter-part-18-executing-procedure-calls';
var disqus_url = 'https://ruslanspivak.com/lsbasi-part18/';
var disqus_config = function () {
this.language = "en";
};
/* * * DON'T EDIT BELOW THIS LINE * * */
(function () {
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by
Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</section>
</article>
</section>
</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>