diff --git a/Makefile b/Makefile index aaa244b..d09ec66 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ CFLAGS = -std=c17 -Wall -Wextra -Wpedantic -Wconversion -pedantic -pedantic-erro CFILES = \ main.c \ + parser.c \ + checker.c \ + vm.c \ OBJECT_FILES = $(patsubst %.c,%.o,$(CFILES)) diff --git a/checker.c b/checker.c new file mode 100644 index 0000000..c1dfa96 --- /dev/null +++ b/checker.c @@ -0,0 +1 @@ +#include "parser.h" diff --git a/main.c b/main.c index 50c765e..61ce2e2 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,25 @@ +#include "parser.h" +#include #include +#include -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); +} diff --git a/parser.c b/parser.c index 89d2ede..be9a96e 100644 --- a/parser.c +++ b/parser.c @@ -1,5 +1,6 @@ #include "parser.h" #include +#include #include #include @@ -65,7 +66,8 @@ static inline TokenType match_id_to_token_type( const char* source, size_t length, struct MatchIdToTokenTypeCase cases[]) { 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; } } @@ -87,7 +89,9 @@ static inline Token lex_id_or_keyword(Lexer* lexer) { "and", TokenType_And }, { "or", TokenType_Or }, { "if", TokenType_If }, + { "else", TokenType_Else }, { "loop", TokenType_Loop }, + { "let", TokenType_Let }, { "fn", TokenType_Fn }, { "return", TokenType_Return }, { "break", TokenType_Break }, @@ -134,11 +138,23 @@ Token lexer_next(Lexer* lexer) } if (c >= '1' && c <= '9') { 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); } 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) { case '0': return lex_single_char(lexer, TokenType_Int); @@ -161,9 +177,6 @@ Token lexer_next(Lexer* lexer) case '+': return lex_single_or_double_char( lexer, TokenType_Plus, '=', TokenType_PlusEqual); - case '-': - return lex_single_or_double_char( - lexer, TokenType_Minus, '=', TokenType_MinusEqual); case '*': return lex_single_or_double_char( lexer, TokenType_Asterisk, '=', TokenType_AsteriskEqual); @@ -292,6 +305,10 @@ void ast_node_free(ASTNode* node) break; case ASTNodeType_Int: break; + case ASTNodeType_Group: + ast_node_free(node->group_value); + break; + case ASTNodeType_Statements: case ASTNodeType_Block: for (size_t i = 0; i < node->statements.length; ++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); break; case ASTNodeType_Let: - if (node->let_node.id != NULL) { - free(node->let_node.id); - } + ast_node_free(node->let_node.id); ast_node_free(node->let_node.value); break; case ASTNodeType_Break: break; case ASTNodeType_Fn: - if (node->fn_node.id != NULL) { - free(node->fn_node.id); - } + ast_node_free(node->fn_node.id); for (size_t i = 0; i < node->fn_node.params.length; ++i) { ast_node_free(node->fn_node.params.data[i]); } ast_node_vec_destroy(&node->fn_node.params); ast_node_free(node->fn_node.body); break; + case ASTNodeType_Return: + if (node->return_node.value != NULL) { + ast_node_free(node->return_node.value); + } + break; } free(node); } @@ -360,7 +378,7 @@ void parser_construct(Parser* parser, const char* text, size_t text_length) .failed = false, }; 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; } @@ -375,11 +393,379 @@ bool parser_done(const Parser* parser) return parser->current.token_type == TokenType_EOF; } -ASTNode* parser_parse(Parser* parser) { return parser_parse_expr(parser); } - -ASTNode* parser_parse_expr(Parser* parser) +ASTNode* parser_parse_statements(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) @@ -393,14 +779,17 @@ ASTNode* parser_parse_operand(Parser* parser) case TokenType_Int: return parser_parse_int(parser); case TokenType_LParen: + return parser_parse_group(parser); case TokenType_LBrace: + return parser_parse_block(parser); case TokenType_If: + return parser_parse_if(parser); case TokenType_Loop: + return parser_parse_loop(parser); default: parser->failed = true; - print_error("expected operand", pos); + print_error("parser: expected operand", pos); 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); if (parser->current.token_type != TokenType_RParen) { parser->failed = true; - print_error("parser: expected ')'", pos); + print_error("parser: expected ')'", parser->current.pos); return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 }); } parser_step(parser); - return expr; + return ast_node_new(ASTNodeType_Group, pos, + (ASTNode) { + .group_value = expr, + }); } ASTNode* parser_parse_block(Parser* parser) @@ -450,7 +842,7 @@ ASTNode* parser_parse_block(Parser* parser) } if (parser->current.token_type != TokenType_RBrace) { parser->failed = true; - print_error("parser: expected '}'", pos); + print_error("parser: expected '}'", parser->current.pos); return ast_node_new(ASTNodeType_Error, pos, (ASTNode) { 0 }); } parser_step(parser); @@ -458,6 +850,49 @@ ASTNode* parser_parse_block(Parser* parser) 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, + }, + }); +} diff --git a/parser.h b/parser.h index 955cef0..813db4a 100644 --- a/parser.h +++ b/parser.h @@ -21,7 +21,9 @@ typedef enum { TokenType_And, TokenType_Or, TokenType_If, + TokenType_Else, TokenType_Loop, + TokenType_Let, TokenType_Fn, TokenType_Return, TokenType_Break, @@ -37,6 +39,7 @@ typedef enum { TokenType_PlusEqual, TokenType_Minus, TokenType_MinusEqual, + TokenType_MinusGT, TokenType_Asterisk, TokenType_AsteriskEqual, TokenType_Equal, @@ -79,6 +82,7 @@ typedef enum { ASTNodeType_Error, ASTNodeType_Id, ASTNodeType_Int, + ASTNodeType_Group, ASTNodeType_Block, ASTNodeType_If, ASTNodeType_Loop, @@ -90,6 +94,8 @@ typedef enum { ASTNodeType_Let, ASTNodeType_Break, ASTNodeType_Fn, + ASTNodeType_Return, + ASTNodeType_Statements, } ASTNodeType; typedef struct ASTNode ASTNode; @@ -137,15 +143,15 @@ typedef struct { typedef enum { BinaryType_And, BinaryType_Or, - BinaryType_Add, - BinaryType_Subtract, - BinaryType_Multiply, BinaryType_EE, BinaryType_NE, BinaryType_LT, BinaryType_GT, BinaryType_LTE, BinaryType_GTE, + BinaryType_Add, + BinaryType_Subtract, + BinaryType_Multiply, } BinaryType; typedef struct { @@ -168,22 +174,27 @@ typedef struct { } ASTAssignNode; typedef struct { - char* id; + ASTNode* id; ASTNode* value; } ASTLetNode; typedef struct { - char* id; + ASTNode* id; ASTNodeVec params; ASTNode* body; } ASTFnNode; +typedef struct { + ASTNode* value; +} ASTReturnNode; + struct ASTNode { ASTNodeType node_type; Pos pos; union { char* id_value; int int_value; + ASTNode* group_value; ASTNodeVec statements; ASTIfNode if_node; ASTLoopNode loop_node; @@ -194,6 +205,7 @@ struct ASTNode { ASTAssignNode assign_node; ASTLetNode let_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); void parser_step(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_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_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_id(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_loop(Parser* parser); +typedef struct { + int _a; +} Checker; + +void checker_construct(Checker* checker); +void checker_(Checker* checker); + #endif diff --git a/vm.c b/vm.c new file mode 100644 index 0000000..d3561cc --- /dev/null +++ b/vm.c @@ -0,0 +1,16 @@ +#include "vm.h" +#include + +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, + }; +} diff --git a/vm.h b/vm.h new file mode 100644 index 0000000..8617b15 --- /dev/null +++ b/vm.h @@ -0,0 +1,70 @@ +#ifndef VM_H +#define VM_H + +#include +#include +#include +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