mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
2531 lines
193 KiB
HTML
2531 lines
193 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="sec24.html">Prev: section24</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec26.html">Next: section26</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 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. I will write about how to use
|
||
those software, but they are not 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. It is similar to
|
||
<code>color</code> program in the previous section.</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 handler of “clicked” signal of the
|
||
<code>Run</code> button prevents from 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></span>
|
||
<span id="cb2-10"><a href="#cb2-10"></a> <span class="co">/* yyparse() and run() are NOT thread safe. */</span></span>
|
||
<span id="cb2-11"><a href="#cb2-11"></a> <span class="co">/* The variable busy avoids reentrance. */</span></span>
|
||
<span id="cb2-12"><a href="#cb2-12"></a> <span class="cf">if</span> <span class="op">(</span>busy<span class="op">)</span></span>
|
||
<span id="cb2-13"><a href="#cb2-13"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb2-14"><a href="#cb2-14"></a> busy <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb2-15"><a href="#cb2-15"></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-16"><a href="#cb2-16"></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-17"><a href="#cb2-17"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a> init_flex <span class="op">(</span>contents<span class="op">);</span></span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a> stat <span class="op">=</span> yyparse <span class="op">();</span></span>
|
||
<span id="cb2-20"><a href="#cb2-20"></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="co">/* No error */</span> <span class="op">{</span></span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> run <span class="op">();</span></span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> <span class="op">}</span></span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a> finalize_flex <span class="op">();</span></span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a> <span class="op">}</span></span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a> gtk_widget_queue_draw <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">));</span></span>
|
||
<span id="cb2-27"><a href="#cb2-27"></a> busy <span class="op">=</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span>
|
||
<span id="cb2-29"><a href="#cb2-29"></a></span>
|
||
<span id="cb2-30"><a href="#cb2-30"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb2-31"><a href="#cb2-31"></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-32"><a href="#cb2-32"></a></span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||
<span id="cb2-35"><a href="#cb2-35"></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-36"><a href="#cb2-36"></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-37"><a href="#cb2-37"></a><span class="op">}</span></span></code></pre></div>
|
||
<ul>
|
||
<li>8-13: 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 again because it’s not a
|
||
re-entrant program. If it is <code>FALSE</code>, it is safe to call the
|
||
interpreter.</li>
|
||
<li>14: Changes <code>busy</code> to TRUE to avoid reentrance.</li>
|
||
<li>15-16: Gets the contents of <code>tb</code>.</li>
|
||
<li>17: 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: Initializes lexical analyzer.</li>
|
||
<li>19: Calls parser. Parser analyzes the program codes syntactically
|
||
and generates a tree structured data.</li>
|
||
<li>20-22: If the parser successfully parsed, it calls <code>run</code>
|
||
(runtime routine).</li>
|
||
<li>23: finalizes the lexical analyzer.</li>
|
||
<li>25: frees <code>contents</code>.</li>
|
||
<li>26: Adds the drawing area widget to the queue to draw.</li>
|
||
<li>27: The interpreter program has finished so <code>busy</code> is now
|
||
changed to FALSE.</li>
|
||
<li>30-37: A “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. Run_cb is called to redraw
|
||
the shape on the drawing area.</li>
|
||
</ul>
|
||
<p>Other part of <code>turtleapplication.c</code> is almost same as the
|
||
codes of <code>colorapplication.c</code> in the previous section. 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 runs with the following program.</p>
|
||
<pre><code>distance = 100
|
||
fd distance*2</code></pre>
|
||
<p>The turtle recognizes the program above 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> with a
|
||
value, which is called a semantic value. The type of <code>yylval</code>
|
||
is union and <code>yylval.ID</code> is string and
|
||
<code>yylval.NUM</code> is double. 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><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><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 surface
|
||
(<code>surface</code>).</li>
|
||
<li>There are no node follows. Runtime routine returns to the function
|
||
<code>run_cb</code>.</li>
|
||
</ol></li>
|
||
<li><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 surface
|
||
(<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="cb4"><pre
|
||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb4-1"><a href="#cb4-1"></a>project('turtle', 'c')</span>
|
||
<span id="cb4-2"><a href="#cb4-2"></a></span>
|
||
<span id="cb4-3"><a href="#cb4-3"></a>compiler = meson.get_compiler('c')</span>
|
||
<span id="cb4-4"><a href="#cb4-4"></a>mathdep = compiler.find_library('m', required : true)</span>
|
||
<span id="cb4-5"><a href="#cb4-5"></a></span>
|
||
<span id="cb4-6"><a href="#cb4-6"></a>gtkdep = dependency('gtk4')</span>
|
||
<span id="cb4-7"><a href="#cb4-7"></a></span>
|
||
<span id="cb4-8"><a href="#cb4-8"></a>gnome=import('gnome')</span>
|
||
<span id="cb4-9"><a href="#cb4-9"></a>resources = gnome.compile_resources('resources','turtle.gresource.xml')</span>
|
||
<span id="cb4-10"><a href="#cb4-10"></a></span>
|
||
<span id="cb4-11"><a href="#cb4-11"></a>flex = find_program('flex')</span>
|
||
<span id="cb4-12"><a href="#cb4-12"></a>bison = find_program('bison')</span>
|
||
<span id="cb4-13"><a href="#cb4-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="cb4-14"><a href="#cb4-14"></a>turtlelexer = custom_target('turtlelexer', input: 'turtle.lex', output: 'turtle_lex.c', command: [flex, '-o', '@OUTPUT@', '@INPUT@'])</span>
|
||
<span id="cb4-15"><a href="#cb4-15"></a></span>
|
||
<span id="cb4-16"><a href="#cb4-16"></a>sourcefiles=files('turtleapplication.c', '../tfetextview/tfetextview.c')</span>
|
||
<span id="cb4-17"><a href="#cb4-17"></a></span>
|
||
<span id="cb4-18"><a href="#cb4-18"></a>executable('turtle', sourcefiles, resources, turtleparser, turtlelexer, turtleparser[1], dependencies: [mathdep, gtkdep], export_dynamic: true, install: true)</span></code></pre></div>
|
||
<ul>
|
||
<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 – GNUME 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.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: Specifies 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="cb6"><pre
|
||
class="sourceCode numberSource lex numberLines"><code class="sourceCode lex"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">%top{</span></span>
|
||
<span id="cb6-2"><a href="#cb6-2"></a>#include <string.h></span>
|
||
<span id="cb6-3"><a href="#cb6-3"></a>#include <stdlib.h></span>
|
||
<span id="cb6-4"><a href="#cb6-4"></a>#include <glib.h></span>
|
||
<span id="cb6-5"><a href="#cb6-5"></a>#include "turtle_parser.h"</span>
|
||
<span id="cb6-6"><a href="#cb6-6"></a></span>
|
||
<span id="cb6-7"><a href="#cb6-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="cb6-8"><a href="#cb6-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="cb6-9"><a href="#cb6-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="cb6-10"><a href="#cb6-10"></a></span>
|
||
<span id="cb6-11"><a href="#cb6-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="cb6-12"><a href="#cb6-12"></a> <span class="at">extern</span> GSList <span class="op">*</span>list<span class="op">;</span></span>
|
||
<span id="cb6-13"><a href="#cb6-13"></a>}</span>
|
||
<span id="cb6-14"><a href="#cb6-14"></a></span>
|
||
<span id="cb6-15"><a href="#cb6-15"></a><span class="kw">%option noyywrap</span></span>
|
||
<span id="cb6-16"><a href="#cb6-16"></a></span>
|
||
<span id="cb6-17"><a href="#cb6-17"></a><span class="dt">REAL_NUMBER </span><span class="st">(0|[1-9][0-9]*)(\.[0-9]+)?</span></span>
|
||
<span id="cb6-18"><a href="#cb6-18"></a><span class="dt">IDENTIFIER </span><span class="st">[a-zA-Z][a-zA-Z0-9]*</span></span>
|
||
<span id="cb6-19"><a href="#cb6-19"></a><span class="bn">%%</span></span>
|
||
<span id="cb6-20"><a href="#cb6-20"></a> <span class="co">/* rules */</span></span>
|
||
<span id="cb6-21"><a href="#cb6-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="cb6-22"><a href="#cb6-22"></a><span class="st">[ ]</span> ncolumn<span class="op">++;</span></span>
|
||
<span id="cb6-23"><a href="#cb6-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="cb6-24"><a href="#cb6-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="cb6-25"><a href="#cb6-25"></a> <span class="co">/* reserved keywords */</span></span>
|
||
<span id="cb6-26"><a href="#cb6-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="cb6-27"><a href="#cb6-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="cb6-28"><a href="#cb6-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="cb6-29"><a href="#cb6-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="cb6-30"><a href="#cb6-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="cb6-31"><a href="#cb6-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 ver 0.5 */</span></span>
|
||
<span id="cb6-32"><a href="#cb6-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="cb6-33"><a href="#cb6-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="cb6-34"><a href="#cb6-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="cb6-35"><a href="#cb6-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="cb6-36"><a href="#cb6-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="cb6-37"><a href="#cb6-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="cb6-38"><a href="#cb6-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 ver 0.5 */</span></span>
|
||
<span id="cb6-39"><a href="#cb6-39"></a> <span class="co">/* constant */</span></span>
|
||
<span id="cb6-40"><a href="#cb6-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="cb6-41"><a href="#cb6-41"></a> <span class="co">/* identifier */</span></span>
|
||
<span id="cb6-42"><a href="#cb6-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="cb6-43"><a href="#cb6-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="cb6-44"><a href="#cb6-44"></a> <span class="cf">return</span> ID<span class="op">;</span></span>
|
||
<span id="cb6-45"><a href="#cb6-45"></a> }</span>
|
||
<span id="cb6-46"><a href="#cb6-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="cb6-47"><a href="#cb6-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="cb6-48"><a href="#cb6-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="cb6-49"><a href="#cb6-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="cb6-50"><a href="#cb6-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="cb6-51"><a href="#cb6-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="cb6-52"><a href="#cb6-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="cb6-53"><a href="#cb6-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="cb6-54"><a href="#cb6-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="cb6-55"><a href="#cb6-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="cb6-56"><a href="#cb6-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="cb6-57"><a href="#cb6-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="cb6-58"><a href="#cb6-58"></a><span class="st">.</span> ncolumn<span class="op">++;</span> <span class="cf">return</span> YYUNDEF<span class="op">;</span></span>
|
||
<span id="cb6-59"><a href="#cb6-59"></a><span class="bn">%%</span></span>
|
||
<span id="cb6-60"><a href="#cb6-60"></a></span>
|
||
<span id="cb6-61"><a href="#cb6-61"></a><span class="at">static</span> <span class="dt">void</span></span>
|
||
<span id="cb6-62"><a href="#cb6-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="cb6-63"><a href="#cb6-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="cb6-64"><a href="#cb6-64"></a> yylloc<span class="op">.</span>first_column <span class="op">=</span> ncolumn<span class="op">;</span></span>
|
||
<span id="cb6-65"><a href="#cb6-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="cb6-66"><a href="#cb6-66"></a><span class="op">}</span></span>
|
||
<span id="cb6-67"><a href="#cb6-67"></a></span>
|
||
<span id="cb6-68"><a href="#cb6-68"></a><span class="at">static</span> YY_BUFFER_STATE state<span class="op">;</span></span>
|
||
<span id="cb6-69"><a href="#cb6-69"></a></span>
|
||
<span id="cb6-70"><a href="#cb6-70"></a><span class="dt">void</span></span>
|
||
<span id="cb6-71"><a href="#cb6-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="cb6-72"><a href="#cb6-72"></a> state <span class="op">=</span> yy_scan_string <span class="op">(</span>text<span class="op">);</span></span>
|
||
<span id="cb6-73"><a href="#cb6-73"></a><span class="op">}</span></span>
|
||
<span id="cb6-74"><a href="#cb6-74"></a></span>
|
||
<span id="cb6-75"><a href="#cb6-75"></a><span class="dt">void</span></span>
|
||
<span id="cb6-76"><a href="#cb6-76"></a>finalize_flex <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb6-77"><a href="#cb6-77"></a> yy_delete_buffer <span class="op">(</span>state<span class="op">);</span></span>
|
||
<span id="cb6-78"><a href="#cb6-78"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The file consists of three sections which are separated by “%%” (line
|
||
18 and 56). 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: The function <code>strlen</code>, in line 65, is defined in
|
||
<code>string.h</code> The function <code>atof</code>, in line 40, is
|
||
defined in <code>stdlib.h</code>.</li>
|
||
<li>7-9: The current input position is pointed by <code>nline</code> and
|
||
<code>ncolumn</code>. The function <code>get_location</code> (line
|
||
61-66) sets <code>yylloc</code>to point the start and end point of
|
||
<code>yytext</code> in the buffer. This function is declared here so
|
||
that it can be called before the function is defined.</li>
|
||
<li>12: GSlist 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 for
|
||
further information. (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. You can leave out such definitions here and use regular
|
||
expressions in rules section directly.</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
|
||
integer. 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>Update the location variable <code>ncolumn</code> and
|
||
<code>yylloc</code>with <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.</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 just updates the location variables
|
||
<code>ncolumn</code> and <code>yylloc</code>, and return the token kinds
|
||
of the keywords.</li>
|
||
<li>40: Real number constant.</li>
|
||
<li>42: <code>IDENTIFIER</code> is defined in line 18. 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-56: Symbols just 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.</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>. Therefore, it is program.</li>
|
||
</ul>
|
||
<p>You can find that a sequence of statements is program like this.</p>
|
||
<p><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_print ("%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>
|
||
<pre><code>/* Value type. */
|
||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||
union YYSTYPE
|
||
{
|
||
char * ID; /* ID */
|
||
double NUM; /* NUM */
|
||
node_t * program; /* program */
|
||
node_t * statement; /* statement */
|
||
node_t * primary_procedure; /* primary_procedure */
|
||
node_t * primary_procedure_list; /* primary_procedure_list */
|
||
node_t * procedure_definition; /* procedure_definition */
|
||
node_t * parameter_list; /* parameter_list */
|
||
node_t * argument_list; /* argument_list */
|
||
node_t * expression; /* expression */
|
||
};</code></pre>
|
||
<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
|
||
%token BC
|
||
%token FC
|
||
%token DP
|
||
%token IF
|
||
%token RT
|
||
%token RS
|
||
%token RP
|
||
/* constant */
|
||
%token <double> NUM
|
||
/* identirier */
|
||
%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>
|
||
<pre><code>typedef struct YYLTYPE YYLTYPE;
|
||
struct YYLTYPE
|
||
{
|
||
int first_line;
|
||
int first_column;
|
||
int last_line;
|
||
int last_column;
|
||
};</code></pre>
|
||
<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>.</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>A 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><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 an 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 an 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>
|
||
<pre class="bison"><code>program:
|
||
statement { node_top = $$ = $1; }
|
||
| program statement {
|
||
node_top = $$ = tree1 (N_program, $1, $2, NULL);
|
||
}
|
||
;
|
||
|
||
statement:
|
||
primary_procedure
|
||
| procedure_definition
|
||
;
|
||
|
||
primary_procedure:
|
||
PU { $$ = tree1 (N_PU, NULL, NULL, NULL); }
|
||
| PD { $$ = tree1 (N_PD, NULL, NULL, NULL); }
|
||
| PW expression { $$ = tree1 (N_PW, $2, NULL, NULL); }
|
||
| FD expression { $$ = tree1 (N_FD, $2, NULL, NULL); }
|
||
| TR expression { $$ = tree1 (N_TR, $2, NULL, NULL); }
|
||
| TL expression { $$ = tree1 (N_TL, $2, NULL, NULL); } /* ver 0.5 */
|
||
| BC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_BC, $3, $5, $7); }
|
||
| FC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_FC, $3, $5, $7); }
|
||
/* assignment */
|
||
| ID '=' expression { $$ = tree1 (N_ASSIGN, tree3 (N_ID, $1), $3, NULL); }
|
||
/* control flow */
|
||
| IF '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_IF, $3, $6, NULL); }
|
||
| RT { $$ = tree1 (N_RT, NULL, NULL, NULL); }
|
||
| RS { $$ = tree1 (N_RS, NULL, NULL, NULL); }
|
||
| RP '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_RP, $3, $6, NULL); }
|
||
/* user defined procedure call */
|
||
| ID '(' ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), NULL, NULL); }
|
||
| ID '(' argument_list ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), $3, NULL); }
|
||
;
|
||
|
||
procedure_definition:
|
||
DP ID '(' ')' '{' primary_procedure_list '}' {
|
||
$$ = tree1 (N_procedure_definition, tree3 (N_ID, $2), NULL, $6);
|
||
}
|
||
| DP ID '(' parameter_list ')' '{' primary_procedure_list '}' {
|
||
$$ = tree1 (N_procedure_definition, tree3 (N_ID, $2), $4, $7);
|
||
}
|
||
;
|
||
|
||
parameter_list:
|
||
ID { $$ = tree3 (N_ID, $1); }
|
||
| parameter_list ',' ID { $$ = tree1 (N_parameter_list, $1, tree3 (N_ID, $3), NULL); }
|
||
;
|
||
|
||
argument_list:
|
||
expression
|
||
| argument_list ',' expression { $$ = tree1 (N_argument_list, $1, $3, NULL); }
|
||
;
|
||
|
||
primary_procedure_list:
|
||
primary_procedure
|
||
| primary_procedure_list primary_procedure {
|
||
$$ = tree1 (N_primary_procedure_list, $1, $2, NULL);
|
||
}
|
||
;
|
||
|
||
expression:
|
||
expression '=' expression { $$ = tree1 (N_EQ, $1, $3, NULL); }
|
||
| expression '>' expression { $$ = tree1 (N_GT, $1, $3, NULL); }
|
||
| expression '<' expression { $$ = tree1 (N_LT, $1, $3, NULL); }
|
||
| expression '+' expression { $$ = tree1 (N_ADD, $1, $3, NULL); }
|
||
| expression '-' expression { $$ = tree1 (N_SUB, $1, $3, NULL); }
|
||
| expression '*' expression { $$ = tree1 (N_MUL, $1, $3, NULL); }
|
||
| expression '/' expression { $$ = tree1 (N_DIV, $1, $3, NULL); }
|
||
| '-' expression %prec UMINUS { $$ = tree1 (N_UMINUS, $2, NULL, NULL); }
|
||
| '(' expression ')' { $$ = $2; }
|
||
| ID { $$ = tree3 (N_ID, $1); }
|
||
| NUM { $$ = tree2 (N_NUM, $1); }
|
||
;</code></pre>
|
||
<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="cb30"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb30-1"><a href="#cb30-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="cb30-2"><a href="#cb30-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="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb30-5"><a href="#cb30-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="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>new_node<span class="op">;</span></span>
|
||
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-8"><a href="#cb30-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="cb30-9"><a href="#cb30-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="cb30-10"><a href="#cb30-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="cb30-11"><a href="#cb30-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="cb30-12"><a href="#cb30-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="cb30-13"><a href="#cb30-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="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> new_node<span class="op">;</span></span>
|
||
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb30-18"><a href="#cb30-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="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>new_node<span class="op">;</span></span>
|
||
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-21"><a href="#cb30-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="cb30-22"><a href="#cb30-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="cb30-23"><a href="#cb30-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="cb30-24"><a href="#cb30-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="cb30-25"><a href="#cb30-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> new_node<span class="op">;</span></span>
|
||
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb30-29"><a href="#cb30-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="cb30-30"><a href="#cb30-30" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>new_node<span class="op">;</span></span>
|
||
<span id="cb30-31"><a href="#cb30-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-32"><a href="#cb30-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="cb30-33"><a href="#cb30-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="cb30-34"><a href="#cb30-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="cb30-35"><a href="#cb30-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="cb30-36"><a href="#cb30-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> new_node<span class="op">;</span></span>
|
||
<span id="cb30-37"><a href="#cb30-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 a symbol
|
||
table. This table is a C array. It should be replaced by more
|
||
appropriate data structure with memory allocation 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="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="pp">#define MAX_TABLE_SIZE 100</span></span>
|
||
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span></span>
|
||
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a> PROC<span class="op">,</span></span>
|
||
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> VAR</span>
|
||
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a><span class="kw">typedef</span> <span class="kw">union</span> _object_t object_t<span class="op">;</span></span>
|
||
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> _object_t <span class="op">{</span></span>
|
||
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a> node_t <span class="op">*</span>node<span class="op">;</span></span>
|
||
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> value<span class="op">;</span></span>
|
||
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||
<span id="cb31-12"><a href="#cb31-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-13"><a href="#cb31-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <span class="op">{</span></span>
|
||
<span id="cb31-14"><a href="#cb31-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> type<span class="op">;</span></span>
|
||
<span id="cb31-15"><a href="#cb31-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||
<span id="cb31-16"><a href="#cb31-16" aria-hidden="true" tabindex="-1"></a> object_t object<span class="op">;</span></span>
|
||
<span id="cb31-17"><a href="#cb31-17" 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="cb31-18"><a href="#cb31-18" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> tp<span class="op">;</span></span>
|
||
<span id="cb31-19"><a href="#cb31-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-20"><a href="#cb31-20" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb31-21"><a href="#cb31-21" 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="cb31-22"><a href="#cb31-22" aria-hidden="true" tabindex="-1"></a> tp <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb31-23"><a href="#cb31-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p><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="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="dt">int</span></span>
|
||
<span id="cb32-2"><a href="#cb32-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="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-5"><a href="#cb32-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="cb32-6"><a href="#cb32-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="cb32-7"><a href="#cb32-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="cb32-8"><a href="#cb32-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="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> i<span class="op">;</span></span>
|
||
<span id="cb32-10"><a href="#cb32-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="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb32-14"><a href="#cb32-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> object_t object<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb32-15"><a href="#cb32-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="cb32-16"><a href="#cb32-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="cb32-17"><a href="#cb32-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="cb32-18"><a href="#cb32-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="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb32-20"><a href="#cb32-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="cb32-21"><a href="#cb32-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="cb32-22"><a href="#cb32-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="cb32-23"><a href="#cb32-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> object<span class="op">.</span>node<span class="op">;</span></span>
|
||
<span id="cb32-24"><a href="#cb32-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb32-25"><a href="#cb32-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> object<span class="op">.</span>value<span class="op">;</span></span>
|
||
<span id="cb32-26"><a href="#cb32-26" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb32-27"><a href="#cb32-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb32-28"><a href="#cb32-28" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-29"><a href="#cb32-29" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb32-30"><a href="#cb32-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="cb32-31"><a href="#cb32-31" aria-hidden="true" tabindex="-1"></a> object_t object<span class="op">;</span></span>
|
||
<span id="cb32-32"><a href="#cb32-32" aria-hidden="true" tabindex="-1"></a> object<span class="op">.</span>node <span class="op">=</span> node<span class="op">;</span></span>
|
||
<span id="cb32-33"><a href="#cb32-33" aria-hidden="true" tabindex="-1"></a> tbl_install <span class="op">(</span>PROC<span class="op">,</span> name<span class="op">,</span> object<span class="op">);</span></span>
|
||
<span id="cb32-34"><a href="#cb32-34" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb32-35"><a href="#cb32-35" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-36"><a href="#cb32-36" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb32-37"><a href="#cb32-37" 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="cb32-38"><a href="#cb32-38" aria-hidden="true" tabindex="-1"></a> object_t object<span class="op">;</span></span>
|
||
<span id="cb32-39"><a href="#cb32-39" aria-hidden="true" tabindex="-1"></a> object<span class="op">.</span>value <span class="op">=</span> value<span class="op">;</span></span>
|
||
<span id="cb32-40"><a href="#cb32-40" aria-hidden="true" tabindex="-1"></a> tbl_install <span class="op">(</span>VAR<span class="op">,</span> name<span class="op">,</span> object<span class="op">);</span></span>
|
||
<span id="cb32-41"><a href="#cb32-41" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb32-42"><a href="#cb32-42" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-43"><a href="#cb32-43" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb32-44"><a href="#cb32-44" 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="cb32-45"><a href="#cb32-45" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb32-46"><a href="#cb32-46" 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="cb32-47"><a href="#cb32-47" 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="cb32-48"><a href="#cb32-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb32-49"><a href="#cb32-49" 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="cb32-50"><a href="#cb32-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb32-51"><a href="#cb32-51" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-52"><a href="#cb32-52" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span></span>
|
||
<span id="cb32-53"><a href="#cb32-53" 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="cb32-54"><a href="#cb32-54" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb32-55"><a href="#cb32-55" 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="cb32-56"><a href="#cb32-56" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> NULL<span class="op">;</span></span>
|
||
<span id="cb32-57"><a href="#cb32-57" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb32-58"><a href="#cb32-58" 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="cb32-59"><a href="#cb32-59" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb32-60"><a href="#cb32-60" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-61"><a href="#cb32-61" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb32-62"><a href="#cb32-62" 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="cb32-63"><a href="#cb32-63" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb32-64"><a href="#cb32-64" 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="cb32-65"><a href="#cb32-65" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb32-66"><a href="#cb32-66" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb32-67"><a href="#cb32-67" 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="cb32-68"><a href="#cb32-68" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb32-69"><a href="#cb32-69" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb32-70"><a href="#cb32-70" 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="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="pp">#define MAX_STACK_SIZE 500</span></span>
|
||
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <span class="op">{</span></span>
|
||
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> value<span class="op">;</span></span>
|
||
<span id="cb33-5"><a href="#cb33-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="cb33-6"><a href="#cb33-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="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb33-9"><a href="#cb33-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="cb33-10"><a href="#cb33-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="cb33-11"><a href="#cb33-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="cb35"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb35-2"><a href="#cb35-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="cb35-3"><a href="#cb35-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="cb35-4"><a href="#cb35-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="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb35-6"><a href="#cb35-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="cb35-7"><a href="#cb35-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="cb35-8"><a href="#cb35-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="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb35-10"><a href="#cb35-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb35-11"><a href="#cb35-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-12"><a href="#cb35-12" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
|
||
<span id="cb35-13"><a href="#cb35-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="cb35-14"><a href="#cb35-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="cb35-15"><a href="#cb35-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-16"><a href="#cb35-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="cb35-17"><a href="#cb35-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="cb35-18"><a href="#cb35-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="cb35-19"><a href="#cb35-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="cb35-20"><a href="#cb35-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="cb35-21"><a href="#cb35-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="cb35-22"><a href="#cb35-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="cb35-23"><a href="#cb35-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="cb35-24"><a href="#cb35-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb35-25"><a href="#cb35-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="cb35-26"><a href="#cb35-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb35-27"><a href="#cb35-27" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-28"><a href="#cb35-28" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb35-29"><a href="#cb35-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="cb35-30"><a href="#cb35-30" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb35-31"><a href="#cb35-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-32"><a href="#cb35-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="cb35-33"><a href="#cb35-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb35-34"><a href="#cb35-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb35-35"><a href="#cb35-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="cb35-36"><a href="#cb35-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb35-37"><a href="#cb35-37" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb35-38"><a href="#cb35-38" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb35-39"><a href="#cb35-39" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-40"><a href="#cb35-40" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb35-41"><a href="#cb35-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="cb35-42"><a href="#cb35-42" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb35-43"><a href="#cb35-43" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-44"><a href="#cb35-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="cb35-45"><a href="#cb35-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb35-46"><a href="#cb35-46" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb35-47"><a href="#cb35-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="cb35-48"><a href="#cb35-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb35-49"><a href="#cb35-49" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb35-50"><a href="#cb35-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb35-51"><a href="#cb35-51" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-52"><a href="#cb35-52" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb35-53"><a href="#cb35-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="cb35-54"><a href="#cb35-54" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> depth<span class="op">;</span></span>
|
||
<span id="cb35-55"><a href="#cb35-55" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb35-56"><a href="#cb35-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="cb35-57"><a href="#cb35-57" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb35-58"><a href="#cb35-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="cb35-59"><a href="#cb35-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="cb35-60"><a href="#cb35-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="cb35-61"><a href="#cb35-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="cb35-62"><a href="#cb35-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 of GtkDrawingArea. 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><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>.
|
||
<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="cb37"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* status of the surface */</span></span>
|
||
<span id="cb37-2"><a href="#cb37-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="cb37-3"><a href="#cb37-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="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a> <span class="co">/* Initially facing to the north */</span></span>
|
||
<span id="cb37-5"><a href="#cb37-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="cb37-6"><a href="#cb37-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="cb37-7"><a href="#cb37-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="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> color <span class="op">{</span></span>
|
||
<span id="cb37-10"><a href="#cb37-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> red<span class="op">;</span></span>
|
||
<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> green<span class="op">;</span></span>
|
||
<span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> blue<span class="op">;</span></span>
|
||
<span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
|
||
<span id="cb37-14"><a href="#cb37-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="cb37-15"><a href="#cb37-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="cb37-16"><a href="#cb37-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb37-17"><a href="#cb37-17" aria-hidden="true" tabindex="-1"></a><span class="co">/* cairo */</span></span>
|
||
<span id="cb37-18"><a href="#cb37-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="cb37-19"><a href="#cb37-19" aria-hidden="true" tabindex="-1"></a>gboolean</span>
|
||
<span id="cb37-20"><a href="#cb37-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="cb37-21"><a href="#cb37-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="cb37-22"><a href="#cb37-22" aria-hidden="true" tabindex="-1"></a> cairo_matrix_t matrix<span class="op">;</span></span>
|
||
<span id="cb37-23"><a href="#cb37-23" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb37-24"><a href="#cb37-24" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb37-25"><a href="#cb37-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="cb37-26"><a href="#cb37-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="cb37-27"><a href="#cb37-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="cb37-28"><a href="#cb37-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="cb37-29"><a href="#cb37-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="cb37-30"><a href="#cb37-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="cb37-31"><a href="#cb37-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb37-32"><a href="#cb37-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="cb37-33"><a href="#cb37-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="cb37-34"><a href="#cb37-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="cb37-35"><a href="#cb37-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="cb37-36"><a href="#cb37-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="cb37-37"><a href="#cb37-37" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb37-38"><a href="#cb37-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="cb37-39"><a href="#cb37-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="cb37-40"><a href="#cb37-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="cb37-41"><a href="#cb37-41" aria-hidden="true" tabindex="-1"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb37-42"><a href="#cb37-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="cb37-43"><a href="#cb37-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="cb37-44"><a href="#cb37-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb37-45"><a href="#cb37-45" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb37-46"><a href="#cb37-46" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> FALSE<span class="op">;</span></span>
|
||
<span id="cb37-47"><a href="#cb37-47" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb37-48"><a href="#cb37-48" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb37-49"><a href="#cb37-49" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb37-50"><a href="#cb37-50" aria-hidden="true" tabindex="-1"></a>destroy_cairo <span class="op">()</span> <span class="op">{</span></span>
|
||
<span id="cb37-51"><a href="#cb37-51" aria-hidden="true" tabindex="-1"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb37-52"><a href="#cb37-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="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="dt">double</span></span>
|
||
<span id="cb38-2"><a href="#cb38-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="cb38-3"><a href="#cb38-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="cb38-4"><a href="#cb38-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="cb38-5"><a href="#cb38-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="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#define calc(op) eval (child1(node)) op eval (child2(node))</span></span>
|
||
<span id="cb38-7"><a href="#cb38-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="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_EQ<span class="op">:</span></span>
|
||
<span id="cb38-9"><a href="#cb38-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="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_GT<span class="op">:</span></span>
|
||
<span id="cb38-12"><a href="#cb38-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="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_LT<span class="op">:</span></span>
|
||
<span id="cb38-15"><a href="#cb38-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="cb38-16"><a href="#cb38-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-17"><a href="#cb38-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_ADD<span class="op">:</span></span>
|
||
<span id="cb38-18"><a href="#cb38-18" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(+);</span></span>
|
||
<span id="cb38-19"><a href="#cb38-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-20"><a href="#cb38-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_SUB<span class="op">:</span></span>
|
||
<span id="cb38-21"><a href="#cb38-21" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(-);</span></span>
|
||
<span id="cb38-22"><a href="#cb38-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-23"><a href="#cb38-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_MUL<span class="op">:</span></span>
|
||
<span id="cb38-24"><a href="#cb38-24" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(*);</span></span>
|
||
<span id="cb38-25"><a href="#cb38-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-26"><a href="#cb38-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_DIV<span class="op">:</span></span>
|
||
<span id="cb38-27"><a href="#cb38-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="cb38-28"><a href="#cb38-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="cb38-29"><a href="#cb38-29" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb38-30"><a href="#cb38-30" aria-hidden="true" tabindex="-1"></a> value <span class="op">=</span> calc<span class="op">(/);</span></span>
|
||
<span id="cb38-31"><a href="#cb38-31" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-32"><a href="#cb38-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_UMINUS<span class="op">:</span></span>
|
||
<span id="cb38-33"><a href="#cb38-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="cb38-34"><a href="#cb38-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-35"><a href="#cb38-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_ID<span class="op">:</span></span>
|
||
<span id="cb38-36"><a href="#cb38-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="cb38-37"><a href="#cb38-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="cb38-38"><a href="#cb38-38" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-39"><a href="#cb38-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_NUM<span class="op">:</span></span>
|
||
<span id="cb38-40"><a href="#cb38-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="cb38-41"><a href="#cb38-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb38-42"><a href="#cb38-42" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span></span>
|
||
<span id="cb38-43"><a href="#cb38-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="cb38-44"><a href="#cb38-44" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb38-45"><a href="#cb38-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> value<span class="op">;</span></span>
|
||
<span id="cb38-46"><a href="#cb38-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="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="co">/* procedure - return status */</span></span>
|
||
<span id="cb39-2"><a href="#cb39-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="cb39-3"><a href="#cb39-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="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb39-6"><a href="#cb39-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="cb39-7"><a href="#cb39-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="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>name<span class="op">;</span></span>
|
||
<span id="cb39-9"><a href="#cb39-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="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb39-11"><a href="#cb39-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="cb39-12"><a href="#cb39-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="cb39-13"><a href="#cb39-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="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb39-15"><a href="#cb39-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="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_program<span class="op">:</span></span>
|
||
<span id="cb39-17"><a href="#cb39-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="cb39-18"><a href="#cb39-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="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_PU<span class="op">:</span></span>
|
||
<span id="cb39-21"><a href="#cb39-21" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> FALSE<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_PD<span class="op">:</span></span>
|
||
<span id="cb39-24"><a href="#cb39-24" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> TRUE<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_PW<span class="op">:</span></span>
|
||
<span id="cb39-27"><a href="#cb39-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="cb39-28"><a href="#cb39-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-29"><a href="#cb39-29" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_FD<span class="op">:</span></span>
|
||
<span id="cb39-30"><a href="#cb39-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="cb39-31"><a href="#cb39-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="cb39-32"><a href="#cb39-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="cb39-33"><a href="#cb39-33" aria-hidden="true" tabindex="-1"></a> <span class="co">/* initialize the current point = start point of the line */</span></span>
|
||
<span id="cb39-34"><a href="#cb39-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="cb39-35"><a href="#cb39-35" aria-hidden="true" tabindex="-1"></a> cur_x <span class="op">+=</span> x<span class="op">;</span></span>
|
||
<span id="cb39-36"><a href="#cb39-36" aria-hidden="true" tabindex="-1"></a> cur_y <span class="op">+=</span> y<span class="op">;</span></span>
|
||
<span id="cb39-37"><a href="#cb39-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="cb39-38"><a href="#cb39-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="cb39-39"><a href="#cb39-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>pen<span class="op">)</span></span>
|
||
<span id="cb39-40"><a href="#cb39-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="cb39-41"><a href="#cb39-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
|
||
<span id="cb39-42"><a href="#cb39-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="cb39-43"><a href="#cb39-43" aria-hidden="true" tabindex="-1"></a> cairo_stroke <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb39-44"><a href="#cb39-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-45"><a href="#cb39-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_TR<span class="op">:</span></span>
|
||
<span id="cb39-46"><a href="#cb39-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="cb39-47"><a href="#cb39-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="cb39-48"><a href="#cb39-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="cb39-49"><a href="#cb39-49" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-50"><a href="#cb39-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_BC<span class="op">:</span></span>
|
||
<span id="cb39-51"><a href="#cb39-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="cb39-52"><a href="#cb39-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="cb39-53"><a href="#cb39-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="cb39-54"><a href="#cb39-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="cb39-55"><a href="#cb39-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="cb39-56"><a href="#cb39-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="cb39-57"><a href="#cb39-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="cb39-58"><a href="#cb39-58" aria-hidden="true" tabindex="-1"></a> <span class="co">/* clear the shapes and set the background color */</span></span>
|
||
<span id="cb39-59"><a href="#cb39-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="cb39-60"><a href="#cb39-60" aria-hidden="true" tabindex="-1"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||
<span id="cb39-61"><a href="#cb39-61" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-62"><a href="#cb39-62" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_FC<span class="op">:</span></span>
|
||
<span id="cb39-63"><a href="#cb39-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="cb39-64"><a href="#cb39-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="cb39-65"><a href="#cb39-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="cb39-66"><a href="#cb39-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="cb39-67"><a href="#cb39-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="cb39-68"><a href="#cb39-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="cb39-69"><a href="#cb39-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-70"><a href="#cb39-70" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_ASSIGN<span class="op">:</span></span>
|
||
<span id="cb39-71"><a href="#cb39-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="cb39-72"><a href="#cb39-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="cb39-73"><a href="#cb39-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="cb39-74"><a href="#cb39-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="cb39-75"><a href="#cb39-75" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-76"><a href="#cb39-76" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_IF<span class="op">:</span></span>
|
||
<span id="cb39-77"><a href="#cb39-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="cb39-78"><a href="#cb39-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="cb39-79"><a href="#cb39-79" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-80"><a href="#cb39-80" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_RT<span class="op">:</span></span>
|
||
<span id="cb39-81"><a href="#cb39-81" aria-hidden="true" tabindex="-1"></a> ret_level<span class="op">--;</span></span>
|
||
<span id="cb39-82"><a href="#cb39-82" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-83"><a href="#cb39-83" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_RS<span class="op">:</span></span>
|
||
<span id="cb39-84"><a href="#cb39-84" aria-hidden="true" tabindex="-1"></a> pen <span class="op">=</span> TRUE<span class="op">;</span></span>
|
||
<span id="cb39-85"><a href="#cb39-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="cb39-86"><a href="#cb39-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="cb39-87"><a href="#cb39-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="cb39-88"><a href="#cb39-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="cb39-89"><a href="#cb39-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="cb39-90"><a href="#cb39-90" aria-hidden="true" tabindex="-1"></a> <span class="co">/* To change background color, use bc. */</span></span>
|
||
<span id="cb39-91"><a href="#cb39-91" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-92"><a href="#cb39-92" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_procedure_call<span class="op">:</span></span>
|
||
<span id="cb39-93"><a href="#cb39-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="cb39-94"><a href="#cb39-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="cb39-95"><a href="#cb39-95" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(!</span> proc<span class="op">)</span></span>
|
||
<span id="cb39-96"><a href="#cb39-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="cb39-97"><a href="#cb39-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="cb39-98"><a href="#cb39-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="cb39-99"><a href="#cb39-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="cb39-100"><a href="#cb39-100" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span>param_list<span class="op">;</span></span>
|
||
<span id="cb39-101"><a href="#cb39-101" aria-hidden="true" tabindex="-1"></a>node_t <span class="op">*</span>arg_list<span class="op">;</span></span>
|
||
<span id="cb39-102"><a href="#cb39-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="cb39-103"><a href="#cb39-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="cb39-104"><a href="#cb39-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="cb39-105"><a href="#cb39-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="cb39-106"><a href="#cb39-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="cb39-107"><a href="#cb39-107" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb39-108"><a href="#cb39-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="cb39-109"><a href="#cb39-109" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span><span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb39-110"><a href="#cb39-110" aria-hidden="true" tabindex="-1"></a><span class="co">/* Don't change the stack until finish evaluating the arguments. */</span></span>
|
||
<span id="cb39-111"><a href="#cb39-111" aria-hidden="true" tabindex="-1"></a><span class="pp">#define TEMP_STACK_SIZE 20</span></span>
|
||
<span id="cb39-112"><a href="#cb39-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="cb39-113"><a href="#cb39-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="cb39-114"><a href="#cb39-114" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb39-115"><a href="#cb39-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="cb39-116"><a href="#cb39-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="cb39-117"><a href="#cb39-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="cb39-118"><a href="#cb39-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="cb39-119"><a href="#cb39-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="cb39-120"><a href="#cb39-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="cb39-121"><a href="#cb39-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="cb39-122"><a href="#cb39-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="cb39-123"><a href="#cb39-123" aria-hidden="true" tabindex="-1"></a> <span class="op">++</span>n<span class="op">;</span></span>
|
||
<span id="cb39-124"><a href="#cb39-124" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb39-125"><a href="#cb39-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="cb39-126"><a href="#cb39-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="cb39-127"><a href="#cb39-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="cb39-128"><a href="#cb39-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="cb39-129"><a href="#cb39-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="cb39-130"><a href="#cb39-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="cb39-131"><a href="#cb39-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="cb39-132"><a href="#cb39-132" aria-hidden="true" tabindex="-1"></a> <span class="op">++</span>n<span class="op">;</span></span>
|
||
<span id="cb39-133"><a href="#cb39-133" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb39-134"><a href="#cb39-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="cb39-135"><a href="#cb39-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="cb39-136"><a href="#cb39-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="cb39-137"><a href="#cb39-137" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb39-138"><a href="#cb39-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="cb39-139"><a href="#cb39-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="cb39-140"><a href="#cb39-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="cb39-141"><a href="#cb39-141" aria-hidden="true" tabindex="-1"></a> stack_return <span class="op">();</span></span>
|
||
<span id="cb39-142"><a href="#cb39-142" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-143"><a href="#cb39-143" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_procedure_definition<span class="op">:</span></span>
|
||
<span id="cb39-144"><a href="#cb39-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="cb39-145"><a href="#cb39-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="cb39-146"><a href="#cb39-146" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-147"><a href="#cb39-147" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> N_primary_procedure_list<span class="op">:</span></span>
|
||
<span id="cb39-148"><a href="#cb39-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="cb39-149"><a href="#cb39-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="cb39-150"><a href="#cb39-150" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb39-151"><a href="#cb39-151" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span></span>
|
||
<span id="cb39-152"><a href="#cb39-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="cb39-153"><a href="#cb39-153" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb39-154"><a href="#cb39-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="cb41"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> jmp_buf buf<span class="op">;</span></span>
|
||
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||
<span id="cb41-4"><a href="#cb41-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="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb41-7"><a href="#cb41-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="cb41-8"><a href="#cb41-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="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
|
||
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a> init_table<span class="op">();</span></span>
|
||
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a> init_stack<span class="op">();</span></span>
|
||
<span id="cb41-13"><a href="#cb41-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="cb41-14"><a href="#cb41-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="cb41-15"><a href="#cb41-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="cb41-16"><a href="#cb41-16" aria-hidden="true" tabindex="-1"></a> execute<span class="op">(</span>node_top<span class="op">);</span></span>
|
||
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true" tabindex="-1"></a> <span class="co">/* else ... get here by calling longjmp */</span></span>
|
||
<span id="cb41-18"><a href="#cb41-18" aria-hidden="true" tabindex="-1"></a> destroy_cairo <span class="op">();</span></span>
|
||
<span id="cb41-19"><a href="#cb41-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="cb41-20"><a href="#cb41-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||
<span id="cb41-21"><a href="#cb41-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb41-22"><a href="#cb41-22" aria-hidden="true" tabindex="-1"></a><span class="co">/* format supports only %s, %f and %d */</span></span>
|
||
<span id="cb41-23"><a href="#cb41-23" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb41-24"><a href="#cb41-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="cb41-25"><a href="#cb41-25" aria-hidden="true" tabindex="-1"></a> <span class="dt">va_list</span> args<span class="op">;</span></span>
|
||
<span id="cb41-26"><a href="#cb41-26" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>f<span class="op">;</span></span>
|
||
<span id="cb41-27"><a href="#cb41-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="cb41-28"><a href="#cb41-28" aria-hidden="true" tabindex="-1"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
|
||
<span id="cb41-29"><a href="#cb41-29" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> v<span class="op">;</span></span>
|
||
<span id="cb41-30"><a href="#cb41-30" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb41-31"><a href="#cb41-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb41-32"><a href="#cb41-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="cb41-33"><a href="#cb41-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="cb41-34"><a href="#cb41-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="cb41-35"><a href="#cb41-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="cb41-36"><a href="#cb41-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="cb41-37"><a href="#cb41-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="cb41-38"><a href="#cb41-38" aria-hidden="true" tabindex="-1"></a> <span class="cf">continue</span><span class="op">;</span></span>
|
||
<span id="cb41-39"><a href="#cb41-39" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb41-40"><a href="#cb41-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="cb41-41"><a href="#cb41-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="ch">'s'</span><span class="op">:</span></span>
|
||
<span id="cb41-42"><a href="#cb41-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="cb41-43"><a href="#cb41-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="cb41-44"><a href="#cb41-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb41-45"><a href="#cb41-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="ch">'f'</span><span class="op">:</span></span>
|
||
<span id="cb41-46"><a href="#cb41-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="cb41-47"><a href="#cb41-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="cb41-48"><a href="#cb41-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb41-49"><a href="#cb41-49" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="ch">'d'</span><span class="op">:</span></span>
|
||
<span id="cb41-50"><a href="#cb41-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="cb41-51"><a href="#cb41-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="cb41-52"><a href="#cb41-52" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb41-53"><a href="#cb41-53" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span></span>
|
||
<span id="cb41-54"><a href="#cb41-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="cb41-55"><a href="#cb41-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="cb41-56"><a href="#cb41-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="cb41-57"><a href="#cb41-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="cb41-58"><a href="#cb41-58" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
|
||
<span id="cb41-59"><a href="#cb41-59" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb41-60"><a href="#cb41-60" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb41-61"><a href="#cb41-61" aria-hidden="true" tabindex="-1"></a> va_end <span class="op">(</span>args<span class="op">);</span></span>
|
||
<span id="cb41-62"><a href="#cb41-62" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb41-63"><a href="#cb41-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="cb41-64"><a href="#cb41-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="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">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>
|