Add output and fix two bugs.
This commit is contained in:
@@ -29,6 +29,103 @@ to only compile source files that have changed,
|
||||
and we want to have a standard definition of how to
|
||||
build our program.
|
||||
|
||||
### Printing Syntax Trees
|
||||
Let's start by printing the trees we get from our parser.
|
||||
This is long overdue - we had no way to verify the structure
|
||||
of what our parser returned to us since Part 2. We'll print
|
||||
the trees top-down, with the children of a node
|
||||
indent one block further than the node itself. For this,
|
||||
we'll make a new virtual function with the signature:
|
||||
```
|
||||
virtual void print(int indent, std::ostream& to) const;
|
||||
```
|
||||
We'll include a similar printing function into our
|
||||
pattern struct, too:
|
||||
```
|
||||
virtual void print(std::ostream& to) const;
|
||||
```
|
||||
|
||||
Let's take a look at the implementation. For `ast_int`,
|
||||
`ast_lid`, and `ast_uid`:
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 18 21 >}}
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 27 30 >}}
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 36 39 >}}
|
||||
|
||||
With `ast_binop` things get a bit more interesting.
|
||||
We call `print` recursively on the children of the
|
||||
`binop` node:
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 45 50 >}}
|
||||
|
||||
The same idea for `ast_app`:
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 66 71 >}}
|
||||
|
||||
Finally, just like `ast_case::typecheck` called
|
||||
`pattern::match`, `ast_case::print` calls `pattern::print`:
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 83 92 >}}
|
||||
|
||||
We follow the same implementation strategy for patterns,
|
||||
but we don't need indentation, or recursion:
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 108 110 >}}
|
||||
{{< codelines "C++" "compiler/04/ast.cpp" 116 121 >}}
|
||||
|
||||
Let's print the bodies of each function we receive from the parser:
|
||||
{{< codelines "C++" "compiler/04/main.cpp" 35 50 >}}
|
||||
|
||||
### Printing Types
|
||||
Types are another thing that we want to be able to inspect, so let's
|
||||
add a similar print method to them:
|
||||
```
|
||||
virtual void print(const type_mgr& mgr, std::ostream& to) const;
|
||||
```
|
||||
We need the type manager so we can follow substitutions.
|
||||
The implementation is simple enough:
|
||||
{{< codelines "C++" "compiler/04/type.cpp" 5 24 >}}
|
||||
|
||||
Let's also print out the types we infer. We'll make it a separate loop
|
||||
in the `typecheck_program` function, because it's mostly just
|
||||
for debugging purposes.
|
||||
|
||||
### Fixing Bugs
|
||||
We actually discover not one, but two bugs in our implementation thanks
|
||||
to this output. Observe the output for `works3.txt`:
|
||||
```
|
||||
length l:
|
||||
CASE:
|
||||
Nil
|
||||
INT: 0
|
||||
*: Int -> (Int -> (Int))
|
||||
+: Int -> (Int -> (Int))
|
||||
-: Int -> (Int -> (Int))
|
||||
/: Int -> (Int -> (Int))
|
||||
Cons: List -> (Int -> (List))
|
||||
Nil: List
|
||||
length: List -> (Int)
|
||||
2
|
||||
```
|
||||
|
||||
First, we're missing the `Cons` branch. The culprit is `parser.y`, specifically
|
||||
this line:
|
||||
```C++
|
||||
: branches branch { $$ = std::move($1); $1.push_back(std::move($2)); }
|
||||
```
|
||||
Notice that we move our list of branches out of `$1`. However, when we
|
||||
`push_back`, we use `$1` again. That's wrong! We need to `push_back`
|
||||
to `$$` instead:
|
||||
{{< codelines "C++" "compiler/04/parser.y" 110 110 >}}
|
||||
|
||||
Next, observe that `Cons` has type `List -> Int -> List`. That's not right,
|
||||
since `Int` comes first in our definition. The culprit is this fragment of code:
|
||||
```C++
|
||||
for(auto& type_name : constructor->types) {
|
||||
type_ptr type = type_ptr(new type_base(type_name));
|
||||
full_type = type_ptr(new type_arr(type, full_type));
|
||||
}
|
||||
```
|
||||
Remember how we build the function type backwards in Part 3? We have to do the same here.
|
||||
We replace the fragment with the proper reverse iteration:
|
||||
{{< codelines "C++" "compiler/04/definition.cpp" 37 40 >}}
|
||||
|
||||
|
||||
### 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 >}}
|
||||
|
||||
Reference in New Issue
Block a user