parsing done + vm
This commit is contained in:
parent
216dbf2fce
commit
afb271be68
3
Makefile
3
Makefile
@ -5,6 +5,9 @@ CFLAGS = -std=c17 -Wall -Wextra -Wpedantic -Wconversion -pedantic -pedantic-erro
|
|||||||
|
|
||||||
CFILES = \
|
CFILES = \
|
||||||
main.c \
|
main.c \
|
||||||
|
parser.c \
|
||||||
|
checker.c \
|
||||||
|
vm.c \
|
||||||
|
|
||||||
OBJECT_FILES = $(patsubst %.c,%.o,$(CFILES))
|
OBJECT_FILES = $(patsubst %.c,%.o,$(CFILES))
|
||||||
|
|
||||||
|
24
main.c
24
main.c
@ -1,3 +1,25 @@
|
|||||||
|
#include "parser.h"
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
int main(void) { printf("hello world\n"); }
|
bool lexer_debug = false;
|
||||||
|
|
||||||
|
void print_error(const char* message, Pos pos)
|
||||||
|
{
|
||||||
|
fprintf(
|
||||||
|
stderr, "\x1b[31merror\x1b[0m: %s, on line %d\n", message, pos.line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
char test_program[] = " if a == true { (1) += 2; } ";
|
||||||
|
|
||||||
|
Parser parser;
|
||||||
|
parser_construct(&parser, test_program, strlen(test_program));
|
||||||
|
|
||||||
|
ASTNode* ast = parser_parse_statements(&parser);
|
||||||
|
|
||||||
|
printf("ast = %d\n", ast->node_type);
|
||||||
|
}
|
||||||
|
481
parser.c
481
parser.c
@ -1,5 +1,6 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -65,7 +66,8 @@ static inline TokenType match_id_to_token_type(
|
|||||||
const char* source, size_t length, struct MatchIdToTokenTypeCase cases[])
|
const char* source, size_t length, struct MatchIdToTokenTypeCase cases[])
|
||||||
{
|
{
|
||||||
for (size_t i = 0; cases[i].keyword != NULL; ++i) {
|
for (size_t i = 0; cases[i].keyword != NULL; ++i) {
|
||||||
if (strncmp(source, cases[i].keyword, length) == 0) {
|
if (strlen(cases[i].keyword) <= length
|
||||||
|
&& strncmp(source, cases[i].keyword, length) == 0) {
|
||||||
return cases[i].token_type;
|
return cases[i].token_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +89,9 @@ static inline Token lex_id_or_keyword(Lexer* lexer)
|
|||||||
{ "and", TokenType_And },
|
{ "and", TokenType_And },
|
||||||
{ "or", TokenType_Or },
|
{ "or", TokenType_Or },
|
||||||
{ "if", TokenType_If },
|
{ "if", TokenType_If },
|
||||||
|
{ "else", TokenType_Else },
|
||||||
{ "loop", TokenType_Loop },
|
{ "loop", TokenType_Loop },
|
||||||
|
{ "let", TokenType_Let },
|
||||||
{ "fn", TokenType_Fn },
|
{ "fn", TokenType_Fn },
|
||||||
{ "return", TokenType_Return },
|
{ "return", TokenType_Return },
|
||||||
{ "break", TokenType_Break },
|
{ "break", TokenType_Break },
|
||||||
@ -134,11 +138,23 @@ Token lexer_next(Lexer* lexer)
|
|||||||
}
|
}
|
||||||
if (c >= '1' && c <= '9') {
|
if (c >= '1' && c <= '9') {
|
||||||
lexer_step(lexer);
|
lexer_step(lexer);
|
||||||
while (!lexer_done(lexer) && c >= '1' && c <= '9') {
|
while (!lexer_done(lexer) && lexer_current(lexer) >= '0'
|
||||||
|
&& lexer_current(lexer) <= '9') {
|
||||||
lexer_step(lexer);
|
lexer_step(lexer);
|
||||||
}
|
}
|
||||||
return lexer_token(lexer, TokenType_Int, pos);
|
return lexer_token(lexer, TokenType_Int, pos);
|
||||||
}
|
}
|
||||||
|
if (c == '-') {
|
||||||
|
lexer_step(lexer);
|
||||||
|
if (lexer_current(lexer) == '=') {
|
||||||
|
lexer_step(lexer);
|
||||||
|
return lexer_token(lexer, TokenType_MinusEqual, pos);
|
||||||
|
} else if (lexer_current(lexer) == '>') {
|
||||||
|
lexer_step(lexer);
|
||||||
|
return lexer_token(lexer, TokenType_MinusGT, pos);
|
||||||
|
}
|
||||||
|
return lexer_token(lexer, TokenType_Minus, pos);
|
||||||
|
}
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '0':
|
case '0':
|
||||||
return lex_single_char(lexer, TokenType_Int);
|
return lex_single_char(lexer, TokenType_Int);
|
||||||
@ -161,9 +177,6 @@ Token lexer_next(Lexer* lexer)
|
|||||||
case '+':
|
case '+':
|
||||||
return lex_single_or_double_char(
|
return lex_single_or_double_char(
|
||||||
lexer, TokenType_Plus, '=', TokenType_PlusEqual);
|
lexer, TokenType_Plus, '=', TokenType_PlusEqual);
|
||||||
case '-':
|
|
||||||
return lex_single_or_double_char(
|
|
||||||
lexer, TokenType_Minus, '=', TokenType_MinusEqual);
|
|
||||||
case '*':
|
case '*':
|
||||||
return lex_single_or_double_char(
|
return lex_single_or_double_char(
|
||||||
lexer, TokenType_Asterisk, '=', TokenType_AsteriskEqual);
|
lexer, TokenType_Asterisk, '=', TokenType_AsteriskEqual);
|
||||||
@ -292,6 +305,10 @@ void ast_node_free(ASTNode* node)
|
|||||||
break;
|
break;
|
||||||
case ASTNodeType_Int:
|
case ASTNodeType_Int:
|
||||||
break;
|
break;
|
||||||
|
case ASTNodeType_Group:
|
||||||
|
ast_node_free(node->group_value);
|
||||||
|
break;
|
||||||
|
case ASTNodeType_Statements:
|
||||||
case ASTNodeType_Block:
|
case ASTNodeType_Block:
|
||||||
for (size_t i = 0; i < node->statements.length; ++i) {
|
for (size_t i = 0; i < node->statements.length; ++i) {
|
||||||
ast_node_free(node->statements.data[i]);
|
ast_node_free(node->statements.data[i]);
|
||||||
@ -329,23 +346,24 @@ void ast_node_free(ASTNode* node)
|
|||||||
ast_node_free(node->assign_node.value);
|
ast_node_free(node->assign_node.value);
|
||||||
break;
|
break;
|
||||||
case ASTNodeType_Let:
|
case ASTNodeType_Let:
|
||||||
if (node->let_node.id != NULL) {
|
ast_node_free(node->let_node.id);
|
||||||
free(node->let_node.id);
|
|
||||||
}
|
|
||||||
ast_node_free(node->let_node.value);
|
ast_node_free(node->let_node.value);
|
||||||
break;
|
break;
|
||||||
case ASTNodeType_Break:
|
case ASTNodeType_Break:
|
||||||
break;
|
break;
|
||||||
case ASTNodeType_Fn:
|
case ASTNodeType_Fn:
|
||||||
if (node->fn_node.id != NULL) {
|
ast_node_free(node->fn_node.id);
|
||||||
free(node->fn_node.id);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < node->fn_node.params.length; ++i) {
|
for (size_t i = 0; i < node->fn_node.params.length; ++i) {
|
||||||
ast_node_free(node->fn_node.params.data[i]);
|
ast_node_free(node->fn_node.params.data[i]);
|
||||||
}
|
}
|
||||||
ast_node_vec_destroy(&node->fn_node.params);
|
ast_node_vec_destroy(&node->fn_node.params);
|
||||||
ast_node_free(node->fn_node.body);
|
ast_node_free(node->fn_node.body);
|
||||||
break;
|
break;
|
||||||
|
case ASTNodeType_Return:
|
||||||
|
if (node->return_node.value != NULL) {
|
||||||
|
ast_node_free(node->return_node.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
free(node);
|
free(node);
|
||||||
}
|
}
|
||||||
@ -360,7 +378,7 @@ void parser_construct(Parser* parser, const char* text, size_t text_length)
|
|||||||
.failed = false,
|
.failed = false,
|
||||||
};
|
};
|
||||||
lexer_construct(&parser->lexer, text, text_length);
|
lexer_construct(&parser->lexer, text, text_length);
|
||||||
parser->current = lexer_next(&parser->lexer);
|
parser_step(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parser_failed(const Parser* parser) { return parser->failed; }
|
bool parser_failed(const Parser* parser) { return parser->failed; }
|
||||||
@ -375,11 +393,379 @@ bool parser_done(const Parser* parser)
|
|||||||
return parser->current.token_type == TokenType_EOF;
|
return parser->current.token_type == TokenType_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode* parser_parse(Parser* parser) { return parser_parse_expr(parser); }
|
ASTNode* parser_parse_statements(Parser* parser)
|
||||||
|
|
||||||
ASTNode* parser_parse_expr(Parser* parser)
|
|
||||||
{
|
{
|
||||||
return parser_parse_operand(parser);
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNodeVec statements;
|
||||||
|
ast_node_vec_construct(&statements);
|
||||||
|
while (!parser_done(parser)) {
|
||||||
|
ASTNode* statement = parser_parse_statement(parser);
|
||||||
|
ast_node_vec_push(&statements, statement);
|
||||||
|
}
|
||||||
|
return ast_node_new(
|
||||||
|
ASTNodeType_Statements, pos, (ASTNode) { .statements = statements });
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_statement(Parser* parser)
|
||||||
|
{
|
||||||
|
if (parser->current.token_type == TokenType_Fn) {
|
||||||
|
return parser_parse_fn(parser);
|
||||||
|
} else if (parser->current.token_type == TokenType_If) {
|
||||||
|
return parser_parse_if(parser);
|
||||||
|
} else if (parser->current.token_type == TokenType_Loop) {
|
||||||
|
return parser_parse_loop(parser);
|
||||||
|
} else {
|
||||||
|
ASTNode* statement = parser_parse_single_line_statement(parser);
|
||||||
|
if (parser->current.token_type != TokenType_Semicolon) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected ';'", parser->current.pos);
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_fn(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type != TokenType_Id) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected 'id'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ASTNode* id = parser_parse_id(parser);
|
||||||
|
if (parser->current.token_type != TokenType_LParen) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected '('", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
ASTNodeVec params;
|
||||||
|
ast_node_vec_construct(¶ms);
|
||||||
|
if (!parser_done(parser)
|
||||||
|
&& parser->current.token_type != TokenType_RParen) {
|
||||||
|
if (parser->current.token_type != TokenType_Id) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected 'id'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ast_node_vec_push(¶ms, parser_parse_id(parser));
|
||||||
|
while (parser->current.token_type == TokenType_Comma) {
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type == TokenType_RParen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (parser->current.token_type != TokenType_Id) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected 'id'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ast_node_vec_push(¶ms, parser_parse_id(parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parser->current.token_type != TokenType_RParen) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected ')'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type != TokenType_LBrace) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected '{'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ASTNode* body = parser_parse_block(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Fn, pos, (ASTNode) {
|
||||||
|
.fn_node = (ASTFnNode) {
|
||||||
|
.id = id,
|
||||||
|
.params = params,
|
||||||
|
.body = body,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_single_line_statement(Parser* parser)
|
||||||
|
{
|
||||||
|
if (parser->current.token_type == TokenType_Let) {
|
||||||
|
return parser_parse_let(parser);
|
||||||
|
} else if (parser->current.token_type == TokenType_Return) {
|
||||||
|
return parser_parse_return(parser);
|
||||||
|
} else if (parser->current.token_type == TokenType_Break) {
|
||||||
|
return parser_parse_break(parser);
|
||||||
|
} else {
|
||||||
|
return parser_parse_assign(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_let(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type != TokenType_Id) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected 'id'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ASTNode* id = parser_parse_id(parser);
|
||||||
|
if (parser->current.token_type != TokenType_Equal) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected '='", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
ASTNode* value = parser_parse_expr(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Let, pos, (ASTNode) {
|
||||||
|
.let_node = (ASTLetNode) {
|
||||||
|
.id = id,
|
||||||
|
.value = value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_return(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
parser_step(parser);
|
||||||
|
ASTNode* value = NULL;
|
||||||
|
if (parser->current.token_type != TokenType_Semicolon) {
|
||||||
|
value = parser_parse_expr(parser);
|
||||||
|
}
|
||||||
|
return ast_node_new(ASTNodeType_Return, pos, (ASTNode) {
|
||||||
|
.return_node = (ASTReturnNode) {
|
||||||
|
.value = value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_break(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
parser_step(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Return, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_assign(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* subject = parser_parse_expr(parser);
|
||||||
|
int assign_type = -1;
|
||||||
|
if (parser->current.token_type == TokenType_Equal) {
|
||||||
|
assign_type = AssignType_Assign;
|
||||||
|
} else if (parser->current.token_type == TokenType_PlusEqual) {
|
||||||
|
assign_type = AssignType_Add;
|
||||||
|
} else if (parser->current.token_type == TokenType_MinusEqual) {
|
||||||
|
assign_type = AssignType_Subtract;
|
||||||
|
} else if (parser->current.token_type == TokenType_AsteriskEqual) {
|
||||||
|
assign_type = AssignType_Multiply;
|
||||||
|
}
|
||||||
|
if (assign_type == -1) {
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Assign, pos, (ASTNode) {
|
||||||
|
.assign_node = (ASTAssignNode) {
|
||||||
|
.assign_type = (AssignType)assign_type,
|
||||||
|
.subject = subject,
|
||||||
|
.value = parser_parse_expr(parser),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_expr(Parser* parser) { return parser_parse_or(parser); }
|
||||||
|
|
||||||
|
static inline ASTNode* binary_node(
|
||||||
|
Pos pos, BinaryType binary_type, ASTNode* left, ASTNode* right)
|
||||||
|
{
|
||||||
|
return ast_node_new(ASTNodeType_Binary, pos, (ASTNode) {
|
||||||
|
.binary_node = (ASTBinaryNode) {
|
||||||
|
.binary_type = binary_type,
|
||||||
|
.left = left,
|
||||||
|
.right = right,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_or(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* left = parser_parse_and(parser);
|
||||||
|
while (parser->current.token_type == TokenType_Or) {
|
||||||
|
parser_step(parser);
|
||||||
|
left = binary_node(pos, BinaryType_Or, left, parser_parse_and(parser));
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_and(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* left = parser_parse_equality(parser);
|
||||||
|
while (parser->current.token_type == TokenType_And) {
|
||||||
|
parser_step(parser);
|
||||||
|
left = binary_node(
|
||||||
|
pos, BinaryType_And, left, parser_parse_equality(parser));
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_equality(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* left = parser_parse_comparison(parser);
|
||||||
|
if (parser->current.token_type == TokenType_EqualEqual) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_EE, left, parser_parse_comparison(parser));
|
||||||
|
} else if (parser->current.token_type == TokenType_ExclamationEqual) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_NE, left, parser_parse_comparison(parser));
|
||||||
|
} else {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_comparison(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* left = parser_parse_term(parser);
|
||||||
|
while (!parser_done(parser)) {
|
||||||
|
if (parser->current.token_type == TokenType_LT) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_LT, left, parser_parse_term(parser));
|
||||||
|
} else if (parser->current.token_type == TokenType_LTEqual) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_LTE, left, parser_parse_term(parser));
|
||||||
|
} else if (parser->current.token_type == TokenType_GT) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_GT, left, parser_parse_term(parser));
|
||||||
|
} else if (parser->current.token_type == TokenType_GTEqual) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_GTE, left, parser_parse_term(parser));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_term(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* left = parser_parse_factor(parser);
|
||||||
|
while (!parser_done(parser)) {
|
||||||
|
if (parser->current.token_type == TokenType_Plus) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_Add, left, parser_parse_factor(parser));
|
||||||
|
} else if (parser->current.token_type == TokenType_Minus) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_Subtract, left, parser_parse_factor(parser));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_factor(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* left = parser_parse_unary(parser);
|
||||||
|
while (!parser_done(parser)) {
|
||||||
|
if (parser->current.token_type == TokenType_Asterisk) {
|
||||||
|
parser_step(parser);
|
||||||
|
return binary_node(
|
||||||
|
pos, BinaryType_Multiply, left, parser_parse_unary(parser));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_unary(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
if (parser->current.token_type == TokenType_Not) {
|
||||||
|
parser_step(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Unary, pos, (ASTNode) {
|
||||||
|
.unary_node = (ASTUnaryNode) {
|
||||||
|
.unary_type = UnaryType_Not,
|
||||||
|
.subject = parser_parse_unary(parser),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (parser->current.token_type == TokenType_Minus) {
|
||||||
|
parser_step(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Unary, pos, (ASTNode) {
|
||||||
|
.unary_node = (ASTUnaryNode) {
|
||||||
|
.unary_type = UnaryType_Negate,
|
||||||
|
.subject = parser_parse_unary(parser),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return parser_parse_index_call(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTNode* parser_parse_index_call(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
ASTNode* subject = parser_parse_operand(parser);
|
||||||
|
while (!parser_done(parser)) {
|
||||||
|
if (parser->current.token_type == TokenType_LParen) {
|
||||||
|
parser_step(parser);
|
||||||
|
ASTNodeVec args;
|
||||||
|
ast_node_vec_construct(&args);
|
||||||
|
if (!parser_done(parser)
|
||||||
|
&& parser->current.token_type != TokenType_RParen) {
|
||||||
|
ast_node_vec_push(&args, parser_parse_expr(parser));
|
||||||
|
while (parser->current.token_type == TokenType_Comma) {
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type == TokenType_RParen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ast_node_vec_push(&args, parser_parse_expr(parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parser->current.token_type != TokenType_RParen) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected ')'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
subject = ast_node_new(ASTNodeType_Call, pos, (ASTNode) {
|
||||||
|
.call_node = (ASTCallNode) {
|
||||||
|
.subject = subject,
|
||||||
|
.args = args,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (parser->current.token_type == TokenType_LBracket) {
|
||||||
|
parser_step(parser);
|
||||||
|
ASTNode* value = parser_parse_expr(parser);
|
||||||
|
if (parser->current.token_type != TokenType_RBracket) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected ']'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
parser_step(parser);
|
||||||
|
subject = ast_node_new(ASTNodeType_Index, pos, (ASTNode) {
|
||||||
|
.index_node = (ASTIndexNode) {
|
||||||
|
.subject = subject,
|
||||||
|
.value = value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode* parser_parse_operand(Parser* parser)
|
ASTNode* parser_parse_operand(Parser* parser)
|
||||||
@ -393,14 +779,17 @@ ASTNode* parser_parse_operand(Parser* parser)
|
|||||||
case TokenType_Int:
|
case TokenType_Int:
|
||||||
return parser_parse_int(parser);
|
return parser_parse_int(parser);
|
||||||
case TokenType_LParen:
|
case TokenType_LParen:
|
||||||
|
return parser_parse_group(parser);
|
||||||
case TokenType_LBrace:
|
case TokenType_LBrace:
|
||||||
|
return parser_parse_block(parser);
|
||||||
case TokenType_If:
|
case TokenType_If:
|
||||||
|
return parser_parse_if(parser);
|
||||||
case TokenType_Loop:
|
case TokenType_Loop:
|
||||||
|
return parser_parse_loop(parser);
|
||||||
default:
|
default:
|
||||||
parser->failed = true;
|
parser->failed = true;
|
||||||
print_error("expected operand", pos);
|
print_error("parser: expected operand", pos);
|
||||||
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,11 +819,14 @@ ASTNode* parser_parse_group(Parser* parser)
|
|||||||
ASTNode* expr = parser_parse_expr(parser);
|
ASTNode* expr = parser_parse_expr(parser);
|
||||||
if (parser->current.token_type != TokenType_RParen) {
|
if (parser->current.token_type != TokenType_RParen) {
|
||||||
parser->failed = true;
|
parser->failed = true;
|
||||||
print_error("parser: expected ')'", pos);
|
print_error("parser: expected ')'", parser->current.pos);
|
||||||
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
}
|
}
|
||||||
parser_step(parser);
|
parser_step(parser);
|
||||||
return expr;
|
return ast_node_new(ASTNodeType_Group, pos,
|
||||||
|
(ASTNode) {
|
||||||
|
.group_value = expr,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode* parser_parse_block(Parser* parser)
|
ASTNode* parser_parse_block(Parser* parser)
|
||||||
@ -450,7 +842,7 @@ ASTNode* parser_parse_block(Parser* parser)
|
|||||||
}
|
}
|
||||||
if (parser->current.token_type != TokenType_RBrace) {
|
if (parser->current.token_type != TokenType_RBrace) {
|
||||||
parser->failed = true;
|
parser->failed = true;
|
||||||
print_error("parser: expected '}'", pos);
|
print_error("parser: expected '}'", parser->current.pos);
|
||||||
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
}
|
}
|
||||||
parser_step(parser);
|
parser_step(parser);
|
||||||
@ -458,6 +850,49 @@ ASTNode* parser_parse_block(Parser* parser)
|
|||||||
ASTNodeType_Block, pos, (ASTNode) { .statements = statements });
|
ASTNodeType_Block, pos, (ASTNode) { .statements = statements });
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTNode* parser_parse_if(Parser* parser);
|
ASTNode* parser_parse_if(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
parser_step(parser);
|
||||||
|
ASTNode* condition = parser_parse_expr(parser);
|
||||||
|
if (parser->current.token_type != TokenType_LBrace) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected '{'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ASTNode* truthy = parser_parse_block(parser);
|
||||||
|
ASTNode* falsy = NULL;
|
||||||
|
if (parser->current.token_type == TokenType_Else) {
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type != TokenType_LBrace) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected '{'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
falsy = parser_parse_block(parser);
|
||||||
|
}
|
||||||
|
return ast_node_new(ASTNodeType_If, pos, (ASTNode) {
|
||||||
|
.if_node = (ASTIfNode) {
|
||||||
|
.condition = condition,
|
||||||
|
.truthy = truthy,
|
||||||
|
.falsy = falsy,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ASTNode* parser_parse_loop(Parser* parser);
|
ASTNode* parser_parse_loop(Parser* parser)
|
||||||
|
{
|
||||||
|
Pos pos = parser->current.pos;
|
||||||
|
parser_step(parser);
|
||||||
|
if (parser->current.token_type != TokenType_RBrace) {
|
||||||
|
parser->failed = true;
|
||||||
|
print_error("parser: expected '}'", parser->current.pos);
|
||||||
|
return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 });
|
||||||
|
}
|
||||||
|
ASTNode* body = parser_parse_block(parser);
|
||||||
|
return ast_node_new(ASTNodeType_Loop, pos, (ASTNode) {
|
||||||
|
.loop_node = (ASTLoopNode) {
|
||||||
|
.body = body,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
45
parser.h
45
parser.h
@ -21,7 +21,9 @@ typedef enum {
|
|||||||
TokenType_And,
|
TokenType_And,
|
||||||
TokenType_Or,
|
TokenType_Or,
|
||||||
TokenType_If,
|
TokenType_If,
|
||||||
|
TokenType_Else,
|
||||||
TokenType_Loop,
|
TokenType_Loop,
|
||||||
|
TokenType_Let,
|
||||||
TokenType_Fn,
|
TokenType_Fn,
|
||||||
TokenType_Return,
|
TokenType_Return,
|
||||||
TokenType_Break,
|
TokenType_Break,
|
||||||
@ -37,6 +39,7 @@ typedef enum {
|
|||||||
TokenType_PlusEqual,
|
TokenType_PlusEqual,
|
||||||
TokenType_Minus,
|
TokenType_Minus,
|
||||||
TokenType_MinusEqual,
|
TokenType_MinusEqual,
|
||||||
|
TokenType_MinusGT,
|
||||||
TokenType_Asterisk,
|
TokenType_Asterisk,
|
||||||
TokenType_AsteriskEqual,
|
TokenType_AsteriskEqual,
|
||||||
TokenType_Equal,
|
TokenType_Equal,
|
||||||
@ -79,6 +82,7 @@ typedef enum {
|
|||||||
ASTNodeType_Error,
|
ASTNodeType_Error,
|
||||||
ASTNodeType_Id,
|
ASTNodeType_Id,
|
||||||
ASTNodeType_Int,
|
ASTNodeType_Int,
|
||||||
|
ASTNodeType_Group,
|
||||||
ASTNodeType_Block,
|
ASTNodeType_Block,
|
||||||
ASTNodeType_If,
|
ASTNodeType_If,
|
||||||
ASTNodeType_Loop,
|
ASTNodeType_Loop,
|
||||||
@ -90,6 +94,8 @@ typedef enum {
|
|||||||
ASTNodeType_Let,
|
ASTNodeType_Let,
|
||||||
ASTNodeType_Break,
|
ASTNodeType_Break,
|
||||||
ASTNodeType_Fn,
|
ASTNodeType_Fn,
|
||||||
|
ASTNodeType_Return,
|
||||||
|
ASTNodeType_Statements,
|
||||||
} ASTNodeType;
|
} ASTNodeType;
|
||||||
|
|
||||||
typedef struct ASTNode ASTNode;
|
typedef struct ASTNode ASTNode;
|
||||||
@ -137,15 +143,15 @@ typedef struct {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
BinaryType_And,
|
BinaryType_And,
|
||||||
BinaryType_Or,
|
BinaryType_Or,
|
||||||
BinaryType_Add,
|
|
||||||
BinaryType_Subtract,
|
|
||||||
BinaryType_Multiply,
|
|
||||||
BinaryType_EE,
|
BinaryType_EE,
|
||||||
BinaryType_NE,
|
BinaryType_NE,
|
||||||
BinaryType_LT,
|
BinaryType_LT,
|
||||||
BinaryType_GT,
|
BinaryType_GT,
|
||||||
BinaryType_LTE,
|
BinaryType_LTE,
|
||||||
BinaryType_GTE,
|
BinaryType_GTE,
|
||||||
|
BinaryType_Add,
|
||||||
|
BinaryType_Subtract,
|
||||||
|
BinaryType_Multiply,
|
||||||
} BinaryType;
|
} BinaryType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -168,22 +174,27 @@ typedef struct {
|
|||||||
} ASTAssignNode;
|
} ASTAssignNode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* id;
|
ASTNode* id;
|
||||||
ASTNode* value;
|
ASTNode* value;
|
||||||
} ASTLetNode;
|
} ASTLetNode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* id;
|
ASTNode* id;
|
||||||
ASTNodeVec params;
|
ASTNodeVec params;
|
||||||
ASTNode* body;
|
ASTNode* body;
|
||||||
} ASTFnNode;
|
} ASTFnNode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ASTNode* value;
|
||||||
|
} ASTReturnNode;
|
||||||
|
|
||||||
struct ASTNode {
|
struct ASTNode {
|
||||||
ASTNodeType node_type;
|
ASTNodeType node_type;
|
||||||
Pos pos;
|
Pos pos;
|
||||||
union {
|
union {
|
||||||
char* id_value;
|
char* id_value;
|
||||||
int int_value;
|
int int_value;
|
||||||
|
ASTNode* group_value;
|
||||||
ASTNodeVec statements;
|
ASTNodeVec statements;
|
||||||
ASTIfNode if_node;
|
ASTIfNode if_node;
|
||||||
ASTLoopNode loop_node;
|
ASTLoopNode loop_node;
|
||||||
@ -194,6 +205,7 @@ struct ASTNode {
|
|||||||
ASTAssignNode assign_node;
|
ASTAssignNode assign_node;
|
||||||
ASTLetNode let_node;
|
ASTLetNode let_node;
|
||||||
ASTFnNode fn_node;
|
ASTFnNode fn_node;
|
||||||
|
ASTReturnNode return_node;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -212,9 +224,23 @@ void parser_construct(Parser* parser, const char* text, size_t text_length);
|
|||||||
bool parser_failed(const Parser* parser);
|
bool parser_failed(const Parser* parser);
|
||||||
void parser_step(Parser* parser);
|
void parser_step(Parser* parser);
|
||||||
bool parser_done(const Parser* parser);
|
bool parser_done(const Parser* parser);
|
||||||
ASTNode* parser_parse(Parser* parser);
|
ASTNode* parser_parse_statements(Parser* parser);
|
||||||
ASTNode* parser_parse_statement(Parser* parser);
|
ASTNode* parser_parse_statement(Parser* parser);
|
||||||
|
ASTNode* parser_parse_fn(Parser* parser);
|
||||||
|
ASTNode* parser_parse_single_line_statement(Parser* parser);
|
||||||
|
ASTNode* parser_parse_let(Parser* parser);
|
||||||
|
ASTNode* parser_parse_return(Parser* parser);
|
||||||
|
ASTNode* parser_parse_break(Parser* parser);
|
||||||
|
ASTNode* parser_parse_assign(Parser* parser);
|
||||||
ASTNode* parser_parse_expr(Parser* parser);
|
ASTNode* parser_parse_expr(Parser* parser);
|
||||||
|
ASTNode* parser_parse_or(Parser* parser);
|
||||||
|
ASTNode* parser_parse_and(Parser* parser);
|
||||||
|
ASTNode* parser_parse_equality(Parser* parser);
|
||||||
|
ASTNode* parser_parse_comparison(Parser* parser);
|
||||||
|
ASTNode* parser_parse_term(Parser* parser);
|
||||||
|
ASTNode* parser_parse_factor(Parser* parser);
|
||||||
|
ASTNode* parser_parse_unary(Parser* parser);
|
||||||
|
ASTNode* parser_parse_index_call(Parser* parser);
|
||||||
ASTNode* parser_parse_operand(Parser* parser);
|
ASTNode* parser_parse_operand(Parser* parser);
|
||||||
ASTNode* parser_parse_id(Parser* parser);
|
ASTNode* parser_parse_id(Parser* parser);
|
||||||
ASTNode* parser_parse_int(Parser* parser);
|
ASTNode* parser_parse_int(Parser* parser);
|
||||||
@ -223,4 +249,11 @@ ASTNode* parser_parse_block(Parser* parser);
|
|||||||
ASTNode* parser_parse_if(Parser* parser);
|
ASTNode* parser_parse_if(Parser* parser);
|
||||||
ASTNode* parser_parse_loop(Parser* parser);
|
ASTNode* parser_parse_loop(Parser* parser);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int _a;
|
||||||
|
} Checker;
|
||||||
|
|
||||||
|
void checker_construct(Checker* checker);
|
||||||
|
void checker_(Checker* checker);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
16
vm.c
Normal file
16
vm.c
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include "vm.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void vm_construct(
|
||||||
|
VM* vm, const Op* program, size_t program_size, size_t stack_size)
|
||||||
|
{
|
||||||
|
*vm = (VM) {
|
||||||
|
.program = program,
|
||||||
|
.program_size = program_size,
|
||||||
|
.pc = 0,
|
||||||
|
.stack = malloc(sizeof(Value) * stack_size),
|
||||||
|
.stack_size = stack_size,
|
||||||
|
.sp = 0,
|
||||||
|
.bp = 0,
|
||||||
|
};
|
||||||
|
}
|
70
vm.h
Normal file
70
vm.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef VM_H
|
||||||
|
#define VM_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef enum {
|
||||||
|
OpType_Nop,
|
||||||
|
OpType_PushNull,
|
||||||
|
OpType_PushInt,
|
||||||
|
OpType_PushBool,
|
||||||
|
OpType_PushPtr,
|
||||||
|
OpType_Pop,
|
||||||
|
OpType_LoadLocal,
|
||||||
|
OpType_StoreLocal,
|
||||||
|
OpType_Jump,
|
||||||
|
OpType_JumpIf,
|
||||||
|
OpType_Load,
|
||||||
|
OpType_Store,
|
||||||
|
OpType_Call,
|
||||||
|
OpType_Return,
|
||||||
|
OpType_And,
|
||||||
|
OpType_Or,
|
||||||
|
OpType_EE,
|
||||||
|
OpType_NE,
|
||||||
|
OpType_LT,
|
||||||
|
OpType_GT,
|
||||||
|
OpType_LTE,
|
||||||
|
OpType_GTE,
|
||||||
|
OpType_Add,
|
||||||
|
OpType_Subtract,
|
||||||
|
OpType_Multiply,
|
||||||
|
OpType_Not,
|
||||||
|
OpType_Negate,
|
||||||
|
} OpType;
|
||||||
|
|
||||||
|
typedef uint32_t Op;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ValueType_Null,
|
||||||
|
ValueType_Int,
|
||||||
|
ValueType_Bool,
|
||||||
|
ValueType_Ptr,
|
||||||
|
} ValueType;
|
||||||
|
|
||||||
|
typedef struct Value Value;
|
||||||
|
|
||||||
|
struct Value {
|
||||||
|
ValueType type;
|
||||||
|
union {
|
||||||
|
int int_value;
|
||||||
|
bool bool_value;
|
||||||
|
void* ptr_value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const Op* program;
|
||||||
|
size_t program_size;
|
||||||
|
size_t pc;
|
||||||
|
Value* stack;
|
||||||
|
size_t stack_size;
|
||||||
|
size_t sp;
|
||||||
|
size_t bp;
|
||||||
|
} VM;
|
||||||
|
|
||||||
|
void vm_construct(
|
||||||
|
VM* vm, const Op* program, size_t program_size, size_t stack_size);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user