<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: James</title>
    <description>The latest articles on DEV Community by James (@miiizen).</description>
    <link>https://dev.to/miiizen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F28215%2F9c3126c8-860f-4fd6-8f8f-39be38e7ff0b.jpg</url>
      <title>DEV Community: James</title>
      <link>https://dev.to/miiizen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/miiizen"/>
    <language>en</language>
    <item>
      <title>Compiler Series Part 5: Lexical analysis</title>
      <dc:creator>James</dc:creator>
      <pubDate>Sat, 24 Aug 2019 12:02:48 +0000</pubDate>
      <link>https://dev.to/miiizen/compiler-series-part-5-lexical-analysis-3kf7</link>
      <guid>https://dev.to/miiizen/compiler-series-part-5-lexical-analysis-3kf7</guid>
      <description>&lt;p&gt;From this post onwards, I will be explaining sections from my compiler and the thoughts gone into designing them.  I will link to the relevant files in my compiler's repository found &lt;a href="https://github.com/miiizen/compiler" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining basic tokens
&lt;/h2&gt;

&lt;p&gt;The smallest "atoms" of my language (aside from individual characters) are called tokens.  The scanner's job is to recognise valid tokens in the input text and reject invalid ones.  The following BNF describes some basic tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;digit&amp;gt; : [0-9]+
&amp;lt;number&amp;gt; ::= [&amp;lt;digit&amp;gt;]+.[&amp;lt;digit&amp;gt;]+

&amp;lt;name&amp;gt; ::= [a-zA-Z][a-zA-Z0-9]*
&amp;lt;string_lit&amp;gt; ::= " [\w*] "

&amp;lt;op&amp;gt; ::= ['+' | '-' | '*' | '/' | '^' | '%' | '=' | '&amp;gt;' | '&amp;lt;' | '!' | '|' | '&amp;amp;']+
&amp;lt;whitespace&amp;gt; ::= [' ' | '\n' | '\t']+
&amp;lt;comment&amp;gt; ::= # &amp;lt;all&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strings will make up identifiers and specific keywords as well as string literals.  Operators can be any combination of the above symbols.  The scanner will then go on to recognise certain combinations.  If the combination of input characters is not recognised, the scanner throws an error.  The scanner also removes whitespace and comments.  &lt;/p&gt;

