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

589 lines
No EOL
40 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 16: Recognizing 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="Learning is like rowing upstream: not to advance is to drop back. — Chinese proverb" />
<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 16: Recognizing Procedure Calls"/>
<meta property="og:url" content="https://ruslanspivak.com/lsbasi-part16/"/>
<meta property="og:description" content="Learning is like rowing upstream: not to advance is to drop back. — Chinese proverb"/>
<meta property="article:published_time" content="2019-07-23" />
<meta property="article:section" content="blog" />
<meta property="article:author" content="Ruslan Spivak" />
<meta property="og:image"
content="https://ruslanspivak.com/lsbasi-part16/lsbasi_part16_img01.png"/>
<meta name="twitter:card" content="summary">
<meta name="twitter:domain" content="https://ruslanspivak.com">
<meta property="twitter:image"
content="https://ruslanspivak.com/lsbasi-part16/lsbasi_part16_img01.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 16: Recognizing Procedure Calls">
Let&#8217;s Build A Simple Interpreter. Part 16: Recognizing 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="2019-07-23T08:20:00-04:00"> Tue, July 23, 2019</time>
</span>
</footer><!-- /.post-info --> </div>
</div>
<blockquote>
<p><em><span class="dquo">&#8220;</span>Learning is like rowing upstream: not to advance is to drop back.&#8221; — Chinese&nbsp;proverb</em></p>
</blockquote>
<p>Today were going to extend our interpreter to recognize procedure calls. I hope by now youve flexed your coding muscles and are ready to tackle this step. This is a necessary step for us before we can learn how to execute procedure calls, which will be a topic that we will cover in great detail in future&nbsp;articles.</p>
<p>The goal for today is to make sure that when our interpreter reads a program with a procedure call, the parser constructs an Abstract Syntax Tree (<span class="caps">AST</span>) with a new tree node for the procedure call, and the semantic analyzer and the interpreter dont throw any errors when walking the <span class="caps">AST</span>.</p>
<p>Lets take a look at a sample program that contains a procedure call <em>Alpha(3 + 5, 7)</em>:</p>
<p><img alt="" src="lsbasi_part16_img01.png" width="640"></p>
<p>Making our interpreter recognize programs like the one above will be our focus for&nbsp;today.</p>
<p>As with any new feature, we need to update various components of the interpreter to support this feature. Lets dive into each of those components one by&nbsp;one.</p>
<p><br/>
First, we need to update the parser. Here is a list of all the parser changes that we need to make to be able to parse procedure calls and build the right <span class="caps">AST</span>:</p>
<ol>
<li>We need to add a new <span class="caps">AST</span> node to represent a procedure&nbsp;call</li>
<li>We need to add a new grammar rule for procedure call statements; then we need to implement the rule in&nbsp;code</li>
<li>We need to extend the <em>statement</em> grammar rule to include the rule for procedure call statements and update the <em>statement</em> method to reflect the changes in the&nbsp;grammar</li>
</ol>
<p>1. Lets start by creating a separate class to represent a procedure call <span class="caps">AST</span> node. Lets call the class <em>ProcedureCall</em>:</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>The <em>ProcedureCall</em> class constructor takes three parameters: a procedure name, a list of actual parameters (a.k.a arguments), and a token. Nothing really special here, just enough information for us to capture a particular procedure&nbsp;call.</p>
<p>2. The next step that we need to take is to extend our grammar and add a grammar rule for procedure calls. Lets call the rule <em>proccall_statement</em>:</p>
<div class="highlight"><pre><span></span><span class="n">proccall_statement</span> <span class="o">:</span> <span class="n">ID</span> <span class="n">LPAREN</span> <span class="o">(</span><span class="n">expr</span> <span class="o">(</span><span class="n">COMMA</span> <span class="n">expr</span><span class="o">)*)?</span> <span class="n">RPAREN</span>
</pre></div>
<p>Here is a corresponding syntax diagram for the&nbsp;rule:</p>
<p><img alt="" src="lsbasi_part16_img02.png" width="640"></p>
<p>From the diagram above you can see that a procedure call is an <span class="caps">ID</span> token followed by a left parenthesis, followed by zero or more expressions separated by commas, followed by a right parenthesis. Here are some of the procedure call examples that fit the&nbsp;rule:</p>
<div class="highlight"><pre><span></span><span class="n">Alpha</span><span class="p">()</span><span class="o">;</span>
<span class="n">Alpha</span><span class="p">(</span><span class="mi">1</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>Next, lets implement the rule in our parser by adding a <em>proccall_statement</em>&nbsp;method</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">proccall_statement</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;proccall_statement : ID LPAREN (expr (COMMA expr)*)? RPAREN&quot;&quot;&quot;</span>
<span class="n">token</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span>
<span class="n">proc_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">value</span>
<span class="bp">self</span><span class="o">.</span><span class="n">eat</span><span class="p">(</span><span class="n">TokenType</span><span class="o">.</span><span class="n">ID</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">eat</span><span class="p">(</span><span class="n">TokenType</span><span class="o">.</span><span class="n">LPAREN</span><span class="p">)</span>
<span class="n">actual_params</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">!=</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">RPAREN</span><span class="p">:</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">expr</span><span class="p">()</span>
<span class="n">actual_params</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">COMMA</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">eat</span><span class="p">(</span><span class="n">TokenType</span><span class="o">.</span><span class="n">COMMA</span><span class="p">)</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">expr</span><span class="p">()</span>
<span class="n">actual_params</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">eat</span><span class="p">(</span><span class="n">TokenType</span><span class="o">.</span><span class="n">RPAREN</span><span class="p">)</span>
<span class="n">node</span> <span class="o">=</span> <span class="n">ProcedureCall</span><span class="p">(</span>
<span class="n">proc_name</span><span class="o">=</span><span class="n">proc_name</span><span class="p">,</span>
<span class="n">actual_params</span><span class="o">=</span><span class="n">actual_params</span><span class="p">,</span>
<span class="n">token</span><span class="o">=</span><span class="n">token</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">node</span>
</pre></div>
<p>The implementation is pretty straightforward and follows the grammar rule: the method parses a procedure call and returns a new <em>ProcedureCall</em> <span class="caps">AST</span>&nbsp;node.</p>
<p>3. And the last changes to the parser that we need to make are: extend the <em>statement</em> grammar rule by adding the <em>proccall_statement</em> rule and update the <em>statement</em> method to call the <em>proccall_statement</em>&nbsp;method.</p>
<p>Here is the updated <em>statement</em> grammar rule, which includes the <em>proccall_statement</em>&nbsp;rule:</p>
<div class="highlight"><pre><span></span><span class="n">statement</span> <span class="o">:</span> <span class="n">compound_statement</span>
<span class="o">|</span> <span class="n">proccall_statement</span>
<span class="o">|</span> <span class="n">assignment_statement</span>
<span class="o">|</span> <span class="n">empty</span>
</pre></div>
<p>Now, we have a tricky situation on hand where we have two grammar rules - <em>proccall_statement</em> and <em>assignment_statement</em> - that start with the same token, the <span class="caps">ID</span> token. Here are their complete grammar rules put together for&nbsp;comparison:</p>
<div class="highlight"><pre><span></span><span class="n">proccall_statement</span> <span class="o">:</span> <span class="n">ID</span> <span class="n">LPAREN</span> <span class="o">(</span><span class="n">expr</span> <span class="o">(</span><span class="n">COMMA</span> <span class="n">expr</span><span class="o">)*)?</span> <span class="n">RPAREN</span>
<span class="n">assignment_statement</span> <span class="o">:</span> <span class="n">variable</span> <span class="n">ASSIGN</span> <span class="n">expr</span>
<span class="n">variable</span><span class="o">:</span> <span class="n">ID</span>
</pre></div>
<p>How do you distinguish between a procedure call and an assignment in a case like that? They are both statements and they both start with an <span class="caps">ID</span> token. In the fragment of code below, the <span class="caps">ID</span> tokens value(lexeme) for both statements is <em>foo</em>:</p>
<div class="highlight"><pre><span></span><span class="n">foo</span><span class="p">()</span><span class="o">;</span> <span class="cm">{ procedure call }</span>
<span class="n">foo</span> <span class="o">:=</span> <span class="mi">5</span><span class="o">;</span> <span class="cm">{ assignment }</span>
</pre></div>
<p>The parser should recognize <em>foo();</em> above as a procedure call and <em>foo := 5;</em> as an assignment. But what can we do to help the parser to distinguish between procedure calls and assignments? According to our new <em>proccall_statement</em> grammar rule, procedure calls start with an <span class="caps">ID</span> token followed by a left parenthesis. And thats what we are going to rely on in the parser to distinguish between procedure calls and assignments to variables - the presence of a left parenthesis after the <span class="caps">ID</span>&nbsp;token:</p>
<div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">ID</span> <span class="ow">and</span>
<span class="bp">self</span><span class="o">.</span><span class="n">lexer</span><span class="o">.</span><span class="n">current_char</span> <span class="o">==</span> <span class="s1">&#39;(&#39;</span>
<span class="p">):</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">proccall_statement</span><span class="p">()</span>
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">ID</span><span class="p">:</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">assignment_statement</span><span class="p">()</span>
</pre></div>
<p>As you can see in the code above, first we check if the current token is an <span class="caps">ID</span> token and then we check if its followed by a left parenthesis. If it is, we parse a procedure call, otherwise we parse an assignment&nbsp;statement.</p>
<p>Here is the full updated version of the <em>statement</em>&nbsp;method:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">statement</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> statement : compound_statement</span>
<span class="sd"> | proccall_statement</span>
<span class="sd"> | assignment_statement</span>
<span class="sd"> | empty</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">BEGIN</span><span class="p">:</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">compound_statement</span><span class="p">()</span>
<span class="k">elif</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">ID</span> <span class="ow">and</span>
<span class="bp">self</span><span class="o">.</span><span class="n">lexer</span><span class="o">.</span><span class="n">current_char</span> <span class="o">==</span> <span class="s1">&#39;(&#39;</span>
<span class="p">):</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">proccall_statement</span><span class="p">()</span>
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">current_token</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">TokenType</span><span class="o">.</span><span class="n">ID</span><span class="p">:</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">assignment_statement</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">empty</span><span class="p">()</span>
<span class="k">return</span> <span class="n">node</span>
</pre></div>
<p><br/>
So far so good. The parser can now parse procedure calls. One thing to keep in mind though is that Pascal procedures dont have return statements, so we cant use procedure calls in expressions. For example, the following example will not work if <em>Alpha</em> is a&nbsp;procedure:</p>
<div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">:=</span> <span class="mi">10</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>Thats why we added <em>proccall_statement</em> to the <em>statements</em> method only and nowhere else. Not to worry, later in the series well learn about Pascal functions that can return values and also can be used in expressions and&nbsp;assignments.</p>
<p>These are all the changes for our parser. Next up is the semantic analyzer&nbsp;changes.</p>
<p><br/>
The only change we need to make in our semantic analyzer to support procedure calls is to add a <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="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>All the method does is iterate over a list of actual parameters passed to a procedure call and visit each parameter node in turn. Its important not to forget to visit each parameter node because each parameter node is an <span class="caps">AST</span> sub-tree in&nbsp;itself.</p>
<p>That was easy, wasnt it? Okay, now moving on to interpreter&nbsp;changes.</p>
<p><br/>
The interpreter changes, compared to the changes to the semantic analyzer, are even simpler - we only need to add an empty <em>visit_ProcedureCall</em> method to 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="k">pass</span>
</pre></div>
<p>With all the above changes in place, we now have an interpreter that can recognize procedure calls. And by that I mean the interpreter can parse procedure calls and create an <span class="caps">AST</span> with <em>ProcedureCall</em> nodes corresponding to those procedure calls. Here is the sample Pascal program we saw at the beginning of the article that we want our interpreter to be tested&nbsp;on:</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 above program from <a href="https://github.com/rspivak/lsbasi/tree/master/part16">GitHub</a> or save the code to the file&nbsp;part16.pas</p>
<p>See for yourself that running our <a href="https://github.com/rspivak/lsbasi/tree/master/part16">updated interpreter</a> with the part16.pas as its input file does not generate any&nbsp;errors:</p>
<div class="highlight"><pre><span></span>$ python spi.py part16.pas
$
</pre></div>
<p>So far so good, but no output is not that exciting. :) Lets get a bit visual and generate an <span class="caps">AST</span> for the above program and then visualize the <span class="caps">AST</span> using an updated version of the <a href="https://github.com/rspivak/lsbasi/tree/master/part16/genastdot.py">genastdot.py</a>&nbsp;utility:</p>
<div class="highlight"><pre><span></span>$ python genastdot.py part16.pas &gt; ast.dot <span class="o">&amp;&amp;</span> dot -Tpng -o ast.png ast.dot
</pre></div>
<p><img alt="" src="lsbasi_part16_img03.png" width="640"></p>
<p>Thats better. In the picture above you can see our new <em>ProcCall</em> <span class="caps">AST</span> node labeled <em>ProcCall:Alpha</em> for the <em>Alpha(3 + 5, 7)</em> procedure call. The two children of the <em>ProcCall:Alpha</em> node are the subtrees for the arguments <em>3 + 5</em> and <em>7</em> passed to the <em>Alpha(3 + 5, 7)</em> procedure&nbsp;call.</p>
<p>Okay, we have accomplished our goal for today: when encountering a procedure call, the parser constructs an <span class="caps">AST</span> with a <em>ProcCall</em> node for the procedure call, and the semantic analyzer and the interpreter dont throw any errors when walking the <span class="caps">AST</span>.</p>
<p><br/>
Now, its time for an&nbsp;exercise.</p>
<p><img alt="" src="lsbasi_part16_img04.png" width="180"></p>
<p>Exercise: Add a check to the semantic analyzer that verifies that the number of arguments (actual parameters) passed to a procedure call equals the number of formal parameters defined in the corresponding procedure declaration. Lets take the <em>Alpha</em> procedure declaration we used earlier in the article as an&nbsp;example:</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="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>
</pre></div>
<p>The number of formal parameters in the procedure declaration above is two (integers <em>a</em> and <em>b</em>). Your check should throw an error if you try to call the procedure with a number of arguments other than&nbsp;two:</p>
<div class="highlight"><pre><span></span><span class="n">Alpha</span><span class="p">()</span><span class="o">;</span> <span class="cm">{ 0 arguments —&gt; ERROR }</span>
<span class="n">Alpha</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">;</span> <span class="cm">{ 1 argument —&gt; ERROR }</span>
<span class="n">Alpha</span><span class="p">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="p">)</span><span class="o">;</span> <span class="cm">{ 3 arguments —&gt; ERROR }</span>
</pre></div>
<p>You can find a solution to the exercise in the file <em>solutions.txt</em> on <a href="https://github.com/rspivak/lsbasi/tree/master/part16">GitHub</a>, but try to work out your own solution first before peeking into the&nbsp;file.</p>
<p><br/>
Thats all for today. In the next article well begin to learn how to interpret procedure calls. We will cover topics like call stack and activation records. It is going to be a wild ride :) So stay tuned and see you next&nbsp;time!</p>
<p><br/>
<em>Resources used in preparation for this article (some 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.freepascal.org/docs-html/current/ref/ref.html">Free Pascal Reference&nbsp;guide</a></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="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>
</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-16-recognizing-procedure-calls';
var disqus_url = 'https://ruslanspivak.com/lsbasi-part16/';
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>