600 lines
34 KiB
HTML
600 lines
34 KiB
HTML
|
<!DOCTYPE html>
|
|||
|
<html lang="en"
|
|||
|
xmlns:og="http://ogp.me/ns#"
|
|||
|
xmlns:fb="https://www.facebook.com/2008/fbml">
|
|||
|
<head>
|
|||
|
<title>Let’s Build A Simple Interpreter. Part 12. - 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="“Be not afraid of going slowly; be afraid only of standing still.” - Chinese proverb. Hello, and welcome back! Today we are going to take a few more baby steps and learn how to parse Pascal procedure declarations. What is a procedure declaration? A procedure declaration is a language construct that …" />
|
|||
|
|
|||
|
<meta property="og:site_name" content="Ruslan's Blog" />
|
|||
|
<meta property="og:type" content="article"/>
|
|||
|
<meta property="og:title" content="Let’s Build A Simple Interpreter. Part 12."/>
|
|||
|
<meta property="og:url" content="https://ruslanspivak.com/lsbasi-part12/"/>
|
|||
|
<meta property="og:description" content="“Be not afraid of going slowly; be afraid only of standing still.” - Chinese proverb. Hello, and welcome back! Today we are going to take a few more baby steps and learn how to parse Pascal procedure declarations. What is a procedure declaration? A procedure declaration is a language construct that …"/>
|
|||
|
<meta property="article:published_time" content="2016-12-01" />
|
|||
|
<meta property="article:section" content="blog" />
|
|||
|
<meta property="article:author" content="Ruslan Spivak" />
|
|||
|
|
|||
|
<meta name="twitter:card" content="summary">
|
|||
|
<meta name="twitter:domain" content="https://ruslanspivak.com">
|
|||
|
|
|||
|
<!-- Bootstrap -->
|
|||
|
<link rel="stylesheet" href="../theme/css/bootstrap.min.css" type="text/css"/>
|
|||
|
<link href="../theme/css/font-awesome.min.css" rel="stylesheet">
|
|||
|
|
|||
|
<link href="../theme/css/pygments/tango.css" rel="stylesheet">
|
|||
|
<link href="../theme/css/typogrify.css" rel="stylesheet">
|
|||
|
<link rel="stylesheet" href="../theme/css/style.css" type="text/css"/>
|
|||
|
<link href="../static/custom.css" rel="stylesheet">
|
|||
|
|
|||
|
<link href="../feeds/all.atom.xml" type="application/atom+xml" rel="alternate"
|
|||
|
title="Ruslan's Blog ATOM Feed"/>
|
|||
|
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
|
|||
|
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
|
|||
|
<div class="container">
|
|||
|
<div class="navbar-header">
|
|||
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
|
|||
|
<span class="sr-only">Toggle navigation</span>
|
|||
|
<span class="icon-bar"></span>
|
|||
|
<span class="icon-bar"></span>
|
|||
|
<span class="icon-bar"></span>
|
|||
|
</button>
|
|||
|
<a href="../index.html" class="navbar-brand">
|
|||
|
Ruslan's Blog </a>
|
|||
|
</div>
|
|||
|
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
|||
|
<ul class="nav navbar-nav">
|
|||
|
</ul>
|
|||
|
<ul class="nav navbar-nav navbar-right">
|
|||
|
<li><a href="../pages/about.html"><i class="fa fa-question"></i><span class="icon-label">About</span></a></li>
|
|||
|
<li><a href="../archives.html"><i class="fa fa-th-list"></i><span class="icon-label">Archives</span></a></li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
<!-- /.navbar-collapse -->
|
|||
|
</div>
|
|||
|
</div> <!-- /.navbar -->
|
|||
|
<!-- Banner -->
|
|||
|
<!-- End Banner -->
|
|||
|
<div class="container">
|
|||
|
<div class="row">
|
|||
|
<div class="col-sm-9">
|
|||
|
|
|||
|
<section id="content">
|
|||
|
<article>
|
|||
|
<header class="page-header">
|
|||
|
<h1>
|
|||
|
<a href="index.html"
|
|||
|
rel="bookmark"
|
|||
|
title="Permalink to Let’s Build A Simple Interpreter. Part 12.">
|
|||
|
Let’s Build A Simple Interpreter. Part 12.
|
|||
|
</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="2016-12-01T16:20:00-05:00"> Thu, December 01, 2016</time>
|
|||
|
</span>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</footer><!-- /.post-info --> </div>
|
|||
|
</div>
|
|||
|
<blockquote>
|
|||
|
<p><em><span class="dquo">“</span>Be not afraid of going slowly; be afraid only of standing still.” - Chinese proverb.</em></p>
|
|||
|
</blockquote>
|
|||
|
<p>Hello, and welcome back!</p>
|
|||
|
<p>Today we are going to take a few more baby steps and learn how to parse Pascal procedure declarations.</p>
|
|||
|
<p><img alt="" src="lsbasi_part12_babysteps.png" width="700"></p>
|
|||
|
<p>What is a <em><strong>procedure declaration</strong></em>? A <em><strong>procedure declaration</strong></em> is a language construct that defines an identifier (a procedure name) and associates it with a block of Pascal code.</p>
|
|||
|
<p>Before we dive in, a few words about Pascal procedures and their declarations:</p>
|
|||
|
<ul>
|
|||
|
<li>Pascal procedures don’t have return statements. They exit when they reach the end of their corresponding block.</li>
|
|||
|
<li>Pascal procedures can be nested within each other.</li>
|
|||
|
<li>For simplicity reasons, procedure declarations in this article won’t have any formal parameters. But, don’t worry, we’ll cover that later in the series.</li>
|
|||
|
</ul>
|
|||
|
<p>This is our test program for today:</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="k">PROGRAM</span> <span class="n">Part12</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
|
|||
|
<span class="k">PROCEDURE</span> <span class="nf">P1</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span> <span class="o">:</span> <span class="kt">REAL</span><span class="o">;</span>
|
|||
|
<span class="n">k</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
|
|||
|
<span class="k">PROCEDURE</span> <span class="nf">P2</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span><span class="o">,</span> <span class="n">z</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{P2}</span>
|
|||
|
<span class="n">z</span> <span class="o">:=</span> <span class="mi">777</span><span class="o">;</span>
|
|||
|
<span class="k">END</span><span class="o">;</span> <span class="cm">{P2}</span>
|
|||
|
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{P1}</span>
|
|||
|
|
|||
|
<span class="k">END</span><span class="o">;</span> <span class="cm">{P1}</span>
|
|||
|
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{Part12}</span>
|
|||
|
<span class="n">a</span> <span class="o">:=</span> <span class="mi">10</span><span class="o">;</span>
|
|||
|
<span class="k">END</span><span class="o">.</span> <span class="cm">{Part12}</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p>As you can see above, we have defined two procedures (<em>P1</em> and <em>P2</em>) and <em>P2</em> is nested within <em>P1</em>.
|
|||
|
In the code above, I used comments with a procedure’s name to clearly indicate where the body of every procedure begins and where it ends.</p>
|
|||
|
<p>Our objective for today is pretty clear: learn how to parse a code like that.</p>
|
|||
|
<p><br/></p>
|
|||
|
<p>First, we need to make some changes to our grammar to add procedure declarations. Well, let’s just do that!</p>
|
|||
|
<p>Here is the updated <em>declarations</em> grammar rule:</p>
|
|||
|
<p><img alt="" src="lsbasi_part12_grammar.png" width="640"></p>
|
|||
|
<p>The procedure declaration sub-rule consists of the reserved keyword <strong><span class="caps">PROCEDURE</span></strong> followed by an identifier (a procedure name),
|
|||
|
followed by a semicolon, which in turn is followed by a <em>block</em> rule, which is terminated by a semicolon.
|
|||
|
Whoa! This is a case where I think the picture is actually worth however many words I just put in the previous sentence! :)</p>
|
|||
|
<p>Here is the updated syntax diagram for the <em>declarations</em> rule:</p>
|
|||
|
<p><img alt="" src="lsbasi_part12_syntaxdiagram.png" width="640"></p>
|
|||
|
<p>From the grammar and the diagram above you can see that you can have as many procedure declarations on the same level as you want.
|
|||
|
For example, in the code snippet below we define two procedure declarations, <em>P1</em> and <em><span class="caps">P1A</span></em>, on the same level:</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="k">PROGRAM</span> <span class="n">Test</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
|
|||
|
<span class="k">PROCEDURE</span> <span class="nf">P1</span><span class="o">;</span>
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{P1}</span>
|
|||
|
|
|||
|
<span class="k">END</span><span class="o">;</span> <span class="cm">{P1}</span>
|
|||
|
|
|||
|
<span class="k">PROCEDURE</span> <span class="nf">P1A</span><span class="o">;</span>
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{P1A}</span>
|
|||
|
|
|||
|
<span class="k">END</span><span class="o">;</span> <span class="cm">{P1A}</span>
|
|||
|
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{Test}</span>
|
|||
|
<span class="n">a</span> <span class="o">:=</span> <span class="mi">10</span><span class="o">;</span>
|
|||
|
<span class="k">END</span><span class="o">.</span> <span class="cm">{Test}</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p>The diagram and the grammar rule above also indicate that procedure declarations can be nested because the
|
|||
|
<em>procedure declaration</em> sub-rule references the <em>block</em> rule which contains the <em>declarations</em> rule, which in turn
|
|||
|
contains the <em>procedure declaration</em> sub-rule. As a reminder, here is the syntax diagram and the grammar
|
|||
|
for the block rule from <a href="../lsbasi-part10/index.html">Part10</a>:</p>
|
|||
|
<p><img alt="" src="lsbasi_part12_block_rule_from_part10.png" width="800"></p>
|
|||
|
<p><br/>
|
|||
|
Okay, now let’s focus on the interpreter components that need to be updated to support procedure declarations:</p>
|
|||
|
<p><em><strong>Updating the Lexer</strong></em></p>
|
|||
|
<p>All we need to do is add a new token named <strong><span class="caps">PROCEDURE</span></strong>:</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="n">PROCEDURE</span> <span class="o">=</span> <span class="s1">'PROCEDURE'</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p>And add <em>‘<span class="caps">PROCEDURE</span>’</em> to the reserved keywords. Here is the complete mapping of reserved keywords to tokens:</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="n">RESERVED_KEYWORDS</span> <span class="o">=</span> <span class="p">{</span>
|
|||
|
<span class="s1">'PROGRAM'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'PROGRAM'</span><span class="p">,</span> <span class="s1">'PROGRAM'</span><span class="p">),</span>
|
|||
|
<span class="s1">'VAR'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'VAR'</span><span class="p">,</span> <span class="s1">'VAR'</span><span class="p">),</span>
|
|||
|
<span class="s1">'DIV'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'INTEGER_DIV'</span><span class="p">,</span> <span class="s1">'DIV'</span><span class="p">),</span>
|
|||
|
<span class="s1">'INTEGER'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'INTEGER'</span><span class="p">,</span> <span class="s1">'INTEGER'</span><span class="p">),</span>
|
|||
|
<span class="s1">'REAL'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'REAL'</span><span class="p">,</span> <span class="s1">'REAL'</span><span class="p">),</span>
|
|||
|
<span class="s1">'BEGIN'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'BEGIN'</span><span class="p">,</span> <span class="s1">'BEGIN'</span><span class="p">),</span>
|
|||
|
<span class="s1">'END'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'END'</span><span class="p">,</span> <span class="s1">'END'</span><span class="p">),</span>
|
|||
|
<span class="s1">'PROCEDURE'</span><span class="p">:</span> <span class="n">Token</span><span class="p">(</span><span class="s1">'PROCEDURE'</span><span class="p">,</span> <span class="s1">'PROCEDURE'</span><span class="p">),</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p><br/>
|
|||
|
<em><strong>Updating the Parser</strong></em></p>
|
|||
|
<p>Here is a summary of the parser changes:</p>
|
|||
|
<ol>
|
|||
|
<li>New <em>ProcedureDecl</em> <span class="caps">AST</span> node</li>
|
|||
|
<li>Update to the parser’s <em>declarations</em> method to support procedure declarations</li>
|
|||
|
</ol>
|
|||
|
<p>Let’s go over the changes.</p>
|
|||
|
<ol>
|
|||
|
<li>
|
|||
|
<p>The <em>ProcedureDecl</em> <span class="caps">AST</span> node represents a <em>procedure declaration</em>. The class constructor takes as parameters the name of the procedure and the <span class="caps">AST</span> node of the block of code that the procedure’s name refers to.</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ProcedureDecl</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">block_node</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">block_node</span> <span class="o">=</span> <span class="n">block_node</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<p>Here is the updated <em>declarations</em> method of the <em>Parser</em> class</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">declarations</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
|||
|
<span class="sd">"""declarations : VAR (variable_declaration SEMI)+</span>
|
|||
|
<span class="sd"> | (PROCEDURE ID SEMI block SEMI)*</span>
|
|||
|
<span class="sd"> | empty</span>
|
|||
|
<span class="sd"> """</span>
|
|||
|
<span class="n">declarations</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">VAR</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">VAR</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">ID</span><span class="p">:</span>
|
|||
|
<span class="n">var_decl</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">variable_declaration</span><span class="p">()</span>
|
|||
|
<span class="n">declarations</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">var_decl</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">SEMI</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">PROCEDURE</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">PROCEDURE</span><span class="p">)</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">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">SEMI</span><span class="p">)</span>
|
|||
|
<span class="n">block_node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">block</span><span class="p">()</span>
|
|||
|
<span class="n">proc_decl</span> <span class="o">=</span> <span class="n">ProcedureDecl</span><span class="p">(</span><span class="n">proc_name</span><span class="p">,</span> <span class="n">block_node</span><span class="p">)</span>
|
|||
|
<span class="n">declarations</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">proc_decl</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">SEMI</span><span class="p">)</span>
|
|||
|
|
|||
|
<span class="k">return</span> <span class="n">declarations</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p>Hopefully, the code above is pretty self-explanatory. It follows the grammar/syntax diagram for procedure declarations that you’ve seen earlier in the article.</p>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
<p><br/>
|
|||
|
<em><strong>Updating the SymbolTable builder</strong></em></p>
|
|||
|
<p>Because we’re not ready yet to handle nested procedure scopes, we’ll simply add an empty <em>visit_ProcedureDecl</em> method to the <em>SymbolTreeBuilder</em> <span class="caps">AST</span> visitor class. We’ll fill it out in the next article.</p>
|
|||
|
<div class="highlight"><pre><span></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="k">pass</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p></br>
|
|||
|
<em><strong>Updating the Interpreter</strong></em></p>
|
|||
|
<p>We also need to add an empty <em>visit_ProcedureDecl</em> method to the <em>Interpreter</em> class, which will cause our interpreter to silently ignore all our procedure declarations.</p>
|
|||
|
<p>So far, so good.</p>
|
|||
|
<p></br>
|
|||
|
Now that we’ve made all the necessary changes, let’s see what the <em>Abstract Syntax Tree</em> looks like with the new <em>ProcedureDecl</em> nodes.</p>
|
|||
|
<p>Here is our Pascal program again (you can download it directly from <a href="https://github.com/rspivak/lsbasi/blob/master/part12/python/part12.pas">GitHub</a>):</p>
|
|||
|
<div class="highlight"><pre><span></span><span class="k">PROGRAM</span> <span class="n">Part12</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
|
|||
|
<span class="k">PROCEDURE</span> <span class="nf">P1</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span> <span class="o">:</span> <span class="kt">REAL</span><span class="o">;</span>
|
|||
|
<span class="n">k</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
|
|||
|
<span class="k">PROCEDURE</span> <span class="nf">P2</span><span class="o">;</span>
|
|||
|
<span class="k">VAR</span>
|
|||
|
<span class="n">a</span><span class="o">,</span> <span class="n">z</span> <span class="o">:</span> <span class="kt">INTEGER</span><span class="o">;</span>
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{P2}</span>
|
|||
|
<span class="n">z</span> <span class="o">:=</span> <span class="mi">777</span><span class="o">;</span>
|
|||
|
<span class="k">END</span><span class="o">;</span> <span class="cm">{P2}</span>
|
|||
|
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{P1}</span>
|
|||
|
|
|||
|
<span class="k">END</span><span class="o">;</span> <span class="cm">{P1}</span>
|
|||
|
|
|||
|
<span class="k">BEGIN</span> <span class="cm">{Part12}</span>
|
|||
|
<span class="n">a</span> <span class="o">:=</span> <span class="mi">10</span><span class="o">;</span>
|
|||
|
<span class="k">END</span><span class="o">.</span> <span class="cm">{Part12}</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p><br/>
|
|||
|
Let’s generate an <span class="caps">AST</span> and visualize it with the <a href="https://github.com/rspivak/lsbasi/blob/master/part12/python/genastdot.py">genastdot.py</a> utility:</p>
|
|||
|
<div class="highlight"><pre><span></span>$ python genastdot.py part12.pas > ast.dot <span class="o">&&</span> dot -Tpng -o ast.png ast.dot
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p><img alt="" src="lsbasi_part12_procdecl_ast.png"></p>
|
|||
|
<p>In the picture above you can see two <em>ProcedureDecl</em> nodes: <em>ProcDecl:P1</em> and <em>ProcDecl:P2</em> that
|
|||
|
correspond to procedures <em>P1</em> and <em>P2</em>. Mission accomplished. :)</p>
|
|||
|
<p>As a last item for today, let’s quickly check that our updated interpreter works as before when
|
|||
|
a Pascal program has procedure declarations in it. Download <a href="https://github.com/rspivak/lsbasi/blob/master/part12/python/spi.py">the interpreter</a>
|
|||
|
and <a href="https://github.com/rspivak/lsbasi/blob/master/part12/python/part12.pas">the test program</a> if you haven’t done so yet, and run it on the command line.
|
|||
|
Your output should look similar to this:</p>
|
|||
|
<div class="highlight"><pre><span></span>$ python spi.py part12.pas
|
|||
|
Define: INTEGER
|
|||
|
Define: REAL
|
|||
|
Lookup: INTEGER
|
|||
|
Define: <a:INTEGER>
|
|||
|
Lookup: a
|
|||
|
|
|||
|
Symbol Table contents:
|
|||
|
Symbols: <span class="o">[</span>INTEGER, REAL, <a:INTEGER><span class="o">]</span>
|
|||
|
|
|||
|
Run-time GLOBAL_MEMORY contents:
|
|||
|
<span class="nv">a</span> <span class="o">=</span> <span class="m">10</span>
|
|||
|
</pre></div>
|
|||
|
|
|||
|
|
|||
|
<p></br>
|
|||
|
Okay, with all that knowledge and experience under our belt, we’re ready to tackle the topic of nested scopes
|
|||
|
that we need to understand in order to be able to analyze nested procedures and prepare ourselves to
|
|||
|
handle procedure and function calls. And that’s exactly what we are going to do in the next article:
|
|||
|
dive deep into nested scopes. So don’t forget to bring your swimming gear next time! Stay tuned and see you soon!</p>
|
|||
|
<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&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="index.html">Let's Build A Simple Interpreter. Part 12.</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part13.html">Let's Build A Simple Interpreter. Part 13: Semantic Analysis</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part14/index.html">Let's Build A Simple Interpreter. Part 14: Nested Scopes and a Source-to-Source Compiler</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part15/index.html">Let's Build A Simple Interpreter. Part 15.</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part16/index.html">Let's Build A Simple Interpreter. Part 16: Recognizing Procedure Calls</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part17.html">Let's Build A Simple Interpreter. Part 17: Call Stack and Activation Records</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part18/index.html">Let's Build A Simple Interpreter. Part 18: Executing Procedure Calls</a>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<a href="../lsbasi-part19/index.html">Let's Build A Simple Interpreter. Part 19: Nested Procedure Calls</a>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</p>
|
|||
|
</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-12';
|
|||
|
var disqus_url = 'https://ruslanspivak.com/lsbasi-part12/';
|
|||
|
|
|||
|
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">© 2020 Ruslan Spivak
|
|||
|
<!-- · 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>
|