    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: A Small Universe</title>
        <link>https://members.accu.org/index.php/journals/2622</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>


        <h2>Journal Articles</h2>


<div class="xar-mod-head"><span class="xar-mod-title">Overload Journal #149 - February 2019 + Design of applications and programs</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c395/">o149</a>
                    (8)
<br />

                                            <a href="https://members.accu.org/index.php/journals/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/journals/c67/">Design</a>
                    (236)
<br />

                                            <a href="https://members.accu.org/index.php/journals/c395-67/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/journals/c395+67/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;A Small Universe</h1>
<p><strong>Author:</strong>&nbsp;Bob Schmidt</p>
<p>
<strong>Date:</strong> 05 February 2019 17:21:07 +00:00 or Tue, 05 February 2019 17:21:07 +00:00</p>
<p><strong>Summary:</strong>&nbsp;Writing a programming language is a hot topic. DeÃ¡k Ferenc shows us how he wrote a compiler for bytecode callable from C++.</p>
<p><strong>Body:</strong>&nbsp;<p>Letâ€™s take a deep dive in the world of programming languages, compilers, virtual machines and embeddable execution environments in this article, since we are not setting a lesser goal than creating a tiny programming language, then writing a compiler for it which will create bytecode for a virtual machine â€“ which, of course, we have the luxury of imagining from scratch â€“ and last but not least, making all this run while being embedded inside a C++ application.</p>

<p>But before we embark on this epic journey, we also need to know what we are dealing with by providing an overview of how compilers work, what the steps are they perform in order to transform human-readable (or better said, human-engineered) source code into a series of bytes incomprehensible for aforementioned humans, but which makes perfect sense for computers. So, our article will start with an overview of the inner working of a generic compiler, on a level more theoretical than practical. From there, we will move to one of the main goals of this article, which is the creation of a very simple programming language and providing a fully functional compiler for it.</p>

<p>Since creating a simple compiler is a task which usually targets the architecture of a computer, we also will introduce a virtual machine, with a set of unique instructions that will be executing our compiled language, so letâ€™s get started.</p>

<h2>How a compiler works</h2>

<p>The widely used mainstream compilers tend to appertain to a family of applications characterized by complexity, with elaborately written source code, most typically engineered over several years by a few experts in the field. When an end user uses a compiler in order to compile a piece of source code, the compiler has to go through a series of intricate steps in order to produce the required executable, or to provide valuable error messages if errors are found during compilation.</p>

<p>On a very high level, Figure 1 shows the steps a compiler does with a source file, in order to generate executable binary code.</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol149/Deak/Deak-01.svg" /></td>
	</tr>
	<tr>
		<td class="title">Figure 1</td>
	</tr>
</table>

<p>First, it takes the source code and reads it. This step provides input for the next, usually in forms of â€˜tokensâ€™. The output of step 1 is run through an analyze phase (step 2), which generates a so-called â€˜Abstract Syntax Treeâ€™, which in turn is used as input for the last stage. The last stage provides the binary code that is runnable on the target platform.</p>

<p>Between these steps, a compiler often translates the data into an Intermediate Representation that is equivalent to the input source code but that the compiler can work with more easily (the data are algorithmically easier to process), such as graphs, trees or other data structures â€“ or even a different (programming) language.</p>

<p>And at a high level, this explanation is more than enough for someone to understand what happens inside a very simple and naÃ¯ve compiler.</p>

<h2>Types of compilers</h2>

<p>When it comes regarding the approach of a compiler to source files, we can differentiate two types of compilers:</p>

<ul>
	<li>One-pass compilers</li>
	<li>Multi-pass compilers</li>
</ul>

<h3>One-pass compiler</h3>

<p>As the name suggests, the one-pass compiler is a compiler which passes through a compilation unit exactly once, and it generates corresponding machine code instantly. â€˜One-passâ€™ does not mean that the source file is read only once but that there is just one logical step affecting the various (compiler internal) data of the compilation steps. The compiler does not go back to run more steps on the data once done; instead the compiler passes from parsing to analyzing and generating the code then going back for the next read.</p>

<p>A compilation unit can be also imagined as just a fancy technical term for a source file, but in practice it can be a bit more. For example, it might contain information provided by the pre-processor, if the target language has this notion, or it might contain all the imported source code of the modules this file needs in order to compile (again if there is support for this feature in the language this compiler targets).</p>

<p>One-pass compilers have a few advantages, and several disadvantages, in comparison to multi-pass compilers. Some advantages are that they are much simpler to write, they are faster and much smaller. For some (most popular) programming languages, it is impossible to write a one-step compiler due to the syntax the languages require. A notable exception is the programming language Pascal, which is a perfectly good candidate for a one-pass compiler because it requires definitions be available before use (by requiring syntactically that the variables are declared at the beginning of the current procedure/function or that the procedure is forward declared). The application provided as educational material within this article is a simple one-pass compiler.</p>

<h3>Multi-pass compilers</h3>

<p>In contrast, multi-pass compilers [<a href="#[Wikipedia-3]">Wikipedia-3</a>] convert the source into several intermediate representations between various steps in the long path from source code to the corresponding machine code. These intermediate representations are passed back and forth between various stages of the compile process between the compilation phases. At all stages, the compiler sees the entire program being compiled in various shapes.</p>

<p>Multi-pass compilers â€“ because they have access to the entire program in each pass (in various internal representations) â€“ can perform optimizations, such as removing irrelevant pieces of binary code to favor smaller code, or excluding redundant code, and they can apply a variety of other gains at the cost of a slower compile time, and higher memory usage.</p>

<p>The typical stages of a multi-pass compiler can be seen in Figure 2<a href="#FN01"><sup>1</sup></a>.</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol149/Deak/Deak-02.svg" /></td>
	</tr>
	<tr>
		<td class="title">Figure 2</td>
	</tr>
</table>

<h2>Lexical analysis</h2>

<p>The lexical analysis stage is the first stage in the front end of a compilerâ€™s implementation. When performing lexical analysis, the compiler considers the source as a big chunk of text, which needs to be broken up into small entities (called tokens).</p>

<p>This stage is responsible for building up the internal representation of the source code using tokens, after removing irrelevant information from it (such as comments, or contiguous space, unless they are relevant to the syntax of the source code, just like in case of <strong>Python</strong>). Each token is assigned a type (for example, identifiers, constants, keywords) among other relevant information, and the information from this point on is passed on to the next stage.</p>

<p>Now follows a very simple example of tokenization.</p>

<p>The following expression <em>x</em> = <em>a</em> + 2; can be tokenized into the resulting sequence (partially using the example from [<a href="#[Wikipedia-2]">Wikipedia-2</a>])</p>

<pre class="programlisting">
  [(identifier, x), (operator, =), (identifier, a),
  (operator, +), (literal, 2), (separator, ;)]</pre>
  
<p>One of the methods of constructing an efficient lexer for a language is to build the language based on a regular grammar for which there are already well defined, efficient and optimal algorithms. A regular expression [<a href="#[Wikipedia-5]">Wikipedia-5</a>] can parse the language generated by the regular grammar and, most importantly, there is a finite state automaton that can interpret the given grammar.</p>

