blog-static/content/blog/07_compiler_runtime.md

45 lines
1.7 KiB
Markdown
Raw Normal View History

2019-10-15 11:13:13 -07:00
---
title: Compiling a Functional Language Using C++, Part 7 - Runtime
date: 2019-08-06T14:26:38-07:00
draft: true
tags: ["C and C++", "Functional Languages", "Compilers"]
---
Wikipedia has the following definition for a __runtime__:
> A [runtime] primarily implements portions of an execution model.
We know what our execution model is! We talked about it in Part 5 - it's the
lazy graph reduction we've been talking about. Creating and manipulating
graph nodes is slightly above hardware level, and all programs in our
functional language will rely on such manipulation (it's how they run!). Furthermore,
most G-machine instructions are also above hardware level (especially unwind!).
Push and Slide and other instructions are pretty complex instructions.
Most computers aren't stack machines. We'll have to implement
our own stack, and whenever a graph-building function will want to modify
the stack, it will have to call library routines for our stack implementation:
```C
void stack_push(struct stack_s* s, struct node_s* n);
struct node_s* stack_slide(struct stack_s* s, size_t c);
/* other stack operation */
```
Furthermore, we observe that Unwind does a lot of the heavy lifting in our
G-machine definition. After we build the graph,
Unwind is what picks it apart and performs function calls. Furthermore,
Unwind pushes Unwind back on the stack: once you've hit it,
you're continuing to Unwind until you reach a function call. This
effectively means we can implement Unwind as a loop:
```C
while(1) {
// Check for Unwind's first rule
// Check for Unwind's second rule
// ...
}
```
In this implementation, Unwind is in charge. We won't need to insert
the Unwind operations at the end of our generated functions.