diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-03-03 13:18:08 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-25 14:36:46 +0200 |
commit | b3b0c807a75c4f854495b547d8e00a598979cbf6 (patch) | |
tree | e42017c2f5b87a939d103f48d5f90dd93193ebcc | |
parent | 4c5ffb35d50d514e3df4788e7cf38245c0127883 (diff) |
Add arithmetic (binop) parsing
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | include/ast.h | 14 | ||||
-rw-r--r-- | include/binop_type.h | 12 | ||||
-rw-r--r-- | include/tokenizer.h | 7 | ||||
-rw-r--r-- | src/ast.c | 7 | ||||
-rw-r--r-- | src/parser.c | 115 | ||||
-rw-r--r-- | src/tokenizer.c | 42 | ||||
-rw-r--r-- | tests/main.amal | 4 |
8 files changed, 189 insertions, 13 deletions
@@ -1,2 +1,3 @@ .vscode/ +.gdb_history amalgam diff --git a/include/ast.h b/include/ast.h index fb0f275..05bb6ee 100644 --- a/include/ast.h +++ b/include/ast.h @@ -5,6 +5,7 @@ #include "std/buffer.h" #include "std/misc.h" #include "std/scoped_allocator.h" +#include "binop_type.h" typedef struct FunctionDecl FunctionDecl; typedef struct FunctionCall FunctionCall; @@ -13,6 +14,7 @@ typedef struct Import Import; typedef struct String String; typedef struct Variable Variable; typedef struct Number Number; +typedef struct Binop Binop; typedef union { FunctionDecl *func_decl; @@ -22,6 +24,7 @@ typedef union { String *string; Number *number; Variable *variable; + Binop *binop; } AstValue; typedef enum { @@ -32,7 +35,8 @@ typedef enum { AST_IMPORT, AST_STRING, AST_NUMBER, - AST_VARIABLE + AST_VARIABLE, + AST_BINOP } AstType; typedef struct { @@ -52,6 +56,7 @@ struct FunctionCall { struct LhsExpr { int isConst; + BufferView type_name; BufferView var_name; Ast rhs_expr; }; @@ -76,6 +81,12 @@ struct Variable { BufferView name; }; +struct Binop { + Ast lhs; + Ast rhs; + BinopType type; +}; + Ast ast_none(); CHECK_RESULT int funcdecl_init(FunctionDecl *self, ScopedAllocator *allocator); @@ -85,5 +96,6 @@ void lhsexpr_init(LhsExpr *self, int isConst, BufferView var_name); void import_init(Import *self, BufferView path); CHECK_RESULT int string_init(String *self, BufferView str); void number_init(Number *self, i64 value, bool is_integer); +void binop_init(Binop *self); #endif diff --git a/include/binop_type.h b/include/binop_type.h new file mode 100644 index 0000000..d04f9d7 --- /dev/null +++ b/include/binop_type.h @@ -0,0 +1,12 @@ +#ifndef AMALGAM_BINOP_TYPE_H +#define AMALGAM_BINOP_TYPE_H + +typedef enum { + BINOP_ADD, + BINOP_SUB, + BINOP_MUL, + BINOP_DIV, + BINOP_DOT +} BinopType; + +#endif
\ No newline at end of file diff --git a/include/tokenizer.h b/include/tokenizer.h index c58917f..21e93ee 100644 --- a/include/tokenizer.h +++ b/include/tokenizer.h @@ -3,6 +3,7 @@ #include "std/buffer_view.h" #include "std/misc.h" +#include "binop_type.h" #define TOKENIZER_OK 0 /* General error */ @@ -25,8 +26,9 @@ typedef enum { TOK_CLOSING_BRACE, TOK_IMPORT, TOK_NUMBER, - TOK_DOT, - TOK_SEMICOLON + TOK_SEMICOLON, + TOK_COLON, + TOK_BINOP } Token; typedef struct { @@ -47,6 +49,7 @@ typedef struct { BufferView string; i64 integer; f64 floating; + BinopType binop_type; } value; bool number_is_integer; } Tokenizer; @@ -24,6 +24,7 @@ int funccall_init(FunctionCall *self, BufferView name, ScopedAllocator *allocato void lhsexpr_init(LhsExpr *self, int isConst, BufferView var_name) { self->isConst = isConst; + self->type_name = create_buffer_view_null(); self->var_name = var_name; self->rhs_expr = ast_none(); } @@ -41,4 +42,10 @@ int string_init(String *self, BufferView str) { void number_init(Number *self, i64 value, bool is_integer) { self->value.integer = value; self->is_integer = is_integer; +} + +void binop_init(Binop *self) { + self->lhs = ast_none(); + self->rhs = ast_none(); + self->type = BINOP_ADD; }
\ No newline at end of file diff --git a/src/parser.c b/src/parser.c index 6ea8d1d..52c5bfe 100644 --- a/src/parser.c +++ b/src/parser.c @@ -70,7 +70,7 @@ static CHECK_RESULT int parser_parse_body_loop(Parser *self, Buffer *body_list, } /* -LHS = 'const'|'var' IDENTIFIER +LHS = 'const'|'var' TOK_IDENTIFIER */ static CHECK_RESULT int parser_parse_lhs(Parser *self, LhsExpr **result, bool *assignment) { bool isConst; @@ -92,6 +92,12 @@ static CHECK_RESULT int parser_parse_lhs(Parser *self, LhsExpr **result, bool *a return_if_error(scoped_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)result)); lhsexpr_init(*result, isConst, var_name); + return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COLON, &match)); + if(match) { + return_if_error(tokenizer_accept(&self->tokenizer, TOK_IDENTIFIER)); + (*result)->type_name = self->tokenizer.value.identifier; + } + return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_EQUALS, &match)); if(match) { *assignment = bool_true; @@ -165,7 +171,7 @@ static CHECK_RESULT int parser_parse_function_args(Parser *self, FunctionCall *f } /* -VARIABLE = IDENTIFIER +VARIABLE = TOK_IDENTIFIER FUNC_CALL_OR_VARIABLE = VARIABLE '(' FUNC_ARGS ')' */ static CHECK_RESULT int parser_parse_function_call_or_variable(Parser *self, Ast *expr) { @@ -227,10 +233,11 @@ static CHECK_RESULT int parser_parse_number(Parser *self, Ast *rhs_expr) { } /* -RHS = STRING | NUMBER | FUNC_CALL_OR_VARIABLE +RHS_S = STRING | NUMBER | FUNC_CALL_OR_VARIABLE */ -static CHECK_RESULT int parser_parse_rhs(Parser *self, Ast *rhs_expr) { +static CHECK_RESULT int parser_parse_rhs_single_expr(Parser *self, Ast *rhs_expr) { bool match; + *rhs_expr = ast_none(); return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_STRING, &match)); if(match) { @@ -254,6 +261,95 @@ static CHECK_RESULT int parser_parse_rhs(Parser *self, Ast *rhs_expr) { return PARSER_UNEXPECTED_TOKEN; } +static CHECK_RESULT int parser_parse_rhs_binop(Parser *self, Ast *expr); + +/* +RHS_BINOP_PAREN = '(' RHS_BINOP ')' (TOK_BINOP RHS_BINOP) +*/ +static CHECK_RESULT int parser_parse_rhs_binop_paren(Parser *self, bool *match, Ast *expr) { + bool binop_match; + Ast lhs; + Ast rhs; + BinopType binop_type; + + return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_OPEN_PAREN, match)); + if(!*match) + return PARSER_OK; + + return_if_error(parser_parse_rhs_binop(self, &lhs)); + return_if_error(tokenizer_accept(&self->tokenizer, TOK_CLOSING_PAREN)); + + return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_BINOP, &binop_match)); + if(!binop_match) { + *expr = lhs; + return PARSER_OK; + } + binop_type = self->tokenizer.value.binop_type; + + return_if_error(parser_parse_rhs_binop(self, &rhs)); + return_if_error(scoped_allocator_alloc(self->allocator, sizeof(Binop), (void**)&expr->value.binop)); + binop_init(expr->value.binop); + expr->value.binop->type = binop_type; + expr->value.binop->lhs = lhs; + expr->value.binop->rhs = rhs; + expr->type = AST_BINOP; + return PARSER_OK; +} + +/* +RHS_BINOP_WO_PAREN = RHS_S | (RHS_S TOK_BINOP RHS_BINOP) +*/ +static CHECK_RESULT int parser_parse_rhs_binop_without_paren(Parser *self, Ast *expr) { + bool match; + Ast lhs; + Ast rhs; + BinopType binop_type; + + return_if_error(parser_parse_rhs_single_expr(self, &lhs)); + return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_BINOP, &match)); + if(!match) { + *expr = lhs; + return PARSER_OK; + } + binop_type = self->tokenizer.value.binop_type; + + return_if_error(parser_parse_rhs_binop(self, &rhs)); + return_if_error(scoped_allocator_alloc(self->allocator, sizeof(Binop), (void**)&expr->value.binop)); + binop_init(expr->value.binop); + expr->value.binop->type = binop_type; + expr->value.binop->lhs = lhs; + expr->value.binop->rhs = rhs; + expr->type = AST_BINOP; + return PARSER_OK; +} + +/* +RHS_BINOP = RHS_BINOP_PAREN | RHS_BINOP_WO_PAREN + +Note: Parantheses count has to match for the beginning paranthesis and the ending parenthesis. +*/ +int parser_parse_rhs_binop(Parser *self, Ast *expr) { + bool match; + return_if_error(parser_parse_rhs_binop_paren(self, &match, expr)); + if(match) + return PARSER_OK; + return parser_parse_rhs_binop_without_paren(self, expr); +} + +/* +RHS = RHS_BINOP ';' + +Note: Parantheses count has to match for the beginning paranthesis and the ending parenthesis. +*/ +static CHECK_RESULT int parser_parse_rhs(Parser *self, Ast *rhs_expr) { + /* TODO: If binop only contains one expression, then use that directly for @rhs_expr */ + return_if_error(parser_parse_rhs_binop(self, rhs_expr)); + + /* TODO: Implement this */ + /*binop_reorder_by_precedence(binop);*/ + return PARSER_OK; +} + /* RHS_START = CLOSURE | IMPORT | RHS */ @@ -312,6 +408,17 @@ int parser_parse_body(Parser *self, Ast *ast) { *ast = rhs_expr; } + if(rhs_expr.type == AST_BINOP) { + bool match; + return_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match)); + if(!match) { + /* TODO: Specify all the binop characters instead of "binop" which doesn't make sense for the user */ + self->error = tokenizer_create_error(&self->tokenizer, "Expected ';' or binop"); + return PARSER_UNEXPECTED_TOKEN; + } + return PARSER_OK; + } + /* TODO: Check for struct and tables */ if(rhs_expr.type != AST_FUNCTION_DECL) return_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON)); diff --git a/src/tokenizer.c b/src/tokenizer.c index afaeb8e..152aec4 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -116,6 +116,8 @@ static CHECK_RESULT int string_to_float_unchecked(BufferView str, f64 *result) { return 0; } +#define SET_BINOP(_binop_type) do { *token = TOK_BINOP; self->value.binop_type = (_binop_type); } while(0) + static CHECK_RESULT int tokenizer_next(Tokenizer *self, Token *token); static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { @@ -182,7 +184,6 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { self->value.string.size = string_end - self->index; self->index = string_end + 1; *token = TOK_STRING; - return TOKENIZER_OK; } else if(isDigit(c)) { int number_start; int dot_index; @@ -225,10 +226,21 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { self->number_is_integer = bool_false; } *token = TOK_NUMBER; - return TOKENIZER_OK; } else if(c == '.') { ++self->index; - *token = TOK_DOT; + SET_BINOP(BINOP_DOT); + } else if(c == '+') { + ++self->index; + SET_BINOP(BINOP_ADD); + } else if(c == '-') { + ++self->index; + SET_BINOP(BINOP_SUB); + } else if(c == '*') { + ++self->index; + SET_BINOP(BINOP_MUL); + } else if(c == '/') { + ++self->index; + SET_BINOP(BINOP_DIV); } else if(c == '=') { ++self->index; *token = TOK_EQUALS; @@ -250,6 +262,9 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { } else if(c == ';') { ++self->index; *token = TOK_SEMICOLON; + } else if(c == ':') { + ++self->index; + *token = TOK_COLON; } else if(c == '@') { const char *err_msg; ++self->index; @@ -313,6 +328,19 @@ static usize strlen(const char *str) { return len; } +/* +static const char* binop_to_string(BinopType binop_type) { + switch(binop_type) { + case BINOP_DOT: return "."; + case BINOP_ADD: return "+"; + case BINOP_SUB: return "-"; + case BINOP_MUL: return "*"; + case BINOP_DIV: return "/"; + } + assert(bool_false && "binop_to_string not implemented for binop_type"); +} +*/ + static BufferView tokenizer_expected_token_as_string(Token token) { const char *str; switch(token) { @@ -361,12 +389,16 @@ static BufferView tokenizer_expected_token_as_string(Token token) { case TOK_NUMBER: str = "number"; break; - case TOK_DOT: - str = "."; + case TOK_BINOP: + /* TODO: binop_to_string */ + str = "binop"; break; case TOK_SEMICOLON: str = ";"; break; + case TOK_COLON: + str = ":"; + break; default: str = "Unknown token"; break; diff --git a/tests/main.amal b/tests/main.amal index 71e962e..a7b4576 100644 --- a/tests/main.amal +++ b/tests/main.amal @@ -6,8 +6,10 @@ const main = fn { } const value = "hello"; print(value, "world", 356, 13.37); - var num1; + var num1: i32; const num2 = 23232; + const num3 = num1 + num2 * 30; + const num4 = (num1 + num2) * num3 * ((34 + 32) / 234.345); } const print = fn { |