blog-static/content/blog/04_compiler_improvements.md

69 lines
2.8 KiB
Markdown
Raw Normal View History

2019-08-26 18:52:25 -07:00
---
title: Compiling a Functional Language Using C++, Part 4 - Small Improvements
date: 2019-08-06T14:26:38-07:00
draft: true
tags: ["C and C++", "Functional Languages", "Compilers"]
---
We've done quite a big push in the previous post. We defined
type rules for our language, implemented unification,
and then implemented unification to enforce these rules for
our program. The post was pretty long, and even then we
weren't able to fit quite everything into it.
For instance, we threw 0 whenever an error occured. This
gives us no indication of what actually went wrong. We should
probably define an exception class, one that can contain
information about the error, and report it to the user.
Also, when there's no error, our compiler doesn't
really tell us anything at all about the code besides
the number of definitions. We probably want to see the types
of these definitions, or at least some intermediate information.
At the very least, we want to have the __ability__ to see
this information.
Finally, we have no build system. We are creating more
and more source files, and so far (unless you've taken
initiative), we've been compiling them by hand. We want
to only compile source files that have changed,
and we want to have a standard definition of how to
build our program.
### Setting up CMake
This would be extremely easy if not for Flex and Bison. We start with the usual:
{{< codelines "CMake" "compiler/04/CMakeLists.txt" 1 2 >}}
Next, we want to set up Flex and Bison. CMake provides two commands for this:
{{< codelines "CMake" "compiler/04/CMakeLists.txt" 4 5 >}}
We now have access to commands that allow us to tell CMake about our parser
and tokenizer (or scanner). We use them as follows:
{{< codelines "CMake" "compiler/04/CMakeLists.txt" 6 12 >}}
We also want CMake to know that the scanner needs to parser's header file
in order to compile. We add this dependency:
{{< codelines "CMake" "compiler/04/CMakeLists.txt" 13 13 >}}
Finally, we add our source code to a CMake target. We use
the `BISON_parser_OUTPUTS` and `FLEX_scanner_OUTPUTS` to
pass in the source files generated by Flex and Bison.
{{< codelines "CMake" "compiler/04/CMakeLists.txt" 15 22 >}}
Almost there! `parser.cpp` will be generated in the `build` directory
during an out-of-source build, and so will `parser.hpp`. When building,
`parser.cpp` will try to look for `ast.hpp`, and `main.cpp` will look for
`parser.hpp`. We want them to be able to find each other, so we
add both the source directory and the build (binary) directory to
the list of includes directories:
{{< codelines "CMake" "compiler/04/CMakeLists.txt" 23 24 >}}
That's it for CMake! Let's try our build:
```
cmake -S . -B build
cd build && make -j8
```
We get an executable called `compiler`. Excellent! Here's the whole file:
{{< codeblock "CMake" "compiler/04/CMakeLists.txt" >}}