<h3>Finite state automatons</h3>

<p>A finite state automaton can be viewed as an abstract machine that is in exactly one specific state at any given moment in time. The automaton changes its state because of an external impact, and this process is called a transition. It can be modelled from a mathematical point of view as a quintuple:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn01.png" /></p>

<p>where:</p>

<ul>
	<li><em>Q</em> is a finite set of states</li>
	
	<li>Î£ is a finite alphabet</li>
	
	<li><em>Î´</em> is the transition function:
		<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn02.png" /></p>
	</li>
	
	<li><em>F</em> represents the set of finite states, and</li>
	
	<li><em>F</em> &#8838; <em>Q</em>, <em>F</em> might be empty.</li>
</ul>

<p>For example, the finite state machine in Figure 3 is designed to recognize integral numbers (without sign).</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol149/Deak/Deak-03.svg" /></td>
	</tr>
	<tr>
		<td class="title">Figure 3</td>
	</tr>
</table>

<p>Working out the mathematical definitions and the regular expression for the given automaton from the diagram is left as a fun homework for the reader.</p>

<h2>Syntax analysis</h2>

<p>In the next phase of the compilation, the tokens (the output of the lexical analysis stage) are checked in order to validate their conformity with the rules of the programming language. Regardless of the success of the lexical analysis, not all randomly gathered tokens can be considered a valid application, and this step ensures that these tokens are indeed a valid embodiment of a program written in this language. Due to the recursive nature of a programming languageâ€™s grammar and syntax, at this stage the application is best represented by a context-free grammar, and the responsible corresponding push-down automaton. Once the rules are satisfied, an internal representation of the source is generated, most probably an abstract syntax tree.</p>

<h2>Context-free grammars</h2>

<p>A context-free grammar is just another way of describing a language and mathematically it can be represented with the following structure:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn03.png" /></p>

<p>where:</p>

<ul>

	<li><em>N</em> is a finite set of non-terminals (<strong>variables</strong>), which represent the syntactic constructs of the language</li>
	
	<li>Î£ contains the symbols (<strong>terminals</strong>) of the alphabet on which the automaton is working, ie. the symbols of the alphabet of the defined language (and not to be confused with Î£ from the previous definition of the automaton: itâ€™s not the same)</li>
	
	<li><em>P</em> is a set of <strong>rules</strong> used to create the syntactic constructs which operate on the variables and result in a string of variables and terminals (rules for different derivation of the same non-terminal are often separated by <code>&quot;|&quot;</code>).</li>
	
	<li><em>S</em> is the start symbol</li>
</ul>

<p>Consider the following context-free grammar:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn04.png" /></p>

<p>which was designed to be able to generate the language <em>L</em>. <em>L(G)</em> is the notation for the language generated by the given grammar <em>G</em>:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn05.png" /></p>

<p>For example, obtaining 000111 can be done by starting with the Start symbol and consecutively applying the rules (2), (2) and (1) resulting in the following <strong>derivation</strong>:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn06.png" /></p>