&lt;p&gt;A lexeme is any combination of characters which matches the tokens.  My complete list of tokens looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Token Types {
    PLUS, MINUS, STAR, SLASH, HAT, MOD, INC, DEC,
    EQ, LESS, GREATER, LEQ, GREQ, NEQ,
    AND, OR, NOT,
    ASSIGN, CONDITIONAL, COLON,

    LEFTPAREN, RIGHTPAREN, LEFTSQ, RIGHTSQ, COMMA,
    NUMBER, STRING, IDENTIFIER, BOOL,
    BEGIN, IF, ENDIF, ELSE, THEN,
    FOR, IN, ENDFOR,
    DEFINE, ENDDEF, EXT,
    NEWLINE, END
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Some language theory&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;The scanner recognises a language which is type 3 on the Chomsky Hierarchy&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.  A type 3 language can be recognised/parsed by regular expressions and state machines.  I could implement a literal state machine for the parser, but I will not, as this approach is not very efficient to write. Similarly, I could have written a complex regex to split the input into tokens, but this obscures a lot of the logic for me.  I started this project to learn, not write a compiler in as few lines as possible. &lt;br&gt;
Later on, the parser will interpret a type 2 language using a push-down automata.  (A type of automata which uses a stack to hold information.  In my implementation, this stack is the C++ function call stack).  The difference between the two languages being interpreted is the main reason to have a separate lexer and parser&lt;sup id="fnref3"&gt;3&lt;/sup&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe5v1ojd7td4t5w27ny9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fe5v1ojd7td4t5w27ny9w.png" alt="The Chomsky Hierarchy"&gt;&lt;/a&gt;&lt;br&gt;
A tool called flex&lt;sup id="fnref4"&gt;4&lt;/sup&gt; exists which can generate scanner state machines in C.  This is a modern version of GNU lex.  I decided that this tool introduced too much overhead into my code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Algorithm
&lt;/h2&gt;

&lt;p&gt;The basic algorithm for the scanner is below.  The functions such as &lt;code&gt;getString()&lt;/code&gt; and &lt;code&gt;getOp()&lt;/code&gt; are described in the BNF above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getNextTok =&amp;gt;
   nextChar()
   if next char is '#' skip line then nextChar() 
   skip whitespace

   if next char is digit, getNumber() and return number token

   getName() if next char is alpha
       if string is keyword return keyword token
       else return identifier token

   getOp() if next char is operator
       if operator string is recognized return operator token
       else error

   getString() if next char is '"'

   if next char is recognized punctuation
       return punctuation token

   if next char is unrecognized
        error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Writing a scanner is not too difficult at all and should come in useful for many projects, when you need to parse any kind of input. &lt;br&gt;
Finally, &lt;a href="https://github.com/miiizen/Compiler/blob/master/Compiler_Lib/scanner.cpp" rel="noopener noreferrer"&gt;here&lt;/a&gt; is the scanner from my compiler. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Aho, A., Lam, M., Sethi, R. and Ullman, J. (2006). Compilers: Principles, Techniques, and Tools. 2nd ed. Pearson Education Inc. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://www.geeksforgeeks.org/toc-chomsky-hierarchy/" rel="noopener noreferrer"&gt;Theory of Computation - Chomsky Hierarchy&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://compilers.iecc.com/crenshaw/tutor7.txt" rel="noopener noreferrer"&gt;Let's Build a Compiler, by Jack Crenshaw - Part 7: LEXICAL SCANNING&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://github.com/westes/flex" rel="noopener noreferrer"&gt;GitHub - westes/flex: The Fast Lexical Analyzer&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>computerscience</category>
      <category>compilers</category>
      <category>cpp</category>
      <category>learning</category>
    </item>
    <item>
      <title>Compiler Series Part 4: Designing the SIMPLE language and compiler</title>
      <dc:creator>James</dc:creator>
      <pubDate>Sat, 10 Aug 2019 13:31:51 +0000</pubDate>
      <link>https://dev.to/miiizen/compiler-series-part-4-designing-the-simple-language-and-compiler-82b</link>
      <guid>https://dev.to/miiizen/compiler-series-part-4-designing-the-simple-language-and-compiler-82b</guid>
      <description>&lt;p&gt;I've chosen to call the language I've designed for the compiler SIMPLE for fairly self evident reasons.  This language is Turing complete as it features conditional statements and variables.&lt;br&gt;
As this compiler is an MVP, there will only be one data type: doubles. &lt;/p&gt;
&lt;h2&gt;
  
  
  Program structure
&lt;/h2&gt;

&lt;p&gt;The program should be enclosed in &lt;code&gt;BEGIN..END&lt;/code&gt;. The top level should contain function definitions with a main function as an entry point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEGIN
   DEFINE average(x, y)
       (x + y) * 0.5
   ENDDEF

   DEFINE main()
       average(5, 8)
   ENDDEF
END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Functions
&lt;/h2&gt;

&lt;p&gt;Functions enclose reusable blocks of code. They can take arguments (must be doubles) and return a value (also a double)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEFINE average(x, y)
       (x + y) * 0.5
ENDDEF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no ‘return’ keyword, the evaluation of the last expression is the return value of the function.&lt;/p&gt;

&lt;p&gt;Functions can be defined as external. This means that a definition exists elsewhere and will be linked later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEFINE EXT printd(x)
DEFINE EXT sin(x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the language to use functions from the c standard library and any user defined functions which may also be linked.&lt;/p&gt;

&lt;h2&gt;
  
  
  If/else statements
&lt;/h2&gt;

&lt;p&gt;If statements decide which block of code to execute based on the result of a conditional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IF 5 &amp;lt; 6 THEN
   ...
ELSE
   ...
ENDIF

IF 4==2 THEN
   ...
ENDIF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  For loops
&lt;/h2&gt;

&lt;p&gt;For loops take the form of an identifier (loop variable), end condition and an optional step value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FOR i = 1, i &amp;lt; n, 1 IN
   ...
ENDFOR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Once finished, the compiler will be capable of emitting an executable for this program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEGIN
 DEFINE EXT sin(x)
 DEFINE EXT putchard(x)

 DEFINE main()
   num = 7
   FOR y = 1, y &amp;gt;= -1, -0.2 IN
     FOR x = 0, x &amp;lt;= num, 0.2 IN
       s = sin(x)
       IF (0.1+y) &amp;gt;= s THEN
         IF (y-0.1) &amp;lt;= s THEN
           putchard(42) # “*“
         ELSE
           putchard(32) # “ ”
         ENDIF
       ELSE
         putchard(32) # “ “
       ENDIF
     ENDFOR
     putchard(10) # “\n”
   ENDFOR
 ENDDEF
END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program's output is an approximate sketch of a sin wave in the terminal!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fha8pmzxsadze5gd8rm4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fha8pmzxsadze5gd8rm4k.png" alt="a very rough sin wave!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiler process
&lt;/h2&gt;

&lt;p&gt;A compiler lends itself to a modular approach.  One can take this to the extreme, for example see the paper on a 'nanopass' approach to compiler design&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;A level 1 DFD outlining the processes happening within my compiler is included below.  It is a linear process,&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftbobjdl8dly5qpsc2jwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftbobjdl8dly5qpsc2jwz.png" alt="level 1 DFD"&gt;&lt;/a&gt;&lt;br&gt;
When a language feature is added to the compiler it's quite straightforward to extend each section to support it.&lt;/p&gt;

&lt;p&gt;In the next section, we'll get into writing the lexer.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://www.cs.indiana.edu/~dyb/pubs/nano-jfp.pdf" rel="noopener noreferrer"&gt;A Nanopass Framework for Compiler Education&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>compilers</category>
      <category>computerscience</category>
      <category>cpp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Compiler Series Part 3: Rust</title>
      <dc:creator>James</dc:creator>
      <pubDate>Thu, 08 Aug 2019 16:09:27 +0000</pubDate>
      <link>https://dev.to/miiizen/compiler-series-part-3-rustc-5e9</link>
      <guid>https://dev.to/miiizen/compiler-series-part-3-rustc-5e9</guid>
      <description>&lt;p&gt;This post will be another fly by look at a production compiler, this time for the Rust language.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Disclaimer!&lt;/em&gt; I wrote this a while ago and have not checked how much has changed!  The compiler and language are still maturing, so changes are frequent.&lt;/p&gt;

&lt;p&gt;The &lt;a href="//www.rust-lang.org"&gt;Rust&lt;/a&gt; project is a compiler for a new systems language.  The compiler and standard library is written in Rust itself, and the project is sponsored by Mozilla.  It merits itself on being "blazingly fast", preventing segfaults and guaranteeing thread safety.&lt;br&gt;&lt;br&gt;
Rust is based on multiple paradigms.  It takes its variable mutability/borrowing rules from functional programming, ensuring thread safety and preventing data races.  For example, after passing a variable as an argument into a function, the variable cannot be used again as it is dropped from the scope.  These ownership rules increase the safety of the language, as most potential problems are picked up by the compiler.  If the program compiles, you can be fairly confident that there won’t be many unexpected runtime errors.&lt;/p&gt;

&lt;p&gt;The compilation process is different to that of gcc, although the underlying idea is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parsing&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;Although parsing can be done by writing a finite state machine, the rust parser is hand written.  First, a lexer takes the input source as UTF-8 text and generates tokens from it.  These tokens are then placed into a token tree&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.  This tree is an intermediate stage between the input source, and the AST.  This stage isn't always necessary, depending on the complexity of the language.  Recursive descent is then used to generate the real AST.  The AST does not include unnecessary bits of the input like parentheses.  They can be implied at this point. &lt;/p&gt;

&lt;h2&gt;
  
  
  Expansion
&lt;/h2&gt;

&lt;p&gt;At this point, the AST is passed over.  At the appropriate locations, external code such as the standard library and other specified modules are injected.  In addition to this, macros are expanded.  This is in contrast to the GCC method, where macros are dealt with by manipulating the source code directly.  Tests (which are also defined with # syntax) are built into a harness at this stage and injected into the AST.  The AST is given node IDs for later use, and optionally can be output at this point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;Semantic analysis happens at this stage.  This involves traversing through the AST and performing different transformations.  At this stage, the AST becomes HIR, &lt;em&gt;High-Level Intermediate Representation&lt;/em&gt;.  This is basically the same as the AST, so we don’t need to worry about the detail too much.  Many tasks are done here, including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name resolution - checking whether identifiers are variables, functions or modules.&lt;/li&gt;
&lt;li&gt;Finding the &lt;code&gt;main&lt;/code&gt; method as this is the entry point for the program&lt;/li&gt;
&lt;li&gt;Type checking - determining the resultant type of expressions&lt;/li&gt;
&lt;li&gt;Checking the rules associated with static, constant and private types are obeyed&lt;/li&gt;
&lt;li&gt;Match checking - Rust’s pattern matching rules are enforced here&lt;/li&gt;
&lt;li&gt;Dead code checking - emits warnings if unreachable code is detected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These steps are not optimisations as such, more implementations of language features.  &lt;/p&gt;

&lt;p&gt;Afterwards, the HIR is translated to MIR, &lt;em&gt;Mid-Level Intermediate Representation&lt;/em&gt;&lt;sup id="fnref3"&gt;3&lt;/sup&gt;.  This breaks up the large step between a fairly high level, abstract representation and the final low level representation.  For example, all control flow, loops and matches are represented using &lt;code&gt;goto&lt;/code&gt; like statements.  Borrow checking is done at this stage, making sure the rules are adhered to, and some optimisations are made before translating MIR into LLVM IR.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLVM
&lt;/h2&gt;

&lt;p&gt;LLVM is a set of tools used to help write compilers.  For now we just need to know that it takes a low level intermediate representation of the source code as an input and generates bytecode for the specified platform.&lt;br&gt;&lt;br&gt;
The first job is to translate Rust’s crates to LLVM’s modules.  "Crates" and "Modules" are similar concepts, it’s just the technicalities of representation that need to be translated.&lt;br&gt;
After this step, LLVM runs its own optimisation passes.  These ensure that the output program is as efficient as possible.  Rust has many implementations of its own optimisations that LLVM could run, but are known to be slow.  For all its efficiency, compile times with LLVM are frequently quite slow.&lt;br&gt;
Once the IR has been optimized, code generation happens.  LLVM either writes object files or assembly in the specified output format to disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linking
&lt;/h2&gt;

&lt;p&gt;If object files were emitted (eg. if we are building a native library or our project contains multiple files) the final step is to link these files.  This is done by calling the platform’s c compiler (eg. cc) and uses it to link the object files into an executable.&lt;/p&gt;

&lt;p&gt;I would like to use LLVM in my compiler, as it a well used system that will make code generation much more straightforward.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/"&gt;"A More Detailed Tour of the Rust Compiler" - Tom Lee&lt;/a&gt;  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://github.com/rust-lang/rust/blob/master/src/libsyntax/ast.rs#L545-L580"&gt;rust/ast.rs at master · rust-lang/rust · GitHub&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://blog.rust-lang.org/2016/04/19/MIR.html"&gt;"Introducing MIR" - The Rust Programming Language Blog&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>compilers</category>
      <category>rust</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Compiler Series Part 2: GCC</title>
      <dc:creator>James</dc:creator>
      <pubDate>Tue, 06 Aug 2019 18:44:32 +0000</pubDate>
      <link>https://dev.to/miiizen/compiler-series-part-2-gcc-2mm4</link>
      <guid>https://dev.to/miiizen/compiler-series-part-2-gcc-2mm4</guid>
      <description>&lt;p&gt;&lt;a href="https://gcc.gnu.org/"&gt;GCC&lt;/a&gt;, originally written for the GNU operating system is a set of front ends, libraries and back ends for a few different programming languages.  This is an old piece of software, but is kept up to date and used regularly by many.  The compiler has front ends for (can compile) C/C++, Objective C, Fortran, Ada and Go.&lt;br&gt;&lt;br&gt;
The compiler was originally built to avoid paying for a license to use a vendor compiler for the GNU operating system.  Since then, it has has risen past proprietary compilers in both popularity and performance.&lt;br&gt;
The process started when a user runs a command like &lt;code&gt;gcc myfile.c&lt;/code&gt; at the terminal can be broken down into 4 steps: preprocessing, compilation, assembly and linking.&lt;/p&gt;
&lt;h2&gt;
  
  
  The preprocessor&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;The preprocessor deals with making modifications to the source code before it is compiled.  We will be looking at the C/C++ preprocessor specifically.  Other preprocessors or frontends are available for different languages as mentioned above.  A certain amount of lexing occurs at this step.  The actions it performs are:&lt;/p&gt;
&lt;h3&gt;
  
  
  Line splicing
&lt;/h3&gt;

&lt;p&gt;This tidies the lines of the source up if escaped newlines are used.  Escaped newlines are backslashes used to break up lines.  They must appear between tokens or within comments.&lt;br&gt;
All comments within the code are also replaced with single spaces.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tokenisation
&lt;/h3&gt;

&lt;p&gt;Once these transformations are complete, the program is split up into preprocessor tokens.  These tokens are going to be passed to the compiler, where they will be used as compiler tokens.  For now, the preprocessor tokens can be put into 5 categories: identifiers, preprocessing numbers, string literals, punctuators, and other.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Identifiers - any sequence of letters, digits or underscores which DOES NOT begin with a number.  Keywords - tokens such as if, else are treated as identifiers.  This means that we can define macros with the same name as reserved keywords in the actual C/C++ language&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Preprocessing numbers - The definition encompasses a large range of representations of numbers.  In order to support hex and other representations, any combination of letters, numbers, periods and underscores are allowed after a decimal digit.  This allows many invalid forms to slip through this step.  They will be picked up by the compiler however.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;String literals - This includes string constants, character constants and arguments for the #include statement wrapped in angular brackets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Punctuators - All punctuation in ASCII except from ‘@’, ‘$’, and ‘’’ are considered punctuators. Punctuators have meaning to the compiler, but what that meaning is depends on the context in which they are found.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Directive and macro handling
&lt;/h3&gt;

&lt;p&gt;This is the step most people associate with the C/C++ preprocessor, as it is seen most often by the user of the compiler.  If the stream of tokens contains nothing in the preprocessing language, it is simply passed to the compiler.&lt;br&gt;&lt;br&gt;
The following are common feature used in the preprocessing language.&lt;/p&gt;
&lt;h4&gt;
  
  
  Including header files
&lt;/h4&gt;

&lt;p&gt;Header files contain C/C++ declarations and other preprocessor instructions.  Header files can be provided by the OS in order to use the system API, or defined by the user.  This makes it possible to share definitions between files.&lt;br&gt;
If we were to look at the code output by all the intermediate steps, we would see any &lt;code&gt;#include &amp;lt;xyz.h&amp;gt;&lt;/code&gt; replaced with the contents of &lt;code&gt;xyz.h&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Macro handling
&lt;/h4&gt;

&lt;p&gt;Macros can be object-like or function-like.  Object-like macros look like data objects.  They are most commonly used to give names to symbolic constants eg. &lt;code&gt;#define MAX_SIZE = 1024&lt;/code&gt;&lt;br&gt;
Where the name &lt;code&gt;MAX_SIZE&lt;/code&gt; is used in our code, the preprocessor will replace this text with &lt;code&gt;1024&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Function-like macros look like function calls when used.  When they are “called” the code that appears in the definition is simply copied to where it has been called. Eg. &lt;br&gt;
&lt;code&gt;#define SQUARE(x) x*x&lt;/code&gt;&lt;br&gt;
Wherever &lt;code&gt;SQUARE(X)&lt;/code&gt; appears in code, it is replaced with &lt;code&gt;x*x&lt;/code&gt;, where x is the value passed into square.&lt;br&gt;
Macros are used to increase performance.  Because the code is just copied by the preprocessor, in the assembly output there is no overhead with function stacks etc.  This paragraph barely scratches the surface of macros and how useful they can be, however, they are not an essential part of a compiler.&lt;/p&gt;
&lt;h4&gt;
  
  
  Conditional compilation
&lt;/h4&gt;

&lt;p&gt;This allows the preprocessor to decide whether to hand the following section of code to the compiler.  There are a few situations in which this is useful, for example include guards.  Include guards prevent the same header file being copied too many times.  This speeds up compilation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// An example include guard&lt;/span&gt;
&lt;span class="cp"&gt;#ifndef __MY_HEADER
#define __MY_HEADER
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Compilation&lt;sup id="fnref2"&gt;2&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;This is the stage which takes our preprocessed code, and generates assembly from it.  The gcc compiler makes multiple passes over representations of the input program, transforming it into different intermediate representations before outputting machine code. &lt;br&gt;
The figure below shows the steps involved&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hzNy_02Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5nq2lrzwq3ktfhet26iy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hzNy_02Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5nq2lrzwq3ktfhet26iy.jpeg" alt="https://upload.wikimedia.org/wikipedia/commons/0/0b/Gcc.JPG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Parsing pass
&lt;/h3&gt;

&lt;p&gt;This is the frontend of the compiler.  The details about the C preprocessor written above apply to this step.  After the preprocessor has done its job, the compiler generates an Abstract Syntax Tree (AST) from the token stream.  For now this can be thought of as a tree data structure that represents the input program.  The AST is very easy to modify and transform, so is useful as an internal representation of the input.  &lt;/p&gt;

&lt;p&gt;Each front end works in a different way, but usually ends up outputting a form called Generic (or GIMPLE).  The history and internal workings around this stage seem to be a little complicated and confused, but as long as Generic is output and passed to the compiler we are happy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gimplification pass
&lt;/h3&gt;

&lt;p&gt;This pass involves transforming our Generic representation into a GIMPLE representation.  This is another intermediate representation however, more restrictive than an AST. It is used for optimization passes later on.  At its most basic, GIMPLE is a collection of tuples representing Generic expressions.  The salient points on their structure are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There can be no more than three operands per expression.  If there are more than three, the expression is split into smaller parts.&lt;/li&gt;
&lt;li&gt;All control flow is made up of conditionals and goto statements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tree SSA
&lt;/h3&gt;

&lt;p&gt;This step involves multiple passes over the internal representation we now have of the code.  SSA stands for &lt;em&gt;Single Static Assignment&lt;/em&gt;.  The GIMPLE representation is modified so that each variable is only assigned to once.  If a variable needs to be assigned to multiple times, new variables are created.&lt;br&gt;
As can be seen in section 9.4 of the gcc internals manual referenced above, this step involves 47 different optimizations.  These involve optimizing loops, conditionals, removing unreachable code and other complex looking operations. A new GIMPLE representation with changes applied is returned from this step and passed onto the next.&lt;/p&gt;

&lt;h3&gt;
  
  
  RTL
&lt;/h3&gt;

&lt;p&gt;RTL stands for &lt;em&gt;Register Transfer Language&lt;/em&gt;, and is a step closer to our desired machine code output.  The GIMPLE representation is translated to RTL, which assumes an abstract processor with an infinite number of registers.  Many passes are made over this form, optimizing the code even further.  The optimized form is passed to a gcc backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assembly
&lt;/h2&gt;

&lt;p&gt;Just like frontends, gcc has support for many backends that deal with outputting platform specific machine code.  These include x86, i386 and arm.  When given the optimized RTL, the backend will emit the assembly for the platform specified.  The most commonly used backend is the GNU assembler known as gas or as. This was released in 1986 but is still being used frequently.&lt;br&gt;
The output from assembly is an object file.  This is passed to the linker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linking&lt;sup id="fnref4"&gt;4&lt;/sup&gt;
&lt;/h2&gt;

&lt;p&gt;The compilation and assembly process is performed on individual files.  The linker is used to connect all parts of a project together, whether that be header and implementation files or external libraries.  If a function is defined in a different file with extern or similar, it is the linker’s job to check if it has actually been defined.  In a project with thousands of lines of code, recompiling everything for one tiny change in a file would be a big pain.  Instead, the file containing the change is recompiled and the project is relinked.&lt;br&gt;&lt;br&gt;
Typically on a GNU/Linux system, the program ld is used.  This is the GNU linker.  The gcc program wraps calls to ld to make life easier for the developer, but if necessary this can be done manually.  &lt;/p&gt;

&lt;p&gt;This was just a glimpse at the huge, huge GCC project - currently sitting at just under 20 million lines of code. Picking through the technical documentation helped me get an overview of how a compiler should be structured.  After this analysis, I could begin to plan my own compiler. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://gcc.gnu.org/onlinedocs/cpp.pdf"&gt;"The C Preprocessor"&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://gcc.gnu.org/onlinedocs/gccint.pdf"&gt;"GCC Internals"&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://en.wikibooks.org/wiki/GNU_C_Compiler_Internals/GNU_C_Compiler_Architecture"&gt;"GCC Internals/GCC Architecture - Wikibooks."&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work"&gt;"c++ - How does the compilation/linking process work? - Stack Overflow."&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>compilers</category>
      <category>cpp</category>
      <category>c</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Compiler Series Part 1: Introduction</title>
      <dc:creator>James</dc:creator>
      <pubDate>Tue, 06 Aug 2019 18:39:38 +0000</pubDate>
      <link>https://dev.to/miiizen/compiler-series-part-1-introduction-1j83</link>
      <guid>https://dev.to/miiizen/compiler-series-part-1-introduction-1j83</guid>
      <description>&lt;p&gt;Programming was my first foray into computer science, and recently I wanted to dig into this topic in more detail.  The posts which follow will be a collection of my notes, made while writing my own compiler in C++.&lt;/p&gt;

&lt;p&gt;Compilers are an essential part of computing, allowing higher level languages to be translated to machine code that the computer can understand.  This provides an important level of abstraction to the programmer, meaning they don’t have to worry about the complexity and quirks of assembly languages.&lt;br&gt;&lt;br&gt;
I will break down the compiler into a collection of separate, easier to understand modules.  Compilers lend themselves to this modular approach quite nicely.  From front to back:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The lexer - This performs lexical analysis, breaking the input up into tokens&lt;/li&gt;
&lt;li&gt;The parser - This puts the tokens we get from the lexer into the context of our language via an intermediate representation&lt;/li&gt;
&lt;li&gt;Transformation - Once we have the intermediate representation, this can be tidied and optimised&lt;/li&gt;
&lt;li&gt;Code generation - The intermediate representation is used to generate the required assembly for each language construct&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the next section, we'll get a bird's eye view of &lt;a href="https://gcc.gnu.org/"&gt;gcc&lt;/a&gt; the GNU Compiler Collection.&lt;/p&gt;

</description>
      <category>compilers</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
