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 = \
|
||||
main.c \
|
||||
parser.c \
|
||||
checker.c \
|
||||
vm.c \
|
||||
|
||||
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 <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 <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.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[])
|
||||
{
|
||||
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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
45
parser.h
45
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
|
||||
|
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