mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
2022 lines
149 KiB
HTML
2022 lines
149 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>Gtk4 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 */
|
||
body {width: 1080px; margin: 0 auto; font-size: large;}
|
||
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 it provides a tool to draw fractal curves. The following diagram is a Koch curve, which is a famous example of fractal curves.</p>
|
||
<figure>
|
||
<img src="image/turtle_koch.png" alt="" /><figcaption>Koch curve</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. So, readers can skip that part of this sections.</p>
|
||
<h2 id="how-to-use-turtle">How to use turtle</h2>
|
||
<p>The documentation of turtle is <a href="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.
|
||
fd 100 # Go forward by 100 pixels.
|
||
tr 90 # Turn right by 90 degrees.
|
||
fd 100
|
||
tr 90
|
||
fd 100
|
||
tr 90
|
||
fd 100
|
||
tr 90</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 documentation above shows some fractal curves such as tree, snow and square-koch. The source code in turtle language is 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 is different from the surface of the GtkDrawingArea widget.</li>
|
||
<li>The widget is added to the queue. It will be redrawn with the drawing function. The function just copies the surface, which is drawn by the interpreter, into the surface of the GtkDrawingArea.</li>
|
||
</ol>
|
||
<figure>
|
||
<img src="image/turtle.png" alt="" /><figcaption>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 (GtkWidget *btnr) {</span>
|
||
<span id="cb2-3"><a href="#cb2-3"></a> GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));</span>
|
||
<span id="cb2-4"><a href="#cb2-4"></a> GtkTextIter start_iter;</span>
|
||
<span id="cb2-5"><a href="#cb2-5"></a> GtkTextIter end_iter;</span>
|
||
<span id="cb2-6"><a href="#cb2-6"></a> <span class="dt">char</span> *contents;</span>
|
||
<span id="cb2-7"><a href="#cb2-7"></a> <span class="dt">int</span> stat;</span>
|
||
<span id="cb2-8"><a href="#cb2-8"></a> <span class="dt">static</span> gboolean busy = FALSE;</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 reentry. */</span></span>
|
||
<span id="cb2-12"><a href="#cb2-12"></a> <span class="cf">if</span> (busy)</span>
|
||
<span id="cb2-13"><a href="#cb2-13"></a> <span class="cf">return</span>;</span>
|
||
<span id="cb2-14"><a href="#cb2-14"></a> busy = TRUE;</span>
|
||
<span id="cb2-15"><a href="#cb2-15"></a> gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);</span>
|
||
<span id="cb2-16"><a href="#cb2-16"></a> contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);</span>
|
||
<span id="cb2-17"><a href="#cb2-17"></a> <span class="cf">if</span> (surface) {</span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a> init_flex (contents);</span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a> stat = yyparse ();</span>
|
||
<span id="cb2-20"><a href="#cb2-20"></a> <span class="cf">if</span> (stat == <span class="dv">0</span>) <span class="co">/* No error */</span> {</span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> run ();</span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> }</span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a> finalize_flex ();</span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a> }</span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a> g_free (contents);</span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a> gtk_widget_queue_draw (GTK_WIDGET (da));</span>
|
||
<span id="cb2-27"><a href="#cb2-27"></a> busy = FALSE;</span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a>}</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 (GtkDrawingArea *drawing_area, <span class="dt">int</span> width, <span class="dt">int</span> height, gpointer user_data) {</span>
|
||
<span id="cb2-32"><a href="#cb2-32"></a> <span class="cf">if</span> (surface)</span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a> cairo_surface_destroy (surface);</span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a> surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);</span>
|
||
<span id="cb2-35"><a href="#cb2-35"></a>}</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: Now it is about to call the interpreter so it changes <code>busy</code> to TRUE.</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 generate 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>29-34: A handler of “resized” signal. If <code>surface</code> isn’t NULL, it destroys the old surface. Then it creates a new surface. Its size is the same as the surface of the GtkDrawingArea instance.</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="" /><figcaption>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.h</code>, <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.h</code>, <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="" /><figcaption>compile process</figcaption>
|
||
</figure>
|
||
<p>Meson controls the process and 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. Module is a system provided by meson. 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 "turtle.h"</span>
|
||
<span id="cb6-5"><a href="#cb6-5"></a></span>
|
||
<span id="cb6-6"><a href="#cb6-6"></a> <span class="at">static</span> <span class="dt">int</span> nline = <span class="dv">1</span>;</span>
|
||
<span id="cb6-7"><a href="#cb6-7"></a> <span class="at">static</span> <span class="dt">int</span> ncolumn = <span class="dv">1</span>;</span>
|
||
<span id="cb6-8"><a href="#cb6-8"></a> <span class="at">static</span> <span class="dt">void</span> get_location (<span class="dt">char</span> *text);</span>
|
||
<span id="cb6-9"><a href="#cb6-9"></a></span>
|
||
<span id="cb6-10"><a href="#cb6-10"></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-11"><a href="#cb6-11"></a> <span class="at">extern</span> GSList *list;</span>
|
||
<span id="cb6-12"><a href="#cb6-12"></a>}</span>
|
||
<span id="cb6-13"><a href="#cb6-13"></a></span>
|
||
<span id="cb6-14"><a href="#cb6-14"></a><span class="kw">%option noyywrap</span></span>
|
||
<span id="cb6-15"><a href="#cb6-15"></a></span>
|
||
<span id="cb6-16"><a href="#cb6-16"></a><span class="dt">REAL_NUMBER </span><span class="st">(0|[1-9][0-9]*)(\.[0-9]+)?</span></span>
|
||
<span id="cb6-17"><a href="#cb6-17"></a><span class="dt">IDENTIFIER </span><span class="st">[a-zA-Z][a-zA-Z0-9]*</span></span>
|
||
<span id="cb6-18"><a href="#cb6-18"></a><span class="bn">%%</span></span>
|
||
<span id="cb6-19"><a href="#cb6-19"></a> <span class="co">/* rules */</span></span>
|
||
<span id="cb6-20"><a href="#cb6-20"></a><span class="st">#.*</span> ; <span class="co">/* comment. Be careful. Dot symbol (.) matches any character but new line. */</span></span>
|
||
<span id="cb6-21"><a href="#cb6-21"></a><span class="st">[ ]</span> ncolumn++;</span>
|
||
<span id="cb6-22"><a href="#cb6-22"></a><span class="st">\t</span> ncolumn += <span class="dv">8</span>; <span class="co">/* assume that tab is 8 spaces. */</span></span>
|
||
<span id="cb6-23"><a href="#cb6-23"></a><span class="st">\n</span> nline++; ncolumn = <span class="dv">1</span>;</span>
|
||
<span id="cb6-24"><a href="#cb6-24"></a> <span class="co">/* reserved keywords */</span></span>
|
||
<span id="cb6-25"><a href="#cb6-25"></a><span class="st">pu</span> get_location (yytext); <span class="cf">return</span> PU; <span class="co">/* pen up */</span></span>
|
||
<span id="cb6-26"><a href="#cb6-26"></a><span class="st">pd</span> get_location (yytext); <span class="cf">return</span> PD; <span class="co">/* pen down */</span></span>
|
||
<span id="cb6-27"><a href="#cb6-27"></a><span class="st">pw</span> get_location (yytext); <span class="cf">return</span> PW; <span class="co">/* pen width = line width */</span></span>
|
||
<span id="cb6-28"><a href="#cb6-28"></a><span class="st">fd</span> get_location (yytext); <span class="cf">return</span> FD; <span class="co">/* forward */</span></span>
|
||
<span id="cb6-29"><a href="#cb6-29"></a><span class="st">tr</span> get_location (yytext); <span class="cf">return</span> TR; <span class="co">/* turn right */</span></span>
|
||
<span id="cb6-30"><a href="#cb6-30"></a><span class="st">bc</span> get_location (yytext); <span class="cf">return</span> BC; <span class="co">/* background color */</span></span>
|
||
<span id="cb6-31"><a href="#cb6-31"></a><span class="st">fc</span> get_location (yytext); <span class="cf">return</span> FC; <span class="co">/* foreground color */</span></span>
|
||
<span id="cb6-32"><a href="#cb6-32"></a><span class="st">dp</span> get_location (yytext); <span class="cf">return</span> DP; <span class="co">/* define procedure */</span></span>
|
||
<span id="cb6-33"><a href="#cb6-33"></a><span class="st">if</span> get_location (yytext); <span class="cf">return</span> IF; <span class="co">/* if statement */</span></span>
|
||
<span id="cb6-34"><a href="#cb6-34"></a><span class="st">rt</span> get_location (yytext); <span class="cf">return</span> RT; <span class="co">/* return statement */</span></span>
|
||
<span id="cb6-35"><a href="#cb6-35"></a><span class="st">rs</span> get_location (yytext); <span class="cf">return</span> RS; <span class="co">/* reset the status */</span></span>
|
||
<span id="cb6-36"><a href="#cb6-36"></a> <span class="co">/* constant */</span></span>
|
||
<span id="cb6-37"><a href="#cb6-37"></a><span class="st">{REAL_NUMBER}</span> get_location (yytext); yylval.NUM = atof (yytext); <span class="cf">return</span> NUM;</span>
|
||
<span id="cb6-38"><a href="#cb6-38"></a> <span class="co">/* identifier */</span></span>
|
||
<span id="cb6-39"><a href="#cb6-39"></a><span class="st">{IDENTIFIER}</span> { get_location (yytext); yylval.ID = <span class="va">g_strdup</span>(yytext);</span>
|
||
<span id="cb6-40"><a href="#cb6-40"></a> list = <span class="va">g_slist_prepend</span> (list, yylval.ID);</span>
|
||
<span id="cb6-41"><a href="#cb6-41"></a> <span class="cf">return</span> ID;</span>
|
||
<span id="cb6-42"><a href="#cb6-42"></a> }</span>
|
||
<span id="cb6-43"><a href="#cb6-43"></a><span class="st">"="</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'='</span>;</span>
|
||
<span id="cb6-44"><a href="#cb6-44"></a><span class="st">">"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'>'</span>;</span>
|
||
<span id="cb6-45"><a href="#cb6-45"></a><span class="st">"<"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'<'</span>;</span>
|
||
<span id="cb6-46"><a href="#cb6-46"></a><span class="st">"+"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'+'</span>;</span>
|
||
<span id="cb6-47"><a href="#cb6-47"></a><span class="st">"-"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'-'</span>;</span>
|
||
<span id="cb6-48"><a href="#cb6-48"></a><span class="st">"*"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'*'</span>;</span>
|
||
<span id="cb6-49"><a href="#cb6-49"></a><span class="st">"/"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'/'</span>;</span>
|
||
<span id="cb6-50"><a href="#cb6-50"></a><span class="st">"("</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'('</span>;</span>
|
||
<span id="cb6-51"><a href="#cb6-51"></a><span class="st">")"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">')'</span>;</span>
|
||
<span id="cb6-52"><a href="#cb6-52"></a><span class="st">"{"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'{'</span>;</span>
|
||
<span id="cb6-53"><a href="#cb6-53"></a><span class="st">"}"</span> get_location (yytext); <span class="cf">return</span> <span class="ch">'}'</span>;</span>
|
||
<span id="cb6-54"><a href="#cb6-54"></a><span class="st">","</span> get_location (yytext); <span class="cf">return</span> <span class="ch">','</span>;</span>
|
||
<span id="cb6-55"><a href="#cb6-55"></a><span class="st">.</span> ncolumn++; <span class="cf">return</span> YYUNDEF;</span>
|
||
<span id="cb6-56"><a href="#cb6-56"></a><span class="bn">%%</span></span>
|
||
<span id="cb6-57"><a href="#cb6-57"></a></span>
|
||
<span id="cb6-58"><a href="#cb6-58"></a><span class="at">static</span> <span class="dt">void</span></span>
|
||
<span id="cb6-59"><a href="#cb6-59"></a>get_location (<span class="dt">char</span> *text) {</span>
|
||
<span id="cb6-60"><a href="#cb6-60"></a> yylloc.first_line = yylloc.last_line = nline;</span>
|
||
<span id="cb6-61"><a href="#cb6-61"></a> yylloc.first_column = ncolumn;</span>
|
||
<span id="cb6-62"><a href="#cb6-62"></a> yylloc.last_column = (ncolumn += strlen(text)) - <span class="dv">1</span>;</span>
|
||
<span id="cb6-63"><a href="#cb6-63"></a>}</span>
|
||
<span id="cb6-64"><a href="#cb6-64"></a></span>
|
||
<span id="cb6-65"><a href="#cb6-65"></a><span class="at">static</span> YY_BUFFER_STATE state;</span>
|
||
<span id="cb6-66"><a href="#cb6-66"></a></span>
|
||
<span id="cb6-67"><a href="#cb6-67"></a><span class="dt">void</span></span>
|
||
<span id="cb6-68"><a href="#cb6-68"></a>init_flex (<span class="at">const</span> <span class="dt">char</span> *text) {</span>
|
||
<span id="cb6-69"><a href="#cb6-69"></a> state = yy_scan_string (text);</span>
|
||
<span id="cb6-70"><a href="#cb6-70"></a>}</span>
|
||
<span id="cb6-71"><a href="#cb6-71"></a></span>
|
||
<span id="cb6-72"><a href="#cb6-72"></a><span class="dt">void</span></span>
|
||
<span id="cb6-73"><a href="#cb6-73"></a>finalize_flex (<span class="dt">void</span>) {</span>
|
||
<span id="cb6-74"><a href="#cb6-74"></a> yy_delete_buffer (state);</span>
|
||
<span id="cb6-75"><a href="#cb6-75"></a>}</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 62, is defined in <code>string.h</code> The function <code>atof</code>, in line 37, is defined in <code>stdlib.h</code>.</li>
|
||
<li>6-8: The current input position is pointed by <code>nline</code> and <code>ncolumn</code>. The function <code>get_location</code> (line 58-63) 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>11: GSlist is used to keep allocated memories.</li>
|
||
<li>14: 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>16-17: <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 definition. 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 37 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 16th line, 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 the input is a number, it matches the pattern in line 37. 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. 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 an integer defined by <code>turtle.y</code>.</p>
|
||
<p>The scanner generated by flex and C compiler 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><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 <code>NUM</code> (number), and its value is 123.4.</p>
|
||
<ul>
|
||
<li>19-55: Rules section.</li>
|
||
<li>20: 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>21: White space just increases a variable <code>ncolumn</code> by one.</li>
|
||
<li>22: Tab is assumed to be equal to eight spaces.</li>
|
||
<li>23: New line increases a variable <code>nline</code> by one and resets <code>ncolumn</code>.</li>
|
||
<li>25-35: Keywords just updates the location variables <code>ncolumn</code> and <code>yylloc</code>, and return the codes of the keywords.</li>
|
||
<li>37: Real number constant.</li>
|
||
<li>38: <code>IDENTIFIER</code> is defined in line 17. 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. Returns <code>ID</code>.</li>
|
||
<li>43-54: Symbols just update the location variable and return the codes. The code is the same as the symbol itself.</li>
|
||
<li>55: If the input doesn’t match above patterns, then it is error. Returns <code>YYUNDEF</code>.</li>
|
||
</ul>
|
||
<h3 id="user-code-section">User code section</h3>
|
||
<p>This section is just copied to C source file.</p>
|
||
<ul>
|
||
<li>58-63: 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>65: <code>YY_BUFFER_STATE</code> is a pointer points the input buffer.</li>
|
||
<li>67-70: <code>init_flex</code> is called by <code>run_cb</code> signal handler, which is called when <code>Run</code> button is clicked on. <code>run_cb</code> calls <code>init_flex</code> with one argument which is the copy of the content of GtkTextBuffer. <code>yy_scan_string</code> sets the input buffer to read from the text.</li>
|
||
<li>72-75: <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 from bison source file. 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 function in C source code. 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). More precisely, it is similar to BNF.</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="turtle/turtle_doc.src.md">document</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
|
||
| BC '(' expression ',' expression ',' expression ')'
|
||
| FC '(' expression ',' expression ',' expression ')'
|
||
| ID '=' expression
|
||
| IF '(' expression ')' '{' primary_procedure_list '}'
|
||
| RT
|
||
| RS
|
||
| 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 statemet</code>. Therefore, it is program.</li>
|
||
<li><code>statement statement statement</code> is <code>program statemet</code>. Therefore, it is program.</li>
|
||
</ul>
|
||
<p>You can find that a list 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>
|
||
<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 "turtle.h"
|
||
|
||
/* 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 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 BC
|
||
%token FC
|
||
%token DP
|
||
%token IF
|
||
%token RT
|
||
%token RS
|
||
/* 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 operater, not an assignment. The logical equal ‘<code>=</code>’ usually used in the conditional expression, for example, in <code>if</code> statement.</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><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><code>$$</code> is a semantic value of the result, which is <code>program</code> in the second line of the example above. The semantic value of <code>program</code> is a pointer to <code>node_t</code> type structure. It was defined in the declaration section.</li>
|
||
<li><code>$1</code> is a semantic value of the first component, which is <code>statement</code>. The semantic value of <code>statement</code> is also a pointer to <code>node_t</code>.</li>
|
||
<li><code>statement</code> is <code>primary_procedure</code>. There’s no action specified. Then, the default action is executed. It is <code>$$ = $1</code>.</li>
|
||
<li><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>. <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><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="" /><figcaption>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); }
|
||
| 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); }
|
||
/* 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"></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"></a>GSList *list = NULL;</span>
|
||
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true"></a></span>
|
||
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true"></a>node_t *</span>
|
||
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true"></a>tree1 (<span class="dt">int</span> type, node_t *child1, node_t *child2, node_t *child3) {</span>
|
||
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true"></a> node_t *new_node;</span>
|
||
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true"></a></span>
|
||
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true"></a> list = g_slist_prepend (list, g_malloc (<span class="kw">sizeof</span> (node_t)));</span>
|
||
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true"></a> new_node = (node_t *) list->data;</span>
|
||
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true"></a> new_node->type = type;</span>
|
||
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true"></a> child1(new_node) = child1;</span>
|
||
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true"></a> child2(new_node) = child2;</span>
|
||
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true"></a> child3(new_node) = child3;</span>
|
||
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true"></a> <span class="cf">return</span> new_node;</span>
|
||
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true"></a>}</span>
|
||
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true"></a></span>
|
||
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true"></a>node_t *</span>
|
||
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true"></a>tree2 (<span class="dt">int</span> type, <span class="dt">double</span> value) {</span>
|
||
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true"></a> node_t *new_node;</span>
|
||
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true"></a></span>
|
||
<span id="cb30-21"><a href="#cb30-21" aria-hidden="true"></a> list = g_slist_prepend (list, g_malloc (<span class="kw">sizeof</span> (node_t)));</span>
|
||
<span id="cb30-22"><a href="#cb30-22" aria-hidden="true"></a> new_node = (node_t *) list->data;</span>
|
||
<span id="cb30-23"><a href="#cb30-23" aria-hidden="true"></a> new_node->type = type;</span>
|
||
<span id="cb30-24"><a href="#cb30-24" aria-hidden="true"></a> value(new_node) = value;</span>
|
||
<span id="cb30-25"><a href="#cb30-25" aria-hidden="true"></a> <span class="cf">return</span> new_node;</span>
|
||
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true"></a>}</span>
|
||
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true"></a></span>
|
||
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true"></a>node_t *</span>
|
||
<span id="cb30-29"><a href="#cb30-29" aria-hidden="true"></a>tree3 (<span class="dt">int</span> type, <span class="dt">char</span> *name) {</span>
|
||
<span id="cb30-30"><a href="#cb30-30" aria-hidden="true"></a> node_t *new_node;</span>
|
||
<span id="cb30-31"><a href="#cb30-31" aria-hidden="true"></a></span>
|
||
<span id="cb30-32"><a href="#cb30-32" aria-hidden="true"></a> list = g_slist_prepend (list, g_malloc (<span class="kw">sizeof</span> (node_t)));</span>
|
||
<span id="cb30-33"><a href="#cb30-33" aria-hidden="true"></a> new_node = (node_t *) list->data;</span>
|
||
<span id="cb30-34"><a href="#cb30-34" aria-hidden="true"></a> new_node->type = type;</span>
|
||
<span id="cb30-35"><a href="#cb30-35" aria-hidden="true"></a> name(new_node) = name;</span>
|
||
<span id="cb30-36"><a href="#cb30-36" aria-hidden="true"></a> <span class="cf">return</span> new_node;</span>
|
||
<span id="cb30-37"><a href="#cb30-37" aria-hidden="true"></a>}</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"></a><span class="pp">#define MAX_TABLE_SIZE 100</span></span>
|
||
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true"></a><span class="kw">enum</span> {</span>
|
||
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true"></a> PROC,</span>
|
||
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true"></a> VAR</span>
|
||
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true"></a>};</span>
|
||
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true"></a></span>
|
||
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true"></a><span class="kw">typedef</span> <span class="kw">union</span> _object_t object_t;</span>
|
||
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true"></a><span class="kw">union</span> _object_t {</span>
|
||
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true"></a> node_t *node;</span>
|
||
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true"></a> <span class="dt">double</span> value;</span>
|
||
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true"></a>};</span>
|
||
<span id="cb31-12"><a href="#cb31-12" aria-hidden="true"></a></span>
|
||
<span id="cb31-13"><a href="#cb31-13" aria-hidden="true"></a><span class="kw">struct</span> {</span>
|
||
<span id="cb31-14"><a href="#cb31-14" aria-hidden="true"></a> <span class="dt">int</span> type;</span>
|
||
<span id="cb31-15"><a href="#cb31-15" aria-hidden="true"></a> <span class="dt">char</span> *name;</span>
|
||
<span id="cb31-16"><a href="#cb31-16" aria-hidden="true"></a> object_t object;</span>
|
||
<span id="cb31-17"><a href="#cb31-17" aria-hidden="true"></a>} table[MAX_TABLE_SIZE];</span>
|
||
<span id="cb31-18"><a href="#cb31-18" aria-hidden="true"></a><span class="dt">int</span> tp;</span>
|
||
<span id="cb31-19"><a href="#cb31-19" aria-hidden="true"></a></span>
|
||
<span id="cb31-20"><a href="#cb31-20" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb31-21"><a href="#cb31-21" aria-hidden="true"></a>init_table (<span class="dt">void</span>) {</span>
|
||
<span id="cb31-22"><a href="#cb31-22" aria-hidden="true"></a> tp = <span class="dv">0</span>;</span>
|
||
<span id="cb31-23"><a href="#cb31-23" aria-hidden="true"></a>}</span></code></pre></div>
|
||
<p><code>init_table</code> initializes the table. This must be called before any 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"></a><span class="dt">int</span></span>
|
||
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true"></a>tbl_lookup (<span class="dt">int</span> type, <span class="dt">char</span> *name) {</span>
|
||
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true"></a></span>
|
||
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true"></a> <span class="cf">if</span> (tp == <span class="dv">0</span>)</span>
|
||
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true"></a> <span class="cf">return</span> -<span class="dv">1</span>;</span>
|
||
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true"></a> <span class="cf">for</span> (i=<span class="dv">0</span>; i<tp; ++i)</span>
|
||
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true"></a> <span class="cf">if</span> (type == table[i].type && strcmp(name, table[i].name) == <span class="dv">0</span>)</span>
|
||
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true"></a> <span class="cf">return</span> i;</span>
|
||
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true"></a> <span class="cf">return</span> -<span class="dv">1</span>;</span>
|
||
<span id="cb32-11"><a href="#cb32-11" aria-hidden="true"></a>}</span>
|
||
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true"></a></span>
|
||
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb32-14"><a href="#cb32-14" aria-hidden="true"></a>tbl_install (<span class="dt">int</span> type, <span class="dt">char</span> *name, object_t object) {</span>
|
||
<span id="cb32-15"><a href="#cb32-15" aria-hidden="true"></a> <span class="cf">if</span> (tp >= MAX_TABLE_SIZE)</span>
|
||
<span id="cb32-16"><a href="#cb32-16" aria-hidden="true"></a> runtime_error (<span class="st">"Symbol table overflow.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb32-17"><a href="#cb32-17" aria-hidden="true"></a> <span class="cf">else</span> <span class="cf">if</span> (tbl_lookup (type, name) >= <span class="dv">0</span>)</span>
|
||
<span id="cb32-18"><a href="#cb32-18" aria-hidden="true"></a> runtime_error (<span class="st">"Name %s is already registered.</span><span class="sc">\n</span><span class="st">"</span>, name);</span>
|
||
<span id="cb32-19"><a href="#cb32-19" aria-hidden="true"></a> <span class="cf">else</span> {</span>
|
||
<span id="cb32-20"><a href="#cb32-20" aria-hidden="true"></a> table[tp].type = type;</span>
|
||
<span id="cb32-21"><a href="#cb32-21" aria-hidden="true"></a> table[tp].name = name;</span>
|
||
<span id="cb32-22"><a href="#cb32-22" aria-hidden="true"></a> <span class="cf">if</span> (type == PROC)</span>
|
||
<span id="cb32-23"><a href="#cb32-23" aria-hidden="true"></a> table[tp++].object.node = object.node;</span>
|
||
<span id="cb32-24"><a href="#cb32-24" aria-hidden="true"></a> <span class="cf">else</span></span>
|
||
<span id="cb32-25"><a href="#cb32-25" aria-hidden="true"></a> table[tp++].object.value = object.value;</span>
|
||
<span id="cb32-26"><a href="#cb32-26" aria-hidden="true"></a> }</span>
|
||
<span id="cb32-27"><a href="#cb32-27" aria-hidden="true"></a>}</span>
|
||
<span id="cb32-28"><a href="#cb32-28" aria-hidden="true"></a></span>
|
||
<span id="cb32-29"><a href="#cb32-29" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb32-30"><a href="#cb32-30" aria-hidden="true"></a>proc_install (<span class="dt">char</span> *name, node_t *node) {</span>
|
||
<span id="cb32-31"><a href="#cb32-31" aria-hidden="true"></a> object_t object;</span>
|
||
<span id="cb32-32"><a href="#cb32-32" aria-hidden="true"></a> object.node = node;</span>
|
||
<span id="cb32-33"><a href="#cb32-33" aria-hidden="true"></a> tbl_install (PROC, name, object);</span>
|
||
<span id="cb32-34"><a href="#cb32-34" aria-hidden="true"></a>}</span>
|
||
<span id="cb32-35"><a href="#cb32-35" aria-hidden="true"></a></span>
|
||
<span id="cb32-36"><a href="#cb32-36" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb32-37"><a href="#cb32-37" aria-hidden="true"></a>var_install (<span class="dt">char</span> *name, <span class="dt">double</span> value) {</span>
|
||
<span id="cb32-38"><a href="#cb32-38" aria-hidden="true"></a> object_t object;</span>
|
||
<span id="cb32-39"><a href="#cb32-39" aria-hidden="true"></a> object.value = value;</span>
|
||
<span id="cb32-40"><a href="#cb32-40" aria-hidden="true"></a> tbl_install (VAR, name, object);</span>
|
||
<span id="cb32-41"><a href="#cb32-41" aria-hidden="true"></a>}</span>
|
||
<span id="cb32-42"><a href="#cb32-42" aria-hidden="true"></a></span>
|
||
<span id="cb32-43"><a href="#cb32-43" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb32-44"><a href="#cb32-44" aria-hidden="true"></a>var_replace (<span class="dt">char</span> *name, <span class="dt">double</span> value) {</span>
|
||
<span id="cb32-45"><a href="#cb32-45" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb32-46"><a href="#cb32-46" aria-hidden="true"></a> <span class="cf">if</span> ((i = tbl_lookup (VAR, name)) >= <span class="dv">0</span>)</span>
|
||
<span id="cb32-47"><a href="#cb32-47" aria-hidden="true"></a> table[i].object.value = value;</span>
|
||
<span id="cb32-48"><a href="#cb32-48" aria-hidden="true"></a> <span class="cf">else</span></span>
|
||
<span id="cb32-49"><a href="#cb32-49" aria-hidden="true"></a> var_install (name, value);</span>
|
||
<span id="cb32-50"><a href="#cb32-50" aria-hidden="true"></a>}</span>
|
||
<span id="cb32-51"><a href="#cb32-51" aria-hidden="true"></a></span>
|
||
<span id="cb32-52"><a href="#cb32-52" aria-hidden="true"></a>node_t *</span>
|
||
<span id="cb32-53"><a href="#cb32-53" aria-hidden="true"></a>proc_lookup (<span class="dt">char</span> *name) {</span>
|
||
<span id="cb32-54"><a href="#cb32-54" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb32-55"><a href="#cb32-55" aria-hidden="true"></a> <span class="cf">if</span> ((i = tbl_lookup (PROC, name)) < <span class="dv">0</span>)</span>
|
||
<span id="cb32-56"><a href="#cb32-56" aria-hidden="true"></a> <span class="cf">return</span> NULL;</span>
|
||
<span id="cb32-57"><a href="#cb32-57" aria-hidden="true"></a> <span class="cf">else</span></span>
|
||
<span id="cb32-58"><a href="#cb32-58" aria-hidden="true"></a> <span class="cf">return</span> table[i].object.node;</span>
|
||
<span id="cb32-59"><a href="#cb32-59" aria-hidden="true"></a>}</span>
|
||
<span id="cb32-60"><a href="#cb32-60" aria-hidden="true"></a></span>
|
||
<span id="cb32-61"><a href="#cb32-61" aria-hidden="true"></a>gboolean</span>
|
||
<span id="cb32-62"><a href="#cb32-62" aria-hidden="true"></a>var_lookup (<span class="dt">char</span> *name, <span class="dt">double</span> *value) {</span>
|
||
<span id="cb32-63"><a href="#cb32-63" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb32-64"><a href="#cb32-64" aria-hidden="true"></a> <span class="cf">if</span> ((i = tbl_lookup (VAR, name)) < <span class="dv">0</span>)</span>
|
||
<span id="cb32-65"><a href="#cb32-65" aria-hidden="true"></a> <span class="cf">return</span> FALSE;</span>
|
||
<span id="cb32-66"><a href="#cb32-66" aria-hidden="true"></a> <span class="cf">else</span> {</span>
|
||
<span id="cb32-67"><a href="#cb32-67" aria-hidden="true"></a> *value = table[i].object.value;</span>
|
||
<span id="cb32-68"><a href="#cb32-68" aria-hidden="true"></a> <span class="cf">return</span> TRUE;</span>
|
||
<span id="cb32-69"><a href="#cb32-69" aria-hidden="true"></a> }</span>
|
||
<span id="cb32-70"><a href="#cb32-70" aria-hidden="true"></a>}</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"></a><span class="pp">#define MAX_STACK_SIZE 500</span></span>
|
||
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true"></a><span class="kw">struct</span> {</span>
|
||
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true"></a> <span class="dt">char</span> *name;</span>
|
||
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true"></a> <span class="dt">double</span> value;</span>
|
||
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true"></a>} stack[MAX_STACK_SIZE];</span>
|
||
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true"></a><span class="dt">int</span> sp, sp_biggest;</span>
|
||
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true"></a></span>
|
||
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true"></a>init_stack (<span class="dt">void</span>) {</span>
|
||
<span id="cb33-10"><a href="#cb33-10" aria-hidden="true"></a> sp = sp_biggest = <span class="dv">0</span>;</span>
|
||
<span id="cb33-11"><a href="#cb33-11" aria-hidden="true"></a>}</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 (“distance”, 100.0) to the stack.</li>
|
||
<li>It pushes (“angle”, 90.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>, which has one parameter, is called. And in the <code>procedure 2</code>, <code>procedure 3</code>, which has three parameters, is called.</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="" /><figcaption>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"></a><span class="dt">void</span></span>
|
||
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true"></a>stack_push (<span class="dt">char</span> *name, <span class="dt">double</span> value) {</span>
|
||
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true"></a> <span class="cf">if</span> (sp >= MAX_STACK_SIZE)</span>
|
||
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true"></a> runtime_error (<span class="st">"Stack overflow.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true"></a> <span class="cf">else</span> {</span>
|
||
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true"></a> stack[sp].name = name;</span>
|
||
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true"></a> stack[sp++].value = value;</span>
|
||
<span id="cb35-8"><a href="#cb35-8" aria-hidden="true"></a> sp_biggest = sp > sp_biggest ? sp : sp_biggest;</span>
|
||
<span id="cb35-9"><a href="#cb35-9" aria-hidden="true"></a> }</span>
|
||
<span id="cb35-10"><a href="#cb35-10" aria-hidden="true"></a>}</span>
|
||
<span id="cb35-11"><a href="#cb35-11" aria-hidden="true"></a></span>
|
||
<span id="cb35-12"><a href="#cb35-12" aria-hidden="true"></a><span class="dt">int</span></span>
|
||
<span id="cb35-13"><a href="#cb35-13" aria-hidden="true"></a>stack_search (<span class="dt">char</span> *name) {</span>
|
||
<span id="cb35-14"><a href="#cb35-14" aria-hidden="true"></a> <span class="dt">int</span> depth, i;</span>
|
||
<span id="cb35-15"><a href="#cb35-15" aria-hidden="true"></a></span>
|
||
<span id="cb35-16"><a href="#cb35-16" aria-hidden="true"></a> <span class="cf">if</span> (sp == <span class="dv">0</span>)</span>
|
||
<span id="cb35-17"><a href="#cb35-17" aria-hidden="true"></a> <span class="cf">return</span> -<span class="dv">1</span>;</span>
|
||
<span id="cb35-18"><a href="#cb35-18" aria-hidden="true"></a> depth = (<span class="dt">int</span>) stack[sp-<span class="dv">1</span>].value;</span>
|
||
<span id="cb35-19"><a href="#cb35-19" aria-hidden="true"></a> <span class="cf">if</span> (depth + <span class="dv">1</span> > sp) <span class="co">/* something strange */</span></span>
|
||
<span id="cb35-20"><a href="#cb35-20" aria-hidden="true"></a> runtime_error (<span class="st">"Stack error.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb35-21"><a href="#cb35-21" aria-hidden="true"></a> <span class="cf">for</span> (i=<span class="dv">0</span>; i<depth; ++i)</span>
|
||
<span id="cb35-22"><a href="#cb35-22" aria-hidden="true"></a> <span class="cf">if</span> (strcmp(name, stack[sp-(i+<span class="dv">2</span>)].name) == <span class="dv">0</span>) {</span>
|
||
<span id="cb35-23"><a href="#cb35-23" aria-hidden="true"></a> <span class="cf">return</span> sp-(i+<span class="dv">2</span>);</span>
|
||
<span id="cb35-24"><a href="#cb35-24" aria-hidden="true"></a> }</span>
|
||
<span id="cb35-25"><a href="#cb35-25" aria-hidden="true"></a> <span class="cf">return</span> -<span class="dv">1</span>;</span>
|
||
<span id="cb35-26"><a href="#cb35-26" aria-hidden="true"></a>}</span>
|
||
<span id="cb35-27"><a href="#cb35-27" aria-hidden="true"></a></span>
|
||
<span id="cb35-28"><a href="#cb35-28" aria-hidden="true"></a>gboolean</span>
|
||
<span id="cb35-29"><a href="#cb35-29" aria-hidden="true"></a>stack_lookup (<span class="dt">char</span> *name, <span class="dt">double</span> *value) {</span>
|
||
<span id="cb35-30"><a href="#cb35-30" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb35-31"><a href="#cb35-31" aria-hidden="true"></a></span>
|
||
<span id="cb35-32"><a href="#cb35-32" aria-hidden="true"></a> <span class="cf">if</span> ((i = stack_search (name)) < <span class="dv">0</span>)</span>
|
||
<span id="cb35-33"><a href="#cb35-33" aria-hidden="true"></a> <span class="cf">return</span> FALSE;</span>
|
||
<span id="cb35-34"><a href="#cb35-34" aria-hidden="true"></a> <span class="cf">else</span> {</span>
|
||
<span id="cb35-35"><a href="#cb35-35" aria-hidden="true"></a> *value = stack[i].value;</span>
|
||
<span id="cb35-36"><a href="#cb35-36" aria-hidden="true"></a> <span class="cf">return</span> TRUE;</span>
|
||
<span id="cb35-37"><a href="#cb35-37" aria-hidden="true"></a> }</span>
|
||
<span id="cb35-38"><a href="#cb35-38" aria-hidden="true"></a>}</span>
|
||
<span id="cb35-39"><a href="#cb35-39" aria-hidden="true"></a></span>
|
||
<span id="cb35-40"><a href="#cb35-40" aria-hidden="true"></a>gboolean</span>
|
||
<span id="cb35-41"><a href="#cb35-41" aria-hidden="true"></a>stack_replace (<span class="dt">char</span> *name, <span class="dt">double</span> value) {</span>
|
||
<span id="cb35-42"><a href="#cb35-42" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb35-43"><a href="#cb35-43" aria-hidden="true"></a></span>
|
||
<span id="cb35-44"><a href="#cb35-44" aria-hidden="true"></a> <span class="cf">if</span> ((i = stack_search (name)) < <span class="dv">0</span>)</span>
|
||
<span id="cb35-45"><a href="#cb35-45" aria-hidden="true"></a> <span class="cf">return</span> FALSE;</span>
|
||
<span id="cb35-46"><a href="#cb35-46" aria-hidden="true"></a> <span class="cf">else</span> {</span>
|
||
<span id="cb35-47"><a href="#cb35-47" aria-hidden="true"></a> stack[i].value = value;</span>
|
||
<span id="cb35-48"><a href="#cb35-48" aria-hidden="true"></a> <span class="cf">return</span> TRUE;</span>
|
||
<span id="cb35-49"><a href="#cb35-49" aria-hidden="true"></a> }</span>
|
||
<span id="cb35-50"><a href="#cb35-50" aria-hidden="true"></a>}</span>
|
||
<span id="cb35-51"><a href="#cb35-51" aria-hidden="true"></a></span>
|
||
<span id="cb35-52"><a href="#cb35-52" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb35-53"><a href="#cb35-53" aria-hidden="true"></a>stack_return(<span class="dt">void</span>) {</span>
|
||
<span id="cb35-54"><a href="#cb35-54" aria-hidden="true"></a> <span class="dt">int</span> depth;</span>
|
||
<span id="cb35-55"><a href="#cb35-55" aria-hidden="true"></a></span>
|
||
<span id="cb35-56"><a href="#cb35-56" aria-hidden="true"></a> <span class="cf">if</span> (sp <= <span class="dv">0</span>)</span>
|
||
<span id="cb35-57"><a href="#cb35-57" aria-hidden="true"></a> <span class="cf">return</span>;</span>
|
||
<span id="cb35-58"><a href="#cb35-58" aria-hidden="true"></a> depth = (<span class="dt">int</span>) stack[sp-<span class="dv">1</span>].value;</span>
|
||
<span id="cb35-59"><a href="#cb35-59" aria-hidden="true"></a> <span class="cf">if</span> (depth + <span class="dv">1</span> > sp) <span class="co">/* something strange */</span></span>
|
||
<span id="cb35-60"><a href="#cb35-60" aria-hidden="true"></a> runtime_error (<span class="st">"Stack error.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb35-61"><a href="#cb35-61" aria-hidden="true"></a> sp -= depth + <span class="dv">1</span>;</span>
|
||
<span id="cb35-62"><a href="#cb35-62" aria-hidden="true"></a>}</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="" /><figcaption>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"></a><span class="co">/* status of the surface */</span></span>
|
||
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true"></a><span class="dt">static</span> gboolean pen = TRUE;</span>
|
||
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">double</span> angle = <span class="fl">90.0</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"></a> <span class="co">/* Initially facing to the north */</span></span>
|
||
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">double</span> cur_x = <span class="fl">0.0</span>;</span>
|
||
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">double</span> cur_y = <span class="fl">0.0</span>;</span>
|
||
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">double</span> line_width = <span class="fl">2.0</span>;</span>
|
||
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true"></a></span>
|
||
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true"></a><span class="kw">struct</span> color {</span>
|
||
<span id="cb37-10"><a href="#cb37-10" aria-hidden="true"></a> <span class="dt">double</span> red;</span>
|
||
<span id="cb37-11"><a href="#cb37-11" aria-hidden="true"></a> <span class="dt">double</span> green;</span>
|
||
<span id="cb37-12"><a href="#cb37-12" aria-hidden="true"></a> <span class="dt">double</span> blue;</span>
|
||
<span id="cb37-13"><a href="#cb37-13" aria-hidden="true"></a>};</span>
|
||
<span id="cb37-14"><a href="#cb37-14" aria-hidden="true"></a><span class="dt">static</span> <span class="kw">struct</span> color bc = {<span class="fl">0.95</span>, <span class="fl">0.95</span>, <span class="fl">0.95</span>}; <span class="co">/* white */</span></span>
|
||
<span id="cb37-15"><a href="#cb37-15" aria-hidden="true"></a><span class="dt">static</span> <span class="kw">struct</span> color fc = {<span class="fl">0.0</span>, <span class="fl">0.0</span>, <span class="fl">0.0</span>}; <span class="co">/* black */</span></span>
|
||
<span id="cb37-16"><a href="#cb37-16" aria-hidden="true"></a></span>
|
||
<span id="cb37-17"><a href="#cb37-17" aria-hidden="true"></a><span class="co">/* cairo */</span></span>
|
||
<span id="cb37-18"><a href="#cb37-18" aria-hidden="true"></a><span class="dt">static</span> cairo_t *cr;</span>
|
||
<span id="cb37-19"><a href="#cb37-19" aria-hidden="true"></a>gboolean</span>
|
||
<span id="cb37-20"><a href="#cb37-20" aria-hidden="true"></a>init_cairo (<span class="dt">void</span>) {</span>
|
||
<span id="cb37-21"><a href="#cb37-21" aria-hidden="true"></a> <span class="dt">int</span> width, height;</span>
|
||
<span id="cb37-22"><a href="#cb37-22" aria-hidden="true"></a> cairo_matrix_t matrix;</span>
|
||
<span id="cb37-23"><a href="#cb37-23" aria-hidden="true"></a></span>
|
||
<span id="cb37-24"><a href="#cb37-24" aria-hidden="true"></a> pen = TRUE;</span>
|
||
<span id="cb37-25"><a href="#cb37-25" aria-hidden="true"></a> angle = <span class="fl">90.0</span>;</span>
|
||
<span id="cb37-26"><a href="#cb37-26" aria-hidden="true"></a> cur_x = <span class="fl">0.0</span>;</span>
|
||
<span id="cb37-27"><a href="#cb37-27" aria-hidden="true"></a> cur_y = <span class="fl">0.0</span>;</span>
|
||
<span id="cb37-28"><a href="#cb37-28" aria-hidden="true"></a> line_width = <span class="fl">2.0</span>;</span>
|
||
<span id="cb37-29"><a href="#cb37-29" aria-hidden="true"></a> bc.red = <span class="fl">0.95</span>; bc.green = <span class="fl">0.95</span>; bc.blue = <span class="fl">0.95</span>;</span>
|
||
<span id="cb37-30"><a href="#cb37-30" aria-hidden="true"></a> fc.red = <span class="fl">0.0</span>; fc.green = <span class="fl">0.0</span>; fc.blue = <span class="fl">0.0</span>;</span>
|
||
<span id="cb37-31"><a href="#cb37-31" aria-hidden="true"></a></span>
|
||
<span id="cb37-32"><a href="#cb37-32" aria-hidden="true"></a> <span class="cf">if</span> (surface) {</span>
|
||
<span id="cb37-33"><a href="#cb37-33" aria-hidden="true"></a> width = cairo_image_surface_get_width (surface);</span>
|
||
<span id="cb37-34"><a href="#cb37-34" aria-hidden="true"></a> height = cairo_image_surface_get_height (surface);</span>
|
||
<span id="cb37-35"><a href="#cb37-35" aria-hidden="true"></a> matrix.xx = <span class="fl">1.0</span>; matrix.xy = <span class="fl">0.0</span>; matrix.x0 = (<span class="dt">double</span>) width / <span class="fl">2.0</span>;</span>
|
||
<span id="cb37-36"><a href="#cb37-36" aria-hidden="true"></a> matrix.yx = <span class="fl">0.0</span>; matrix.yy = -<span class="fl">1.0</span>; matrix.y0 = (<span class="dt">double</span>) height / <span class="fl">2.0</span>;</span>
|
||
<span id="cb37-37"><a href="#cb37-37" aria-hidden="true"></a></span>
|
||
<span id="cb37-38"><a href="#cb37-38" aria-hidden="true"></a> cr = cairo_create (surface);</span>
|
||
<span id="cb37-39"><a href="#cb37-39" aria-hidden="true"></a> cairo_transform (cr, &matrix);</span>
|
||
<span id="cb37-40"><a href="#cb37-40" aria-hidden="true"></a> cairo_set_source_rgb (cr, bc.red, bc.green, bc.blue);</span>
|
||
<span id="cb37-41"><a href="#cb37-41" aria-hidden="true"></a> cairo_paint (cr);</span>
|
||
<span id="cb37-42"><a href="#cb37-42" aria-hidden="true"></a> cairo_set_source_rgb (cr, fc.red, fc.green, fc.blue);</span>
|
||
<span id="cb37-43"><a href="#cb37-43" aria-hidden="true"></a> cairo_move_to (cr, cur_x, cur_y);</span>
|
||
<span id="cb37-44"><a href="#cb37-44" aria-hidden="true"></a> <span class="cf">return</span> TRUE;</span>
|
||
<span id="cb37-45"><a href="#cb37-45" aria-hidden="true"></a> } <span class="cf">else</span></span>
|
||
<span id="cb37-46"><a href="#cb37-46" aria-hidden="true"></a> <span class="cf">return</span> FALSE;</span>
|
||
<span id="cb37-47"><a href="#cb37-47" aria-hidden="true"></a>}</span>
|
||
<span id="cb37-48"><a href="#cb37-48" aria-hidden="true"></a></span>
|
||
<span id="cb37-49"><a href="#cb37-49" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb37-50"><a href="#cb37-50" aria-hidden="true"></a>destroy_cairo () {</span>
|
||
<span id="cb37-51"><a href="#cb37-51" aria-hidden="true"></a> cairo_destroy (cr);</span>
|
||
<span id="cb37-52"><a href="#cb37-52" aria-hidden="true"></a>}</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"></a><span class="dt">double</span></span>
|
||
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true"></a>eval (node_t *node) {</span>
|
||
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true"></a><span class="dt">double</span> value = <span class="fl">0.0</span>;</span>
|
||
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true"></a> <span class="cf">if</span> (node == NULL)</span>
|
||
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true"></a> runtime_error (<span class="st">"No expression to evaluate.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true"></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"></a> <span class="cf">switch</span> (node->type) {</span>
|
||
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true"></a> <span class="cf">case</span> N_EQ:</span>
|
||
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true"></a> value = (<span class="dt">double</span>) calc(==);</span>
|
||
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true"></a> <span class="cf">case</span> N_GT:</span>
|
||
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true"></a> value = (<span class="dt">double</span>) calc(>);</span>
|
||
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true"></a> <span class="cf">case</span> N_LT:</span>
|
||
<span id="cb38-15"><a href="#cb38-15" aria-hidden="true"></a> value = (<span class="dt">double</span>) calc(<);</span>
|
||
<span id="cb38-16"><a href="#cb38-16" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-17"><a href="#cb38-17" aria-hidden="true"></a> <span class="cf">case</span> N_ADD:</span>
|
||
<span id="cb38-18"><a href="#cb38-18" aria-hidden="true"></a> value = calc(+);</span>
|
||
<span id="cb38-19"><a href="#cb38-19" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-20"><a href="#cb38-20" aria-hidden="true"></a> <span class="cf">case</span> N_SUB:</span>
|
||
<span id="cb38-21"><a href="#cb38-21" aria-hidden="true"></a> value = calc(-);</span>
|
||
<span id="cb38-22"><a href="#cb38-22" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-23"><a href="#cb38-23" aria-hidden="true"></a> <span class="cf">case</span> N_MUL:</span>
|
||
<span id="cb38-24"><a href="#cb38-24" aria-hidden="true"></a> value = calc(*);</span>
|
||
<span id="cb38-25"><a href="#cb38-25" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-26"><a href="#cb38-26" aria-hidden="true"></a> <span class="cf">case</span> N_DIV:</span>
|
||
<span id="cb38-27"><a href="#cb38-27" aria-hidden="true"></a> <span class="cf">if</span> (eval (child2(node)) == <span class="fl">0.0</span>)</span>
|
||
<span id="cb38-28"><a href="#cb38-28" aria-hidden="true"></a> runtime_error (<span class="st">"Division by zerp.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb38-29"><a href="#cb38-29" aria-hidden="true"></a> <span class="cf">else</span></span>
|
||
<span id="cb38-30"><a href="#cb38-30" aria-hidden="true"></a> value = calc(/);</span>
|
||
<span id="cb38-31"><a href="#cb38-31" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-32"><a href="#cb38-32" aria-hidden="true"></a> <span class="cf">case</span> N_UMINUS:</span>
|
||
<span id="cb38-33"><a href="#cb38-33" aria-hidden="true"></a> value = -(eval (child1(node)));</span>
|
||
<span id="cb38-34"><a href="#cb38-34" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-35"><a href="#cb38-35" aria-hidden="true"></a> <span class="cf">case</span> N_ID:</span>
|
||
<span id="cb38-36"><a href="#cb38-36" aria-hidden="true"></a> <span class="cf">if</span> (! (stack_lookup (name(node), &value)) && ! var_lookup (name(node), &value) )</span>
|
||
<span id="cb38-37"><a href="#cb38-37" aria-hidden="true"></a> runtime_error (<span class="st">"Variable %s not defined.</span><span class="sc">\n</span><span class="st">"</span>, name(node));</span>
|
||
<span id="cb38-38"><a href="#cb38-38" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-39"><a href="#cb38-39" aria-hidden="true"></a> <span class="cf">case</span> N_NUM:</span>
|
||
<span id="cb38-40"><a href="#cb38-40" aria-hidden="true"></a> value = value(node);</span>
|
||
<span id="cb38-41"><a href="#cb38-41" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb38-42"><a href="#cb38-42" aria-hidden="true"></a> <span class="cf">default</span>:</span>
|
||
<span id="cb38-43"><a href="#cb38-43" aria-hidden="true"></a> runtime_error (<span class="st">"Illegal expression.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb38-44"><a href="#cb38-44" aria-hidden="true"></a> }</span>
|
||
<span id="cb38-45"><a href="#cb38-45" aria-hidden="true"></a> <span class="cf">return</span> value;</span>
|
||
<span id="cb38-46"><a href="#cb38-46" aria-hidden="true"></a>}</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"></a><span class="co">/* procedure - return status */</span></span>
|
||
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">int</span> proc_level = <span class="dv">0</span>;</span>
|
||
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">int</span> ret_level = <span class="dv">0</span>;</span>
|
||
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true"></a></span>
|
||
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true"></a>execute (node_t *node) {</span>
|
||
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true"></a> <span class="dt">double</span> d, x, y;</span>
|
||
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true"></a> <span class="dt">char</span> *name;</span>
|
||
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true"></a> <span class="dt">int</span> n, i;</span>
|
||
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true"></a></span>
|
||
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true"></a> <span class="cf">if</span> (node == NULL)</span>
|
||
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true"></a> runtime_error (<span class="st">"Node is NULL.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true"></a> <span class="cf">if</span> (proc_level > ret_level)</span>
|
||
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true"></a> <span class="cf">return</span>;</span>
|
||
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true"></a> <span class="cf">switch</span> (node->type) {</span>
|
||
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true"></a> <span class="cf">case</span> N_program:</span>
|
||
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true"></a> execute (child1(node));</span>
|
||
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true"></a> execute (child2(node));</span>
|
||
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-20"><a href="#cb39-20" aria-hidden="true"></a> <span class="cf">case</span> N_PU:</span>
|
||
<span id="cb39-21"><a href="#cb39-21" aria-hidden="true"></a> pen = FALSE;</span>
|
||
<span id="cb39-22"><a href="#cb39-22" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-23"><a href="#cb39-23" aria-hidden="true"></a> <span class="cf">case</span> N_PD:</span>
|
||
<span id="cb39-24"><a href="#cb39-24" aria-hidden="true"></a> pen = TRUE;</span>
|
||
<span id="cb39-25"><a href="#cb39-25" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-26"><a href="#cb39-26" aria-hidden="true"></a> <span class="cf">case</span> N_PW:</span>
|
||
<span id="cb39-27"><a href="#cb39-27" aria-hidden="true"></a> line_width = eval (child1(node)); <span class="co">/* line width */</span></span>
|
||
<span id="cb39-28"><a href="#cb39-28" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-29"><a href="#cb39-29" aria-hidden="true"></a> <span class="cf">case</span> N_FD:</span>
|
||
<span id="cb39-30"><a href="#cb39-30" aria-hidden="true"></a> d = eval (child1(node)); <span class="co">/* distance */</span></span>
|
||
<span id="cb39-31"><a href="#cb39-31" aria-hidden="true"></a> x = d * cos (angle*M_PI/<span class="dv">180</span>);</span>
|
||
<span id="cb39-32"><a href="#cb39-32" aria-hidden="true"></a> y = d * sin (angle*M_PI/<span class="dv">180</span>);</span>
|
||
<span id="cb39-33"><a href="#cb39-33" aria-hidden="true"></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"></a> cairo_move_to (cr, cur_x, cur_y);</span>
|
||
<span id="cb39-35"><a href="#cb39-35" aria-hidden="true"></a> cur_x += x;</span>
|
||
<span id="cb39-36"><a href="#cb39-36" aria-hidden="true"></a> cur_y += y;</span>
|
||
<span id="cb39-37"><a href="#cb39-37" aria-hidden="true"></a> cairo_set_line_width (cr, line_width);</span>
|
||
<span id="cb39-38"><a href="#cb39-38" aria-hidden="true"></a> cairo_set_source_rgb (cr, fc.red, fc.green, fc.blue);</span>
|
||
<span id="cb39-39"><a href="#cb39-39" aria-hidden="true"></a> <span class="cf">if</span> (pen)</span>
|
||
<span id="cb39-40"><a href="#cb39-40" aria-hidden="true"></a> cairo_line_to (cr, cur_x, cur_y);</span>
|
||
<span id="cb39-41"><a href="#cb39-41" aria-hidden="true"></a> <span class="cf">else</span></span>
|
||
<span id="cb39-42"><a href="#cb39-42" aria-hidden="true"></a> cairo_move_to (cr, cur_x, cur_y);</span>
|
||
<span id="cb39-43"><a href="#cb39-43" aria-hidden="true"></a> cairo_stroke (cr);</span>
|
||
<span id="cb39-44"><a href="#cb39-44" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-45"><a href="#cb39-45" aria-hidden="true"></a> <span class="cf">case</span> N_TR:</span>
|
||
<span id="cb39-46"><a href="#cb39-46" aria-hidden="true"></a> angle -= eval (child1(node));</span>
|
||
<span id="cb39-47"><a href="#cb39-47" aria-hidden="true"></a> <span class="cf">for</span> (; angle < <span class="dv">0</span>; angle += <span class="fl">360.0</span>);</span>
|
||
<span id="cb39-48"><a href="#cb39-48" aria-hidden="true"></a> <span class="cf">for</span> (; angle><span class="dv">360</span>; angle -= <span class="fl">360.0</span>);</span>
|
||
<span id="cb39-49"><a href="#cb39-49" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-50"><a href="#cb39-50" aria-hidden="true"></a> <span class="cf">case</span> N_BC:</span>
|
||
<span id="cb39-51"><a href="#cb39-51" aria-hidden="true"></a> bc.red = eval (child1(node));</span>
|
||
<span id="cb39-52"><a href="#cb39-52" aria-hidden="true"></a> bc.green = eval (child2(node));</span>
|
||
<span id="cb39-53"><a href="#cb39-53" aria-hidden="true"></a> bc.blue = eval (child3(node));</span>
|
||
<span id="cb39-54"><a href="#cb39-54" aria-hidden="true"></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"></a> fixcolor (bc.red);</span>
|
||
<span id="cb39-56"><a href="#cb39-56" aria-hidden="true"></a> fixcolor (bc.green);</span>
|
||
<span id="cb39-57"><a href="#cb39-57" aria-hidden="true"></a> fixcolor (bc.blue);</span>
|
||
<span id="cb39-58"><a href="#cb39-58" aria-hidden="true"></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"></a> cairo_set_source_rgb (cr, bc.red, bc.green, bc.blue);</span>
|
||
<span id="cb39-60"><a href="#cb39-60" aria-hidden="true"></a> cairo_paint (cr);</span>
|
||
<span id="cb39-61"><a href="#cb39-61" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-62"><a href="#cb39-62" aria-hidden="true"></a> <span class="cf">case</span> N_FC:</span>
|
||
<span id="cb39-63"><a href="#cb39-63" aria-hidden="true"></a> fc.red = eval (child1(node));</span>
|
||
<span id="cb39-64"><a href="#cb39-64" aria-hidden="true"></a> fc.green = eval (child2(node));</span>
|
||
<span id="cb39-65"><a href="#cb39-65" aria-hidden="true"></a> fc.blue = eval (child3(node));</span>
|
||
<span id="cb39-66"><a href="#cb39-66" aria-hidden="true"></a> fixcolor (fc.red);</span>
|
||
<span id="cb39-67"><a href="#cb39-67" aria-hidden="true"></a> fixcolor (fc.green);</span>
|
||
<span id="cb39-68"><a href="#cb39-68" aria-hidden="true"></a> fixcolor (fc.blue);</span>
|
||
<span id="cb39-69"><a href="#cb39-69" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-70"><a href="#cb39-70" aria-hidden="true"></a> <span class="cf">case</span> N_ASSIGN:</span>
|
||
<span id="cb39-71"><a href="#cb39-71" aria-hidden="true"></a> name = name(child1(node));</span>
|
||
<span id="cb39-72"><a href="#cb39-72" aria-hidden="true"></a> d = eval (child2(node));</span>
|
||
<span id="cb39-73"><a href="#cb39-73" aria-hidden="true"></a> <span class="cf">if</span> (! stack_replace (name, d)) <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"></a> var_replace (name, d); <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"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-76"><a href="#cb39-76" aria-hidden="true"></a> <span class="cf">case</span> N_IF:</span>
|
||
<span id="cb39-77"><a href="#cb39-77" aria-hidden="true"></a> <span class="cf">if</span> (eval (child1(node)))</span>
|
||
<span id="cb39-78"><a href="#cb39-78" aria-hidden="true"></a> execute (child2(node));</span>
|
||
<span id="cb39-79"><a href="#cb39-79" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-80"><a href="#cb39-80" aria-hidden="true"></a> <span class="cf">case</span> N_RT:</span>
|
||
<span id="cb39-81"><a href="#cb39-81" aria-hidden="true"></a> ret_level--;</span>
|
||
<span id="cb39-82"><a href="#cb39-82" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-83"><a href="#cb39-83" aria-hidden="true"></a> <span class="cf">case</span> N_RS:</span>
|
||
<span id="cb39-84"><a href="#cb39-84" aria-hidden="true"></a> pen = TRUE;</span>
|
||
<span id="cb39-85"><a href="#cb39-85" aria-hidden="true"></a> angle = <span class="fl">90.0</span>;</span>
|
||
<span id="cb39-86"><a href="#cb39-86" aria-hidden="true"></a> cur_x = <span class="fl">0.0</span>;</span>
|
||
<span id="cb39-87"><a href="#cb39-87" aria-hidden="true"></a> cur_y = <span class="fl">0.0</span>;</span>
|
||
<span id="cb39-88"><a href="#cb39-88" aria-hidden="true"></a> line_width = <span class="fl">2.0</span>;</span>
|
||
<span id="cb39-89"><a href="#cb39-89" aria-hidden="true"></a> fc.red = <span class="fl">0.0</span>; fc.green = <span class="fl">0.0</span>; fc.blue = <span class="fl">0.0</span>;</span>
|
||
<span id="cb39-90"><a href="#cb39-90" aria-hidden="true"></a> <span class="co">/* To change background color, use bc. */</span></span>
|
||
<span id="cb39-91"><a href="#cb39-91" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-92"><a href="#cb39-92" aria-hidden="true"></a> <span class="cf">case</span> N_procedure_call:</span>
|
||
<span id="cb39-93"><a href="#cb39-93" aria-hidden="true"></a> name = name(child1(node));</span>
|
||
<span id="cb39-94"><a href="#cb39-94" aria-hidden="true"></a>node_t *proc = proc_lookup (name);</span>
|
||
<span id="cb39-95"><a href="#cb39-95" aria-hidden="true"></a> <span class="cf">if</span> (! proc)</span>
|
||
<span id="cb39-96"><a href="#cb39-96" aria-hidden="true"></a> runtime_error (<span class="st">"Procedure %s not defined.</span><span class="sc">\n</span><span class="st">"</span>, name);</span>
|
||
<span id="cb39-97"><a href="#cb39-97" aria-hidden="true"></a> <span class="cf">if</span> (strcmp (name, name(child1(proc))) != <span class="dv">0</span>)</span>
|
||
<span id="cb39-98"><a href="#cb39-98" aria-hidden="true"></a> runtime_error (<span class="st">"Unexpected error. Procedure %s is called, but invoked procedure is %s.</span><span class="sc">\n</span><span class="st">"</span>, name, name(child1(proc)));</span>
|
||
<span id="cb39-99"><a href="#cb39-99" aria-hidden="true"></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"></a>node_t *param_list;</span>
|
||
<span id="cb39-101"><a href="#cb39-101" aria-hidden="true"></a>node_t *arg_list;</span>
|
||
<span id="cb39-102"><a href="#cb39-102" aria-hidden="true"></a> param_list = child2(proc);</span>
|
||
<span id="cb39-103"><a href="#cb39-103" aria-hidden="true"></a> arg_list = child2(node);</span>
|
||
<span id="cb39-104"><a href="#cb39-104" aria-hidden="true"></a> <span class="cf">if</span> (param_list == NULL) {</span>
|
||
<span id="cb39-105"><a href="#cb39-105" aria-hidden="true"></a> <span class="cf">if</span> (arg_list == NULL) {</span>
|
||
<span id="cb39-106"><a href="#cb39-106" aria-hidden="true"></a> stack_push (NULL, <span class="fl">0.0</span>); <span class="co">/* number of argument == 0 */</span></span>
|
||
<span id="cb39-107"><a href="#cb39-107" aria-hidden="true"></a> } <span class="cf">else</span></span>
|
||
<span id="cb39-108"><a href="#cb39-108" aria-hidden="true"></a> runtime_error (<span class="st">"Procedure %s has different number of argument and parameter.</span><span class="sc">\n</span><span class="st">"</span>, name);</span>
|
||
<span id="cb39-109"><a href="#cb39-109" aria-hidden="true"></a> }<span class="cf">else</span> {</span>
|
||
<span id="cb39-110"><a href="#cb39-110" aria-hidden="true"></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"></a><span class="pp">#define TEMP_STACK_SIZE 20</span></span>
|
||
<span id="cb39-112"><a href="#cb39-112" aria-hidden="true"></a> <span class="dt">char</span> *temp_param[TEMP_STACK_SIZE];</span>
|
||
<span id="cb39-113"><a href="#cb39-113" aria-hidden="true"></a> <span class="dt">double</span> temp_arg[TEMP_STACK_SIZE];</span>
|
||
<span id="cb39-114"><a href="#cb39-114" aria-hidden="true"></a> n = <span class="dv">0</span>;</span>
|
||
<span id="cb39-115"><a href="#cb39-115" aria-hidden="true"></a> <span class="cf">for</span> (; param_list->type == N_parameter_list; param_list = child1(param_list)) {</span>
|
||
<span id="cb39-116"><a href="#cb39-116" aria-hidden="true"></a> <span class="cf">if</span> (arg_list->type != N_argument_list)</span>
|
||
<span id="cb39-117"><a href="#cb39-117" aria-hidden="true"></a> runtime_error (<span class="st">"Procedure %s has different number of argument and parameter.</span><span class="sc">\n</span><span class="st">"</span>, name);</span>
|
||
<span id="cb39-118"><a href="#cb39-118" aria-hidden="true"></a> <span class="cf">if</span> (n >= TEMP_STACK_SIZE)</span>
|
||
<span id="cb39-119"><a href="#cb39-119" aria-hidden="true"></a> runtime_error (<span class="st">"Too many parameters. the number must be %d or less.</span><span class="sc">\n</span><span class="st">"</span>, TEMP_STACK_SIZE);</span>
|
||
<span id="cb39-120"><a href="#cb39-120" aria-hidden="true"></a> temp_param[n] = name(child2(param_list));</span>
|
||
<span id="cb39-121"><a href="#cb39-121" aria-hidden="true"></a> temp_arg[n] = eval (child2(arg_list));</span>
|
||
<span id="cb39-122"><a href="#cb39-122" aria-hidden="true"></a> arg_list = child1(arg_list);</span>
|
||
<span id="cb39-123"><a href="#cb39-123" aria-hidden="true"></a> ++n;</span>
|
||
<span id="cb39-124"><a href="#cb39-124" aria-hidden="true"></a> }</span>
|
||
<span id="cb39-125"><a href="#cb39-125" aria-hidden="true"></a> <span class="cf">if</span> (param_list->type == N_ID && arg_list -> type != N_argument_list) {</span>
|
||
<span id="cb39-126"><a href="#cb39-126" aria-hidden="true"></a> temp_param[n] = name(param_list);</span>
|
||
<span id="cb39-127"><a href="#cb39-127" aria-hidden="true"></a> temp_arg[n] = eval (arg_list);</span>
|
||
<span id="cb39-128"><a href="#cb39-128" aria-hidden="true"></a> <span class="cf">if</span> (++n >= TEMP_STACK_SIZE)</span>
|
||
<span id="cb39-129"><a href="#cb39-129" aria-hidden="true"></a> runtime_error (<span class="st">"Too many parameters. the number must be %d or less.</span><span class="sc">\n</span><span class="st">"</span>, TEMP_STACK_SIZE);</span>
|
||
<span id="cb39-130"><a href="#cb39-130" aria-hidden="true"></a> temp_param[n] = NULL;</span>
|
||
<span id="cb39-131"><a href="#cb39-131" aria-hidden="true"></a> temp_arg[n] = (<span class="dt">double</span>) n;</span>
|
||
<span id="cb39-132"><a href="#cb39-132" aria-hidden="true"></a> ++n;</span>
|
||
<span id="cb39-133"><a href="#cb39-133" aria-hidden="true"></a> } <span class="cf">else</span></span>
|
||
<span id="cb39-134"><a href="#cb39-134" aria-hidden="true"></a> runtime_error (<span class="st">"Unexpected error.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb39-135"><a href="#cb39-135" aria-hidden="true"></a> <span class="cf">for</span> (i = <span class="dv">0</span>; i < n; ++i)</span>
|
||
<span id="cb39-136"><a href="#cb39-136" aria-hidden="true"></a> stack_push (temp_param[i], temp_arg[i]);</span>
|
||
<span id="cb39-137"><a href="#cb39-137" aria-hidden="true"></a> }</span>
|
||
<span id="cb39-138"><a href="#cb39-138" aria-hidden="true"></a> ret_level = ++proc_level;</span>
|
||
<span id="cb39-139"><a href="#cb39-139" aria-hidden="true"></a> execute (child3(proc));</span>
|
||
<span id="cb39-140"><a href="#cb39-140" aria-hidden="true"></a> ret_level = --proc_level;</span>
|
||
<span id="cb39-141"><a href="#cb39-141" aria-hidden="true"></a> stack_return ();</span>
|
||
<span id="cb39-142"><a href="#cb39-142" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-143"><a href="#cb39-143" aria-hidden="true"></a> <span class="cf">case</span> N_procedure_definition:</span>
|
||
<span id="cb39-144"><a href="#cb39-144" aria-hidden="true"></a> name = name(child1(node));</span>
|
||
<span id="cb39-145"><a href="#cb39-145" aria-hidden="true"></a> proc_install (name, node);</span>
|
||
<span id="cb39-146"><a href="#cb39-146" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-147"><a href="#cb39-147" aria-hidden="true"></a> <span class="cf">case</span> N_primary_procedure_list:</span>
|
||
<span id="cb39-148"><a href="#cb39-148" aria-hidden="true"></a> execute (child1(node));</span>
|
||
<span id="cb39-149"><a href="#cb39-149" aria-hidden="true"></a> execute (child2(node));</span>
|
||
<span id="cb39-150"><a href="#cb39-150" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb39-151"><a href="#cb39-151" aria-hidden="true"></a> <span class="cf">default</span>:</span>
|
||
<span id="cb39-152"><a href="#cb39-152" aria-hidden="true"></a> runtime_error (<span class="st">"Unknown statement.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb39-153"><a href="#cb39-153" aria-hidden="true"></a> }</span>
|
||
<span id="cb39-154"><a href="#cb39-154" aria-hidden="true"></a>}</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="" /><figcaption>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="" /><figcaption>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="" /><figcaption>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"></a><span class="dt">static</span> jmp_buf buf;</span>
|
||
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true"></a></span>
|
||
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true"></a><span class="dt">void</span></span>
|
||
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true"></a>run (<span class="dt">void</span>) {</span>
|
||
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true"></a></span>
|
||
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true"></a> <span class="cf">if</span> (! init_cairo()) {</span>
|
||
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true"></a> g_print (<span class="st">"Cairo not initialized.</span><span class="sc">\n</span><span class="st">"</span>);</span>
|
||
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true"></a> <span class="cf">return</span>;</span>
|
||
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true"></a> }</span>
|
||
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true"></a> init_table();</span>
|
||
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true"></a> init_stack();</span>
|
||
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true"></a> ret_level = proc_level = <span class="dv">1</span>;</span>
|
||
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true"></a> i = setjmp (buf);</span>
|
||
<span id="cb41-15"><a href="#cb41-15" aria-hidden="true"></a> <span class="cf">if</span> (i == <span class="dv">0</span>)</span>
|
||
<span id="cb41-16"><a href="#cb41-16" aria-hidden="true"></a> execute(node_top);</span>
|
||
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true"></a> <span class="co">/* else ... get here by calling longjmp */</span></span>
|
||
<span id="cb41-18"><a href="#cb41-18" aria-hidden="true"></a> destroy_cairo ();</span>
|
||
<span id="cb41-19"><a href="#cb41-19" aria-hidden="true"></a> g_slist_free_full (g_steal_pointer (&list), g_free);</span>
|
||
<span id="cb41-20"><a href="#cb41-20" aria-hidden="true"></a>}</span>
|
||
<span id="cb41-21"><a href="#cb41-21" aria-hidden="true"></a></span>
|
||
<span id="cb41-22"><a href="#cb41-22" aria-hidden="true"></a><span class="co">/* format supports only %s, %f and %d */</span></span>
|
||
<span id="cb41-23"><a href="#cb41-23" aria-hidden="true"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb41-24"><a href="#cb41-24" aria-hidden="true"></a>runtime_error (<span class="dt">char</span> *format, ...) {</span>
|
||
<span id="cb41-25"><a href="#cb41-25" aria-hidden="true"></a> <span class="dt">va_list</span> args;</span>
|
||
<span id="cb41-26"><a href="#cb41-26" aria-hidden="true"></a> <span class="dt">char</span> *f;</span>
|
||
<span id="cb41-27"><a href="#cb41-27" aria-hidden="true"></a> <span class="dt">char</span> b[<span class="dv">3</span>];</span>
|
||
<span id="cb41-28"><a href="#cb41-28" aria-hidden="true"></a> <span class="dt">char</span> *s;</span>
|
||
<span id="cb41-29"><a href="#cb41-29" aria-hidden="true"></a> <span class="dt">double</span> v;</span>
|
||
<span id="cb41-30"><a href="#cb41-30" aria-hidden="true"></a> <span class="dt">int</span> i;</span>
|
||
<span id="cb41-31"><a href="#cb41-31" aria-hidden="true"></a></span>
|
||
<span id="cb41-32"><a href="#cb41-32" aria-hidden="true"></a> va_start (args, format);</span>
|
||
<span id="cb41-33"><a href="#cb41-33" aria-hidden="true"></a> <span class="cf">for</span> (f = format; *f; f++) {</span>
|
||
<span id="cb41-34"><a href="#cb41-34" aria-hidden="true"></a> <span class="cf">if</span> (*f != <span class="ch">'%'</span>) {</span>
|
||
<span id="cb41-35"><a href="#cb41-35" aria-hidden="true"></a> b[<span class="dv">0</span>] = *f;</span>
|
||
<span id="cb41-36"><a href="#cb41-36" aria-hidden="true"></a> b[<span class="dv">1</span>] = <span class="ch">'\0'</span>;</span>
|
||
<span id="cb41-37"><a href="#cb41-37" aria-hidden="true"></a> g_print (<span class="st">"%s"</span>, b);</span>
|
||
<span id="cb41-38"><a href="#cb41-38" aria-hidden="true"></a> <span class="cf">continue</span>;</span>
|
||
<span id="cb41-39"><a href="#cb41-39" aria-hidden="true"></a> }</span>
|
||
<span id="cb41-40"><a href="#cb41-40" aria-hidden="true"></a> <span class="cf">switch</span> (*++f) {</span>
|
||
<span id="cb41-41"><a href="#cb41-41" aria-hidden="true"></a> <span class="cf">case</span> <span class="ch">'s'</span>:</span>
|
||
<span id="cb41-42"><a href="#cb41-42" aria-hidden="true"></a> s = va_arg(args, <span class="dt">char</span> *);</span>
|
||
<span id="cb41-43"><a href="#cb41-43" aria-hidden="true"></a> g_print (<span class="st">"%s"</span>, s);</span>
|
||
<span id="cb41-44"><a href="#cb41-44" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb41-45"><a href="#cb41-45" aria-hidden="true"></a> <span class="cf">case</span> <span class="ch">'f'</span>:</span>
|
||
<span id="cb41-46"><a href="#cb41-46" aria-hidden="true"></a> v = va_arg(args, <span class="dt">double</span>);</span>
|
||
<span id="cb41-47"><a href="#cb41-47" aria-hidden="true"></a> g_print(<span class="st">"%f"</span>, v);</span>
|
||
<span id="cb41-48"><a href="#cb41-48" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb41-49"><a href="#cb41-49" aria-hidden="true"></a> <span class="cf">case</span> <span class="ch">'d'</span>:</span>
|
||
<span id="cb41-50"><a href="#cb41-50" aria-hidden="true"></a> i = va_arg(args, <span class="dt">int</span>);</span>
|
||
<span id="cb41-51"><a href="#cb41-51" aria-hidden="true"></a> g_print(<span class="st">"%d"</span>, i);</span>
|
||
<span id="cb41-52"><a href="#cb41-52" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb41-53"><a href="#cb41-53" aria-hidden="true"></a> <span class="cf">default</span>:</span>
|
||
<span id="cb41-54"><a href="#cb41-54" aria-hidden="true"></a> b[<span class="dv">0</span>] = <span class="ch">'%'</span>;</span>
|
||
<span id="cb41-55"><a href="#cb41-55" aria-hidden="true"></a> b[<span class="dv">1</span>] = *f;</span>
|
||
<span id="cb41-56"><a href="#cb41-56" aria-hidden="true"></a> b[<span class="dv">2</span>] = <span class="ch">'\0'</span>;</span>
|
||
<span id="cb41-57"><a href="#cb41-57" aria-hidden="true"></a> g_print (<span class="st">"%s"</span>, b);</span>
|
||
<span id="cb41-58"><a href="#cb41-58" aria-hidden="true"></a> <span class="cf">break</span>;</span>
|
||
<span id="cb41-59"><a href="#cb41-59" aria-hidden="true"></a> }</span>
|
||
<span id="cb41-60"><a href="#cb41-60" aria-hidden="true"></a> }</span>
|
||
<span id="cb41-61"><a href="#cb41-61" aria-hidden="true"></a> va_end (args);</span>
|
||
<span id="cb41-62"><a href="#cb41-62" aria-hidden="true"></a></span>
|
||
<span id="cb41-63"><a href="#cb41-63" aria-hidden="true"></a> longjmp (buf, <span class="dv">1</span>);</span>
|
||
<span id="cb41-64"><a href="#cb41-64" aria-hidden="true"></a>}</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"></a><span class="dt">void</span> runtime_error (<span class="dt">char</span> *format, ...)</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 are 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>
|