<p>A derivation in CFGs, which have rules in their rulesets involving more than one non-terminal (for example, ({<em>S</em>},{+,1},{<em>S</em>â†’<em> S</em>+<em> S</em>|<em> S</em>|<em></em>1},<em> S</em>) is called a left-most (right-most) derivation. At each step, we replace the left-most (right-most) non terminal:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn07.png" /></p>

<p>thus obtaining the expression 1+1 and the parse tree (shown in Figure 4), which is an ordered tree representing the structure of the string according to the context-free grammar used to derive it.</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol149/Deak/Deak-04.svg" /></td>
	</tr>
	<tr>
		<td class="title">Figure 4</td>
	</tr>
</table>

<h2>Push-down automaton</h2>

<p>A push-down automaton can be imagined like a finite state-machine but with an extra stack attached to it. The following 7-tuple gives a more or less formal definition for it:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn08.png" /></p>

<p>where:</p>

<ul>
	<li><em>Q</em>, Î£ and <em>F</em> are defined likely as for a finite-state automaton</li>
	<li>Î“ is the alphabet of the stack</li>
	<li><em>q</em><sub>0</sub> is the start state of the automaton</li>
	<li><em>Z</em><sub>0</sub> is the start symbol, <em>Z</em><sub>0</sub> &#8712; Î“</li>
</ul>

<p>and the transition function is:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn09.png" /></p>

<p>so it takes in a triplet of a state from <em>Q</em>, an input symbol (which can also be the empty string, called Ïµ â€“ epsilon) from Î£ and a stack symbol from <em>Î“</em>and it gives result a set of zero or more actions of the form (<em>p</em>, Î±) where <em>p</em> is a state and Î± is a string of concatenated stack symbols.</p>

<p>Remembering the context-free grammar from our previous paragraph, we can construct a push-down automaton which will recognize the elements of {0<sup>n</sup> 1<sup>n</sup> | <em>n</em>â‰¥ 1}:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn10.png" /></p>

<p>Concerning the states:</p>

<ul>
	<li><em>q</em> is the initial state and the automaton is in this state if it has not detected the symbol 1 so far but only 0s.</li>
	<li><em>p</em> is the state where the automaton lies if it has detected at least one 1 and it can proceed forward only if there are 1s in the input.</li>
	<li><em>f</em> is the final state</li>
</ul>

<p>And where the transition function is defined as:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn11.png" /></p>

<p>These two rules are handling the 0 from the input: both of them push one <em>X</em> onto the stack of the automaton for each 0 identified.</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn12.png" /></p>

<p>This rule will change to state <em>p</em> and pop one <em>X</em> from the stack</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn13.png" /></p>

<p>If in state <em>p</em> and we encounter a 1 in the input, pop one <em>X</em> from the stack</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn14.png" /></p>

<p>And finally, at this stage we have supposedly successfully identified our string of 0s and 1s. Our stack needs to be empty, the input fully consumed and then we can advance to the final state.</p>

<p>So, if we have 000111, the automaton goes through the following steps in order to recognize it as a valid input for the given grammar:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn15.png" /></p>

<p>Now we can hopefully see the methodology involved in this step, we just need to create a push down automaton for our language which will successfully consume the series of tokens from the previous step thus resulting in a syntactically correct application.</p>

<p>In the paragraphs below, we frequently mention elements of a push-down automaton and refer to (context-free) grammars, hence this very short theoretical introduction. Unfortunately, a deeper study of this very exciting subject is beyond the scope of this article, being such a huge subject in the field of computer science that there are semester-long courses dedicated to the research of this domain. It is practically impossible for us to dig deeper into this field now. For everyone interested in this fascinating domain, I highly recommend <em>Introduction to Automata Theory, Languages, and Computation</em> by Hopcroft, Motwani and Ullman (2nd, 2001 edition).</p>

<h2>The parser</h2>

<p>The component responsible for this step in the compilerâ€™s architecture is called the parser. Depending on the approach chosen to build the parse tree upon encountering an expression, we differentiate between the following types of parsers:</p>

<ul>
	<li>descending â€“ the tree is built from the root towards the leaves. In this situation, the parsing starts by applying consecutive transformations to the start symbol till we obtain the required expression. This approach is also called top-down parsing.</li>
	
	<li>ascending â€“ the tree is built from the leaves towards the root, upon applying reverse transformations to the expression in order to reach the start symbol. This is also called bottom-up parsing.</li>
</ul>

<h3>Recursive-descent parsing</h3>

<p>Usually the top-down parsers, which process the input from left to right, and the parse tree, which is constructed from top to bottom, are also known as recursive-descent parsers due to the recursive nature of context-free grammars. In the construction of the tree, a backtracking mechanism might be involved, which results in a less effective performance due to the constant back-stepping of the algorithm. These parsers are usually avoided in case of large grammars.</p>

<p>The parsers which are able to â€˜predictâ€™ which production is to be used on the input string do not require any backtracking steps and are called predictive parsers. These parsers operate on specialized <em>LL</em>(<em>k</em>) grammars, which are a simplified subset of the context-free grammars. Due to some applied restrictions and a precomputed state transition table introduced in the algorithm (which determines how to compute the next state from the current state and the lookahead symbol), they gain an extra simplicity when it comes to implementation.</p>

<p><em>LL</em>(<em>k</em>) can be interpreted in the following manner:</p>

<ul>
	<li>the first <em>L</em> means: <strong>L</strong>eft to right</li>
	<li>the second <em>L</em> means: <strong>L</strong>eft-most derivation</li>
	<li>and the <em>k</em> represents the number of lookaheads the parser can perform.</li>
</ul>

<p>Parsers which operate on <em>LL</em>(<em>k</em>) grammars are also called <em>LL</em>(<em>k</em>) parsers.</p>

<h3>Shift-reduce parsing</h3>

<p>While reading the input, usually from left to right and trying to build up sequences on the stack which are recognized as the right side of a production, the parser can use two steps:</p>

<ul>
	<li>Reduce: Letâ€™s consider the rule <code>A</code>â†’<code>w</code>. When the stack contains <code>qw</code>, its content can be reduced to <code>qA</code>, where <code>A</code> is a non-terminal from our grammar. When the entire content of the stack is reduced to the start symbol, we have successfully parsed the expression.</li>
	
	<li>Shift: If we canâ€™t perform a reduction (or â€˜if we canâ€™t reduce the stackâ€™) of the stack, this step advances the input stream by one symbol, which is pushed onto the stack. This shifted symbol will be treated as a node in the parse tree.</li>
</ul>

<p>Parsers using these steps are called shift-reduce parsers.</p>

<h3>LR-parsers</h3>

<p>A more performant family of the shift-reduce parsers are the <em>LR</em> parsers (invented by Donald Knuth in 1965 [<a href="#[Knuth65]">Knuth65</a>]). They operate in linear time, producing correct results without backtracking on the input, using a <strong>L</strong>eft to right order and always use the <strong>R</strong>ight-most derivation in reverse. They are also known as <em>LR</em>(<em>k</em>) parsers, where <em>k</em> denotes the number of lookahead symbols the parser uses (which is mostly 1) in the decision-making step. Similarly to <em>LL</em> parsers, <em>LR</em> parsers use a state transition table that must be precomputed from the given grammar.</p>

<p>Several variants of the <em>LR</em> parsers are known:</p>

<ul>
	<li><em>SLR</em> parsers: these are the <strong>S</strong>imple <strong>LR</strong> parsers, categorized by a very small state transition table, working on the smallest grammars. They are easy to construct.</li>
	
	<li><em>LR</em>(1)parser: these parsers work on large grammars. They have large generated tables, and they are theoretically enough to handle any reasonably constructed language â€“ they are just slow to generate due to the huge state transition table.</li>
	
	<li><em>LALR</em>(1) parsers: the <strong>L</strong>ook <strong>A</strong>head <strong>LR</strong> parsers are a simplified version of the <em>LR</em> parsers, able to handle intermediate size grammars, with the number of states being similar to <em>SLR</em> parsers.</li>
</ul>

<p><em>LR</em> parsers operate on <em>LR</em> grammars, whose pure theoretical definition we will skip for now. We will just mention that as per the [<a href="#[Dragon]">Dragon</a>] book, page 242, the requirement of an <em>LR</em>(<em>k</em>) grammar states that â€œ<em>we must be able to recognize the occurrence of the right side of a production in a right-sentential form with</em><em>k</em><em> input symbols of lookahead</em>â€ is less strict than the one for <em>LL</em>(<em>k</em>) grammars â€œ<em>where we must be able to recognize the use of a production seeing only the first</em><em>k</em><em> symbols of what its right side derives</em>â€. This allows <em>LR</em> grammars to describe a wider family of languages than <em>LL</em> grammars with only one drawback: the allowed complexity of the grammar makes it difficult to hand-construct a proper parser for it, so for a context-free grammar with a decent complexity, a parser generator will be required to generate a parser.</p>

<p>With this, we have ended our long but still frivolous journey in the world of parsers and syntax analysis, but for anyone interested there is no better source to turn to, than Chapter 4 of the dragon book [<a href="#[Dragon]">Dragon</a>] where all these concepts are discussed in great length.</p>

<h2>Semantic analysis</h2>

<p>The semantic analysis stage during compilation validates the output generated by the syntax analysis and applies semantic rules to it in order to confirm the requirements of the language, such as strict type checking or other language-specific rules.</p>

<p>The input to this stage is an intermediate representation, mostly in the form of an abstract syntax tree created by the previous step, and the following operations may be performed on it, resulting in an annotated abstract syntax tree (or, if our product is a source-to-source translator, even the final variant of the result). The following list contains a few of the rules that can be applied in this stage; however, since semantic analysis is a highly programming-language-specific step, it is worth mentioning that each of the items can be prepended with â€˜if the language has support for it thenâ€™:</p>

<ul>
	<li>Type checking for various entities (such as, does the language require that indexes to an array must be a positive integer â€“ for example, Pascal allows also negative indexes in the syntax).</li>
	
	<li>Validation of operands of various operators (some programming languages may consider having a multiplication sign between a string and an integer to be ill-formed to have, but not Python).</li>
	
	<li>Verification of implicit conversions (what will be the result of an addition of a real type variable to an integer type variable).</li>
</ul>

<h2>Code generation</h2>

<p>In the last step of the compilation process, a typical compiler will generate executable code for the application. This is done by converting the resulting intermediate representation into a set of instructions (usually target architecture assembly, if we are compiling through assembly, or direct binary code).</p>

<p>The code generation phase, depending on the compiler itself, might be through the introduction and use of intermediate code, or some compilers can generate code directly for the target architecture. The intermediate code is a sort of machine code, which without being architecture specific can still represent the operations of the real machine.</p>

<p>The intermediate code is very often represented in the form of a 3-address code. The 3-address code can be viewed as a set of instructions where each instruction has at most 3 operands, and they are usually a combination of an assignment operation and a binary operation. For example, the following expression:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn16.png" /></p>

<p>can be represented by the following sequence of 3-address code instructions:</p>

<p style="margin-left:1em"><img src="/content/images/journals/ol149/Deak/Eqn17.png" /></p>

<p>The importance of a 3-address code is that a very complex expression is broken down into several separate instructions which are very close to assembly level and they are very easily translated into the required machine code instruction.</p>

<p>Transforming an abstract syntax tree into a series of 3-address instructions is not an extremely complex task; basically, it just means traversing the tree and correctly identifying the set of temporaries and the values assigned to them, so generating code for the simple expressions of the language is possible using this process.</p>

<p>Generating code for compound statements, such as representing <code>IF</code> or <code>FOR</code> loops, usually boils down to a combination of jumps depending on the conditions imposed on the statements and then again generating code for simple expressions.</p>

<p>Generating code for function calls requires the presence of a stack, where â€“ in the currently used Von Neumann architecture â€“ we store not only the ingoing parameters to a function (if any) but also the addresses of return after the completion of the function.</p>

<p>First, the parameters are calculated, and their value is pushed onto the stack, then we issue the call command to invoke the method. This will also push the address where the called function should return after completing its execution. After the function has returned, we are back to the first instruction after the call of the method; the only thing that remains is to adjust the stack properly and continue execution.</p>

<h2>Architecture of a compiler</h2>

<p>For complex compiler projects, we usually see a three-stage structure like in Figure 5.</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol149/Deak/Deak-05.svg" /></td>
	</tr>
	<tr>
		<td class="title">Figure 5</td>
	</tr>
</table>

<p>This design has the advantage that several programming languages can be compiled using the same compiler (applying the same optimizations to all the source code written in different programming languages) to several machines and architectures (image courtesy of Wikipedia).</p>

<h2>The front end</h2>

<p>The front end section of the compiler is the one responsible for the lexical and syntax analysis of a dedicated programming language. It produces an intermediate representation of the program and should also manage the symbol table (which is a map of the symbols that were encountered in the program, such as variable names and function names, together with their location).</p>

<p>The lexical analysis, the syntax analysis and the semantic analysis steps are all part of the front end since these steps are all programming-language dependent.</p>

<p>If there is macro support in the language, the preprocessing phase is also part of the front end. The front end is responsible for creating an intermediate representation for further processing by the middle end.</p>

<h2>The middle end</h2>

<p>The middle end of the compiler is responsible for performing optimizations on the intermediary code. This is a platform and programming language independent operation, so all the programs compiled from languages that the compilerâ€™s front end supports will benefit from this optimization phase. Some of the easiest to implement optimizations that can be performed on the intermediary code are in the section following, but for those interested in this subject [<a href="#[CompOpt]">CompOpt</a>] and [<a href="#[Wikipedia-1]">Wikipedia-1</a>] contain pretty exhaustive lists.</p>

<h3>Constant folding and constant propagation</h3>

<p>This optimization is responsible for finding values in code that occur in calculations that will never change during the lifetime of the application and for calculating them instead of doing the operations at runtime. for example:</p>

<pre class="programlisting">
  const int SECONDS_IN_HOUR = 60 * 60;
  const int SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;</pre>
  
<p>can be replaced with</p>

<pre class="programlisting">
  const int SECONDS_IN_DAY = 86400;</pre>
  
<p>where the value of <code>SECONDS_IN_HOUR</code> has been propagated to contain the correctly calculated (folding) value.</p>

<h3>Dead code elimination</h3>

<p>Sometimes there is a piece of code in the application which will not be reached. Dead code elimination will identify these cases and remove them, thus reducing the size of the code. For example:</p>

<pre class="programlisting">
  bool some_fun(int a)
  {
    if( a &lt; 10)
    {
      return true;
    }
    else
    {
      return false;
    }
    std::cout &lt;&lt; &quot;some_fun exiting&quot;;
  }</pre>
  
<p>In this case, the <code>std::cou</code>t will never be called, so the compiler is free to remove it.</p>

<h3>Common sub-expression identification</h3>

<p>This optimization is responsible for identifying calculations which are performed more than once. It extracts them into a commonly used part which can be inserted into the location where the calculation was done.</p>

<pre class="programlisting">
  int x = a + b + c;
  int z = a + b - d;</pre>
  
<p>This can be optimized into the following sequence of code by extracting the common part <code>(a+b</code>) and reducing the generated code to the following:</p>

<pre class="programlisting">
  int temp = a + b;
  int x = temp + c;
  int z = temp - d;</pre>
  
<p>These items are just a quick peek into the exhaustive list that an optimizing compiler does to your source code, so feel free to do more research in this field if you are interested in this fascinating domain.</p>

<h2>The back end</h2>

<p>The back end component of a compiler is the one which actually generates the code for the specified platform that this back end was written for. It receives the optimized intermediate representation (either an abstract syntax tree or a parse tree) from the middle end, and it may do some optimizations which are platform specific. In cases where is support for debugging the applications on the given platform, debug info is collected and inserted into the generated code.</p>

<p>As presented in the code generation paragraph, the abstract syntax tree is converted into a 3-address code representation, which the back end then re-works and re-organizes in order to represent the real computer architecture related concepts, such as registers, memory addresses, etcâ€¦</p>

<p>Modern compilers also have support for generating code for a specific platform (for example x86/64) but for different processor architecture, with the risk that the generated code will not run on anything else, but that specific processor, or it is possible to have the back end generate code for a totally different architecture (which process is called cross compilation).</p>

<h2>Real-life compilers</h2>

<p>In real life, it is a very frequent situation that a compiler is split up into several smaller applications, for example considering <strong>gcc</strong>, the following applications can be found on the system [<a href="#[GCCArchitecture]">GCCArchitecture</a>]:</p>

<ul>
	<li><strong>gcc</strong> is a driver program which invokes the appropriate compilation application for the target language (for example <strong>cc1</strong> being the preprocessor and the compiler for the C language, or <strong>gdc</strong> is the front end for the D language)</li>
	
	<li><strong>as</strong> being the assembler (the assembler is the application which creates object (machine) code for specific compilation units), actually it is a part of the binutils package shipped with various systems</li>
	
	<li><strong>collect2</strong> is the linker (the application that creates a system specific binary from the various object files)</li>
</ul>

<p>For <strong>clang</strong>, the overall system architecture and design is very similar to <strong>GCC</strong>, with the major difference being that clang was created with the aim of integration into various IDEs so there is a considerable set of libraries that make the project more flexible and easier to work with [<a href="#[Guntli11]">Guntli11</a>], and also <strong>clang</strong> has the advantage of using the LLVM compiler infrastructure [<a href="#[LLVM]">LLVM</a>].</p>

<p>For those not familiar with the terminology, LLVM used to stand for â€˜Low Level Virtual Machineâ€™, but right now it is just â€¦ LLVM, since the project outgrew the notion of a virtual machine, and evolved into a collection of various compiler-related artifacts that include a set of high quality components. This includes an implementation of the C++Standard Library to a debugger (<strong>lldb</strong>), and a set of front and back ends for various languages and target architectures via a powerful intermediate representation of the compiled language with a unique language (which is similar to assembly, and can be read by humans too) that the middle layer uses to perform strong optimizations on it before emitting architecture-specific code.</p>

<h2>A script called primal</h2>

<p>Now that we are done with the theoretical introduction of what a compiler is, how it works, and the algorithms and data structures behind the wall, it is time to sail into more practical waters, by introducing a small scripting language for which we create a compiler from scratch, and also a virtual machine to actually run the compiled code.</p>

<p>I mentioned that we will create the compiler from scratch although there is a plethora of tools available for this purpose. However, in my experience they have a tendency to generate code which is overly complex, difficult to read, and not suitable for our situation, where we want to explain the methodology of creating a compiler. Regardless, feel free to browse [<a href="#[Wikipedia-4]">Wikipedia-4</a>] to find a list of these tools stacked up against each other and find your favourite in there, dare you endeavour to create a new programming language.</p>

<h2>The basic syntax</h2>

<p>The scriptâ€™s syntax is highly inspired by BASIC and for now it will support the following (very limited set of) operations:</p>

<ul>
	<li>Mathematical operations: + (addition), - (subtraction), * (multiplication), / (division)</li>
	
	<li>Binary operations: &amp; (and), | (or), ! (not), ^ (xor)</li>
	
	<li>Comparison operators: &gt; (greater than), &lt; (less than), == (equals), &#8804; (less than or equals), &#8805; (greater than or equals)</li>
	
	<li>Assignment operator: = (assignment)</li>
</ul>

<p>And the following keywords will be implemented:</p>

<ul>
	<li><code>if</code> and <code>then</code> to verify the truthness of an expression (sadly, no <code>else</code> is implemented yet)</li>
	
	<li><code>goto</code> to hijack the execution flow by jumping to a specified label</li>
	
	<li><code>let</code> to define a variable (if not found) and assign a value to it</li>
	
	<li><code>asm</code> to directly tell the compiler to compile assembly syntax as per the VMâ€™s opcodes (presented below)</li>
	
	<li><code>var</code> to introduce a variable to the system
		<p>As a side note, all variables need to be declared before they are used, Ã  la Pascal. And for the moment, only numeric variables are supported.</p>
	</li>
	
	<li><code>end</code> to close the code blocks of commands which have blocks (such as <code>if</code>)</li>
	
	<li><code>import</code> to include the content of another source file into the current one</li>
</ul>

<p>In order to define a label we use the following syntax:</p>

<pre class="programlisting">
  :label</pre>
  
<p>And as an extra feature, we will implement a <code>write</code> function which simply writes out what is passed in as parameters.</p>

<p>And now, armed with this knowledge we can write the following short application to print out a few Fibonacci numbers (see Listing 1).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
import write

var t1, t2, nextTerm, n

let n = 100
let t1 = 0
let t2 = 1

:again

let nextTerm = t1 + t2

let t1 = t2
let t2 = nextTerm
if nextTerm &lt; n then
    write(nextTerm, &quot;  &quot;)
    goto again
end
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 1</td>
	</tr>
</table>

<p>As you have correctly observed, each line contains exactly one instruction. And also as you have observed, each line starts with a keyword. Both of these play an important role in the design of an application and will be explained later in the article.</p>

<p>In case you wish to compile scripts upon compilation, there are two executables in the build directory: <strong>primc</strong> is the compiler for the script language and <strong>primv</strong> is the virtual machine which runs the output of the compiler.</p>

<h2>The Backus-Naur form of the primitive script</h2>

<p>The Backus-Naur form is a notation scheme for context-free grammars, and it can be used to describe programming languages. Our own primitive script can be described (with a more complete version) of the following sequence of BNF (where <code>|</code> is used to indicate that only one can be chosen from the given set between <code>{</code>and <code>}</code>, the items between <code>[</code> and <code>]</code> are optional, <code>...</code> means a repetition of the previous group and <code>CR</code> means a newline).</p>

<p>I have omitted few of the supported keywords from Listing 2 in order to not to have the listing very long and boring; however, the example gives an overview of the complexity of how to start implementing the grammar required for a programming language, which in turn can be fed into a compiler compiler (for example yacc or bison) in order to generate a parser for the language.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
&lt;identifier&gt;              ::= &lt;letter&gt;[{&lt;letter&gt;|&lt;digit&gt;}...]
&lt;label identifier&gt;        ::= &lt;identifier&gt;
&lt;letter&gt;                  ::= &lt;small letter&gt; | &lt;capital letter&gt;
&lt;small letter&gt;            ::= a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
&lt;capital letter&gt;          ::= A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
&lt;digit&gt;                   ::= 0|1|2|3|4|5|6|7|8|9
&lt;digit string&gt;            ::= digit [{digit}...]
&lt;label&gt;                   ::= :&lt;label identifier&gt;
&lt;immediate statement&gt;     ::= &lt;compound statement&gt; CR
&lt;compound statement&gt;      ::= &lt;statement&gt; | &lt;immediate statement&gt;
&lt;statement&gt;               ::= let &lt;identifier&gt;=&lt;expression&gt;                   |
                              if &lt;expression&gt; then &lt;compound statement&gt; endif |
                              goto &lt;label&gt;                                    |
                              &lt;label&gt;                                         |
&lt;comp op&gt;                 ::= &lt; | &gt; | &lt;= | &gt;= | == | !=
&lt;add op&gt;                  ::= + | -
&lt;mul op&gt;                  ::= * | /
&lt;expression&gt;              ::= &lt;term1&gt; | &lt;expression&gt; \| &lt;term1&gt;
&lt;term1&gt;                   ::= &lt;term2&gt; | &lt;term1&gt; &amp; &lt;term2&gt; | !&lt;term2&gt;
&lt;term2&gt;                   ::= &lt;term3&gt; | &lt;term2&gt; &lt;comp op&gt; &lt;term3&gt;
&lt;term3&gt;                   ::= &lt;term4&gt; | &lt;term3&gt; &lt;add op&gt; &lt;term4&gt;
&lt;term4&gt;                   ::= &lt;term5&gt; | &lt;term4&gt; &lt;mul op&gt; &lt;term5&gt;
&lt;term5&gt;                   ::= &lt;term5&gt; | &lt;term5&gt; ^ &lt;term6&gt;
&lt;term6&gt;                   ::= &lt;expression&gt; | &lt;identifier&gt; | &lt;digit string&gt;
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 2</td>
	</tr>
</table>

<h2>Our compiler</h2>

<p>The project is a simple one-pass compiler, without any implemented optimizations. It was written in C++ and uses CMake as the build system. After you have checked out the project from <a href="https://github.com/fritzone/primal">https://github.com/fritzone/primal</a>, you will find a directory structure, where the names of the directories are hopefully self-explanatory:</p>

<ul>
	<li><strong>compiler</strong> is where the compiler files are to be found</li>
	
	<li><strong>vm</strong> stands for the source code for the virtual machine</li>
	
	<li><strong>hal</strong> stands for the â€˜Hardware Abstraction Layerâ€™, just a fancy name</li>
	
	<li><strong>opcodes</strong> stands for the assembly opcodes supported by the virtual machine</li>
	
	<li><strong>tests</strong> is the directory of the unit tests, right now we use Catch2</li>
</ul>

<p>But before we dig deeper here, just a quick mention: this entire project was created as a homegrown fun project, mostly for research purposes, so donâ€™t expect production-quality speed (or code) neither from the compiler, nor from the compiled part. There are several excellent compilers in the market right now. I have tried to keep the primal compiler as simple and understandable as possible, and sometimes I had to cut a few corners to have it in a digestible size. For now, the entire project is released under an Affero GPL license, so feel free to modify, contribute and distribute in the spirit of true open source.</p>

<h3>Banalities of the compiler</h3>

<p>I had to create a few wrappers around common notions, such as â€˜sourceâ€™ in order to have an easier approach to them, but the entire project is packed in the primal namespace to not to pollute the global one. As mentioned above, the compiler does not follow the standard mechanisms of creating a compiler, as we have not created a context-free grammar for it that can be fed in one into one of the automated tools to generate the proper mechanisms to automatically deal with situations that you can (will) encounter while writing a compiler. Instead, we tried to â€˜guessâ€™ how to approach these situations and â€˜solvedâ€™ what had to be solved in a more manual manner, and â€“ with explanations â€“ they are presented here.</p>

<ul>
	<li>The compiler itself is located in the class <code>compiler</code>.</li>
	
	<li>The source code is wrapped into the class <code>source</code>. Very conveniently for us, this class uses <code>std::stringstream</code> to read in the required source code, from a string variable. As mentioned before, each line in the script lives its own life, and we have abused the string stream to serve us the text line by line by using <code>std::getline</code>. The text of the source is traversed only once.</li>
	
	<li>Each line of code is wrapped into a <code>class sequence</code> derived keyword object. As mentioned before, in this programming language each line starts with a keyword, and these keywords are stored in their separate classes too, in the <span class="filename">keywords</span> folder inside the compiler. This decision was mainly influenced by the following
		<ul>
			<li>To keep it simple and easy to implement.</li>
			<li>To make it extensible without too much hassle â€“ for example, introducing a new keyword should not be an extremely complex operation.</li>
		</ul>
	</li>
</ul>

<h3>Parsing and tokenizing</h3>

<p>For our little compiler, we have created a very simple tokenizer with a few lines of code, which suits very well our primitive scriptâ€™s syntax. It can be found spread across the classes <code>lexer</code>, <code>parser</code> and <code>token</code>.</p>

<p>The <code>parser</code> class is responsible for parsing the entire source object that it was assigned, and the method <code>parser::parse</code> does the actual work:</p>

<pre class="programlisting">
  template&lt;class CH&gt; parse(source&amp; input, 
  CH checker, std::string&amp; last_read) { ... }</pre>
  
<p>The <code>checker</code> parameter has a specific role: the caller of the parse method can specify the condition at which the current sequence can stop. For the main compiler, this method is called like (from inside<code>compiler::compile</code>):</p>

<pre class="programlisting">
  std::string last;
  auto seqs = p.parse(m_src, [&amp;](std::string) {
    return false;}, last);</pre>
	
<p>however the implementation of the <code>if</code> keyword does something else:</p>

<pre class="programlisting">
  parser p;
  std::string last;
  auto seqs = p.parse(m_src,[&amp;](std::string s)
    {
      return util::to_upper(s) == &quot;END&quot;;
    },
    last);
  m_if_body = std::get&lt;0&gt;(seqs);</pre>
  
<p>The reasoning is the following: in the primal languageâ€™s implementation, each keyword manages its own parsing and compilation, with some backup from the underlying architecture. So, the <code>if</code> keyword was responsible of extracting its own body (<code>m_if_body</code>) from the <code>source</code> object (<code>m_src</code>) and due to the syntax of the language, the body of the <code>if</code> is between the current position in the <code>m_src</code> and the corresponding <code>endif</code> keyword.</p>

<p>The inner workings of the <code>parser::parse</code> method are as following:</p>

<pre class="programlisting">
  std::string next_seq = input.next();</pre>
  
<p>which will extract the next sequence of code (for us: next line) from the input (remember, this was of type <code>source</code>), and at the same time advance the location in the input. We see the result of the checker on the current sequence: if it evaluates to true, we will not continue the parsing but will go back to the entity which requested the parsing of the source from its specific location.</p>

<p>If we are still in the parsing phase, the tokenizer jumps in:</p>

<pre class="programlisting">
  lexer l(next_seq);
  std::vector&lt;token&gt; tokens = l.tokenize();</pre>
  
<p>where the tokenize method is just a very rudimentary implementation of splitting a string into several components separated by space, comma or other characters. The result of the method is a vector of tokens, where each token has its own type that you can check out in <span class="filename">token.h</span>:</p>

<pre class="programlisting">
  enum class type
  {
    TT_OPERATOR  = 1, // omitting the rest
                      // to save space</pre>
					  
<p>The very first token, as per the definition of the language, must be a keyword. After tokenizing the sequence, we try to identify the keyword object and pass the control to it in order to prepare the sequence in the requested manner (for example, the way it was done for the <code>if</code> keyword is presented a few lines above). Different keywords do different preparations and checks, in order to validate the sequence.</p>

<p>When the keyword has successfully prepared and validated the sequence of tokens, it is time for us to run Edsger Dijkstraâ€™s shunt-yard algorithm [<a href="#[Dijkstra61]">Dijkstra61</a>] on it in order to obtain a reverse Polish notation from which we will construct the abstract syntax tree of the expression.</p>

<p>Building the ast is done in a recursive manner in</p>

<pre class="programlisting">
  static void build_ast(std::vector&lt;token&gt;&amp; output,
  std::shared_ptr&lt;ast&gt;&amp; croot);</pre>
  
<p>where the parameter output is the actual output of the shuntyard algorithm:</p>

<pre class="programlisting">  // create the RPN for the expression
  std::vector&lt;token&gt; output = shuntyard(tokens);
  // build the abstract syntax tree for the result
  // of the shuntyard
  ast::build_ast(output, seq-&gt;root());</pre>

<h3>Compiling</h3>

<p>When the parsing is done, we get back the list of sequences â€“ and by continuing our journey in <code>compiler::compile</code> we have reached the stage where we need to actually compile the sequences into the corresponding machine code. This is achieved by:</p>

<pre class="programlisting">  // now compile the sequences coming from the parser
  for(const auto&amp; seq : std::get&lt;0&gt;(seqs))
  {
    seq-&gt;compile(this);
  }</pre>
  
<p>donâ€™t let <code>std::get&lt;0&gt;(seqs)</code> scare you: as you can see in the source code, <code>parser::parse</code> actually returns a tuple of vector of sequences, where the first one means the instructions from the global namespace. Also, now you might want to jump down to the virtual machine section and read a bit about the architecture of it, to understand the instructions below, and come back after that.</p>

<p>As mentioned before, each keyword is required to compile its own code. Letâ€™s present (in Listing 3), as an example, how the <code>if</code> keyword is actually doing its work (<code>kw_if::compile</code>).</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
// to compile the expression on which the IF takes
// its decision
sequence::compile(c);

// and set up the jumps depending on the trueness
// of the expression
label lbl_after_if = 
  label::create(c-&gt;get_source());
label lbl_if_body = 
  label::create(c-&gt;get_source());

// the comparator which evaluates the expression
comp* comparator =
  dynamic_cast&lt;comp*&gt;
  (operators[m_root-&gt;data.data()].get());

// generate code for the true case of it
(*c-&gt;generator()) &lt;&lt; comparator-&gt;jump 
  &lt;&lt; lbl_if_body;
(*c-&gt;generator()) &lt;&lt; DJMP() &lt;&lt; lbl_after_if;

(*c-&gt;generator()) &lt;&lt; declare_label(lbl_if_body);
for(const auto&gt;amp; seq : m_if_body)
{
  seq-&gt;compile(c);
}
(*c-&gt;generator()) &lt;&lt; declare_label(lbl_after_if);
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 3</td>
	</tr>
</table>

<p>In the very first step: we compile this sequence via <code>sequence::compile(c);</code> to obtain the expression, the trueness of which is used by the if to decide whether to execute its body or not. Then we create two labels, one for the body of the <code>if</code>, the other one for the immediate location after the <code>if</code>.</p>

<p>Now, we obtain the comparator object from the root of the abstract syntax tree of this <code>if</code> object. At the current stage of the script (when writing this article), that must be a check for equality or comparison as no other operation is supported. The comparators are stored in the global map of <code>primal::operators</code> found in <span class="filename">operators.h</span>. This just lists all the operators the scripting language supports at the moment, together with the assembly opcode (more about this at a later stage, when we discuss the virtual machine) and a jump operation depending on the trueness of the operation.</p>

<p>The expression <code>*c-&gt;generator()</code> will yield a <code>generate</code> object which is actually a convenience class for seamlessly accessing (read: appending to) the <code>compiled_code</code> class, which is the part of the compiler where the compiled code actually resides.</p>

<p>Now that we have a <code>generate</code> object, first we output into it the <code>JUMP</code> operation (which is currently a jump depending on the state of a flag in the machine where this will run, which will be set depending on the trueness of the expression of the <code>if</code>) and the label of the body of the <code>if</code>.</p>

<p>After that, we output a direct jump to the first instruction after the body of the if (just in case the if was actually false).</p>

<p>Now it is time to compile the body of the <code>if</code>, and we are done.</p>

<h3>Implementing the jumps</h3>

<p>There is just one issue with compiling the jumps. Some of the labels might refer to locations/labels that at the current moment are not known because they come way after the current location. How this is solved currently is that the compiler inserts a bogus value at the location of the jump label, and in an internal map marks the spot of the label and its reference point. This happens in <code>generate::operator&lt;&lt;(const label&amp; l)</code>.</p>

<p>When a label declaration happens, the compiler will finally know the location of the label, so it can update its map with the location in <code>generate::operator&lt;&lt;(declare_label &amp;&amp;dl)</code>.</p>

<p>When the compilation is done and all the locations of the labels are known, <code>compiled_code::finalize()</code> will patch the locations of the labels with the correct value.</p>

<h3>The sequence compiler</h3>

<p>At the very lowest level of the compiler is the sequence compiler found in <code>sequence::traverse_ast(uint8_t level, const std::shared_ptr&lt;ast&gt;&amp; croot, compiler* c)</code>. This is responsible for compiling basic arithmetic expressions, dealing with numbers and variables, etcâ€¦ The result â€“ the compiled code â€“ is actually a 3-address representation of the code, and the virtual machine interpreting the compiled bytecode was written to execute this representation.</p>

<p>This level tracks the variable index of the 3-address code. Initially, this starts at 0, is very conveniently mapped to registers in the virtual machine, and each descent in the abstract syntax tree will increment this. At the end of the traversal of the tree, the Reg(0) of the virtual machine will contain the value of the expression.</p>

<p>Depending on the type of the expression found in the current node of the tree, a different set of instructions is created. For example, the arithmetic operations generate the sequence of code shown in Listing 4.</p>

<table class="sidebartable">
	<tr>
		<td>
			<pre class="programlisting">
if (croot-&gt;data.get_type() ==
  token::type::TT_OPERATOR)
{
  traverse_ast(level + 1, croot-&gt;left, c);
  (*c-&gt;generator()) &lt;&lt; MOV() &lt;&lt; reg(level) 
    &lt;&lt; reg(level + 1);
  traverse_ast(level + 1, croot-&gt;right, c);
  (*c-&gt;generator())
    &lt;&lt; operators.at(croot-&gt;data.data())-&gt;opcode 
    &lt;&lt; reg(level) &lt;&lt; reg(level + 1) ;
}
			</pre>
		</td>
	</tr>
	<tr>
		<td class="title">Listing 4</td>
	</tr>
</table>

<p>To understand this piece of code, letâ€™s consider that we are trying to compile the expression <code>2+3</code>.</p>

<p>This has yielded the following tokens, where <code>TT</code> stands for <strong>T</strong>oken <strong>T</strong>ype: <code>(2, TT_NUMBER)</code>, <code>(+, TT_OPERATOR)</code> and <code>(3, TT_NUMBER)</code>.</p>

<p>After shuntyarding the expression, we have the following reverse Polish notation: <code>(+, TT_OPERATOR)</code>, <code>(3, TT_NUMBER)</code>, <code>(2, TT_NUMBER)</code>.</p>

<p>This was transformed into the abstract syntax tree in Figure 6.</p>

<table class="sidebartable">
	<tr>
		<td><img src="/content/images/journals/ol149/Deak/Deak-06.svg" /></td>
	</tr>
	<tr>
		<td class="title">Figure 6</td>
	</tr>
</table>

<p>Now we enter the <code>sequence::traverse_ast</code> method with the current root pointing to the root of the above tree, on level 0. The code sees that we actually have to deal with an operator: <code>+</code>.</p>

<p>It enters the <code>if</code> above, and it will immediately start descending into the tree on the next level, towards the left side of the tree. Now the current node points towards the <code>2</code>. The code sees that the data is actually a number, so it enters here:</p>

<pre class="programlisting">
  if (tt == token::type::TT_NUMBER)
  {
    (*c-&gt;generator()) &lt;&lt; MOV() &lt;&lt; reg(level) 
      &lt;&lt; croot-&gt;data;
  }</pre>
  
<p>Now the following piece of code will be generated (which has the significance of initializing the register number 1 to 2):</p>

<pre class="programlisting">
  MOV $r1 2</pre>

<p>Since there is nothing more to be done here, we go back to the previous step (we were inside the <code>TT_OPERATOR if</code> branch), where the following instruction waits for us:</p>

<pre class="programlisting">
  (*c-&gt;generator()) &lt;&lt; MOV() &lt;&lt; reg(level) 
    &lt;&lt; reg(level + 1);</pre>
	
<p>which will generate:</p>

<pre class="programlisting">
  MOV $r0 $r1</pre>

<p>ie. move the content of register 1 into register 0. Donâ€™t forget that register 1 was initialized to 2 a few lines above. Now, we descend the tree to the right branch, where we see the <code>3</code> thus giving us the following:</p>

<pre class="programlisting">
  MOV $r1 3</pre>
  
<p>and we are done with that part too. Back to the inside of the <code>if</code> for <code>TT_OPERATOR</code> where the next operation is:</p>

<pre class="programlisting">
  (*c-&gt;generator()) 
    &lt;&lt; operators.at(croot-&gt;data.data())-&gt;opcode 
    &lt;&lt; reg(level) &lt;&lt; reg(level + 1)</pre>
	
<p>This will go searching in the global <code>operators</code> table for the operator which is at the current level in the tree, and it will find the following row:</p>

<pre class="programlisting">
  (&quot;+&quot;,  util::make_unique&lt;ops&gt; (&quot;+&quot;, PRIO_10, 
    new opcodes::ADD))</pre>
	
<p>where the <code>opcodes::ADD</code> is the opcode responsible for executing addition in the system. So it will generate the following assembly code sequence:</p>

<pre class="programlisting">
  ADD $r0 $r1</pre>

<p>Since we are done with the tree, we are also done with the compilation, and we just exit. And at a very high level, this is the logic based on which the compiler is built.</p>

<p>There is just one drawback for this entire mechanism: since the virtual machine was built to have 256 register (see below) at some point in very complex expressions, we simply might run out of registers. A resolution for future versions would be to implement the inclusion of a temporary variable in the code generation where the partial results are accumulated, but I reserve this for future enhancements of the compiler.</p>

<h3>The assembly compiler</h3>

<p>The script provides the programmer with the possibility of writing virtual-machine-specific assembly instructions. The keyword responsible for this is <code>asm</code> and the implementation is found in <span class="filename">kw_asm.cpp</span>. The build system generates a set of compiler files for the registered opcodes (please see below on how to register new opcodes) and a special component called the <code>asm_compiler</code> found in <span class="filename">asm_compiler.h</span> will generate the required code for the assembly instruction.</p>

<h3>How to deal with the write function calls</h3>

<p>As mentioned above, the function <code>write</code> is added to the system (see its source code in the <a href="#[Appendix]">Appendix</a>) as a way to output data onto the screen. The <code>write</code> function is a dynamic function, meaning it can take in a various number and type of arguments (strings, variables and numbers) so I had to come up with a way to make it flexible enough to be usable.</p>

<p>One way to deal with it would have been the C way with a format string where various format specifiers are representing various interpretations of the data, but personally Iâ€™m not a great fan of it. Another way of dealing with this situation is presented by the Pascal compiler: while printing out, each type printed out is represented by a different function being called, and the compiler generates a list of method calls for all the parameters. Simple and effective. But unfortunately, at this moment I donâ€™t have the infrastructure to support this.</p>

<p>So, I went in a third direction with this. With the help of the stack, I specify the number of parameters the function is having, then their type (string constant/number for now) and then the actual parameters. Now all is needed is just a clever write function which interprets the data from the stack, and all is done.</p>

[Web Editor's Note:  Article is continued 
<a href="/index.php/journals/2637" >here</a>.]

<h2>References</h2>

<p class="bibliomixed"><a id="[CompOpt]"></a>[CompOpt] Compiler optimizations: <a href="http://compileroptimizations.com/">http://compileroptimizations.com/</a></p>

<p class="bibliomixed"><a id="[Dijkstra61]"></a>[Dijkstra61] EdsgerW.Dijkstra (1961) <em>ALGOL Bulletin Supplement no. 10</em>: <a href="http://www.cs.utexas.edu/~EWD/MCReps/MR35.PDF">http://www.cs.utexas.edu/~EWD/MCReps/MR35.PDF</a></p>

<p class="bibliomixed"><a id="[Dragon]"></a>[Dragon] Alfred V. Aho, Monica S. Lam, Ravi Sethi and Jeffrey D. Ullman (2006) <em>Compilers: Principles, Techniques, and Tools</em></p>

<p class="bibliomixed"><a id="[GCCArchitecture]"></a>[GCCArchitecture] GNU C Compiler Architecture: <a href="https://en.wikibooks.org/wiki/GNU_C_Compiler_Internals/GNU_C_Compiler_Architecture">https://en.wikibooks.org/wiki/GNU_C_Compiler_Internals/GNU_C_Compiler_Architecture</a></p>

<p class="bibliomixed"><a id="[Guntli11]"></a>[Guntli11] Christopher Guntli (2011) â€˜Architecture of clangâ€™, <a href="https://wiki.ifs.hsr.ch/SemProgAnTr/files/Clang_Architecture_-_ChristopherGuntli.pdf">https://wiki.ifs.hsr.ch/SemProgAnTr/files/Clang_Architecture_-_ChristopherGuntli.pdf</a></p>

<p class="bibliomixed"><a id="[Knuth65]"></a>[Knuth65] Donald E. Knuth (July 1965). â€˜On the translation of languages from left to rightâ€™. <em>Information and Control</em> 8(6): 607 - 639. doi: 10.1016/S0019 - 9958(65)90426-2</p>

<p class="bibliomixed"><a id="[LLVM]"></a>[LLVM] The LLVM Compiler Infrastructure:<a href="https://llvm.org/">https://llvm.org/</a></p>

<p class="bibliomixed"><a id="[Wikipedia-1]"></a>[Wikipedia-1] Compiler optimizations: <a href="https://en.wikipedia.org/wiki/Category:Compiler_optimizations">https://en.wikipedia.org/wiki/Category:Compiler_optimizations</a></p>

<p class="bibliomixed"><a id="[Wikipedia-2]"></a>[Wikipedia-2] Lexical analysis: <a href="https://en.wikipedia.org/wiki/Lexical_analysis">https://en.wikipedia.org/wiki/Lexical_analysis</a></p>

<p class="bibliomixed"><a id="[Wikipedia-3]"></a>[Wikipedia-3] Multi-pass compiler: <a href="https://en.wikipedia.org/wiki/Multi-pass_compiler">https://en.wikipedia.org/wiki/Multi-pass_compiler</a></p>

<p class="bibliomixed"><a id="[Wikipedia-4]"></a>[Wikipedia-4] Parser generators: <a href="https://en.wikipedia.org/wiki/Comparisonofparser_generators">https://en.wikipedia.org/wiki/Comparisonofparser_generators</a></p>

<p class="bibliomixed"><a id="[Wikipedia-5]"></a>[Wikipedia-5] Regular expression: <a href="https://en.wikipedia.org/wiki/Regular_expression">https://en.wikipedia.org/wiki/Regular_expression</a></p>

<p class="footnote"></p>
<ol>
	<li><a id="FN01"></a>Original diagram by Kenstruys (own work) and placed in the public domain. Gratefully downloaded from Wikimedia Commons <a href="https://commons.wikimedia.org/w/index.php?curid=6020058">https://commons.wikimedia.org/w/index.php?curid=6020058</a></li>
</ol>

</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
