Making A Compiler: Difference between revisions
Jump to navigation
Jump to search
(3 intermediate revisions by the same user not shown) | |||
Line 21: | Line 21: | ||
==Abstract Syntax Tree== | ==Abstract Syntax Tree== | ||
==Continuation vs Recursion== | ==Continuation vs Recursion== | ||
===Original Implementation=== | |||
From the start we had recursion where we parse expression which in turn parses an expression. | |||
<syntaxhighlight lang="c"> | |||
const char* contents = read_file(path); | |||
ParsingContext* context = parsing_context_create(); | |||
ParsingContext* context = parsing_context_create(); | |||
// Make the program node | |||
Node* program = node_allocate(); | |||
program->type = NODE_TYPE_PROGRAM; | |||
// Make the expression node | |||
Node* expression = node_allocate(); | |||
memset(expression, 0, sizeof(Node)); | |||
for (;;) { | |||
Error err = parse_expr(context, contents_it, &contents_it, expression); | |||
while ((err = lex_advance(¤t_token, &token_length, end)).type == | |||
ERROR_NONE) { | |||
... | |||
err = parse_expr(context, current_token.end, end, assigned_expr); | |||
... | |||
} | |||
// Check if we have reached the end of the file | |||
if (!(*contents_it)) | |||
break; | |||
Node* child = node_allocate(); | |||
node_copy(expression, child); | |||
node_add_child(program, child); | |||
} | |||
</syntaxhighlight> | |||
===Next Implementation=== | |||
==Typical Flow Control== | ==Typical Flow Control== | ||
*Jump goto, while, functions | *Jump goto, while, functions |
Latest revision as of 03:55, 7 October 2024
Introduction
This page is how someone went about build a compiler and is here for reference
Steps
- Write example file
- Read contents of file
- Parse Lines
- Parse Tokens in
- Decide on Node Types
- Decide what AST should look like
- Create Nodes
Parsing Context
We made a context to store
- type e.g. integers
- variables e.g. a, b
Types
This is the storing of which types would be valid in our code
Variables
This is the storing of which variable are in our code. Against each variable we store which type and which variable e.g. a : integer = 69
Things I learnt
Abstract Syntax Tree
Continuation vs Recursion
Original Implementation
From the start we had recursion where we parse expression which in turn parses an expression.
const char* contents = read_file(path);
ParsingContext* context = parsing_context_create();
ParsingContext* context = parsing_context_create();
// Make the program node
Node* program = node_allocate();
program->type = NODE_TYPE_PROGRAM;
// Make the expression node
Node* expression = node_allocate();
memset(expression, 0, sizeof(Node));
for (;;) {
Error err = parse_expr(context, contents_it, &contents_it, expression);
while ((err = lex_advance(¤t_token, &token_length, end)).type ==
ERROR_NONE) {
...
err = parse_expr(context, current_token.end, end, assigned_expr);
...
}
// Check if we have reached the end of the file
if (!(*contents_it))
break;
Node* child = node_allocate();
node_copy(expression, child);
node_add_child(program, child);
}
Next Implementation
Typical Flow Control
- Jump goto, while, functions
- Conditional (if/then/else)
- Early Exit (break, continue, skip)
- Exception handling (try/throw/catch)
- Lazy evaluation (delay/force)
- Threading (thread create,stop, yield)
- Generator (yield)