mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
2589 lines
207 KiB
HTML
2589 lines
207 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="generator" content="pandoc" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
||
<title>GTK 4 tutorial</title>
|
||
<style>
|
||
code{white-space: pre-wrap;}
|
||
span.smallcaps{font-variant: small-caps;}
|
||
span.underline{text-decoration: underline;}
|
||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||
ul.task-list{list-style: none;}
|
||
pre{overflow: visible;}
|
||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||
div.sourceCode { margin: 1em 0; }
|
||
pre.sourceCode { margin: 0; }
|
||
@media screen {
|
||
div.sourceCode { overflow: auto; }
|
||
}
|
||
@media print {
|
||
pre > code.sourceCode { white-space: pre-wrap; }
|
||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||
}
|
||
pre.numberSource code
|
||
{ counter-reset: source-line 0; }
|
||
pre.numberSource code > span
|
||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||
pre.numberSource code > span > a:first-child::after
|
||
{ content: counter(source-line);
|
||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||
border: none; display: inline-block;
|
||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||
-khtml-user-select: none; -moz-user-select: none;
|
||
-ms-user-select: none; user-select: none;
|
||
padding: 0 4px; width: 4em;
|
||
color: #aaaaaa;
|
||
}
|
||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||
div.sourceCode
|
||
{ }
|
||
@media screen {
|
||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||
}
|
||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||
code span.at { color: #7d9029; } /* Attribute */
|
||
code span.bn { color: #40a070; } /* BaseN */
|
||
code span.bu { } /* BuiltIn */
|
||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||
code span.ch { color: #4070a0; } /* Char */
|
||
code span.cn { color: #880000; } /* Constant */
|
||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||
code span.dt { color: #902000; } /* DataType */
|
||
code span.dv { color: #40a070; } /* DecVal */
|
||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||
code span.ex { } /* Extension */
|
||
code span.fl { color: #40a070; } /* Float */
|
||
code span.fu { color: #06287e; } /* Function */
|
||
code span.im { } /* Import */
|
||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||
code span.op { color: #666666; } /* Operator */
|
||
code span.ot { color: #007020; } /* Other */
|
||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||
code span.ss { color: #bb6688; } /* SpecialString */
|
||
code span.st { color: #4070a0; } /* String */
|
||
code span.va { color: #19177c; } /* Variable */
|
||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
|
||
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
|
||
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
|
||
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
|
||
td {padding: 2px 6px; border: 1px solid;}
|
||
img {display: block; margin-left: auto; margin-right: auto;}
|
||
figcaption {text-align: center;}
|
||
</style>
|
||
</head>
|
||
<body style="padding-top: 70px;">
|
||
<div class="container">
|
||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||
<div class="container-fluid">
|
||
<span class="navbar-brand">Gtk4 tutorial</span>
|
||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||
<span class="navbar-toggler-icon"></span>
|
||
</button>
|
||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="index.html">Home</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec26.html">Prev: section26</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec28.html">Next: section28</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
<h1 id="tiny-turtle-graphics-interpreter">Tiny turtle graphics
|
||
interpreter</h1>
|
||
<p>A program <code>turtle</code> is an example with the combination of
|
||
TfeTextView and GtkDrawingArea objects. It is a very small interpreter
|
||
but you can draw fractal curves with it. The following diagram is a Koch
|
||
curve, which is one of the famous fractal curves.</p>
|
||
<figure>
|
||
<img src="image/turtle_koch.png" alt="Koch curve" />
|
||
<figcaption aria-hidden="true">Koch curve</figcaption>
|
||
</figure>
|
||
<p>The following is a snow-crystal-shaped curve. It is composed of six
|
||
Koch curves.</p>
|
||
<figure>
|
||
<img src="image/turtle_snow.png" alt="Snow" />
|
||
<figcaption aria-hidden="true">Snow</figcaption>
|
||
</figure>
|
||
<p>This program uses flex and bison. Flex is a lexical analyzer. Bison
|
||
is a parser generator. These two programs are similar to lex and yacc
|
||
which are proprietary software developed in Bell Laboratory. However,
|
||
flex and bison are open source software. This section describes them and
|
||
they are not the topics about GTK 4. So, readers can skip this
|
||
section.</p>
|
||
<h2 id="how-to-use-turtle">How to use turtle</h2>
|
||
<p>The turtle document is <a
|
||
href="https://toshiocp.github.io/Gtk4-tutorial/turtle_doc.html">here</a>.
|
||
I’ll show you a simple example.</p>
|
||
<pre><code>fc (1,0,0) # Foreground color is red, rgb = (1,0,0).
|
||
pd # Pen down.
|
||
rp (4) { # Repeat four times.
|
||
fd 100 # Go forward by 100 pixels.
|
||
tr 90 # Turn right by 90 degrees.
|
||
}</code></pre>
|
||
<ol type="1">
|
||
<li>Compile and install <code>turtle</code> (See the documentation
|
||
above). Then, run <code>turtle</code>.</li>
|
||
<li>Type the program above in the editor (left part of the window).</li>
|
||
<li>Click on the <code>Run</code> button, then a red square appears on
|
||
the right part of the window. The side of the square is 100 pixels
|
||
long.</li>
|
||
</ol>
|
||
<p>In the same way, you can draw other curves. The turtle document
|
||
includes some fractal curves such as tree, snow and square-koch. The
|
||
source codes are located at src/turtle/example directory. You can read
|
||
these files into <code>turtle</code> editor by clicking on the
|
||
<code>Open</code> button.</p>
|
||
<h2
|
||
id="combination-of-tfetextview-and-gtkdrawingarea-objects">Combination
|
||
of TfeTextView and GtkDrawingArea objects</h2>
|
||
<p>Turtle uses TfeTextView and GtkDrawingArea.</p>
|
||
<ol type="1">
|
||
<li>A user inputs/reads a turtle program into the buffer in the
|
||
TfeTextView instance.</li>
|
||
<li>The user clicks on the “Run” button.</li>
|
||
<li>The parser reads the program and generates tree-structured
|
||
data.</li>
|
||
<li>The interpriter reads the data and executes it step by step. And it
|
||
draws shapes on a surface. The surface isn’t the one in the
|
||
GtkDrawingArea widget.</li>
|
||
<li>The widget is added to the queue. It will be redrawn with the
|
||
drawing function, which just copies the surface into the one in the
|
||
GtkDrawingArea.</li>
|
||
</ol>
|
||
<figure>
|
||
<img src="image/turtle.png"
|
||
alt="Parser, interpreter and drawing function" />
|
||
<figcaption aria-hidden="true">Parser, interpreter and drawing
|
||
function</figcaption>
|
||
</figure>
|
||
<p>The body of the interpreter is written with flex and bison. The codes
|
||
are not thread safe. So the callback function <code>run_cb</code>, which
|
||
is the handler of “clicked” signal on the <code>Run</code> button,
|
||
prevents reentering.</p>
|
||
<div class="sourceCode" id="cb2"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="dt">void</span></span>
|
||
<span id="cb2-2"><a href="#cb2-2"></a>run_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnr<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-3"><a href="#cb2-3"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||
<span id="cb2-4"><a href="#cb2-4"></a> GtkTextIter start_iter<span class="op">;</span></span>
|
||
<span id="cb2-5"><a href="#cb2-5"></a> GtkTextIter end_iter<span class="op">;</span></span>
|
||
<span id="cb2-6"><a href="#cb2-6"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||
<span id="cb2-7"><a href="#cb2-7"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||
<span id="cb2-8"><a href="#cb2-8"></a> <span class="dt">static</span> gboolean busy <span class="op">=</span> FALSE<span class="op">;</span> <span class="co">/* initialized only once */</span></span>
|
||
<span id="cb2-9"><a href="#cb2-9"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||
<span id="cb2-10"><a href="#cb2-10"></a></span>
|
||
<span id="cb2-11"><a href="#cb2-11"></a> <span class="co">/* yyparse() and run() are NOT thread safe. */</span></span>
|
||
<span id="cb2-12"><a href="#cb2-12"></a> <span class="co">/* The variable busy avoids reentrance. */</span></span>
|
||
<span id="cb2-13"><a href="#cb2-13"></a> <span class="cf">if</span> <span class="op">(</span>busy<span class="op">)</span></span>
|
||
<span id="cb2-14"><a href="#cb2-14"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb2-15"><a href="#cb2-15"></a> busy <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb2-16"><a href="#cb2-16"></a> gtk_text_buffer_get_bounds <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">);</span></span>
|
||
<span id="cb2-17"><a href="#cb2-17"></a> contents <span class="op">=</span> gtk_text_buffer_get_text <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">,</span> FALSE<span class="op">);</span></span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a> <span class="cf">if</span> <span class="op">(</span>surface <span class="op">&&</span> contents<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">!=</span> <span class="ch">'\0'</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a> init_flex <span class="op">(</span>contents<span class="op">);</span></span>
|
||
<span id="cb2-20"><a href="#cb2-20"></a> stat <span class="op">=</span> yyparse <span class="op">();</span></span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> <span class="cf">if</span> <span class="op">(</span>stat <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span> <span class="co">/* No error */</span></span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> run <span class="op">();</span></span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a> <span class="op">}</span></span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a> finalize_flex <span class="op">();</span></span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a> <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||
<span id="cb2-27"><a href="#cb2-27"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">);</span></span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb2-29"><a href="#cb2-29"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb2-30"><a href="#cb2-30"></a> <span class="op">}</span></span>
|
||
<span id="cb2-31"><a href="#cb2-31"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||
<span id="cb2-32"><a href="#cb2-32"></a> gtk_widget_queue_draw <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">));</span></span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a> busy <span class="op">=</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a><span class="op">}</span></span>
|
||
<span id="cb2-35"><a href="#cb2-35"></a></span>
|
||
<span id="cb2-36"><a href="#cb2-36"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-37"><a href="#cb2-37"></a>resize_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-38"><a href="#cb2-38"></a></span>
|
||
<span id="cb2-39"><a href="#cb2-39"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||
<span id="cb2-40"><a href="#cb2-40"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||
<span id="cb2-41"><a href="#cb2-41"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_ARGB32<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||
<span id="cb2-42"><a href="#cb2-42"></a> run_cb <span class="op">(</span>NULL<span class="op">);</span> <span class="co">// NULL is a fake (run button).</span></span>
|
||
<span id="cb2-43"><a href="#cb2-43"></a><span class="op">}</span></span></code></pre></div>
|
||
<ul>
|
||
<li>8, 13-15: The static value <code>busy</code> holds a status of the
|
||
interpreter. If it is <code>TRUE</code>, the interpreter is running and
|
||
it is not possible to call the interpreter because it’s not a re-entrant
|
||
program. If it is <code>FALSE</code>, it is safe to call the interpreter
|
||
and set the variable <code>busy</code> to TRUE.</li>
|
||
<li>16-17: Gets the contents of <code>tb</code>.</li>
|
||
<li>18-30: The variable <code>surface</code> is a static variable. It
|
||
points to a <code>cairo_surface_t</code> instance. It is created when
|
||
the GtkDrawingArea instance is realized and whenever it is resized.
|
||
Therefore, <code>surface</code> isn’t NULL usually. But if it is NULL,
|
||
the interpreter won’t be called.</li>
|
||
<li>18-24: If <code>surface</code> points a surface instance and the
|
||
string <code>contents</code> isn’t empty, it calls the interpreter.
|
||
<ul>
|
||
<li>Initializes the lexical analyzer.</li>
|
||
<li>Calls the parser. The parser analyzes the program codes
|
||
syntactically and generates a tree structured data.</li>
|
||
<li>If the parser successfully parsed, it calls the runtime routine
|
||
‘run’.</li>
|
||
<li>Finalizes the lexical analyzer.</li>
|
||
</ul></li>
|
||
<li>25-29: If <code>surface</code> points a surface instance and the
|
||
string <code>contents</code> is empty, it clears the surface
|
||
<code>surface</code>.</li>
|
||
<li>31: Frees <code>contents</code>.</li>
|
||
<li>32: Adds the drawing area widget to the queue to draw.</li>
|
||
<li>33: Sets the variable <code>busy</code> to FALSE.</li>
|
||
<li>36-43: The “resized” signal handler. If the <code>surface</code>
|
||
isn’t NULL, it is destroyed. A new surface is created. Its size is the
|
||
same as the surface of the GtkDrawingArea instance. It calls the
|
||
callback function <code>run_cb</code> to redraw the shape on the drawing
|
||
area.</li>
|
||
</ul>
|
||
<p>If the open button is clicked and a file is read, the filename will
|
||
be shown on the header bar.</p>
|
||
<div class="sourceCode" id="cb3"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb3-2"><a href="#cb3-2"></a>show_filename <span class="op">(</span>TfeTextView <span class="op">*</span>tv<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb3-3"><a href="#cb3-3"></a> GFile <span class="op">*</span>file<span class="op">;</span></span>
|
||
<span id="cb3-4"><a href="#cb3-4"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span>
|
||
<span id="cb3-5"><a href="#cb3-5"></a> <span class="dt">char</span> <span class="op">*</span>title<span class="op">;</span></span>
|
||
<span id="cb3-6"><a href="#cb3-6"></a></span>
|
||
<span id="cb3-7"><a href="#cb3-7"></a> file <span class="op">=</span> tfe_text_view_get_file <span class="op">(</span>tv<span class="op">);</span></span>
|
||
<span id="cb3-8"><a href="#cb3-8"></a> <span class="cf">if</span> <span class="op">(</span>G_IS_FILE <span class="op">(</span>file<span class="op">))</span> <span class="op">{</span></span>
|
||
<span id="cb3-9"><a href="#cb3-9"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>file<span class="op">);</span></span>
|
||
<span id="cb3-10"><a href="#cb3-10"></a> title <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"Turtle (%s)"</span><span class="op">,</span> filename<span class="op">);</span></span>
|
||
<span id="cb3-11"><a href="#cb3-11"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span>
|
||
<span id="cb3-12"><a href="#cb3-12"></a> g_object_unref <span class="op">(</span>file<span class="op">);</span></span>
|
||
<span id="cb3-13"><a href="#cb3-13"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb3-14"><a href="#cb3-14"></a> title <span class="op">=</span> g_strdup <span class="op">(</span><span class="st">"Turtle"</span><span class="op">);</span></span>
|
||
<span id="cb3-15"><a href="#cb3-15"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> title<span class="op">);</span></span>
|
||
<span id="cb3-16"><a href="#cb3-16"></a> g_free <span class="op">(</span>title<span class="op">);</span></span>
|
||
<span id="cb3-17"><a href="#cb3-17"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>This function is the callback function of the “change-file” signal on
|
||
the TfeTextView instance. It calls
|
||
<code>tfe_text_view_get_file</code>.</p>
|
||
<ul>
|
||
<li>If the return value is a GFile instance, the title will be “Turtle
|
||
(the filename)”.</li>
|
||
<li>Otherwise, the title will be “Turtle”.</li>
|
||
</ul>
|
||
<p>Other part of <code>turtleapplication.c</code> is very simple and
|
||
similar to the codes in the former applications. The codes of
|
||
<code>turtleapplication.c</code> is in the turtle directory.</p>
|
||
<h2 id="what-does-the-interpreter-do">What does the interpreter do?</h2>
|
||
<p>Suppose that the turtle application runs with the following
|
||
program.</p>
|
||
<pre><code>distance = 100
|
||
fd distance*2</code></pre>
|
||
<p>The application recognizes the program and works as follows.</p>
|
||
<ul>
|
||
<li>Generally, a program consists of tokens. Tokens are “distance”, “=”,
|
||
“100”, “fd”, “*” and “2” in the above example..</li>
|
||
<li>The parser calls a function <code>yylex</code> to read a token in
|
||
the source file. <code>yylex</code> returns a code which is called
|
||
“token kind” and sets a global variable <code>yylval</code> to a value,
|
||
which is called a semantic value. The type of <code>yylval</code> is
|
||
union. The type of <code>yylval.ID</code> and <code>yylval.NUM</code>
|
||
are string and double respectively. There are seven tokens in the
|
||
program so <code>yylex</code> is called seven times.</li>
|
||
</ul>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: center;"></th>
|
||
<th style="text-align: center;">token kind</th>
|
||
<th style="text-align: center;">yylval.ID</th>
|
||
<th style="text-align: center;">yylval.NUM</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">1</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">distance</td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">2</td>
|
||
<td style="text-align: center;">=</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">3</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">100</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">4</td>
|
||
<td style="text-align: center;">FD</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">5</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">distance</td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">6</td>
|
||
<td style="text-align: center;">*</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">7</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">2</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<ul>
|
||
<li>The function <code>yylex</code> returns a token kind every time, but
|
||
it doesn’t set <code>yylval.ID</code> or <code>yylval.NUM</code> every
|
||
time. It is because keywords (<code>FD</code>) and symbols
|
||
(<code>=</code> and <code>*</code>) don’t have any semantic values. The
|
||
function <code>yylex</code> is called lexical analyzer or scanner.</li>
|
||
<li>The application <code>turtle</code> makes a tree structured data.
|
||
This part of <code>turtle</code> is called parser.</li>
|
||
</ul>
|
||
<figure>
|
||
<img src="image/turtle_parser_tree.png" alt="turtle parser tree" />
|
||
<figcaption aria-hidden="true">turtle parser tree</figcaption>
|
||
</figure>
|
||
<ul>
|
||
<li><code>Turtle</code> analyzes the tree and executes it. This part of
|
||
<code>turtle</code> is called runtime routine or interpreter. The tree
|
||
consists of rectangles and line segments between the rectangles. The
|
||
rectangles are called nodes. For example, N_PROGRAM, N_ASSIGN, N_FD and
|
||
N_MUL are nodes.
|
||
<ol type="1">
|
||
<li>Goes down from N_PROGRAM to N_ASSIGN.</li>
|
||
<li>N_ASSIGN node has two children, ID and NUM. This node comes from
|
||
“distance = 100” which is “ID = NUM” syntactically. First,
|
||
<code>turtle</code> checks if the first child is ID. If it’s ID, then
|
||
<code>turtle</code> looks for the variable in the variable table. If it
|
||
doesn’t exist, it registers the ID (<code>distance</code>) to the table.
|
||
Then go back to the N_ASSIGN node.</li>
|
||
<li><code>Turtle</code> calculates the second child. In this case its a
|
||
number 100. Saves 100 to the variable table at the <code>distance</code>
|
||
record.</li>
|
||
<li><code>Turtle</code> goes back to N_PROGRAM then go to the next node
|
||
N_FD. It has only one child. Goes down to the child N_MUL.</li>
|
||
<li>The first child is ID (distance). Searches the variable table for
|
||
the variable <code>distance</code> and gets the value 100. The second
|
||
child is a number 2. Multiplies 100 by 2 and gets 200. Then
|
||
<code>turtle</code> goes back to N_FD.</li>
|
||
<li>Now <code>turtle</code> knows the distance is 200. It moves the
|
||
cursor forward by 200 pixels. The segment is drawn on the
|
||
<code>surface</code>.</li>
|
||
<li>There are no node follows. Runtime routine returns to the function
|
||
<code>run_cb</code>.</li>
|
||
</ol></li>
|
||
<li>The function <code>run_cb</code> calls
|
||
<code>gtk_widget_queue_draw</code> and put the GtkDrawingArea widget to
|
||
the queue.</li>
|
||
<li>The system redraws the widget. At that time drawing function
|
||
<code>draw_func</code> is called. The function copies the
|
||
<code>surface</code> to the surface in the GtkDrawingArea.</li>
|
||
</ul>
|
||
<p>Actual turtle program is more complicated than the example above.
|
||
However, what turtle does is basically the same. Interpretation consists
|
||
of three parts.</p>
|
||
<ul>
|
||
<li>Lexical analysis</li>
|
||
<li>Syntax Parsing and tree generation</li>
|
||
<li>Interpretation and execution of the tree.</li>
|
||
</ul>
|
||
<h2 id="compilation-flow">Compilation flow</h2>
|
||
<p>The source files are:</p>
|
||
<ul>
|
||
<li>flex source file => <code>turtle.lex</code></li>
|
||
<li>bison source file => <code>turtle.y</code></li>
|
||
<li>C header file => <code>turtle_lex.h</code></li>
|
||
<li>C source file => <code>turtleapplication.c</code></li>
|
||
<li>other files => <code>turtle.ui</code>,
|
||
<code>turtle.gresources.xml</code> and <code>meson.build</code></li>
|
||
</ul>
|
||
<p>The compilation process is a bit complicated.</p>
|
||
<ol type="1">
|
||
<li>glib-compile-resources compiles <code>turtle.ui</code> to
|
||
<code>resources.c</code> according to <code>turtle.gresource.xml</code>.
|
||
It also generates <code>resources.h</code>.</li>
|
||
<li>bison compiles <code>turtle.y</code> to <code>turtle_parser.c</code>
|
||
and generates <code>turtle_parser.h</code></li>
|
||
<li>flex compiles <code>turtle.lex</code> to
|
||
<code>turtle_lex.c</code>.</li>
|
||
<li>gcc compiles <code>application.c</code>, <code>resources.c</code>,
|
||
<code>turtle_parser.c</code> and <code>turtle_lex.c</code> with
|
||
<code>turtle_lex.h</code>, <code>resources.h</code> and
|
||
<code>turtle_parser.h</code>. It generates an executable file
|
||
<code>turtle</code>.</li>
|
||
</ol>
|
||
<figure>
|
||
<img src="image/turtle_compile_process.png" alt="compile process" />
|
||
<figcaption aria-hidden="true">compile process</figcaption>
|
||
</figure>
|
||
<p>Meson controls the process. The instruction is described in
|
||
<code>meson.build</code>.</p>
|
||
<div class="sourceCode" id="cb5"><pre
|
||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb5-1"><a href="#cb5-1"></a>project('turtle', 'c')</span>
|
||
<span id="cb5-2"><a href="#cb5-2"></a></span>
|
||
<span id="cb5-3"><a href="#cb5-3"></a>compiler = meson.get_compiler('c')</span>
|
||
<span id="cb5-4"><a href="#cb5-4"></a>mathdep = compiler.find_library('m', required : true)</span>
|
||
<span id="cb5-5"><a href="#cb5-5"></a></span>
|
||
<span id="cb5-6"><a href="#cb5-6"></a>gtkdep = dependency('gtk4')</span>
|
||
<span id="cb5-7"><a href="#cb5-7"></a></span>
|
||
<span id="cb5-8"><a href="#cb5-8"></a>gnome=import('gnome')</span>
|
||
<span id="cb5-9"><a href="#cb5-9"></a>resources = gnome.compile_resources('resources','turtle.gresource.xml')</span>
|
||
<span id="cb5-10"><a href="#cb5-10"></a></span>
|
||
<span id="cb5-11"><a href="#cb5-11"></a>flex = find_program('flex')</span>
|
||
<span id="cb5-12"><a href="#cb5-12"></a>bison = find_program('bison')</span>
|
||
<span id="cb5-13"><a href="#cb5-13"></a>turtleparser = custom_target('turtleparser', input: 'turtle.y', output: ['turtle_parser.c', 'turtle_parser.h'], command: [bison, '-d', '-o', 'turtle_parser.c', '@INPUT@'])</span>
|
||
<span id="cb5-14"><a href="#cb5-14"></a>turtlelexer = custom_target('turtlelexer', input: 'turtle.lex', output: 'turtle_lex.c', command: [flex, '-o', '@OUTPUT@', '@INPUT@'])</span>
|
||
<span id="cb5-15"><a href="#cb5-15"></a></span>
|
||
<span id="cb5-16"><a href="#cb5-16"></a>sourcefiles=files('turtleapplication.c', '../tfetextview/tfetextview.c')</span>
|
||
<span id="cb5-17"><a href="#cb5-17"></a></span>
|
||
<span id="cb5-18"><a href="#cb5-18"></a>executable('turtle', sourcefiles, resources, turtleparser, turtlelexer, turtleparser[1], dependencies: [mathdep, gtkdep], export_dynamic: true, install: true)</span></code></pre></div>
|
||
<ul>
|
||
<li>1: The project name is “turtle” and the program language is C.</li>
|
||
<li>3: Gets C compiler. It is usually <code>gcc</code> in linux.</li>
|
||
<li>4: Gets math library. This program uses trigonometric functions.
|
||
They are defined in the math library, but the library is optional. So,
|
||
it is necessary to include it by <code>#include <math.h></code>
|
||
and also link the library with the linker.</li>
|
||
<li>6: Gets gtk4 library.</li>
|
||
<li>8: Gets gnome module.See <a
|
||
href="https://mesonbuild.com/Gnome-module.html#gnome-module">Meson build
|
||
system website – GNOME module</a> for further information.</li>
|
||
<li>9: Compiles ui file to C source file according to the XML file
|
||
<code>turtle.gresource.xml</code>.</li>
|
||
<li>11: Gets flex.</li>
|
||
<li>12: Gets bison.</li>
|
||
<li>13: Compiles <code>turtle.y</code> to <code>turtle_parser.c</code>
|
||
and <code>turtle_parser.h</code> by bison. The function
|
||
<code>custom_target</code> creates a custom top level target. See <a
|
||
href="https://mesonbuild.com/Reference-manual_functions.html#custom_target">Meson
|
||
build system website – custom target</a> for further information.</li>
|
||
<li>14: Compiles <code>turtle.lex</code> to <code>turtle_lex.c</code> by
|
||
flex.</li>
|
||
<li>16: The variable <code>sourcefiles</code> is a file object created
|
||
with the C source files.</li>
|
||
<li>18: Compiles C source files including generated files by
|
||
glib-compile-resources, bison and flex. The argument
|
||
<code>turtleparser[1]</code> refers to <code>tirtle_parser.h</code>
|
||
which is the second output in the line 13.</li>
|
||
</ul>
|
||
<h2 id="turtle.lex">Turtle.lex</h2>
|
||
<h3 id="what-does-flex-do">What does flex do?</h3>
|
||
<p>Flex creates lexical analyzer from flex source file. Flex source file
|
||
is a text file. Its syntactic rule will be explained later. Generated
|
||
lexical analyzer is a C source file. It is also called scanner. It reads
|
||
a text file, which is a source file of a program language, and gets
|
||
variable names, numbers and symbols. Suppose here is a turtle source
|
||
file.</p>
|
||
<pre><code>fc (1,0,0) # Foreground color is red, rgb = (1,0,0).
|
||
pd # Pen down.
|
||
distance = 100
|
||
angle = 90
|
||
fd distance # Go forward by distance (100) pixels.
|
||
tr angle # Turn right by angle (90) degrees.</code></pre>
|
||
<p>The content of the text file is separated into <code>fc</code>,
|
||
<code>(</code>, <code>1</code> and so on. The words <code>fc</code>,
|
||
<code>pd</code>, <code>distance</code>, <code>angle</code>,
|
||
<code>tr</code>, <code>1</code>, <code>0</code>, <code>100</code> and
|
||
<code>90</code> are called tokens. The characters ‘<code>(</code>’ (left
|
||
parenthesis), ‘<code>,</code>’ (comma), ‘<code>)</code>’ (right
|
||
parenthesis) and ‘<code>=</code>’ (equal sign) are called symbols. (
|
||
Sometimes those symbols called tokens, too.)</p>
|
||
<p>Flex reads <code>turtle.lex</code> and generates the C source file of
|
||
a scanner. The file <code>turtle.lex</code> specifies tokens, symbols
|
||
and the behavior which corresponds to each token or symbol. Turtle.lex
|
||
isn’t a big program.</p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode numberSource lex numberLines"><code class="sourceCode lex"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">%top{</span></span>
|
||
<span id="cb7-2"><a href="#cb7-2"></a>#include <string.h></span>
|
||
<span id="cb7-3"><a href="#cb7-3"></a>#include <stdlib.h></span>
|
||
<span id="cb7-4"><a href="#cb7-4"></a>#include <glib.h></span>
|
||
<span id="cb7-5"><a href="#cb7-5"></a>#include "turtle_parser.h"</span>
|
||
<span id="cb7-6"><a href="#cb7-6"></a></span>
|
||
<span id="cb7-7"><a href="#cb7-7"></a> <span class="at">static</span> <span class="dt">int</span> nline <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb7-8"><a href="#cb7-8"></a> <span class="at">static</span> <span class="dt">int</span> ncolumn <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb7-9"><a href="#cb7-9"></a> <span class="at">static</span> <span class="dt">void</span> get_location <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>text<span class="op">);</span></span>
|
||
<span id="cb7-10"><a href="#cb7-10"></a></span>
|
||
<span id="cb7-11"><a href="#cb7-11"></a> <span class="co">/* Dinamically allocated memories are added to the single list. They will be freed in the finalize function. */</span></span>
|
||
<span id="cb7-12"><a href="#cb7-12"></a> <span class="at">extern</span> GSList <span class="op">*</span>list<span class="op">;</span></span>
|
||
<span id="cb7-13"><a href="#cb7-13"></a>}</span>
|
||
<span id="cb7-14"><a href="#cb7-14"></a></span>
|
||
<span id="cb7-15"><a href="#cb7-15"></a><span class="kw">%option noyywrap</span></span>
|
||
<span id="cb7-16"><a href="#cb7-16"></a></span>
|
||
<span id="cb7-17"><a href="#cb7-17"></a><span class="dt">REAL_NUMBER </span><span class="st">(0|[1-9][0-9]*)(\.[0-9]+)?</span></span>
|
||
<span id="cb7-18"><a href="#cb7-18"></a><span class="dt">IDENTIFIER </span><span class="st">[a-zA-Z][a-zA-Z0-9]*</span></span>
|
||
<span id="cb7-19"><a href="#cb7-19"></a><span class="bn">%%</span></span>
|
||
<span id="cb7-20"><a href="#cb7-20"></a> <span class="co">/* rules */</span></span>
|
||
<span id="cb7-21"><a href="#cb7-21"></a><span class="st">#.*</span> <span class="op">;</span> <span class="co">/* comment. Be careful. Dot symbol (.) matches any character but new line. */</span></span>
|
||
<span id="cb7-22"><a href="#cb7-22"></a><span class="st">[ ]</span> ncolumn<span class="op">++;</span> <span class="co">/* white space. [ and ] is a "character class". */</span></span>
|
||
<span id="cb7-23"><a href="#cb7-23"></a><span class="st">\t</span> ncolumn <span class="op">+=</span> <span class="dv">8</span><span class="op">;</span> <span class="co">/* assume that tab is 8 spaces. */</span></span>
|
||
<span id="cb7-24"><a href="#cb7-24"></a><span class="st">\n</span> nline<span class="op">++;</span> ncolumn <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb7-25"><a href="#cb7-25"></a> <span class="co">/* reserved keywords */</span></span>
|
||
<span id="cb7-26"><a href="#cb7-26"></a><span class="st">pu</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> PU<span class="op">;</span> <span class="co">/* pen up */</span></span>
|
||
<span id="cb7-27"><a href="#cb7-27"></a><span class="st">pd</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> PD<span class="op">;</span> <span class="co">/* pen down */</span></span>
|
||
<span id="cb7-28"><a href="#cb7-28"></a><span class="st">pw</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> PW<span class="op">;</span> <span class="co">/* pen width = line width */</span></span>
|
||
<span id="cb7-29"><a href="#cb7-29"></a><span class="st">fd</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> FD<span class="op">;</span> <span class="co">/* forward */</span></span>
|
||
<span id="cb7-30"><a href="#cb7-30"></a><span class="st">tr</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> TR<span class="op">;</span> <span class="co">/* turn right */</span></span>
|
||
<span id="cb7-31"><a href="#cb7-31"></a><span class="st">tl</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> TL<span class="op">;</span> <span class="co">/* turn left, since ver 0.5 */</span></span>
|
||
<span id="cb7-32"><a href="#cb7-32"></a><span class="st">bc</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> BC<span class="op">;</span> <span class="co">/* background color */</span></span>
|
||
<span id="cb7-33"><a href="#cb7-33"></a><span class="st">fc</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> FC<span class="op">;</span> <span class="co">/* foreground color */</span></span>
|
||
<span id="cb7-34"><a href="#cb7-34"></a><span class="st">dp</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> DP<span class="op">;</span> <span class="co">/* define procedure */</span></span>
|
||
<span id="cb7-35"><a href="#cb7-35"></a><span class="st">if</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> IF<span class="op">;</span> <span class="co">/* if statement */</span></span>
|
||
<span id="cb7-36"><a href="#cb7-36"></a><span class="st">rt</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> RT<span class="op">;</span> <span class="co">/* return statement */</span></span>
|
||
<span id="cb7-37"><a href="#cb7-37"></a><span class="st">rs</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> RS<span class="op">;</span> <span class="co">/* reset the status */</span></span>
|
||
<span id="cb7-38"><a href="#cb7-38"></a><span class="st">rp</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> RP<span class="op">;</span> <span class="co">/* repeat, since ver 0.5 */</span></span>
|
||
<span id="cb7-39"><a href="#cb7-39"></a> <span class="co">/* constant */</span></span>
|
||
<span id="cb7-40"><a href="#cb7-40"></a><span class="st">{REAL_NUMBER}</span> get_location <span class="op">(</span>yytext<span class="op">);</span> yylval<span class="op">.</span>NUM <span class="op">=</span> atof <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> NUM<span class="op">;</span></span>
|
||
<span id="cb7-41"><a href="#cb7-41"></a> <span class="co">/* identifier */</span></span>
|
||
<span id="cb7-42"><a href="#cb7-42"></a><span class="st">{IDENTIFIER}</span> { get_location <span class="op">(</span>yytext<span class="op">);</span> yylval<span class="op">.</span>ID <span class="op">=</span> <span class="va">g_strdup</span><span class="op">(</span>yytext<span class="op">);</span></span>
|
||
<span id="cb7-43"><a href="#cb7-43"></a> list <span class="op">=</span> <span class="va">g_slist_prepend</span> <span class="op">(</span>list<span class="op">,</span> yylval<span class="op">.</span>ID<span class="op">);</span></span>
|
||
<span id="cb7-44"><a href="#cb7-44"></a> <span class="cf">return</span> ID<span class="op">;</span></span>
|
||
<span id="cb7-45"><a href="#cb7-45"></a> }</span>
|
||
<span id="cb7-46"><a href="#cb7-46"></a><span class="st">"="</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'='</span><span class="op">;</span></span>
|
||
<span id="cb7-47"><a href="#cb7-47"></a><span class="st">">"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'>'</span><span class="op">;</span></span>
|
||
<span id="cb7-48"><a href="#cb7-48"></a><span class="st">"<"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'<'</span><span class="op">;</span></span>
|
||
<span id="cb7-49"><a href="#cb7-49"></a><span class="st">"+"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'+'</span><span class="op">;</span></span>
|
||
<span id="cb7-50"><a href="#cb7-50"></a><span class="st">"-"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'-'</span><span class="op">;</span></span>
|
||
<span id="cb7-51"><a href="#cb7-51"></a><span class="st">"*"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'*'</span><span class="op">;</span></span>
|
||
<span id="cb7-52"><a href="#cb7-52"></a><span class="st">"/"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'/'</span><span class="op">;</span></span>
|
||
<span id="cb7-53"><a href="#cb7-53"></a><span class="st">"("</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'('</span><span class="op">;</span></span>
|
||
<span id="cb7-54"><a href="#cb7-54"></a><span class="st">")"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">')'</span><span class="op">;</span></span>
|
||
<span id="cb7-55"><a href="#cb7-55"></a><span class="st">"{"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'{'</span><span class="op">;</span></span>
|
||
<span id="cb7-56"><a href="#cb7-56"></a><span class="st">"}"</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">'}'</span><span class="op">;</span></span>
|
||
<span id="cb7-57"><a href="#cb7-57"></a><span class="st">","</span> get_location <span class="op">(</span>yytext<span class="op">);</span> <span class="cf">return</span> <span class="ch">','</span><span class="op">;</span></span>
|
||
<span id="cb7-58"><a href="#cb7-58"></a><span class="st">.</span> ncolumn<span class="op">++;</span> <span class="cf">return</span> YYUNDEF<span class="op">;</span></span>
|
||
<span id="cb7-59"><a href="#cb7-59"></a><span class="bn">%%</span></span>
|
||
<span id="cb7-60"><a href="#cb7-60"></a></span>
|
||
<span id="cb7-61"><a href="#cb7-61"></a><span class="at">static</span> <span class="dt">void</span></span>
|
||
<span id="cb7-62"><a href="#cb7-62"></a>get_location <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>text<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-63"><a href="#cb7-63"></a> yylloc<span class="op">.</span>first_line <span class="op">=</span> yylloc<span class="op">.</span>last_line <span class="op">=</span> nline<span class="op">;</span></span>
|
||
<span id="cb7-64"><a href="#cb7-64"></a> yylloc<span class="op">.</span>first_column <span class="op">=</span> ncolumn<span class="op">;</span></span>
|
||
<span id="cb7-65"><a href="#cb7-65"></a> yylloc<span class="op">.</span>last_column <span class="op">=</span> <span class="op">(</span>ncolumn <span class="op">+=</span> strlen<span class="op">(</span>text<span class="op">))</span> <span class="op">-</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb7-66"><a href="#cb7-66"></a><span class="op">}</span></span>
|
||
<span id="cb7-67"><a href="#cb7-67"></a></span>
|
||
<span id="cb7-68"><a href="#cb7-68"></a><span class="at">static</span> YY_BUFFER_STATE state<span class="op">;</span></span>
|
||
<span id="cb7-69"><a href="#cb7-69"></a></span>
|
||
<span id="cb7-70"><a href="#cb7-70"></a><span class="dt">void</span></span>
|
||
<span id="cb7-71"><a href="#cb7-71"></a>init_flex <span class="op">(</span><span class="at">const</span> <span class="dt">char</span> <span class="op">*</span>text<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-72"><a href="#cb7-72"></a> state <span class="op">=</span> yy_scan_string <span class="op">(</span>text<span class="op">);</span></span>
|
||
<span id="cb7-73"><a href="#cb7-73"></a><span class="op">}</span></span>
|
||
<span id="cb7-74"><a href="#cb7-74"></a></span>
|
||
<span id="cb7-75"><a href="#cb7-75"></a><span class="dt">void</span></span>
|
||
<span id="cb7-76"><a href="#cb7-76"></a>finalize_flex <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb7-77"><a href="#cb7-77"></a> yy_delete_buffer <span class="op">(</span>state<span class="op">);</span></span>
|
||
<span id="cb7-78"><a href="#cb7-78"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The file consists of three sections which are separated by “%%” (line
|
||
19 and 59). They are definitions, rules and user code sections.</p>
|
||
<h3 id="definitions-section">Definitions section</h3>
|
||
<ul>
|
||
<li>1-12: Lines between “%top{” and “}” are C source codes. They will be
|
||
copied to the top of the generated C source file.</li>
|
||
<li>2-3: This program uses two functions <code>strlen</code> (l.65) and
|
||
<code>atof</code> (l.40). They are defined in <code>string.h</code> and
|
||
<code>stdlib.h</code> respectively. These two header files are included
|
||
here.</li>
|
||
<li>4: This program uses some GLib functions and structures like
|
||
<code>g_strdup</code> and <code>GSList</code>. GLib header file is
|
||
<code>glib.h</code> and it is included here.</li>
|
||
<li>5: The header file “turtle_parser.h” is generated from “turtle.y” by
|
||
bison. It defines some constants and functions like <code>PU</code> and
|
||
<code>yylloc</code>. The header file is included here.</li>
|
||
<li>7-9: The current input position is pointed by <code>nline</code> and
|
||
<code>ncolumn</code>. The function <code>get_location</code> is declared
|
||
here so that it can be called before the function is defined
|
||
(l.61-65).</li>
|
||
<li>12: GSlist is a structure for a singly-linked list. The variable
|
||
<code>list</code> is defined in <code>turtle.y</code> so its class is
|
||
<code>extern</code>. It is the start point of the list. The list is used
|
||
to keep allocated memories.</li>
|
||
<li>15: This option <code>%option noyywrap</code> must be specified when
|
||
you have only single source file to the scanner. Refer to “9 The
|
||
Generated Scanner” in the flex documentation in your distribution. (The
|
||
documentation is not on the internet.)</li>
|
||
<li>17-18: <code>REAL_NUMBER</code> and <code>IDENTIFIER</code> are
|
||
names. A name begins with a letter or an underscore followed by zero or
|
||
more letters, digits, underscores (<code>_</code>) or dashes
|
||
(<code>-</code>). They are followed by regular expressions which are
|
||
their definitions. They will be used in rules section and will expand to
|
||
the definition.</li>
|
||
</ul>
|
||
<h3 id="rules-section">Rules section</h3>
|
||
<p>This section is the most important part. Rules consist of patterns
|
||
and actions. The patterns are regular expressions or names surrounded by
|
||
braces. The names must be defined in the definitions section. The
|
||
definition of the regular expression is written in the flex
|
||
documentation.</p>
|
||
<p>For example, line 40 is a rule.</p>
|
||
<ul>
|
||
<li><code>{REAL_NUMBER}</code> is a pattern</li>
|
||
<li><code>get_location (yytext); yylval.NUM = atof (yytext); return NUM;</code>
|
||
is an action.</li>
|
||
</ul>
|
||
<p><code>{REAL_NUMBER}</code> is defined in the line 17, so it expands
|
||
to <code>(0|[1-9][0-9]*)(\.[0-9]+)?</code>. This regular expression
|
||
matches numbers like <code>0</code>, <code>12</code> and
|
||
<code>1.5</code>. If an input is a number, it matches the pattern in
|
||
line 40. Then the matched text is assigned to <code>yytext</code> and
|
||
corresponding action is executed. A function <code>get_location</code>
|
||
changes the location variables to the position at the text. It assigns
|
||
<code>atof (yytext)</code>, which is double sized number converted from
|
||
<code>yytext</code>, to <code>yylval.NUM</code> and return
|
||
<code>NUM</code>. <code>NUM</code> is a token kind and it represents
|
||
(double type) numbers. It is defined in <code>turtle.y</code>.</p>
|
||
<p>The scanner generated by flex has <code>yylex</code> function. If
|
||
<code>yylex</code> is called and the input is “123.4”, then it works as
|
||
follows.</p>
|
||
<ol type="1">
|
||
<li>A string “123.4” matches <code>{REAL_NUMBER}</code>.</li>
|
||
<li>Updates the location variable <code>ncolumn</code>. The structure
|
||
<code>yylloc</code> is set by <code>get_location</code>.</li>
|
||
<li>The function <code>atof</code> converts the string “123.4” to double
|
||
type number 123.4.</li>
|
||
<li>It is assigned to <code>yylval.NUM</code>.</li>
|
||
<li><code>yylex</code> returns <code>NUM</code> to the caller.</li>
|
||
</ol>
|
||
<p>Then the caller knows the input is a number (<code>NUM</code>), and
|
||
its value is 123.4.</p>
|
||
<ul>
|
||
<li>20-58: Rules section.</li>
|
||
<li>21: The symbol <code>.</code> (dot) matches any character except
|
||
newline. Therefore, a comment begins <code>#</code> followed by any
|
||
characters except newline. No action happens. That means that comments
|
||
are ignored.</li>
|
||
<li>22: White space just increases the variable <code>ncolumn</code> by
|
||
one.</li>
|
||
<li>23: Tab is assumed to be equal to eight spaces.</li>
|
||
<li>24: New line increases a variable <code>nline</code> by one and
|
||
resets <code>ncolumn</code>.</li>
|
||
<li>26-38: Keywords updates the location variables <code>ncolumn</code>
|
||
and <code>yylloc</code>, and returns the token kinds of the
|
||
keywords.</li>
|
||
<li>40: Real number constant. The action converts the
|
||
text<code>yytext</code> to a double type number, puts it into
|
||
<code>yylval.NUM</code> and returns <code>NUM</code>.</li>
|
||
<li>42: <code>IDENTIFIER</code> is defined in line 18. The identifier is
|
||
a name of variable or procedure. It begins with a letter and followed by
|
||
letters or digits. The location variables are updated and the name of
|
||
the identifier is assigned to <code>yylval.ID</code>. The memory of the
|
||
name is allocated by the function <code>g_strdup</code>. The memory is
|
||
registered to the list (GSlist type list). The memory will be freed
|
||
after the runtime routine finishes. A token kind <code>ID</code> is
|
||
returned.</li>
|
||
<li>46-57: Symbols update the location variable and return the token
|
||
kinds. The token kind is the same as the symbol itself.</li>
|
||
<li>58: If the input doesn’t match the patterns, then it is an error. A
|
||
special token kind <code>YYUNDEF</code> is returned.</li>
|
||
</ul>
|
||
<h3 id="user-code-section">User code section</h3>
|
||
<p>This section is just copied to C source file.</p>
|
||
<ul>
|
||
<li>61-66: A function <code>get_location</code>. The location of the
|
||
input is recorded to <code>nline</code> and <code>ncolumn</code>. A
|
||
variable <code>yylloc</code> is referred by the parser. It is a C
|
||
structure and has four members, <code>first_line</code>,
|
||
<code>first_column</code>, <code>last_line</code> and
|
||
<code>last_column</code>. They point the start and end of the current
|
||
input text.</li>
|
||
<li>68: <code>YY_BUFFER_STATE</code> is a pointer points the input
|
||
buffer. Flex makes the definition of <code>YY_BUFFER_STATE</code> in the
|
||
C file (scanner source file <code>turtle_lex.c</code>). See your flex
|
||
document, section 11 Multiple Input Buffers, for further
|
||
information.</li>
|
||
<li>70-73: A function <code>init_flex</code> is called by
|
||
<code>run_cb</code> which is a “clicked” signal handler on the
|
||
<code>Run</code> button. It has one string type parameter. The caller
|
||
assigns it with the content of the GtkTextBuffer instance. A function
|
||
<code>yy_scan_string</code> sets the input buffer for the scanner.</li>
|
||
<li>75-78: A function <code>finalize_flex</code> is called after runtime
|
||
routine finishes. It deletes the input buffer.</li>
|
||
</ul>
|
||
<h2 id="turtle.y">Turtle.y</h2>
|
||
<p>Turtle.y has more than 800 lines so it is difficult to explain all
|
||
the source code. So I will explain the key points and leave out other
|
||
less important parts.</p>
|
||
<h3 id="what-does-bison-do">What does bison do?</h3>
|
||
<p>Bison creates C source file of a parser from a bison source file. The
|
||
bison source file is a text file. A parser analyzes a program source
|
||
code according to its grammar. Suppose here is a turtle source file.</p>
|
||
<pre><code>fc (1,0,0) # Foreground color is red, rgb = (1,0,0).
|
||
pd # Pen down.
|
||
distance = 100
|
||
angle = 90
|
||
fd distance # Go forward by distance (100) pixels.
|
||
tr angle # Turn right by angle (90) degrees.</code></pre>
|
||
<p>The parser calls <code>yylex</code> to get a token. The token
|
||
consists of its type (token kind) and value (semantic value). So, the
|
||
parser gets items in the following table whenever it calls
|
||
<code>yylex</code>.</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: center;"></th>
|
||
<th style="text-align: center;">token kind</th>
|
||
<th style="text-align: center;">yylval.ID</th>
|
||
<th style="text-align: center;">yylval.NUM</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">1</td>
|
||
<td style="text-align: center;">FC</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">2</td>
|
||
<td style="text-align: center;">(</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">3</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">1.0</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">4</td>
|
||
<td style="text-align: center;">,</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">5</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">0.0</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">6</td>
|
||
<td style="text-align: center;">,</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">7</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">0.0</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">8</td>
|
||
<td style="text-align: center;">)</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">9</td>
|
||
<td style="text-align: center;">PD</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">10</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">distance</td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">11</td>
|
||
<td style="text-align: center;">=</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">12</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">100.0</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">13</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">angle</td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">14</td>
|
||
<td style="text-align: center;">=</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">15</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">90.0</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">16</td>
|
||
<td style="text-align: center;">FD</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">17</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">distance</td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">18</td>
|
||
<td style="text-align: center;">TR</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">19</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">angle</td>
|
||
<td style="text-align: center;"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Bison source code specifies the grammar rules of turtle language. For
|
||
example, <code>fc (1,0,0)</code> is called primary procedure. A
|
||
procedure is like a void type C function. It doesn’t return any values.
|
||
Programmers can define their own procedures. On the other hand,
|
||
<code>fc</code> is a built-in procedure. Such procedures are called
|
||
primary procedures. It is described in bison source code like:</p>
|
||
<pre><code>primary_procedure: FC '(' expression ',' expression ',' expression ')';
|
||
expression: ID | NUM;</code></pre>
|
||
<p>This means:</p>
|
||
<ul>
|
||
<li>Primary procedure is FC followed by ‘(’, expression, ‘,’,
|
||
expression, ‘,’, expression and ‘)’.</li>
|
||
<li>expression is ID or NUM.</li>
|
||
</ul>
|
||
<p>The description above is called BNF (Backus-Naur form). Precisely
|
||
speaking, it is not exactly the same as BNF. But the difference is
|
||
small.</p>
|
||
<p>The first line is:</p>
|
||
<pre><code>FC '(' NUM ',' NUM ',' NUM ')';</code></pre>
|
||
<p>The parser analyzes the turtle source code and if the input matches
|
||
the definition above, the parser recognizes it as a primary
|
||
procedure.</p>
|
||
<p>The grammar of turtle is described in the <a
|
||
href="https://toshiocp.github.io/Gtk4-tutorial/turtle_doc.html">Turtle
|
||
manual</a>. The following is an extract from the document.</p>
|
||
<pre><code>program:
|
||
statement
|
||
| program statement
|
||
;
|
||
|
||
statement:
|
||
primary_procedure
|
||
| procedure_definition
|
||
;
|
||
|
||
primary_procedure:
|
||
PU
|
||
| PD
|
||
| PW expression
|
||
| FD expression
|
||
| TR expression
|
||
| TL expression
|
||
| BC '(' expression ',' expression ',' expression ')'
|
||
| FC '(' expression ',' expression ',' expression ')'
|
||
| ID '=' expression
|
||
| IF '(' expression ')' '{' primary_procedure_list '}'
|
||
| RT
|
||
| RS
|
||
| RP '(' expression ')' '{' primary_procedure_list '}'
|
||
| ID '(' ')'
|
||
| ID '(' argument_list ')'
|
||
;
|
||
|
||
procedure_definition:
|
||
DP ID '(' ')' '{' primary_procedure_list '}'
|
||
| DP ID '(' parameter_list ')' '{' primary_procedure_list '}'
|
||
;
|
||
|
||
parameter_list:
|
||
ID
|
||
| parameter_list ',' ID
|
||
;
|
||
|
||
argument_list:
|
||
expression
|
||
| argument_list ',' expression
|
||
;
|
||
|
||
primary_procedure_list:
|
||
primary_procedure
|
||
| primary_procedure_list primary_procedure
|
||
;
|
||
|
||
expression:
|
||
expression '=' expression
|
||
| expression '>' expression
|
||
| expression '<' expression
|
||
| expression '+' expression
|
||
| expression '-' expression
|
||
| expression '*' expression
|
||
| expression '/' expression
|
||
| '-' expression %prec UMINUS
|
||
| '(' expression ')'
|
||
| ID
|
||
| NUM
|
||
;</code></pre>
|
||
<p>The grammar rule defines <code>program</code> first.</p>
|
||
<ul>
|
||
<li>program is a statement or a program followed by a statement.</li>
|
||
</ul>
|
||
<p>The definition is recursive.</p>
|
||
<ul>
|
||
<li><code>statement</code> is program.</li>
|
||
<li><code>statement statement</code> is <code>program statement</code>.
|
||
Therefore, it is program.</li>
|
||
<li><code>statement statement statement</code> is
|
||
<code>program statement</code> because the first two statements are
|
||
<code>program</code>. Therefore, it is program.</li>
|
||
</ul>
|
||
<p>You can find that a sequence of statements is program as well.</p>
|
||
<p>The symbols <code>program</code> and <code>statement</code> aren’t
|
||
tokens. They don’t appear in the input. They are called non terminal
|
||
symbols. On the other hand, tokens are called terminal symbols. The word
|
||
“token” used here has wide meaning, it includes tokens and symbols which
|
||
appear in the input. Non terminal symbols are often shortened to
|
||
nterm.</p>
|
||
<p>Let’s analyze the program above as bison does.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 4%" />
|
||
<col style="width: 14%" />
|
||
<col style="width: 12%" />
|
||
<col style="width: 14%" />
|
||
<col style="width: 50%" />
|
||
<col style="width: 4%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: center;"></th>
|
||
<th style="text-align: center;">token kind</th>
|
||
<th style="text-align: center;">yylval.ID</th>
|
||
<th style="text-align: center;">yylval.NUM</th>
|
||
<th style="text-align: left;">parse</th>
|
||
<th style="text-align: center;">S/R</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">1</td>
|
||
<td style="text-align: center;">FC</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">2</td>
|
||
<td style="text-align: center;">(</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">3</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">1.0</td>
|
||
<td style="text-align: left;">FC(NUM</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">4</td>
|
||
<td style="text-align: center;">,</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(expression,</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">5</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">0.0</td>
|
||
<td style="text-align: left;">FC(expression,NUM</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(expression,expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">6</td>
|
||
<td style="text-align: center;">,</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(expression,expression,</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">7</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">0.0</td>
|
||
<td style="text-align: left;">FC(expression,expression,NUM</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(expression,expression,expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">8</td>
|
||
<td style="text-align: center;">)</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">FC(expression,expression,expression)</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">primary_procedure</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">statement</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">9</td>
|
||
<td style="text-align: center;">PD</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program PD</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program primary_procedure</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program statement</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">10</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">distance</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program ID</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">11</td>
|
||
<td style="text-align: center;">=</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program ID=</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">12</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">100.0</td>
|
||
<td style="text-align: left;">program ID=NUM</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program ID=expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program primary_procedure</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program statement</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">13</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">angle</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program ID</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">14</td>
|
||
<td style="text-align: center;">=</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program ID=</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">15</td>
|
||
<td style="text-align: center;">NUM</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;">90.0</td>
|
||
<td style="text-align: left;">program ID=NUM</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program ID=expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program primary_procedure</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program statement</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">16</td>
|
||
<td style="text-align: center;">FD</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program FD</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">17</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">distance</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program FD ID</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program FD expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program primary_procedure</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program statement</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;">18</td>
|
||
<td style="text-align: center;">TR</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program TR</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;">19</td>
|
||
<td style="text-align: center;">ID</td>
|
||
<td style="text-align: center;">angle</td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program TR ID</td>
|
||
<td style="text-align: center;">S</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program TR expression</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program primary_procedure</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program statement</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: center;"></td>
|
||
<td style="text-align: left;">program</td>
|
||
<td style="text-align: center;">R</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>The right most column shows shift/reduce. Shift is appending an input
|
||
to the buffer. Reduce is substituting a higher nterm for the pattern in
|
||
the buffer. For example, NUM is replaced by expression in the forth row.
|
||
This substitution is “reduce”.</p>
|
||
<p>Bison repeats shift and reduction until the end of the input. If the
|
||
result is reduced to <code>program</code>, the input is syntactically
|
||
valid. Bison executes an action whenever reduction occurs. Actions build
|
||
a tree. The tree is analyzed and executed by runtime routine later.</p>
|
||
<p>Bison source files are called bison grammar files. A bison grammar
|
||
file consists of four sections, prologue, declarations, rules and
|
||
epilogue. The format is as follows.</p>
|
||
<pre><code>%{
|
||
prologue
|
||
%}
|
||
declarations
|
||
%%
|
||
rules
|
||
%%
|
||
epilogue</code></pre>
|
||
<h3 id="prologue">Prologue</h3>
|
||
<p>Prologue section consists of C codes and the codes are copied to the
|
||
parser implementation file. You can use <code>%code</code> directives to
|
||
qualify the prologue and identifies the purpose explicitly. The
|
||
following is an extract from <code>turtle.y</code>.</p>
|
||
<pre class="bison"><code>%code top{
|
||
#include <stdarg.h>
|
||
#include <setjmp.h>
|
||
#include <math.h>
|
||
#include <glib.h>
|
||
#include <cairo.h>
|
||
#include "turtle_parser.h"
|
||
|
||
/* The following line defines 'debug' so that debug information is printed out during the run time. */
|
||
/* However it makes the program slow. */
|
||
/* If you want to debug on, uncomment the line. */
|
||
|
||
/* #define debug 1 */
|
||
|
||
extern cairo_surface_t *surface;
|
||
|
||
/* error reporting */
|
||
static void yyerror (char const *s) { /* for syntax error */
|
||
g_printerr ("%s from line %d, column %d to line %d, column %d\n",s, yylloc.first_line, yylloc.first_column, yylloc.last_line, yylloc.last_column);
|
||
}
|
||
/* Node type */
|
||
enum {
|
||
N_PU,
|
||
N_PD,
|
||
N_PW,
|
||
... ... ...
|
||
};
|
||
}</code></pre>
|
||
<p>The directive <code>%code top</code> copies its contents to the top
|
||
of the parser implementation file. It usually includes
|
||
<code>#include</code> directives, declarations of functions and
|
||
definitions of constants. A function <code>yyerror</code> reports a
|
||
syntax error and is called by the parser. Node type identifies a node in
|
||
the tree.</p>
|
||
<p>Another directive <code>%code requires</code> copies its contents to
|
||
both the parser implementation file and header file. The header file is
|
||
read by the scanner C source file and other files.</p>
|
||
<pre class="bison"><code>%code requires {
|
||
int yylex (void);
|
||
int yyparse (void);
|
||
void run (void);
|
||
|
||
/* semantic value type */
|
||
typedef struct _node_t node_t;
|
||
struct _node_t {
|
||
int type;
|
||
union {
|
||
struct {
|
||
node_t *child1, *child2, *child3;
|
||
} child;
|
||
char *name;
|
||
double value;
|
||
} content;
|
||
};
|
||
}</code></pre>
|
||
<ul>
|
||
<li><code>yylex</code> is shared by the parser implementation file and
|
||
scanner file.</li>
|
||
<li><code>yyparse</code> and <code>run</code> is called by
|
||
<code>run_cb</code> in <code>turtleapplication.c</code>.</li>
|
||
<li><code>node_t</code> is the type of the semantic value of nterms. The
|
||
header file defines <code>YYSTYPE</code>, which is the semantic value
|
||
type, with all the token and nterm value types. The following is
|
||
extracted from the header file.</li>
|
||
</ul>
|
||
<div class="sourceCode" id="cb15"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* Value type. */</span></span>
|
||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED</span></span>
|
||
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> YYSTYPE</span>
|
||
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
|
||
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span> ID<span class="op">;</span> <span class="co">/* ID */</span></span>
|
||
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> NUM<span class="op">;</span> <span class="co">/* NUM */</span></span>
|
||
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> program<span class="op">;</span> <span class="co">/* program */</span></span>
|
||
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> statement<span class="op">;</span> <span class="co">/* statement */</span></span>
|
||
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> primary_procedure<span class="op">;</span> <span class="co">/* primary_procedure */</span></span>
|
||
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> primary_procedure_list<span class="op">;</span> <span class="co">/* primary_procedure_list */</span></span>
|
||
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> procedure_definition<span class="op">;</span> <span class="co">/* procedure_definition */</span></span>
|
||
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> parameter_list<span class="op">;</span> <span class="co">/* parameter_list */</span></span>
|
||
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> argument_list<span class="op">;</span> <span class="co">/* argument_list */</span></span>
|
||
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span> expression<span class="op">;</span> <span class="co">/* expression */</span></span>
|
||
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
||
<p>Other useful macros and declarations are put into the
|
||
<code>%code</code> directive.</p>
|
||
<pre><code>%code {
|
||
/* The following macro is convenient to get the member of the node. */
|
||
#define child1(n) (n)->content.child.child1
|
||
#define child2(n) (n)->content.child.child2
|
||
#define child3(n) (n)->content.child.child3
|
||
#define name(n) (n)->content.name
|
||
#define value(n) (n)->content.value
|
||
|
||
/* start of nodes */
|
||
static node_t *node_top = NULL;
|
||
/* functions to generate trees */
|
||
static node_t *tree1 (int type, node_t *child1, node_t *child2, node_t *child3);
|
||
static node_t *tree2 (int type, double value);
|
||
static node_t *tree3 (int type, char *name);
|
||
}</code></pre>
|
||
<h3 id="bison-declarations">Bison declarations</h3>
|
||
<p>Bison declarations defines terminal and non-terminal symbols. It also
|
||
specifies some directives.</p>
|
||
<pre><code>%locations
|
||
%define api.value.type union /* YYSTYPE, the type of semantic values, is union of following types */
|
||
/* key words */
|
||
%token PU
|
||
%token PD
|
||
%token PW
|
||
%token FD
|
||
%token TR
|
||
%token TL /* ver 0.5 */
|
||
%token BC
|
||
%token FC
|
||
%token DP
|
||
%token IF
|
||
%token RT
|
||
%token RS
|
||
%token RP /* ver 0.5 */
|
||
/* constant */
|
||
%token <double> NUM
|
||
/* identifier */
|
||
%token <char *> ID
|
||
/* non terminal symbol */
|
||
%nterm <node_t *> program
|
||
%nterm <node_t *> statement
|
||
%nterm <node_t *> primary_procedure
|
||
%nterm <node_t *> primary_procedure_list
|
||
%nterm <node_t *> procedure_definition
|
||
%nterm <node_t *> parameter_list
|
||
%nterm <node_t *> argument_list
|
||
%nterm <node_t *> expression
|
||
/* logical relation symbol */
|
||
%left '=' '<' '>'
|
||
/* arithmetic symbol */
|
||
%left '+' '-'
|
||
%left '*' '/'
|
||
%precedence UMINUS /* unary minus */</code></pre>
|
||
<p><code>%locations</code> directive inserts the location structure into
|
||
the header file. It is like this.</p>
|
||
<div class="sourceCode" id="cb18"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">typedef</span> <span class="kw">struct</span> YYLTYPE YYLTYPE<span class="op">;</span></span>
|
||
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> YYLTYPE</span>
|
||
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
|
||
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> first_line<span class="op">;</span></span>
|
||
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> first_column<span class="op">;</span></span>
|
||
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> last_line<span class="op">;</span></span>
|
||
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> last_column<span class="op">;</span></span>
|
||
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
|
||
<p>This type is shared by the scanner file and the parser implementation
|
||
file. The error report function <code>yyerror</code> uses it so that it
|
||
can inform the location that error occurs.</p>
|
||
<p><code>%define api.value.type union</code> generates semantic value
|
||
type with tokens and nterms and inserts it to the header file. The
|
||
inserted part is shown in the previous subsection as the extracts that
|
||
shows the value type (YYSTYPE).</p>
|
||
<p><code>%token</code> and <code>%nterm</code> directives define tokens
|
||
and non terminal symbols respectively.</p>
|
||
<pre><code>%token PU
|
||
... ...
|
||
%token <double> NUM</code></pre>
|
||
<p>These directives define a token <code>PU</code> and <code>NUM</code>.
|
||
The values of token kinds <code>PU</code> and <code>NUM</code> are
|
||
defined as an enumeration constant in the header file.</p>
|
||
<pre><code> enum yytokentype
|
||
{
|
||
... ... ...
|
||
PU = 258, /* PU */
|
||
... ... ...
|
||
NUM = 269, /* NUM */
|
||
... ... ...
|
||
};
|
||
typedef enum yytokentype yytoken_kind_t;</code></pre>
|
||
<p>In addition, the type of the semantic value of <code>NUM</code> is
|
||
defined as double in the header file because of
|
||
<code><double></code> tag.</p>
|
||
<pre><code>union YYSTYPE
|
||
{
|
||
char * ID; /* ID */
|
||
double NUM; /* NUM */
|
||
... ...
|
||
}</code></pre>
|
||
<p>All the nterm symbols have the same type <code>*node_t</code> of the
|
||
semantic value.</p>
|
||
<p><code>%left</code> and <code>%precedence</code> directives define the
|
||
precedence of operation symbols.</p>
|
||
<pre><code> /* logical relation symbol */
|
||
%left '=' '<' '>'
|
||
/* arithmetic symbol */
|
||
%left '+' '-'
|
||
%left '*' '/'
|
||
%precedence UMINUS /* unary minus */</code></pre>
|
||
<p><code>%left</code> directive defines the following symbols as
|
||
left-associated operators. If an operator <code>+</code> is
|
||
left-associated, then</p>
|
||
<pre><code>A + B + C = (A + B) + C</code></pre>
|
||
<p>That is, the calculation is carried out the left operator first, then
|
||
the right operator. If an operator <code>*</code> is right-associated,
|
||
then:</p>
|
||
<pre><code>A * B * C = A * (B * C)</code></pre>
|
||
<p>The definition above decides the behavior of the parser. Addition and
|
||
multiplication hold associative law so the result of
|
||
<code>(A+B)+C</code> and <code>A+(B+C)</code> are equal in terms of
|
||
mathematics. However, the parser will be confused if left (or right)
|
||
associativity is not specified.</p>
|
||
<p><code>%left</code> and <code>%precedence</code> directives show the
|
||
precedence of operators. Later declared operators have higher precedence
|
||
than former declared ones. The declaration above says, for example,</p>
|
||
<pre><code>v=w+z*5+7 is the same as v=((w+(z*5))+7)</code></pre>
|
||
<p>Be careful. The operator <code>=</code> above is an assignment.
|
||
Assignment is not expression in turtle language. It is
|
||
primary_procedure. But if <code>=</code> appears in an expression, it is
|
||
a logical operator, not an assignment. The logical equal
|
||
‘<code>=</code>’ usually used in the conditional expression, for
|
||
example, in <code>if</code> statement. (Turtle language uses ‘=’ instead
|
||
of ‘==’ in C language).</p>
|
||
<h3 id="grammar-rules">Grammar rules</h3>
|
||
<p>Grammar rules section defines the syntactic grammar of the language.
|
||
It is similar to BNF form.</p>
|
||
<pre><code>result: components { action };</code></pre>
|
||
<ul>
|
||
<li>result is a nterm.</li>
|
||
<li>components are list of tokens or nterms.</li>
|
||
<li>action is C codes. It is executed whenever the components are
|
||
reduced to the result. Action can be left out.</li>
|
||
</ul>
|
||
<p>The following is a part of the grammar rule in <code>turtle.y</code>.
|
||
But it is not exactly the same.</p>
|
||
<pre><code>program:
|
||
statement { node_top = $$ = $1; }
|
||
;
|
||
statement:
|
||
primary_procedure
|
||
;
|
||
primary_procedure:
|
||
FD expression { $$ = tree1 (N_FD, $2, NULL, NULL); }
|
||
;
|
||
expression:
|
||
NUM { $$ = tree2 (N_NUM, $1); }
|
||
;</code></pre>
|
||
<ul>
|
||
<li>The first two lines tell that <code>program</code> is
|
||
<code>statement</code>.</li>
|
||
<li>Whenever <code>statement</code> is reduced to <code>program</code>,
|
||
an action <code>node_top=$$=$1;</code> is executed.</li>
|
||
<li><code>node_top</code> is a static variable. It points the top node
|
||
of the tree.</li>
|
||
<li>The symbol <code>$$</code> is a semantic value of the result. For
|
||
example, <code>$$</code> in line 2 is the semantic value of
|
||
<code>program</code>. It is a pointer to a <code>node_t</code> type
|
||
structure.</li>
|
||
<li>The symbol <code>$1</code> is a semantic value of the first
|
||
component. For example, <code>$1</code> in line 2 is the semantic value
|
||
of <code>statement</code>. It is also a pointer to
|
||
<code>node_t</code>.</li>
|
||
<li>The next rule is that <code>statement</code> is
|
||
<code>primary_procedure</code>. There’s no action specified. Then, the
|
||
default action <code>$$ = $1</code> is executed.</li>
|
||
<li>The next rule is that <code>primary_procedure</code> is
|
||
<code>FD</code> followed by expression. The action calls
|
||
<code>tree1</code> and assigns its return value to <code>$$</code>. The
|
||
function <code>tree1</code> makes a tree node. The tree node has type
|
||
and union of three pointers to children nodes, string or double.</li>
|
||
</ul>
|
||
<pre><code>node --+-- type
|
||
+-- union contents
|
||
+---struct {node_t *child1, *child2, *child3;};
|
||
+---char *name
|
||
+---double value</code></pre>
|
||
<ul>
|
||
<li><code>tree1</code> assigns the four arguments to type, child1,
|
||
child2 and child3 members.</li>
|
||
<li>The last rule is that <code>expression</code> is
|
||
<code>NUM</code>.</li>
|
||
<li><code>tree2</code> makes a tree node. The paremeters of
|
||
<code>tree2</code> are a type and a semantic value.</li>
|
||
</ul>
|
||
<p>Suppose the parser reads the following program.</p>
|
||
<pre><code>fd 100</code></pre>
|
||
<p>What does the parser do?</p>
|
||
<ol type="1">
|
||
<li>The parser recognizes the input is <code>FD</code>. Maybe it is the
|
||
start of <code>primary_procedure</code>, but parser needs to read the
|
||
next token.</li>
|
||
<li><code>yylex</code> returns the token kind <code>NUM</code> and sets
|
||
<code>yylval.NUM</code> to 100.0 (the type is double). The parser
|
||
reduces <code>NUM</code> to <code>expression</code>. At the same time,
|
||
it sets the semantic value of the <code>expression</code> to point a new
|
||
node. The node has the type <code>N_NUM</code> and a semantic value
|
||
100.0.</li>
|
||
<li>After the reduction, the buffer has <code>FD</code> and
|
||
<code>expression</code>. The parser reduces it to
|
||
<code>primary_procedure</code>. And it sets the semantic value of the
|
||
<code>primary_procedure</code> to point a new node. The node has the
|
||
type <code>N_FD</code> and its member child1 points the node of
|
||
<code>expression</code>, whose type is <code>N_NUM</code>.</li>
|
||
<li>The parser reduces <code>primary_procedure</code> to
|
||
<code>statement</code>. The semantic value of <code>statement</code> is
|
||
the same as the one of <code>primary_procedure</code>, which points to
|
||
the node <code>N_FD</code>.</li>
|
||
<li>The parser reduces <code>statement</code> to <code>program</code>.
|
||
The semantic value of <code>statement</code> is assigned to the one of
|
||
<code>program</code> and the static variable <code>node_top</code>.</li>
|
||
<li>Finally <code>node_top</code> points the node <code>N_FD</code> and
|
||
the node <code>N_FD</code> points the node <code>N_NUM</code>.</li>
|
||
</ol>
|
||
<figure>
|
||
<img src="image/tree.png" alt="tree" />
|
||
<figcaption aria-hidden="true">tree</figcaption>
|
||
</figure>
|
||
<p>The following is the grammar rule extracted from
|
||
<code>turtle.y</code>. The rules there are based on the same idea above.
|
||
I don’t want to explain the whole rules below. Please look into each
|
||
line carefully so that you will understand all the rules and
|
||
actions.</p>
|
||
<div class="sourceCode" id="cb30"><pre
|
||
class="sourceCode yacc"><code class="sourceCode yacc"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a>program:</span>
|
||
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a> statement { node_top = $$ = $1; }</span>
|
||
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>| program statement {</span>
|
||
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a> node_top = $$ = tree1 (N_program, $1, $2, NULL);</span>
|
||
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>#ifdef debug</span>
|
||
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a>if (node_top == NULL) g_printerr ("program: node_top is NULL.\n"); else g_printerr ("program: node_top is NOT NULL.\n");</span>
|
||
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a>#endif</span>
|
||
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a>statement:</span>
|
||
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a> primary_procedure</span>
|
||
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a>| procedure_definition</span>
|
||
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a>primary_procedure:</span>
|
||
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a> PU { $$ = tree1 (N_PU, NULL, NULL, NULL); }</span>
|
||
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true" tabindex="-1"></a>| PD { $$ = tree1 (N_PD, NULL, NULL, NULL); }</span>
|
||
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a>| PW expression { $$ = tree1 (N_PW, $2, NULL, NULL); }</span>
|
||
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true" tabindex="-1"></a>| FD expression { $$ = tree1 (N_FD, $2, NULL, NULL); }</span>
|
||
<span id="cb30-21"><a href="#cb30-21" aria-hidden="true" tabindex="-1"></a>| TR expression { $$ = tree1 (N_TR, $2, NULL, NULL); }</span>
|
||
<span id="cb30-22"><a href="#cb30-22" aria-hidden="true" tabindex="-1"></a>| TL expression { $$ = tree1 (N_TL, $2, NULL, NULL); } <span class="co">/* ver 0.5 */</span></span>
|
||
<span id="cb30-23"><a href="#cb30-23" aria-hidden="true" tabindex="-1"></a>| BC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_BC, $3, $5, $7); }</span>
|
||
<span id="cb30-24"><a href="#cb30-24" aria-hidden="true" tabindex="-1"></a>| FC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_FC, $3, $5, $7); }</span>
|
||
<span id="cb30-25"><a href="#cb30-25" aria-hidden="true" tabindex="-1"></a> <span class="co">/* assignment */</span></span>
|
||
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true" tabindex="-1"></a>| ID '=' expression { $$ = tree1 (N_ASSIGN, tree3 (N_ID, $1), $3, NULL); }</span>
|
||
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true" tabindex="-1"></a> <span class="co">/* control flow */</span></span>
|
||
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true" tabindex="-1"></a>| IF '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_IF, $3, $6, NULL); }</span>
|
||
<span id="cb30-29"><a href="#cb30-29" aria-hidden="true" tabindex="-1"></a>| RT { $$ = tree1 (N_RT, NULL, NULL, NULL); }</span>
|
||
<span id="cb30-30"><a href="#cb30-30" aria-hidden="true" tabindex="-1"></a>| RS { $$ = tree1 (N_RS, NULL, NULL, NULL); }</span>
|
||
<span id="cb30-31"><a href="#cb30-31" aria-hidden="true" tabindex="-1"></a>| RP '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_RP, $3, $6, NULL); }</span>
|
||
<span id="cb30-32"><a href="#cb30-32" aria-hidden="true" tabindex="-1"></a> <span class="co">/* user defined procedure call */</span></span>
|
||
<span id="cb30-33"><a href="#cb30-33" aria-hidden="true" tabindex="-1"></a>| ID '(' ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), NULL, NULL); }</span>
|
||
<span id="cb30-34"><a href="#cb30-34" aria-hidden="true" tabindex="-1"></a>| ID '(' argument_list ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), $3, NULL); }</span>
|
||
<span id="cb30-35"><a href="#cb30-35" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-36"><a href="#cb30-36" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-37"><a href="#cb30-37" aria-hidden="true" tabindex="-1"></a>procedure_definition:</span>
|
||
<span id="cb30-38"><a href="#cb30-38" aria-hidden="true" tabindex="-1"></a> DP ID '(' ')' '{' primary_procedure_list '}' {</span>
|
||
<span id="cb30-39"><a href="#cb30-39" aria-hidden="true" tabindex="-1"></a> $$ = tree1 (N_procedure_definition, tree3 (N_ID, $2), NULL, $6);</span>
|
||
<span id="cb30-40"><a href="#cb30-40" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb30-41"><a href="#cb30-41" aria-hidden="true" tabindex="-1"></a>| DP ID '(' parameter_list ')' '{' primary_procedure_list '}' {</span>
|
||
<span id="cb30-42"><a href="#cb30-42" aria-hidden="true" tabindex="-1"></a> $$ = tree1 (N_procedure_definition, tree3 (N_ID, $2), $4, $7);</span>
|
||
<span id="cb30-43"><a href="#cb30-43" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb30-44"><a href="#cb30-44" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-45"><a href="#cb30-45" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-46"><a href="#cb30-46" aria-hidden="true" tabindex="-1"></a>parameter_list:</span>
|
||
<span id="cb30-47"><a href="#cb30-47" aria-hidden="true" tabindex="-1"></a> ID { $$ = tree3 (N_ID, $1); }</span>
|
||
<span id="cb30-48"><a href="#cb30-48" aria-hidden="true" tabindex="-1"></a>| parameter_list ',' ID { $$ = tree1 (N_parameter_list, $1, tree3 (N_ID, $3), NULL); }</span>
|
||
<span id="cb30-49"><a href="#cb30-49" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-50"><a href="#cb30-50" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-51"><a href="#cb30-51" aria-hidden="true" tabindex="-1"></a>argument_list:</span>
|
||
<span id="cb30-52"><a href="#cb30-52" aria-hidden="true" tabindex="-1"></a> expression</span>
|
||
<span id="cb30-53"><a href="#cb30-53" aria-hidden="true" tabindex="-1"></a>| argument_list ',' expression { $$ = tree1 (N_argument_list, $1, $3, NULL); }</span>
|
||
<span id="cb30-54"><a href="#cb30-54" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-55"><a href="#cb30-55" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-56"><a href="#cb30-56" aria-hidden="true" tabindex="-1"></a>primary_procedure_list:</span>
|
||
<span id="cb30-57"><a href="#cb30-57" aria-hidden="true" tabindex="-1"></a> primary_procedure</span>
|
||
<span id="cb30-58"><a href="#cb30-58" aria-hidden="true" tabindex="-1"></a>| primary_procedure_list primary_procedure {</span>
|
||
<span id="cb30-59"><a href="#cb30-59" aria-hidden="true" tabindex="-1"></a> $$ = tree1 (N_primary_procedure_list, $1, $2, NULL);</span>
|
||
<span id="cb30-60"><a href="#cb30-60" aria-hidden="true" tabindex="-1"></a> }</span>
|
||
<span id="cb30-61"><a href="#cb30-61" aria-hidden="true" tabindex="-1"></a>;</span>
|
||
<span id="cb30-62"><a href="#cb30-62" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-63"><a href="#cb30-63" aria-hidden="true" tabindex="-1"></a>expression:</span>
|
||
<span id="cb30-64"><a href="#cb30-64" aria-hidden="true" tabindex="-1"></a> expression '=' expression { $$ = tree1 (N_EQ, $1, $3, NULL); }</span>
|
||
<span id="cb30-65"><a href="#cb30-65" aria-hidden="true" tabindex="-1"></a>| expression '>' expression { $$ = tree1 (N_GT, $1, $3, NULL); }</span>
|
||
<span id="cb30-66"><a href="#cb30-66" aria-hidden="true" tabindex="-1"></a>| expression '<' expression { $$ = tree1 (N_LT, $1, $3, NULL); }</span>
|
||
<span id="cb30-67"><a href="#cb30-67" aria-hidden="true" tabindex="-1"></a>| expression '+' expression { $$ = tree1 (N_ADD, $1, $3, NULL); }</span>
|
||
<span id="cb30-68"><a href="#cb30-68" aria-hidden="true" tabindex="-1"></a>| expression '-' expression { $$ = tree1 (N_SUB, $1, $3, NULL); }</span>
|
||
<span id="cb30-69"><a href="#cb30-69" aria-hidden="true" tabindex="-1"></a>| expression '*' expression { $$ = tree1 (N_MUL, $1, $3, NULL); }</span>
|
||
<span id="cb30-70"><a href="#cb30-70" aria-hidden="true" tabindex="-1"></a>| expression '/' expression { $$ = tree1 (N_DIV, $1, $3, NULL); }</span>
|
||
<span id="cb30-71"><a href="#cb30-71" aria-hidden="true" tabindex="-1"></a>| '-' expression <span class="kw">%prec</span> UMINUS { $$ = tree1 (N_UMINUS, $2, NULL, NULL); }</span>
|
||
<span id="cb30-72"><a href="#cb30-72" aria-hidden="true" tabindex="-1"></a>| '(' expression ')' { $$ = $2; }</span>
|
||
<span id="cb30-73"><a href="#cb30-73" aria-hidden="true" tabindex="-1"></a>| ID { $$ = tree3 (N_ID, $1); }</span>
|
||
<span id="cb30-74"><a href="#cb30-74" aria-hidden="true" tabindex="-1"></a>| NUM { $$ = tree2 (N_NUM, $1); }</span>
|
||
<span id="cb30-75"><a href="#cb30-75" aria-hidden="true" tabindex="-1"></a>;</span></code></pre></div>
|
||
<h3 id="epilogue">Epilogue</h3>
|
||
<p>The epilogue is written in C language and copied to the parser
|
||
implementation file. Generally, you can put anything into the epilogue.
|
||
In the case of turtle interpreter, the runtime routine and some other
|
||
functions are in the epilogue.</p>
|
||
<h4 id="functions-to-create-tree-nodes">Functions to create tree
|
||
nodes</h4>
|
||
<p>There are three functions, <code>tree1</code>, <code>tree2</code> and
|
||
<code>tree3</code>.</p>
|
||
<ul>
|
||
<li><code>tree1</code> creates a node and sets the node type and
|
||
pointers to its three children (NULL is possible).</li>
|
||
<li><code>tree2</code> creates a node and sets the node type and a value
|
||
(double).</li>
|
||
<li><code>tree3</code> creates a node and sets the node type and a
|
||
pointer to a string.</li>
|
||
</ul>
|
||
<p>Each function gets memories first and build a node on them. The
|
||
memories are inserted to the list. They will be freed when runtime
|
||
routine finishes.</p>
|
||
<p>The three functions are called in the actions in the rules
|
||
section.</p>
|
||
<div class="sourceCode" id="cb31"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* Dynamically allocated memories are added to the single list. They will be freed in the finalize function. */</span></span>
|
||
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>GSList <span class="op">*</span>list <span class="op">=</span> NULL<span class="op">;</span></span>
|
||
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a>tree1 <span class="op">(</span><span class="dt">int</span> type<span class="op">,</span> node_t <span class="op">*</span>child1<span class="op">,</span> node_t <span class="op">*</span>child2<span class="op">,</span> node_t <span class="op">*</span>child3<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>new_node<span class="op">;</span></span>
|
||
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a> list <span class="op">=</span> g_slist_prepend <span class="op">(</span>list<span class="op">,</span> g_malloc <span class="op">(</span><span class="kw">sizeof</span> <span class="op">(</span>node_t<span class="op">)));</span></span>
|
||
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a> new_node <span class="op">=</span> <span class="op">(</span>node_t <span class="op">*)</span> list<span class="op">-></span>data<span class="op">;</span></span>
|
||
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a> new_node<span class="op">-></span>type <span class="op">=</span> type<span class="op">;</span></span>
|
||
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a> child1<span class="op">(</span>new_node<span class="op">)</span> <span class="op">=</span> child1<span class="op">;</span></span>
|
||
<span id="cb31-12"><a href="#cb31-12" aria-hidden="true" tabindex="-1"></a> child2<span class="op">(</span>new_node<span class="op">)</span> <span class="op">=</span> child2<span class="op">;</span></span>
|
||
<span id="cb31-13"><a href="#cb31-13" aria-hidden="true" tabindex="-1"></a> child3<span class="op">(</span>new_node<span class="op">)</span> <span class="op">=</span> child3<span class="op">;</span></span>
|
||
<span id="cb31-14"><a href="#cb31-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> new_node<span class="op">;</span></span>
|
||
<span id="cb31-15"><a href="#cb31-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb31-16"><a href="#cb31-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-17"><a href="#cb31-17" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb31-18"><a href="#cb31-18" aria-hidden="true" tabindex="-1"></a>tree2 <span class="op">(</span><span class="dt">int</span> type<span class="op">,</span> <span class="dt">double</span> value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb31-19"><a href="#cb31-19" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>new_node<span class="op">;</span></span>
|
||
<span id="cb31-20"><a href="#cb31-20" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-21"><a href="#cb31-21" aria-hidden="true" tabindex="-1"></a> list <span class="op">=</span> g_slist_prepend <span class="op">(</span>list<span class="op">,</span> g_malloc <span class="op">(</span><span class="kw">sizeof</span> <span class="op">(</span>node_t<span class="op">)));</span></span>
|
||
<span id="cb31-22"><a href="#cb31-22" aria-hidden="true" tabindex="-1"></a> new_node <span class="op">=</span> <span class="op">(</span>node_t <span class="op">*)</span> list<span class="op">-></span>data<span class="op">;</span></span>
|
||
<span id="cb31-23"><a href="#cb31-23" aria-hidden="true" tabindex="-1"></a> new_node<span class="op">-></span>type <span class="op">=</span> type<span class="op">;</span></span>
|
||
<span id="cb31-24"><a href="#cb31-24" aria-hidden="true" tabindex="-1"></a> value<span class="op">(</span>new_node<span class="op">)</span> <span class="op">=</span> value<span class="op">;</span></span>
|
||
<span id="cb31-25"><a href="#cb31-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> new_node<span class="op">;</span></span>
|
||
<span id="cb31-26"><a href="#cb31-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb31-27"><a href="#cb31-27" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-28"><a href="#cb31-28" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb31-29"><a href="#cb31-29" aria-hidden="true" tabindex="-1"></a>tree3 <span class="op">(</span><span class="dt">int</span> type<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>name<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb31-30"><a href="#cb31-30" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>new_node<span class="op">;</span></span>
|
||
<span id="cb31-31"><a href="#cb31-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-32"><a href="#cb31-32" aria-hidden="true" tabindex="-1"></a> list <span class="op">=</span> g_slist_prepend <span class="op">(</span>list<span class="op">,</span> g_malloc <span class="op">(</span><span class="kw">sizeof</span> <span class="op">(</span>node_t<span class="op">)));</span></span>
|
||
<span id="cb31-33"><a href="#cb31-33" aria-hidden="true" tabindex="-1"></a> new_node <span class="op">=</span> <span class="op">(</span>node_t <span class="op">*)</span> list<span class="op">-></span>data<span class="op">;</span></span>
|
||
<span id="cb31-34"><a href="#cb31-34" aria-hidden="true" tabindex="-1"></a> new_node<span class="op">-></span>type <span class="op">=</span> type<span class="op">;</span></span>
|
||
<span id="cb31-35"><a href="#cb31-35" aria-hidden="true" tabindex="-1"></a> name<span class="op">(</span>new_node<span class="op">)</span> <span class="op">=</span> name<span class="op">;</span></span>
|
||
<span id="cb31-36"><a href="#cb31-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> new_node<span class="op">;</span></span>
|
||
<span id="cb31-37"><a href="#cb31-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<h4 id="symbol-table">Symbol table</h4>
|
||
<p>Variables and user defined procedures are registered in the symbol
|
||
table. This table is a C array. It should be replaced by better
|
||
algorithm and data structure, for example hash, in the future
|
||
version</p>
|
||
<ul>
|
||
<li>Variables are registered with its name and value.</li>
|
||
<li>Procedures are registered with its name and a pointer to the node of
|
||
the procedure.</li>
|
||
</ul>
|
||
<p>Therefore the table has the following fields.</p>
|
||
<ul>
|
||
<li>type to identify variable or procedure</li>
|
||
<li>name</li>
|
||
<li>value or pointer to a node</li>
|
||
</ul>
|
||
<div class="sourceCode" id="cb32"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define MAX_TABLE_SIZE 100</span></span>
|
||
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span></span>
|
||
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> PROC<span class="op">,</span></span>
|
||
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a> VAR</span>
|
||
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <span class="op">{</span></span>
|
||
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> type<span class="op">;</span></span>
|
||
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">union</span> <span class="op">{</span></span>
|
||
<span id="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>node<span class="op">;</span></span>
|
||
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> value<span class="op">;</span></span>
|
||
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> object<span class="op">;</span></span>
|
||
<span id="cb32-14"><a href="#cb32-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> table<span class="op">[</span>MAX_TABLE_SIZE<span class="op">];</span></span>
|
||
<span id="cb32-15"><a href="#cb32-15" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> tp<span class="op">;</span></span>
|
||
<span id="cb32-16"><a href="#cb32-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-17"><a href="#cb32-17" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb32-18"><a href="#cb32-18" aria-hidden="true" tabindex="-1"></a>init_table <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a> tp <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb32-20"><a href="#cb32-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The function <code>init_table</code> initializes the table. This must
|
||
be called before registrations.</p>
|
||
<p>There are five functions to access the table,</p>
|
||
<ul>
|
||
<li><code>proc_install</code> installs a procedure.</li>
|
||
<li><code>var_install</code> installs a variable.</li>
|
||
<li><code>proc_lookup</code> looks up a procedure. If the procedure is
|
||
found, it returns a pointer to the node. Otherwise it returns NULL.</li>
|
||
<li><code>var_lookup</code> looks up a variable. If the variable is
|
||
found, it returns TRUE and sets the pointer (argument) to point the
|
||
value. Otherwise it returns FALSE.</li>
|
||
<li><code>var_replace</code> replaces the value of a variable. If the
|
||
variable hasn’t registered yet, it installs the variable.</li>
|
||
</ul>
|
||
<div class="sourceCode" id="cb33"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
|
||
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>tbl_lookup <span class="op">(</span><span class="dt">int</span> type<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>name<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>tp <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op"><</span>tp<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span></span>
|
||
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>type <span class="op">==</span> table<span class="op">[</span>i<span class="op">].</span>type <span class="op">&&</span> strcmp<span class="op">(</span>name<span class="op">,</span> table<span class="op">[</span>i<span class="op">].</span>name<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> i<span class="op">;</span></span>
|
||
<span id="cb33-10"><a href="#cb33-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb33-11"><a href="#cb33-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb33-12"><a href="#cb33-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-13"><a href="#cb33-13" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb33-14"><a href="#cb33-14" aria-hidden="true" tabindex="-1"></a>tbl_install <span class="op">(</span><span class="dt">int</span> type<span class="op">,</span> <span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> node_t <span class="op">*</span>node<span class="op">,</span> <span class="dt">double</span> value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-15"><a href="#cb33-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>tp <span class="op">>=</span> MAX_TABLE_SIZE<span class="op">)</span></span>
|
||
<span id="cb33-16"><a href="#cb33-16" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Symbol table overflow.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb33-17"><a href="#cb33-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>tbl_lookup <span class="op">(</span>type<span class="op">,</span> name<span class="op">)</span> <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb33-18"><a href="#cb33-18" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Name %s is already registered.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> name<span class="op">);</span></span>
|
||
<span id="cb33-19"><a href="#cb33-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb33-20"><a href="#cb33-20" aria-hidden="true" tabindex="-1"></a> table<span class="op">[</span>tp<span class="op">].</span>type <span class="op">=</span> type<span class="op">;</span></span>
|
||
<span id="cb33-21"><a href="#cb33-21" aria-hidden="true" tabindex="-1"></a> table<span class="op">[</span>tp<span class="op">].</span>name <span class="op">=</span> name<span class="op">;</span></span>
|
||
<span id="cb33-22"><a href="#cb33-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>type <span class="op">==</span> PROC<span class="op">)</span></span>
|
||
<span id="cb33-23"><a href="#cb33-23" aria-hidden="true" tabindex="-1"></a> table<span class="op">[</span>tp<span class="op">++].</span>object<span class="op">.</span>node <span class="op">=</span> node<span class="op">;</span></span>
|
||
<span id="cb33-24"><a href="#cb33-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb33-25"><a href="#cb33-25" aria-hidden="true" tabindex="-1"></a> table<span class="op">[</span>tp<span class="op">++].</span>object<span class="op">.</span>value <span class="op">=</span> value<span class="op">;</span></span>
|
||
<span id="cb33-26"><a href="#cb33-26" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb33-27"><a href="#cb33-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb33-28"><a href="#cb33-28" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-29"><a href="#cb33-29" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb33-30"><a href="#cb33-30" aria-hidden="true" tabindex="-1"></a>proc_install <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> node_t <span class="op">*</span>node<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-31"><a href="#cb33-31" aria-hidden="true" tabindex="-1"></a> tbl_install <span class="op">(</span>PROC<span class="op">,</span> name<span class="op">,</span> node<span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
|
||
<span id="cb33-32"><a href="#cb33-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb33-33"><a href="#cb33-33" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-34"><a href="#cb33-34" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb33-35"><a href="#cb33-35" aria-hidden="true" tabindex="-1"></a>var_install <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> <span class="dt">double</span> value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-36"><a href="#cb33-36" aria-hidden="true" tabindex="-1"></a> tbl_install <span class="op">(</span>VAR<span class="op">,</span> name<span class="op">,</span> NULL<span class="op">,</span> value<span class="op">);</span></span>
|
||
<span id="cb33-37"><a href="#cb33-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb33-38"><a href="#cb33-38" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-39"><a href="#cb33-39" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb33-40"><a href="#cb33-40" aria-hidden="true" tabindex="-1"></a>var_replace <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> <span class="dt">double</span> value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-41"><a href="#cb33-41" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb33-42"><a href="#cb33-42" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">((</span>i <span class="op">=</span> tbl_lookup <span class="op">(</span>VAR<span class="op">,</span> name<span class="op">))</span> <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb33-43"><a href="#cb33-43" aria-hidden="true" tabindex="-1"></a> table<span class="op">[</span>i<span class="op">].</span>object<span class="op">.</span>value <span class="op">=</span> value<span class="op">;</span></span>
|
||
<span id="cb33-44"><a href="#cb33-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb33-45"><a href="#cb33-45" aria-hidden="true" tabindex="-1"></a> var_install <span class="op">(</span>name<span class="op">,</span> value<span class="op">);</span></span>
|
||
<span id="cb33-46"><a href="#cb33-46" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb33-47"><a href="#cb33-47" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-48"><a href="#cb33-48" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb33-49"><a href="#cb33-49" aria-hidden="true" tabindex="-1"></a>proc_lookup <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-50"><a href="#cb33-50" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb33-51"><a href="#cb33-51" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">((</span>i <span class="op">=</span> tbl_lookup <span class="op">(</span>PROC<span class="op">,</span> name<span class="op">))</span> <span class="op"><</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb33-52"><a href="#cb33-52" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
|
||
<span id="cb33-53"><a href="#cb33-53" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb33-54"><a href="#cb33-54" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> table<span class="op">[</span>i<span class="op">].</span>object<span class="op">.</span>node<span class="op">;</span></span>
|
||
<span id="cb33-55"><a href="#cb33-55" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb33-56"><a href="#cb33-56" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-57"><a href="#cb33-57" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb33-58"><a href="#cb33-58" aria-hidden="true" tabindex="-1"></a>var_lookup <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> <span class="dt">double</span> <span class="op">*</span>value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb33-59"><a href="#cb33-59" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb33-60"><a href="#cb33-60" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">((</span>i <span class="op">=</span> tbl_lookup <span class="op">(</span>VAR<span class="op">,</span> name<span class="op">))</span> <span class="op"><</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb33-61"><a href="#cb33-61" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb33-62"><a href="#cb33-62" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb33-63"><a href="#cb33-63" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span>value <span class="op">=</span> table<span class="op">[</span>i<span class="op">].</span>object<span class="op">.</span>value<span class="op">;</span></span>
|
||
<span id="cb33-64"><a href="#cb33-64" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb33-65"><a href="#cb33-65" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb33-66"><a href="#cb33-66" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<h4 id="stack-for-parameters-and-arguments">Stack for parameters and
|
||
arguments</h4>
|
||
<p>Stack is a last-in first-out data structure. It is shortened to LIFO.
|
||
Turtle uses a stack to keep parameters and arguments. They are like
|
||
<code>auto</code> class variables in C language. They are pushed to the
|
||
stack whenever the procedure is called. LIFO structure is useful for
|
||
recursive calls.</p>
|
||
<p>Each element of the stack has name and value.</p>
|
||
<div class="sourceCode" id="cb34"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define MAX_STACK_SIZE 500</span></span>
|
||
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <span class="op">{</span></span>
|
||
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> value<span class="op">;</span></span>
|
||
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> stack<span class="op">[</span>MAX_STACK_SIZE<span class="op">];</span></span>
|
||
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> sp<span class="op">,</span> sp_biggest<span class="op">;</span></span>
|
||
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a>init_stack <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a> sp <span class="op">=</span> sp_biggest <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb34-11"><a href="#cb34-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><code>sp</code> is a stack pointer. It is an index of the array
|
||
<code>stack</code> and it always points an element of the array to store
|
||
the next data. <code>sp_biggest</code> is the biggest number assigned to
|
||
<code>sp</code>. We can know the amount of elements used in the array
|
||
during the runtime. The purpose of the variable is to find appropriate
|
||
<code>MAX_STACK_SIZE</code>. It will be unnecessary in the future
|
||
version if the stack is implemented with better data structure and
|
||
memory allocation.</p>
|
||
<p>The runtime routine push data to the stack when it executes a node of
|
||
a procedure call. (The type of the node is
|
||
<code>N_procedure_call</code>.)</p>
|
||
<pre><code>dp drawline (angle, distance) { ... ... ... }
|
||
drawline (90, 100)</code></pre>
|
||
<ul>
|
||
<li>The first line defines a procedure <code>drawline</code>. The
|
||
runtime routine stores the name <code>drawline</code> and the node of
|
||
the procedure to the symbol table.</li>
|
||
<li>The second line calls the procedure. First, it looks for the
|
||
procedure in the symbol table and gets its node. Then it searches the
|
||
node for the parameters and gets <code>angle</code> and
|
||
<code>distance</code>.</li>
|
||
<li>It pushes (“angle”, 90.0) to the stack.</li>
|
||
<li>It pushes (“distance”, 100.0) to the stack.</li>
|
||
<li>It pushes (NULL, 2.0) to the stack. The number 2.0 is the number of
|
||
parameters (or arguments). It is used when the procedure returns.</li>
|
||
</ul>
|
||
<p>The following diagram shows the structure of the stack. First,
|
||
<code>procedure 1</code> is called. The procedure has two parameters. In
|
||
the <code>procedure 1</code>, another procedure <code>procedure 2</code>
|
||
is called. It has one parameter. In the <code>procedure 2</code>,
|
||
another procedure <code>procedure 3</code> is called. It has three
|
||
parameters. These three procedures are nested.</p>
|
||
<p>Programs push data to a stack from a low address memory to a high
|
||
address memory. In the following diagram, the lowest address is at the
|
||
top and the highest address is at the bottom. That is the order of the
|
||
address. However, “the top of the stack” is the last pushed data and
|
||
“the bottom of the stack” is the first pushed data. Therefore, “the top
|
||
of the stack” is the bottom of the rectangle in the diagram and “the
|
||
bottom of the stack” is the top of the rectangle.</p>
|
||
<figure>
|
||
<img src="image/stack.png" alt="Stack" />
|
||
<figcaption aria-hidden="true">Stack</figcaption>
|
||
</figure>
|
||
<p>There are four functions to access the stack.</p>
|
||
<ul>
|
||
<li><code>stack_push</code> pushes data to the stack.</li>
|
||
<li><code>stack_lookup</code> searches the stack for the variable given
|
||
its name as an argument. It searches only the parameters of the latest
|
||
procedure. It returns TRUE and sets the argument <code>value</code> to
|
||
point the value, if the variable has been found. Otherwise it returns
|
||
FALSE.</li>
|
||
<li><code>stack_replace</code> replaces the value of the variable in the
|
||
stack. If it succeeds, it returns TRUE. Otherwise returns FALSE.</li>
|
||
<li><code>stack_return</code> throws away the latest parameters. The
|
||
stack pointer goes back to the point before the latest procedure call so
|
||
that it points to parameters of the previous called procedure.</li>
|
||
</ul>
|
||
<div class="sourceCode" id="cb36"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>stack_push <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> <span class="dt">double</span> value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>sp <span class="op">>=</span> MAX_STACK_SIZE<span class="op">)</span></span>
|
||
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Stack overflow.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a> stack<span class="op">[</span>sp<span class="op">].</span>name <span class="op">=</span> name<span class="op">;</span></span>
|
||
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a> stack<span class="op">[</span>sp<span class="op">++].</span>value <span class="op">=</span> value<span class="op">;</span></span>
|
||
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a> sp_biggest <span class="op">=</span> sp <span class="op">></span> sp_biggest <span class="op">?</span> sp <span class="op">:</span> sp_biggest<span class="op">;</span></span>
|
||
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
|
||
<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a>stack_search <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> depth<span class="op">,</span> i<span class="op">;</span></span>
|
||
<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>sp <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb36-17"><a href="#cb36-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb36-18"><a href="#cb36-18" aria-hidden="true" tabindex="-1"></a> depth <span class="op">=</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> stack<span class="op">[</span>sp<span class="op">-</span><span class="dv">1</span><span class="op">].</span>value<span class="op">;</span></span>
|
||
<span id="cb36-19"><a href="#cb36-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>depth <span class="op">+</span> <span class="dv">1</span> <span class="op">></span> sp<span class="op">)</span> <span class="co">/* something strange */</span></span>
|
||
<span id="cb36-20"><a href="#cb36-20" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Stack error.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb36-21"><a href="#cb36-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op"><</span>depth<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span></span>
|
||
<span id="cb36-22"><a href="#cb36-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>strcmp<span class="op">(</span>name<span class="op">,</span> stack<span class="op">[</span>sp<span class="op">-(</span>i<span class="op">+</span><span class="dv">2</span><span class="op">)].</span>name<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb36-23"><a href="#cb36-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> sp<span class="op">-(</span>i<span class="op">+</span><span class="dv">2</span><span class="op">);</span></span>
|
||
<span id="cb36-24"><a href="#cb36-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb36-25"><a href="#cb36-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb36-26"><a href="#cb36-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb36-27"><a href="#cb36-27" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-28"><a href="#cb36-28" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb36-29"><a href="#cb36-29" aria-hidden="true" tabindex="-1"></a>stack_lookup <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> <span class="dt">double</span> <span class="op">*</span>value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb36-30"><a href="#cb36-30" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb36-31"><a href="#cb36-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-32"><a href="#cb36-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">((</span>i <span class="op">=</span> stack_search <span class="op">(</span>name<span class="op">))</span> <span class="op"><</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb36-33"><a href="#cb36-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb36-34"><a href="#cb36-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb36-35"><a href="#cb36-35" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span>value <span class="op">=</span> stack<span class="op">[</span>i<span class="op">].</span>value<span class="op">;</span></span>
|
||
<span id="cb36-36"><a href="#cb36-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb36-37"><a href="#cb36-37" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb36-38"><a href="#cb36-38" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb36-39"><a href="#cb36-39" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-40"><a href="#cb36-40" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb36-41"><a href="#cb36-41" aria-hidden="true" tabindex="-1"></a>stack_replace <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>name<span class="op">,</span> <span class="dt">double</span> value<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb36-42"><a href="#cb36-42" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb36-43"><a href="#cb36-43" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-44"><a href="#cb36-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">((</span>i <span class="op">=</span> stack_search <span class="op">(</span>name<span class="op">))</span> <span class="op"><</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb36-45"><a href="#cb36-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb36-46"><a href="#cb36-46" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb36-47"><a href="#cb36-47" aria-hidden="true" tabindex="-1"></a> stack<span class="op">[</span>i<span class="op">].</span>value <span class="op">=</span> value<span class="op">;</span></span>
|
||
<span id="cb36-48"><a href="#cb36-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb36-49"><a href="#cb36-49" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb36-50"><a href="#cb36-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb36-51"><a href="#cb36-51" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-52"><a href="#cb36-52" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb36-53"><a href="#cb36-53" aria-hidden="true" tabindex="-1"></a>stack_return<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb36-54"><a href="#cb36-54" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> depth<span class="op">;</span></span>
|
||
<span id="cb36-55"><a href="#cb36-55" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb36-56"><a href="#cb36-56" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>sp <span class="op"><=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb36-57"><a href="#cb36-57" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb36-58"><a href="#cb36-58" aria-hidden="true" tabindex="-1"></a> depth <span class="op">=</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> stack<span class="op">[</span>sp<span class="op">-</span><span class="dv">1</span><span class="op">].</span>value<span class="op">;</span></span>
|
||
<span id="cb36-59"><a href="#cb36-59" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>depth <span class="op">+</span> <span class="dv">1</span> <span class="op">></span> sp<span class="op">)</span> <span class="co">/* something strange */</span></span>
|
||
<span id="cb36-60"><a href="#cb36-60" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Stack error.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb36-61"><a href="#cb36-61" aria-hidden="true" tabindex="-1"></a> sp <span class="op">-=</span> depth <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb36-62"><a href="#cb36-62" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<h4 id="surface-and-cairo">Surface and cairo</h4>
|
||
<p>A global variable <code>surface</code> is shared by
|
||
<code>turtleapplication.c</code> and <code>turtle.y</code>. It is
|
||
initialized in <code>turtleapplication.c</code>.</p>
|
||
<p>The runtime routine has its own cairo context. This is different from
|
||
the cairo in the GtkDrawingArea instance. The runtime routine draws a
|
||
shape on the <code>surface</code> with the cairo context. After runtime
|
||
routine returns to <code>run_cb</code>, <code>run_cb</code> adds the
|
||
GtkDrawingArea widget to the queue to redraw. When the widget is
|
||
redraw,the drawing function <code>draw_func</code> is called. It copies
|
||
the <code>surface</code> to the surface in the GtkDrawingArea
|
||
object.</p>
|
||
<p><code>turtle.y</code> has two functions <code>init_cairo</code> and
|
||
<code>destroy_cairo</code>.</p>
|
||
<ul>
|
||
<li><code>init_cairo</code> initializes static variables and cairo
|
||
context. The variables keep pen status (up or down), direction, initial
|
||
location, line width and color. The size of the <code>surface</code>
|
||
changes according to the size of the window. Whenever a user drags and
|
||
resizes the window, the <code>surface</code> is also resized.
|
||
<code>init_cairo</code> gets the size first and sets the initial
|
||
location of the turtle (center of the surface) and the transformation
|
||
matrix.</li>
|
||
<li><code>destroy_cairo</code> just destroys the cairo context.</li>
|
||
</ul>
|
||
<p>Turtle has its own coordinate. The origin is at the center of the
|
||
surface, and positive direction of x and y axes are right and up
|
||
respectively. But surfaces have its own coordinate. Its origin is at the
|
||
top-left corner of the surface and positive direction of x and y are
|
||
right and down respectively. A plane with the turtle’s coordinate is
|
||
called user space, which is the same as cairo’s user space. A plane with
|
||
the surface’s coordinate is called device space.</p>
|
||
<p>Cairo provides a transformation which is an affine transformation. It
|
||
transforms a user-space coordinate (x, y) into a device-space coordinate
|
||
(z, w).</p>
|
||
<figure>
|
||
<img src="image/transformation.png" alt="transformation" />
|
||
<figcaption aria-hidden="true">transformation</figcaption>
|
||
</figure>
|
||
<p>The function <code>init_cairo</code> gets the width and height of the
|
||
<code>surface</code> (See the program below).</p>
|
||
<ul>
|
||
<li>The center of the surface is (0,0) with regard to the user-space
|
||
coordinate and (width/2, height/2) with regard to the device-space
|
||
coordinate.</li>
|
||
<li>The positive direction of x axis in the two spaces are the same. So,
|
||
(1,0) is transformed into (1+width/2,height/2).</li>
|
||
<li>The positive direction of y axis in the two spaces are opposite. So,
|
||
(0,1) is transformed into (width/2,-1+height/2).</li>
|
||
</ul>
|
||
<p>You can determine a, b, c, d, p and q by substituting the numbers
|
||
above for x, y, z and w in the equation above. The solution of the
|
||
simultaneous equations is:</p>
|
||
<pre><code>a = 1, b = 0, c = 0, d = -1, p = width/2, q = height/2</code></pre>
|
||
<p>Cairo provides a structure <code>cairo_matrix_t</code>. The function
|
||
<code>init_cairo</code> uses it and sets the cairo transformation (See
|
||
the program below). Once the matrix is set, the transformation always
|
||
performs whenever <code>cairo_stroke</code> function is invoked.</p>
|
||
<div class="sourceCode" id="cb38"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* status of the surface */</span></span>
|
||
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> gboolean pen <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">double</span> angle <span class="op">=</span> <span class="fl">90.0</span><span class="op">;</span> <span class="co">/* angle starts from x axis and measured counterclockwise */</span></span>
|
||
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a> <span class="co">/* Initially facing to the north */</span></span>
|
||
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">double</span> cur_x <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">double</span> cur_y <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">double</span> line_width <span class="op">=</span> <span class="fl">2.0</span><span class="op">;</span></span>
|
||
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> color <span class="op">{</span></span>
|
||
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> red<span class="op">;</span></span>
|
||
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> green<span class="op">;</span></span>
|
||
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> blue<span class="op">;</span></span>
|
||
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="kw">struct</span> color bc <span class="op">=</span> <span class="op">{</span><span class="fl">0.95</span><span class="op">,</span> <span class="fl">0.95</span><span class="op">,</span> <span class="fl">0.95</span><span class="op">};</span> <span class="co">/* white */</span></span>
|
||
<span id="cb38-15"><a href="#cb38-15" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="kw">struct</span> color fc <span class="op">=</span> <span class="op">{</span><span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">};</span> <span class="co">/* black */</span></span>
|
||
<span id="cb38-16"><a href="#cb38-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb38-17"><a href="#cb38-17" aria-hidden="true" tabindex="-1"></a><span class="co">/* cairo */</span></span>
|
||
<span id="cb38-18"><a href="#cb38-18" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||
<span id="cb38-19"><a href="#cb38-19" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb38-20"><a href="#cb38-20" aria-hidden="true" tabindex="-1"></a>init_cairo <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb38-21"><a href="#cb38-21" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> width<span class="op">,</span> height<span class="op">;</span></span>
|
||
<span id="cb38-22"><a href="#cb38-22" aria-hidden="true" tabindex="-1"></a> cairo_matrix_t matrix<span class="op">;</span></span>
|
||
<span id="cb38-23"><a href="#cb38-23" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb38-24"><a href="#cb38-24" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb38-25"><a href="#cb38-25" aria-hidden="true" tabindex="-1"></a> angle <span class="op">=</span> <span class="fl">90.0</span><span class="op">;</span></span>
|
||
<span id="cb38-26"><a href="#cb38-26" aria-hidden="true" tabindex="-1"></a> cur_x <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb38-27"><a href="#cb38-27" aria-hidden="true" tabindex="-1"></a> cur_y <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb38-28"><a href="#cb38-28" aria-hidden="true" tabindex="-1"></a> line_width <span class="op">=</span> <span class="fl">2.0</span><span class="op">;</span></span>
|
||
<span id="cb38-29"><a href="#cb38-29" aria-hidden="true" tabindex="-1"></a> bc<span class="op">.</span>red <span class="op">=</span> <span class="fl">0.95</span><span class="op">;</span> bc<span class="op">.</span>green <span class="op">=</span> <span class="fl">0.95</span><span class="op">;</span> bc<span class="op">.</span>blue <span class="op">=</span> <span class="fl">0.95</span><span class="op">;</span></span>
|
||
<span id="cb38-30"><a href="#cb38-30" aria-hidden="true" tabindex="-1"></a> fc<span class="op">.</span>red <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span> fc<span class="op">.</span>green <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span> fc<span class="op">.</span>blue <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb38-31"><a href="#cb38-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb38-32"><a href="#cb38-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb38-33"><a href="#cb38-33" aria-hidden="true" tabindex="-1"></a> width <span class="op">=</span> cairo_image_surface_get_width <span class="op">(</span>surface<span class="op">);</span></span>
|
||
<span id="cb38-34"><a href="#cb38-34" aria-hidden="true" tabindex="-1"></a> height <span class="op">=</span> cairo_image_surface_get_height <span class="op">(</span>surface<span class="op">);</span></span>
|
||
<span id="cb38-35"><a href="#cb38-35" aria-hidden="true" tabindex="-1"></a> matrix<span class="op">.</span>xx <span class="op">=</span> <span class="fl">1.0</span><span class="op">;</span> matrix<span class="op">.</span>xy <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span> matrix<span class="op">.</span>x0 <span class="op">=</span> <span class="op">(</span><span class="dt">double</span><span class="op">)</span> width <span class="op">/</span> <span class="fl">2.0</span><span class="op">;</span></span>
|
||
<span id="cb38-36"><a href="#cb38-36" aria-hidden="true" tabindex="-1"></a> matrix<span class="op">.</span>yx <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span> matrix<span class="op">.</span>yy <span class="op">=</span> <span class="op">-</span><span class="fl">1.0</span><span class="op">;</span> matrix<span class="op">.</span>y0 <span class="op">=</span> <span class="op">(</span><span class="dt">double</span><span class="op">)</span> height <span class="op">/</span> <span class="fl">2.0</span><span class="op">;</span></span>
|
||
<span id="cb38-37"><a href="#cb38-37" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb38-38"><a href="#cb38-38" aria-hidden="true" tabindex="-1"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||
<span id="cb38-39"><a href="#cb38-39" aria-hidden="true" tabindex="-1"></a> cairo_transform <span class="op">(</span>cr<span class="op">,</span> <span class="op">&</span>matrix<span class="op">);</span></span>
|
||
<span id="cb38-40"><a href="#cb38-40" aria-hidden="true" tabindex="-1"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> bc<span class="op">.</span>red<span class="op">,</span> bc<span class="op">.</span>green<span class="op">,</span> bc<span class="op">.</span>blue<span class="op">);</span></span>
|
||
<span id="cb38-41"><a href="#cb38-41" aria-hidden="true" tabindex="-1"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb38-42"><a href="#cb38-42" aria-hidden="true" tabindex="-1"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> fc<span class="op">.</span>red<span class="op">,</span> fc<span class="op">.</span>green<span class="op">,</span> fc<span class="op">.</span>blue<span class="op">);</span></span>
|
||
<span id="cb38-43"><a href="#cb38-43" aria-hidden="true" tabindex="-1"></a> cairo_move_to <span class="op">(</span>cr<span class="op">,</span> cur_x<span class="op">,</span> cur_y<span class="op">);</span></span>
|
||
<span id="cb38-44"><a href="#cb38-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb38-45"><a href="#cb38-45" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb38-46"><a href="#cb38-46" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb38-47"><a href="#cb38-47" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb38-48"><a href="#cb38-48" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb38-49"><a href="#cb38-49" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb38-50"><a href="#cb38-50" aria-hidden="true" tabindex="-1"></a>destroy_cairo <span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb38-51"><a href="#cb38-51" aria-hidden="true" tabindex="-1"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb38-52"><a href="#cb38-52" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<h4 id="eval-function">Eval function</h4>
|
||
<p>A function <code>eval</code> evaluates an expression and returns the
|
||
value of the expression. It calls itself recursively. For example, if
|
||
the node is <code>N_ADD</code>, then:</p>
|
||
<ol type="1">
|
||
<li>Calls eval(child1(node)) and gets the value1.</li>
|
||
<li>Calls eval(child2(node)) and gets the value2.</li>
|
||
<li>Returns value1+value2.</li>
|
||
</ol>
|
||
<p>This is performed by a macro <code>calc</code> defined in the sixth
|
||
line in the following program.</p>
|
||
<div class="sourceCode" id="cb39"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span></span>
|
||
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a>eval <span class="op">(</span>node_t <span class="op">*</span>node<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> value <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>node <span class="op">==</span> NULL<span class="op">)</span></span>
|
||
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"No expression to evaluate.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#define calc(op) eval (child1(node)) op eval (child2(node))</span></span>
|
||
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(</span>node<span class="op">-></span>type<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_EQ<span class="op">:</span></span>
|
||
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> <span class="op">(</span><span class="dt">double</span><span class="op">)</span> calc<span class="op">(==);</span></span>
|
||
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_GT<span class="op">:</span></span>
|
||
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> <span class="op">(</span><span class="dt">double</span><span class="op">)</span> calc<span class="op">(>);</span></span>
|
||
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_LT<span class="op">:</span></span>
|
||
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> <span class="op">(</span><span class="dt">double</span><span class="op">)</span> calc<span class="op">(<);</span></span>
|
||
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_ADD<span class="op">:</span></span>
|
||
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(+);</span></span>
|
||
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-20"><a href="#cb39-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_SUB<span class="op">:</span></span>
|
||
<span id="cb39-21"><a href="#cb39-21" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(-);</span></span>
|
||
<span id="cb39-22"><a href="#cb39-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-23"><a href="#cb39-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_MUL<span class="op">:</span></span>
|
||
<span id="cb39-24"><a href="#cb39-24" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(*);</span></span>
|
||
<span id="cb39-25"><a href="#cb39-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-26"><a href="#cb39-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_DIV<span class="op">:</span></span>
|
||
<span id="cb39-27"><a href="#cb39-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>eval <span class="op">(</span>child2<span class="op">(</span>node<span class="op">))</span> <span class="op">==</span> <span class="fl">0.0</span><span class="op">)</span></span>
|
||
<span id="cb39-28"><a href="#cb39-28" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Division by zerp.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb39-29"><a href="#cb39-29" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb39-30"><a href="#cb39-30" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(/);</span></span>
|
||
<span id="cb39-31"><a href="#cb39-31" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-32"><a href="#cb39-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_UMINUS<span class="op">:</span></span>
|
||
<span id="cb39-33"><a href="#cb39-33" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> <span class="op">-(</span>eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">)));</span></span>
|
||
<span id="cb39-34"><a href="#cb39-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-35"><a href="#cb39-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_ID<span class="op">:</span></span>
|
||
<span id="cb39-36"><a href="#cb39-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> <span class="op">(</span>stack_lookup <span class="op">(</span>name<span class="op">(</span>node<span class="op">),</span> <span class="op">&</span>value<span class="op">))</span> <span class="op">&&</span> <span class="op">!</span> var_lookup <span class="op">(</span>name<span class="op">(</span>node<span class="op">),</span> <span class="op">&</span>value<span class="op">)</span> <span class="op">)</span></span>
|
||
<span id="cb39-37"><a href="#cb39-37" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Variable %s not defined.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> name<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb39-38"><a href="#cb39-38" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-39"><a href="#cb39-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_NUM<span class="op">:</span></span>
|
||
<span id="cb39-40"><a href="#cb39-40" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> value<span class="op">(</span>node<span class="op">);</span></span>
|
||
<span id="cb39-41"><a href="#cb39-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-42"><a href="#cb39-42" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span></span>
|
||
<span id="cb39-43"><a href="#cb39-43" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Illegal expression.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb39-44"><a href="#cb39-44" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb39-45"><a href="#cb39-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> value<span class="op">;</span></span>
|
||
<span id="cb39-46"><a href="#cb39-46" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<h4 id="execute-function">Execute function</h4>
|
||
<p>Primary procedures and procedure definitions are analyzed and
|
||
executed by the function <code>execute</code>. It doesn’t return any
|
||
values. It calls itself recursively. The process of <code>N_RT</code>
|
||
and <code>N_procedure_call</code> is complicated. It will explained
|
||
after the following program. Other parts are not so difficult. Read the
|
||
program below carefully so that you will understand the process.</p>
|
||
<div class="sourceCode" id="cb40"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* procedure - return status */</span></span>
|
||
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> proc_level <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> ret_level <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a>execute <span class="op">(</span>node_t <span class="op">*</span>node<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> d<span class="op">,</span> x<span class="op">,</span> y<span class="op">;</span></span>
|
||
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> n<span class="op">,</span> i<span class="op">;</span></span>
|
||
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>node <span class="op">==</span> NULL<span class="op">)</span></span>
|
||
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Node is NULL.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>proc_level <span class="op">></span> ret_level<span class="op">)</span></span>
|
||
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(</span>node<span class="op">-></span>type<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_program<span class="op">:</span></span>
|
||
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a> execute <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a> execute <span class="op">(</span>child2<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_PU<span class="op">:</span></span>
|
||
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_PD<span class="op">:</span></span>
|
||
<span id="cb40-24"><a href="#cb40-24" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-26"><a href="#cb40-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_PW<span class="op">:</span></span>
|
||
<span id="cb40-27"><a href="#cb40-27" aria-hidden="true" tabindex="-1"></a> line_width <span class="op">=</span> eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span> <span class="co">/* line width */</span></span>
|
||
<span id="cb40-28"><a href="#cb40-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-29"><a href="#cb40-29" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_FD<span class="op">:</span></span>
|
||
<span id="cb40-30"><a href="#cb40-30" aria-hidden="true" tabindex="-1"></a> d <span class="op">=</span> eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span> <span class="co">/* distance */</span></span>
|
||
<span id="cb40-31"><a href="#cb40-31" aria-hidden="true" tabindex="-1"></a> x <span class="op">=</span> d <span class="op">*</span> cos <span class="op">(</span>angle<span class="op">*</span>M_PI<span class="op">/</span><span class="dv">180</span><span class="op">);</span></span>
|
||
<span id="cb40-32"><a href="#cb40-32" aria-hidden="true" tabindex="-1"></a> y <span class="op">=</span> d <span class="op">*</span> sin <span class="op">(</span>angle<span class="op">*</span>M_PI<span class="op">/</span><span class="dv">180</span><span class="op">);</span></span>
|
||
<span id="cb40-33"><a href="#cb40-33" aria-hidden="true" tabindex="-1"></a> <span class="co">/* initialize the current point = start point of the line */</span></span>
|
||
<span id="cb40-34"><a href="#cb40-34" aria-hidden="true" tabindex="-1"></a> cairo_move_to <span class="op">(</span>cr<span class="op">,</span> cur_x<span class="op">,</span> cur_y<span class="op">);</span></span>
|
||
<span id="cb40-35"><a href="#cb40-35" aria-hidden="true" tabindex="-1"></a> cur_x <span class="op">+=</span> x<span class="op">;</span></span>
|
||
<span id="cb40-36"><a href="#cb40-36" aria-hidden="true" tabindex="-1"></a> cur_y <span class="op">+=</span> y<span class="op">;</span></span>
|
||
<span id="cb40-37"><a href="#cb40-37" aria-hidden="true" tabindex="-1"></a> cairo_set_line_width <span class="op">(</span>cr<span class="op">,</span> line_width<span class="op">);</span></span>
|
||
<span id="cb40-38"><a href="#cb40-38" aria-hidden="true" tabindex="-1"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> fc<span class="op">.</span>red<span class="op">,</span> fc<span class="op">.</span>green<span class="op">,</span> fc<span class="op">.</span>blue<span class="op">);</span></span>
|
||
<span id="cb40-39"><a href="#cb40-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>pen<span class="op">)</span></span>
|
||
<span id="cb40-40"><a href="#cb40-40" aria-hidden="true" tabindex="-1"></a> cairo_line_to <span class="op">(</span>cr<span class="op">,</span> cur_x<span class="op">,</span> cur_y<span class="op">);</span></span>
|
||
<span id="cb40-41"><a href="#cb40-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb40-42"><a href="#cb40-42" aria-hidden="true" tabindex="-1"></a> cairo_move_to <span class="op">(</span>cr<span class="op">,</span> cur_x<span class="op">,</span> cur_y<span class="op">);</span></span>
|
||
<span id="cb40-43"><a href="#cb40-43" aria-hidden="true" tabindex="-1"></a> cairo_stroke <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb40-44"><a href="#cb40-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-45"><a href="#cb40-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_TR<span class="op">:</span></span>
|
||
<span id="cb40-46"><a href="#cb40-46" aria-hidden="true" tabindex="-1"></a> angle <span class="op">-=</span> eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-47"><a href="#cb40-47" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(;</span> angle <span class="op"><</span> <span class="dv">0</span><span class="op">;</span> angle <span class="op">+=</span> <span class="fl">360.0</span><span class="op">);</span></span>
|
||
<span id="cb40-48"><a href="#cb40-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(;</span> angle<span class="op">></span><span class="dv">360</span><span class="op">;</span> angle <span class="op">-=</span> <span class="fl">360.0</span><span class="op">);</span></span>
|
||
<span id="cb40-49"><a href="#cb40-49" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-50"><a href="#cb40-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_BC<span class="op">:</span></span>
|
||
<span id="cb40-51"><a href="#cb40-51" aria-hidden="true" tabindex="-1"></a> bc<span class="op">.</span>red <span class="op">=</span> eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-52"><a href="#cb40-52" aria-hidden="true" tabindex="-1"></a> bc<span class="op">.</span>green <span class="op">=</span> eval <span class="op">(</span>child2<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-53"><a href="#cb40-53" aria-hidden="true" tabindex="-1"></a> bc<span class="op">.</span>blue <span class="op">=</span> eval <span class="op">(</span>child3<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-54"><a href="#cb40-54" aria-hidden="true" tabindex="-1"></a><span class="pp">#define fixcolor(c) c = c < 0 ? 0 : (c > 1 ? 1 : c)</span></span>
|
||
<span id="cb40-55"><a href="#cb40-55" aria-hidden="true" tabindex="-1"></a> fixcolor <span class="op">(</span>bc<span class="op">.</span>red<span class="op">);</span></span>
|
||
<span id="cb40-56"><a href="#cb40-56" aria-hidden="true" tabindex="-1"></a> fixcolor <span class="op">(</span>bc<span class="op">.</span>green<span class="op">);</span></span>
|
||
<span id="cb40-57"><a href="#cb40-57" aria-hidden="true" tabindex="-1"></a> fixcolor <span class="op">(</span>bc<span class="op">.</span>blue<span class="op">);</span></span>
|
||
<span id="cb40-58"><a href="#cb40-58" aria-hidden="true" tabindex="-1"></a> <span class="co">/* clear the shapes and set the background color */</span></span>
|
||
<span id="cb40-59"><a href="#cb40-59" aria-hidden="true" tabindex="-1"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> bc<span class="op">.</span>red<span class="op">,</span> bc<span class="op">.</span>green<span class="op">,</span> bc<span class="op">.</span>blue<span class="op">);</span></span>
|
||
<span id="cb40-60"><a href="#cb40-60" aria-hidden="true" tabindex="-1"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb40-61"><a href="#cb40-61" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-62"><a href="#cb40-62" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_FC<span class="op">:</span></span>
|
||
<span id="cb40-63"><a href="#cb40-63" aria-hidden="true" tabindex="-1"></a> fc<span class="op">.</span>red <span class="op">=</span> eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-64"><a href="#cb40-64" aria-hidden="true" tabindex="-1"></a> fc<span class="op">.</span>green <span class="op">=</span> eval <span class="op">(</span>child2<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-65"><a href="#cb40-65" aria-hidden="true" tabindex="-1"></a> fc<span class="op">.</span>blue <span class="op">=</span> eval <span class="op">(</span>child3<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-66"><a href="#cb40-66" aria-hidden="true" tabindex="-1"></a> fixcolor <span class="op">(</span>fc<span class="op">.</span>red<span class="op">);</span></span>
|
||
<span id="cb40-67"><a href="#cb40-67" aria-hidden="true" tabindex="-1"></a> fixcolor <span class="op">(</span>fc<span class="op">.</span>green<span class="op">);</span></span>
|
||
<span id="cb40-68"><a href="#cb40-68" aria-hidden="true" tabindex="-1"></a> fixcolor <span class="op">(</span>fc<span class="op">.</span>blue<span class="op">);</span></span>
|
||
<span id="cb40-69"><a href="#cb40-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-70"><a href="#cb40-70" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_ASSIGN<span class="op">:</span></span>
|
||
<span id="cb40-71"><a href="#cb40-71" aria-hidden="true" tabindex="-1"></a> name <span class="op">=</span> name<span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-72"><a href="#cb40-72" aria-hidden="true" tabindex="-1"></a> d <span class="op">=</span> eval <span class="op">(</span>child2<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-73"><a href="#cb40-73" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> stack_replace <span class="op">(</span>name<span class="op">,</span> d<span class="op">))</span> <span class="co">/* First, tries to replace the value in the stack (parameter).*/</span></span>
|
||
<span id="cb40-74"><a href="#cb40-74" aria-hidden="true" tabindex="-1"></a> var_replace <span class="op">(</span>name<span class="op">,</span> d<span class="op">);</span> <span class="co">/* If the above fails, tries to replace the value in the table. If the variable isn't in the table, installs it, */</span></span>
|
||
<span id="cb40-75"><a href="#cb40-75" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-76"><a href="#cb40-76" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_IF<span class="op">:</span></span>
|
||
<span id="cb40-77"><a href="#cb40-77" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>eval <span class="op">(</span>child1<span class="op">(</span>node<span class="op">)))</span></span>
|
||
<span id="cb40-78"><a href="#cb40-78" aria-hidden="true" tabindex="-1"></a> execute <span class="op">(</span>child2<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-79"><a href="#cb40-79" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-80"><a href="#cb40-80" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_RT<span class="op">:</span></span>
|
||
<span id="cb40-81"><a href="#cb40-81" aria-hidden="true" tabindex="-1"></a> ret_level<span class="op">--;</span></span>
|
||
<span id="cb40-82"><a href="#cb40-82" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-83"><a href="#cb40-83" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_RS<span class="op">:</span></span>
|
||
<span id="cb40-84"><a href="#cb40-84" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb40-85"><a href="#cb40-85" aria-hidden="true" tabindex="-1"></a> angle <span class="op">=</span> <span class="fl">90.0</span><span class="op">;</span></span>
|
||
<span id="cb40-86"><a href="#cb40-86" aria-hidden="true" tabindex="-1"></a> cur_x <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb40-87"><a href="#cb40-87" aria-hidden="true" tabindex="-1"></a> cur_y <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb40-88"><a href="#cb40-88" aria-hidden="true" tabindex="-1"></a> line_width <span class="op">=</span> <span class="fl">2.0</span><span class="op">;</span></span>
|
||
<span id="cb40-89"><a href="#cb40-89" aria-hidden="true" tabindex="-1"></a> fc<span class="op">.</span>red <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span> fc<span class="op">.</span>green <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span> fc<span class="op">.</span>blue <span class="op">=</span> <span class="fl">0.0</span><span class="op">;</span></span>
|
||
<span id="cb40-90"><a href="#cb40-90" aria-hidden="true" tabindex="-1"></a> <span class="co">/* To change background color, use bc. */</span></span>
|
||
<span id="cb40-91"><a href="#cb40-91" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-92"><a href="#cb40-92" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_procedure_call<span class="op">:</span></span>
|
||
<span id="cb40-93"><a href="#cb40-93" aria-hidden="true" tabindex="-1"></a> name <span class="op">=</span> name<span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-94"><a href="#cb40-94" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span>proc <span class="op">=</span> proc_lookup <span class="op">(</span>name<span class="op">);</span></span>
|
||
<span id="cb40-95"><a href="#cb40-95" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> proc<span class="op">)</span></span>
|
||
<span id="cb40-96"><a href="#cb40-96" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Procedure %s not defined.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> name<span class="op">);</span></span>
|
||
<span id="cb40-97"><a href="#cb40-97" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>strcmp <span class="op">(</span>name<span class="op">,</span> name<span class="op">(</span>child1<span class="op">(</span>proc<span class="op">)))</span> <span class="op">!=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb40-98"><a href="#cb40-98" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Unexpected error. Procedure %s is called, but invoked procedure is %s.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> name<span class="op">,</span> name<span class="op">(</span>child1<span class="op">(</span>proc<span class="op">)));</span></span>
|
||
<span id="cb40-99"><a href="#cb40-99" aria-hidden="true" tabindex="-1"></a><span class="co">/* make tuples (parameter (name), argument (value)) and push them to the stack */</span></span>
|
||
<span id="cb40-100"><a href="#cb40-100" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span>param_list<span class="op">;</span></span>
|
||
<span id="cb40-101"><a href="#cb40-101" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span>arg_list<span class="op">;</span></span>
|
||
<span id="cb40-102"><a href="#cb40-102" aria-hidden="true" tabindex="-1"></a> param_list <span class="op">=</span> child2<span class="op">(</span>proc<span class="op">);</span></span>
|
||
<span id="cb40-103"><a href="#cb40-103" aria-hidden="true" tabindex="-1"></a> arg_list <span class="op">=</span> child2<span class="op">(</span>node<span class="op">);</span></span>
|
||
<span id="cb40-104"><a href="#cb40-104" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>param_list <span class="op">==</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb40-105"><a href="#cb40-105" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>arg_list <span class="op">==</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb40-106"><a href="#cb40-106" aria-hidden="true" tabindex="-1"></a> stack_push <span class="op">(</span>NULL<span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span> <span class="co">/* number of argument == 0 */</span></span>
|
||
<span id="cb40-107"><a href="#cb40-107" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb40-108"><a href="#cb40-108" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Procedure %s has different number of argument and parameter.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> name<span class="op">);</span></span>
|
||
<span id="cb40-109"><a href="#cb40-109" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span><span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb40-110"><a href="#cb40-110" aria-hidden="true" tabindex="-1"></a><span class="co">/* Don't change the stack until finish evaluating the arguments. */</span></span>
|
||
<span id="cb40-111"><a href="#cb40-111" aria-hidden="true" tabindex="-1"></a><span class="pp">#define TEMP_STACK_SIZE 20</span></span>
|
||
<span id="cb40-112"><a href="#cb40-112" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>temp_param<span class="op">[</span>TEMP_STACK_SIZE<span class="op">];</span></span>
|
||
<span id="cb40-113"><a href="#cb40-113" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> temp_arg<span class="op">[</span>TEMP_STACK_SIZE<span class="op">];</span></span>
|
||
<span id="cb40-114"><a href="#cb40-114" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb40-115"><a href="#cb40-115" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(;</span> param_list<span class="op">-></span>type <span class="op">==</span> N_parameter_list<span class="op">;</span> param_list <span class="op">=</span> child1<span class="op">(</span>param_list<span class="op">))</span> <span class="op">{</span></span>
|
||
<span id="cb40-116"><a href="#cb40-116" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>arg_list<span class="op">-></span>type <span class="op">!=</span> N_argument_list<span class="op">)</span></span>
|
||
<span id="cb40-117"><a href="#cb40-117" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Procedure %s has different number of argument and parameter.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> name<span class="op">);</span></span>
|
||
<span id="cb40-118"><a href="#cb40-118" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>n <span class="op">>=</span> TEMP_STACK_SIZE<span class="op">)</span></span>
|
||
<span id="cb40-119"><a href="#cb40-119" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Too many parameters. the number must be %d or less.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> TEMP_STACK_SIZE<span class="op">);</span></span>
|
||
<span id="cb40-120"><a href="#cb40-120" aria-hidden="true" tabindex="-1"></a> temp_param<span class="op">[</span>n<span class="op">]</span> <span class="op">=</span> name<span class="op">(</span>child2<span class="op">(</span>param_list<span class="op">));</span></span>
|
||
<span id="cb40-121"><a href="#cb40-121" aria-hidden="true" tabindex="-1"></a> temp_arg<span class="op">[</span>n<span class="op">]</span> <span class="op">=</span> eval <span class="op">(</span>child2<span class="op">(</span>arg_list<span class="op">));</span></span>
|
||
<span id="cb40-122"><a href="#cb40-122" aria-hidden="true" tabindex="-1"></a> arg_list <span class="op">=</span> child1<span class="op">(</span>arg_list<span class="op">);</span></span>
|
||
<span id="cb40-123"><a href="#cb40-123" aria-hidden="true" tabindex="-1"></a> <span class="op">++</span>n<span class="op">;</span></span>
|
||
<span id="cb40-124"><a href="#cb40-124" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb40-125"><a href="#cb40-125" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>param_list<span class="op">-></span>type <span class="op">==</span> N_ID <span class="op">&&</span> arg_list <span class="op">-></span> type <span class="op">!=</span> N_argument_list<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb40-126"><a href="#cb40-126" aria-hidden="true" tabindex="-1"></a> temp_param<span class="op">[</span>n<span class="op">]</span> <span class="op">=</span> name<span class="op">(</span>param_list<span class="op">);</span></span>
|
||
<span id="cb40-127"><a href="#cb40-127" aria-hidden="true" tabindex="-1"></a> temp_arg<span class="op">[</span>n<span class="op">]</span> <span class="op">=</span> eval <span class="op">(</span>arg_list<span class="op">);</span></span>
|
||
<span id="cb40-128"><a href="#cb40-128" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>n <span class="op">>=</span> TEMP_STACK_SIZE<span class="op">)</span></span>
|
||
<span id="cb40-129"><a href="#cb40-129" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Too many parameters. the number must be %d or less.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> TEMP_STACK_SIZE<span class="op">);</span></span>
|
||
<span id="cb40-130"><a href="#cb40-130" aria-hidden="true" tabindex="-1"></a> temp_param<span class="op">[</span>n<span class="op">]</span> <span class="op">=</span> NULL<span class="op">;</span></span>
|
||
<span id="cb40-131"><a href="#cb40-131" aria-hidden="true" tabindex="-1"></a> temp_arg<span class="op">[</span>n<span class="op">]</span> <span class="op">=</span> <span class="op">(</span><span class="dt">double</span><span class="op">)</span> n<span class="op">;</span></span>
|
||
<span id="cb40-132"><a href="#cb40-132" aria-hidden="true" tabindex="-1"></a> <span class="op">++</span>n<span class="op">;</span></span>
|
||
<span id="cb40-133"><a href="#cb40-133" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb40-134"><a href="#cb40-134" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Unexpected error.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb40-135"><a href="#cb40-135" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> n<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span></span>
|
||
<span id="cb40-136"><a href="#cb40-136" aria-hidden="true" tabindex="-1"></a> stack_push <span class="op">(</span>temp_param<span class="op">[</span>i<span class="op">],</span> temp_arg<span class="op">[</span>i<span class="op">]);</span></span>
|
||
<span id="cb40-137"><a href="#cb40-137" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb40-138"><a href="#cb40-138" aria-hidden="true" tabindex="-1"></a> ret_level <span class="op">=</span> <span class="op">++</span>proc_level<span class="op">;</span></span>
|
||
<span id="cb40-139"><a href="#cb40-139" aria-hidden="true" tabindex="-1"></a> execute <span class="op">(</span>child3<span class="op">(</span>proc<span class="op">));</span></span>
|
||
<span id="cb40-140"><a href="#cb40-140" aria-hidden="true" tabindex="-1"></a> ret_level <span class="op">=</span> <span class="op">--</span>proc_level<span class="op">;</span></span>
|
||
<span id="cb40-141"><a href="#cb40-141" aria-hidden="true" tabindex="-1"></a> stack_return <span class="op">();</span></span>
|
||
<span id="cb40-142"><a href="#cb40-142" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-143"><a href="#cb40-143" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_procedure_definition<span class="op">:</span></span>
|
||
<span id="cb40-144"><a href="#cb40-144" aria-hidden="true" tabindex="-1"></a> name <span class="op">=</span> name<span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-145"><a href="#cb40-145" aria-hidden="true" tabindex="-1"></a> proc_install <span class="op">(</span>name<span class="op">,</span> node<span class="op">);</span></span>
|
||
<span id="cb40-146"><a href="#cb40-146" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-147"><a href="#cb40-147" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_primary_procedure_list<span class="op">:</span></span>
|
||
<span id="cb40-148"><a href="#cb40-148" aria-hidden="true" tabindex="-1"></a> execute <span class="op">(</span>child1<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-149"><a href="#cb40-149" aria-hidden="true" tabindex="-1"></a> execute <span class="op">(</span>child2<span class="op">(</span>node<span class="op">));</span></span>
|
||
<span id="cb40-150"><a href="#cb40-150" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb40-151"><a href="#cb40-151" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span></span>
|
||
<span id="cb40-152"><a href="#cb40-152" aria-hidden="true" tabindex="-1"></a> runtime_error <span class="op">(</span><span class="st">"Unknown statement.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb40-153"><a href="#cb40-153" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb40-154"><a href="#cb40-154" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>A node <code>N_procedure_call</code> is created by the parser when it
|
||
has found a user defined procedure call. The procedure has been defined
|
||
in the prior statement. Suppose the parser reads the following example
|
||
code.</p>
|
||
<pre><code>dp drawline (angle, distance) {
|
||
tr angle
|
||
fd distance
|
||
}
|
||
drawline (90, 100)
|
||
drawline (90, 100)
|
||
drawline (90, 100)
|
||
drawline (90, 100)</code></pre>
|
||
<p>This example draws a square.</p>
|
||
<p>When The parser reads the lines from one to four, it creates nodes
|
||
like this:</p>
|
||
<figure>
|
||
<img src="image/tree2.png" alt="Nodes of drawline" />
|
||
<figcaption aria-hidden="true">Nodes of drawline</figcaption>
|
||
</figure>
|
||
<p>Runtime routine just stores the procedure to the symbol table with
|
||
its name and node.</p>
|
||
<figure>
|
||
<img src="image/table.png" alt="Symbol table" />
|
||
<figcaption aria-hidden="true">Symbol table</figcaption>
|
||
</figure>
|
||
<p>When the parser reads the fifth line in the example, it creates nodes
|
||
like this:</p>
|
||
<figure>
|
||
<img src="image/proc_call.png" alt="Nodes of procedure call" />
|
||
<figcaption aria-hidden="true">Nodes of procedure call</figcaption>
|
||
</figure>
|
||
<p>When the runtime routine meets <code>N_procedure_call</code> node, it
|
||
behaves like this:</p>
|
||
<ol type="1">
|
||
<li>Searches the symbol table for the procedure with the name.</li>
|
||
<li>Gets pointers to the node to parameters and the node to the
|
||
body.</li>
|
||
<li>Creates a temporary stack. Makes a tuple of each parameter name and
|
||
argument value. Pushes the tuples into the stack, and (NULL, number of
|
||
parameters) finally. If no error occurs, copies them from the temporary
|
||
stack to the parameter stack.</li>
|
||
<li>Increases <code>prc_level</code> by one. Sets <code>ret_level</code>
|
||
to the same value as <code>proc_level</code>. <code>proc_level</code> is
|
||
zero when runtime routine runs on the main routine. If it goes into a
|
||
procedure, <code>proc_level</code> increases by one. Therefore,
|
||
<code>proc_level</code> is the depth of the procedure call.
|
||
<code>ret_level</code> is the level to return. If it is the same as
|
||
<code>proc_level</code>, runtime routine executes commands in order of
|
||
the commands in the procedure. If it is smaller than
|
||
<code>proc_level</code>, runtime routine doesn’t execute commands until
|
||
it becomes the same level as <code>proc_level</code>.
|
||
<code>ret_level</code> is used to return the procedure.</li>
|
||
<li>Executes the node of the body of the procedure.</li>
|
||
<li>Decreases <code>proc_level</code> by one. Sets
|
||
<code>ret_level</code> to the same value as <code>proc_level</code>.
|
||
Calls <code>stack_return</code>.</li>
|
||
</ol>
|
||
<p>When the runtime routine meets <code>N_RT</code> node, it decreases
|
||
<code>ret_level</code> by one so that the following commands in the
|
||
procedure are ignored by the runtime routine.</p>
|
||
<h4 id="runtime-entry-and-error-functions">Runtime entry and error
|
||
functions</h4>
|
||
<p>A function <code>run</code> is the entry of the runtime routine. A
|
||
function <code>runtime_error</code> reports an error occurred during the
|
||
runtime routine runs. (Errors which occur during the parsing are called
|
||
syntax error and reported by <code>yyerror</code>.) After
|
||
<code>runtime_error</code> reports an error, it stops the command
|
||
execution and goes back to <code>run</code> to exit.</p>
|
||
<p>Setjmp and longjmp functions are used. They are declared in
|
||
<code><setjmp.h></code>. <code>setjmp (buf)</code> saves state
|
||
information in <code>buf</code> and returns zero.
|
||
<code>longjmp(buf, 1)</code> restores the state information from
|
||
<code>buf</code> and returns <code>1</code> (the second argument).
|
||
Because the information is the status at the time <code>setjmp</code> is
|
||
called, so longjmp resumes the execution at the next of setjmp function
|
||
call. In the following program, longjmp resumes at the assignment to the
|
||
variable <code>i</code>. When setjmp is called, 0 is assigned to
|
||
<code>i</code> and <code>execute(node_top)</code> is called. On the
|
||
other hand, when longjmp is called, 1 is assigned to <code>i</code> and
|
||
<code>execute(node_top)</code> is not called..</p>
|
||
<p><code>g_slist_free_full</code> frees all the allocated memories.</p>
|
||
<div class="sourceCode" id="cb42"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> jmp_buf buf<span class="op">;</span></span>
|
||
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a>run <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> init_cairo<span class="op">())</span> <span class="op">{</span></span>
|
||
<span id="cb42-8"><a href="#cb42-8" aria-hidden="true" tabindex="-1"></a> g_print <span class="op">(</span><span class="st">"Cairo not initialized.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||
<span id="cb42-9"><a href="#cb42-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb42-10"><a href="#cb42-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb42-11"><a href="#cb42-11" aria-hidden="true" tabindex="-1"></a> init_table<span class="op">();</span></span>
|
||
<span id="cb42-12"><a href="#cb42-12" aria-hidden="true" tabindex="-1"></a> init_stack<span class="op">();</span></span>
|
||
<span id="cb42-13"><a href="#cb42-13" aria-hidden="true" tabindex="-1"></a> ret_level <span class="op">=</span> proc_level <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb42-14"><a href="#cb42-14" aria-hidden="true" tabindex="-1"></a> i <span class="op">=</span> setjmp <span class="op">(</span>buf<span class="op">);</span></span>
|
||
<span id="cb42-15"><a href="#cb42-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>i <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||
<span id="cb42-16"><a href="#cb42-16" aria-hidden="true" tabindex="-1"></a> execute<span class="op">(</span>node_top<span class="op">);</span></span>
|
||
<span id="cb42-17"><a href="#cb42-17" aria-hidden="true" tabindex="-1"></a> <span class="co">/* else ... get here by calling longjmp */</span></span>
|
||
<span id="cb42-18"><a href="#cb42-18" aria-hidden="true" tabindex="-1"></a> destroy_cairo <span class="op">();</span></span>
|
||
<span id="cb42-19"><a href="#cb42-19" aria-hidden="true" tabindex="-1"></a> g_slist_free_full <span class="op">(</span>g_steal_pointer <span class="op">(&</span>list<span class="op">),</span> g_free<span class="op">);</span></span>
|
||
<span id="cb42-20"><a href="#cb42-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb42-21"><a href="#cb42-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb42-22"><a href="#cb42-22" aria-hidden="true" tabindex="-1"></a><span class="co">/* format supports only %s, %f and %d */</span></span>
|
||
<span id="cb42-23"><a href="#cb42-23" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb42-24"><a href="#cb42-24" aria-hidden="true" tabindex="-1"></a>runtime_error <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>format<span class="op">,</span> <span class="op">...)</span> <span class="op">{</span></span>
|
||
<span id="cb42-25"><a href="#cb42-25" aria-hidden="true" tabindex="-1"></a> <span class="dt">va_list</span> args<span class="op">;</span></span>
|
||
<span id="cb42-26"><a href="#cb42-26" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>f<span class="op">;</span></span>
|
||
<span id="cb42-27"><a href="#cb42-27" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> b<span class="op">[</span><span class="dv">3</span><span class="op">];</span></span>
|
||
<span id="cb42-28"><a href="#cb42-28" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
|
||
<span id="cb42-29"><a href="#cb42-29" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> v<span class="op">;</span></span>
|
||
<span id="cb42-30"><a href="#cb42-30" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb42-31"><a href="#cb42-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb42-32"><a href="#cb42-32" aria-hidden="true" tabindex="-1"></a> va_start <span class="op">(</span>args<span class="op">,</span> format<span class="op">);</span></span>
|
||
<span id="cb42-33"><a href="#cb42-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>f <span class="op">=</span> format<span class="op">;</span> <span class="op">*</span>f<span class="op">;</span> f<span class="op">++)</span> <span class="op">{</span></span>
|
||
<span id="cb42-34"><a href="#cb42-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(*</span>f <span class="op">!=</span> <span class="ch">'%'</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb42-35"><a href="#cb42-35" aria-hidden="true" tabindex="-1"></a> b<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> <span class="op">*</span>f<span class="op">;</span></span>
|
||
<span id="cb42-36"><a href="#cb42-36" aria-hidden="true" tabindex="-1"></a> b<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="ch">'\0'</span><span class="op">;</span></span>
|
||
<span id="cb42-37"><a href="#cb42-37" aria-hidden="true" tabindex="-1"></a> g_print <span class="op">(</span><span class="st">"%s"</span><span class="op">,</span> b<span class="op">);</span></span>
|
||
<span id="cb42-38"><a href="#cb42-38" aria-hidden="true" tabindex="-1"></a> <span class="cf">continue</span><span class="op">;</span></span>
|
||
<span id="cb42-39"><a href="#cb42-39" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb42-40"><a href="#cb42-40" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(*++</span>f<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb42-41"><a href="#cb42-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="ch">'s'</span><span class="op">:</span></span>
|
||
<span id="cb42-42"><a href="#cb42-42" aria-hidden="true" tabindex="-1"></a> s <span class="op">=</span> va_arg<span class="op">(</span>args<span class="op">,</span> <span class="dt">char</span> <span class="op">*);</span></span>
|
||
<span id="cb42-43"><a href="#cb42-43" aria-hidden="true" tabindex="-1"></a> g_print <span class="op">(</span><span class="st">"%s"</span><span class="op">,</span> s<span class="op">);</span></span>
|
||
<span id="cb42-44"><a href="#cb42-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb42-45"><a href="#cb42-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="ch">'f'</span><span class="op">:</span></span>
|
||
<span id="cb42-46"><a href="#cb42-46" aria-hidden="true" tabindex="-1"></a> v <span class="op">=</span> va_arg<span class="op">(</span>args<span class="op">,</span> <span class="dt">double</span><span class="op">);</span></span>
|
||
<span id="cb42-47"><a href="#cb42-47" aria-hidden="true" tabindex="-1"></a> g_print<span class="op">(</span><span class="st">"%f"</span><span class="op">,</span> v<span class="op">);</span></span>
|
||
<span id="cb42-48"><a href="#cb42-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb42-49"><a href="#cb42-49" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="ch">'d'</span><span class="op">:</span></span>
|
||
<span id="cb42-50"><a href="#cb42-50" aria-hidden="true" tabindex="-1"></a> i <span class="op">=</span> va_arg<span class="op">(</span>args<span class="op">,</span> <span class="dt">int</span><span class="op">);</span></span>
|
||
<span id="cb42-51"><a href="#cb42-51" aria-hidden="true" tabindex="-1"></a> g_print<span class="op">(</span><span class="st">"%d"</span><span class="op">,</span> i<span class="op">);</span></span>
|
||
<span id="cb42-52"><a href="#cb42-52" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb42-53"><a href="#cb42-53" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span></span>
|
||
<span id="cb42-54"><a href="#cb42-54" aria-hidden="true" tabindex="-1"></a> b<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> <span class="ch">'%'</span><span class="op">;</span></span>
|
||
<span id="cb42-55"><a href="#cb42-55" aria-hidden="true" tabindex="-1"></a> b<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">*</span>f<span class="op">;</span></span>
|
||
<span id="cb42-56"><a href="#cb42-56" aria-hidden="true" tabindex="-1"></a> b<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="ch">'\0'</span><span class="op">;</span></span>
|
||
<span id="cb42-57"><a href="#cb42-57" aria-hidden="true" tabindex="-1"></a> g_print <span class="op">(</span><span class="st">"%s"</span><span class="op">,</span> b<span class="op">);</span></span>
|
||
<span id="cb42-58"><a href="#cb42-58" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb42-59"><a href="#cb42-59" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb42-60"><a href="#cb42-60" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb42-61"><a href="#cb42-61" aria-hidden="true" tabindex="-1"></a> va_end <span class="op">(</span>args<span class="op">);</span></span>
|
||
<span id="cb42-62"><a href="#cb42-62" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb42-63"><a href="#cb42-63" aria-hidden="true" tabindex="-1"></a> longjmp <span class="op">(</span>buf<span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||
<span id="cb42-64"><a href="#cb42-64" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>A function <code>runtime_error</code> has a variable-length argument
|
||
list.</p>
|
||
<div class="sourceCode" id="cb43"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> runtime_error <span class="op">(</span><span class="dt">char</span> <span class="op">*</span>format<span class="op">,</span> <span class="op">...)</span></span></code></pre></div>
|
||
<p>This is implemented with <code><stdarg.h></code> header file.
|
||
The <code>va_list</code> type variable <code>args</code> will refer to
|
||
each argument in turn. A function <code>va_start</code> initializes
|
||
<code>args</code>. A function <code>va_arg</code> returns an argument
|
||
and moves the reference of <code>args</code> to the next. A function
|
||
<code>va_end</code> cleans up everything necessary at the end.</p>
|
||
<p>The function <code>runtime_error</code> has a similar format of
|
||
printf standard function. But its format has only <code>%s</code>,
|
||
<code>%f</code> and <code>%d</code>.</p>
|
||
<p>The functions declared in <code><setjmp.h></code> and
|
||
<code><stdarg.h></code> are explained in the very famous book “The
|
||
C programming language” written by Brian Kernighan and Dennis Ritchie. I
|
||
referred to the book to write the program above.</p>
|
||
<p>The program <code>turtle</code> is unsophisticated and unpolished. If
|
||
you want to make your own language, you need to know more and more. I
|
||
don’t know any good textbook about compilers and interpreters. If you
|
||
know a good book, please let me know.</p>
|
||
<p>However, the following information is very useful (but old).</p>
|
||
<ul>
|
||
<li>Bison documentation</li>
|
||
<li>Flex documentation</li>
|
||
<li>Software tools written by Brian W. Kernighan & P. J. Plauger
|
||
(1976)</li>
|
||
<li>Unix programming environment written by Brian W. Kernighan and Rob
|
||
Pike (1984)</li>
|
||
<li>Source code of a language, for example, ruby.</li>
|
||
</ul>
|
||
<p>Lately, lots of source codes are in the internet. Maybe reading
|
||
source codes is the most useful for programmers.</p>
|
||
</div>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||
</body>
|
||
</html>
|