aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-03-03 13:18:08 +0100
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commitb3b0c807a75c4f854495b547d8e00a598979cbf6 (patch)
treee42017c2f5b87a939d103f48d5f90dd93193ebcc
parent4c5ffb35d50d514e3df4788e7cf38245c0127883 (diff)
Add arithmetic (binop) parsing
-rw-r--r--.gitignore1
-rw-r--r--include/ast.h14
-rw-r--r--include/binop_type.h12
-rw-r--r--include/tokenizer.h7
-rw-r--r--src/ast.c7
-rw-r--r--src/parser.c115
-rw-r--r--src/tokenizer.c42
-rw-r--r--tests/main.amal4
8 files changed, 189 insertions, 13 deletions
diff --git a/.gitignore b/.gitignore
index fcd2802..c551744 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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;
diff --git a/src/ast.c b/src/ast.c
index 75c8afc..4b72f43 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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 {