G

G Programming Language
git clone http://git.omkov.net/G
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-05-02 06:29:28
Commit6dd92231459df661805b3d79c648ceb86f29413c
Parent04569e6b84d3462bf923847abc39428e3c82fc21

Implement variable assignments

Diffstat

M README.md | 5 +++--
M examples/main.g | 1 +
M src/lex.h | 1 +
M src/llvm.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
M src/parse.c | 23 ++++++++++++++++++++++-
M src/parse.h | 8 +++++++-

6 files changed, 83 insertions, 4 deletions

diff --git a/README.md b/README.md
index 8697cdf..7cff0eb 100644
--- a/README.md
+++ b/README.md
@@ -59,19 +59,20 @@ command. The second command will output an executable file, *a.out* by default.
 
 - [x] Implement procedure declarations
 - [ ] Implement procedure calls
+- [ ] Implement procedure arguments
 - [x] Implement variable declarations
-- [ ] Implement variable assignments
+- [x] Implement variable assignments
 - [x] Implement integers
 - [ ] Implement reals
 - [ ] Implement arrays
 - [x] Implement expression parsing
 - [x] Implement expression code generation
 - [ ] Implement the *type* type
-- [ ] Implement multiple return values
 - [ ] Implement *defer*
 - [ ] Implement *errdefer*
 - [ ] Implement *if* and *else*
 - [ ] Implement *for*
+- [ ] Implement multiple return values
 - [ ] Implement generics of some kind
 - [ ] Implement module definition
 - [ ] Implement module use
diff --git a/examples/main.g b/examples/main.g
index 97fa5ae..dc809b6 100644
--- a/examples/main.g
+++ b/examples/main.g
@@ -1,4 +1,5 @@
 main :: proc() -> s64 {
 	var := 42 + 8;
+	var += 2;
 	return var;
 }
diff --git a/src/lex.h b/src/lex.h
index 4c06cff..24a451f 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -25,6 +25,7 @@ typedef enum {
 	TK_AS_NOT, TK_AS_AND, TK_AS_OR,  TK_AS_XOR, TK_AS_SHL, TK_AS_SHR,
 } tok_k;
 
+/* k : Kind, ln : Line, cl : Column, h : Hash, s : String, v_? : Value */
 typedef struct {
 	tok_k k; UINT ln, cl; u64 h; char *s;
 	union { u64 v_u64; s64 v_s64; f64 v_f64; };
diff --git a/src/llvm.c b/src/llvm.c
index 6dfd355..5eeb3e6 100644
--- a/src/llvm.c
+++ b/src/llvm.c
@@ -26,6 +26,7 @@ static LLVMBuilderRef llvm_builder = NULL;
 static LLVMValueRef llvm_stmt(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_compound(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_decl(ast *a, syt *st);
+static LLVMValueRef llvm_stmt_assn(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_expr(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_return(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_if(ast *a, syt *st);
@@ -85,6 +86,8 @@ static LLVMValueRef llvm_stmt(ast *a, syt *st) {
 	switch (a->k) {
 	case AK_COMP:   { return llvm_stmt_compound(a, st); } break;
 	case AK_DECL:   { return llvm_stmt_decl(a, st);     } break;
+	case AK_ASSIGN: case AK_AS_ADD: case AK_AS_SUB: case AK_AS_MUL: case AK_AS_DIV: case AK_AS_MOD:
+		{ return llvm_stmt_assn(a, st); } break;
 	case AK_RETURN: { return llvm_stmt_return(a, st);   } break;
 	case AK_IF:     { return llvm_stmt_if(a, st);       } break;
 	case AK_FOR:    { return llvm_stmt_for(a, st);      } break;
@@ -129,6 +132,52 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) {
 	return NULL;
 }
 
+/* Generate IR for an assignment statement. */
+static LLVMValueRef llvm_stmt_assn(ast *a, syt *st) {
+	assert(
+		a->k == AK_ASSIGN ||
+		a->k == AK_AS_ADD ||
+		a->k == AK_AS_SUB ||
+		a->k == AK_AS_MUL ||
+		a->k == AK_AS_DIV ||
+		a->k == AK_AS_MOD
+	);
+	
+	ast *v = syt_search(st, a->s);
+	if (v == NULL) { error(2, "llvm_expr: Undefined variable %s", a->s); }
+	
+	switch (a->k) {
+	case AK_ASSIGN: {
+		return LLVMBuildStore(llvm_builder, llvm_expr(C[0], st), v->llvm_v);
+	} break;
+	case AK_AS_ADD: {
+		LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s);
+		LLVMValueRef rr = LLVMBuildAdd(llvm_builder, vr, llvm_expr(C[0], st), "as_add");
+		return LLVMBuildStore(llvm_builder, rr, v->llvm_v);
+	} break;
+	case AK_AS_SUB: {
+		LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s);
+		LLVMValueRef rr = LLVMBuildSub(llvm_builder, vr, llvm_expr(C[0], st), "as_sub");
+		return LLVMBuildStore(llvm_builder, rr, v->llvm_v);
+	} break;
+	case AK_AS_MUL: {
+		LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s);
+		LLVMValueRef rr = LLVMBuildMul(llvm_builder, vr, llvm_expr(C[0], st), "as_mul");
+		return LLVMBuildStore(llvm_builder, rr, v->llvm_v);
+	} break;
+	case AK_AS_DIV: {
+		LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s);
+		LLVMValueRef rr = LLVMBuildSDiv(llvm_builder, vr, llvm_expr(C[0], st), "as_div");
+		return LLVMBuildStore(llvm_builder, rr, v->llvm_v);
+	} break;
+	case AK_AS_MOD: {
+		LLVMValueRef vr = LLVMBuildLoad2(llvm_builder, llvm_type(v->t), v->llvm_v, v->s);
+		LLVMValueRef rr = LLVMBuildSRem(llvm_builder, vr, llvm_expr(C[0], st), "as_mod");
+		return LLVMBuildStore(llvm_builder, rr, v->llvm_v);
+	} break;
+	}
+}
+
 /* Generate IR for an expression statement. */
 static LLVMValueRef llvm_stmt_expr(ast *a, syt *st) {
 
diff --git a/src/parse.c b/src/parse.c
index ad11863..aa9b2ec 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -26,12 +26,15 @@ char *ast_ks[] = {
 	"AK_OP_POS", "AK_OP_NEG",
 	"AK_OP_ADD", "AK_OP_SUB", "AK_OP_MUL", "AK_OP_DIV", "AK_OP_MOD",
 
+	"AK_ASSIGN", "AK_AS_ADD", "AK_AS_SUB", "AK_AS_MUL", "AK_AS_DIV", "AK_AS_MOD",
+	
 	"AK_ID_VAR", "AK_ID_PROC", "AK_INT",
 };
 
 static ast *parse_stmt(lex *l, syt *st);
 static ast *parse_stmt_compound(lex *l, syt *st);
 static ast *parse_stmt_decl(lex *l, syt *st);
+static ast *parse_stmt_assn(lex *l, syt *st, ast *a);
 static ast *parse_stmt_expr(lex *l, syt *st);
 static ast *parse_stmt_return(lex *l, syt *st);
 static ast *parse_stmt_if(lex *l, syt *st);
@@ -112,7 +115,9 @@ static ast *parse_stmt_decl(lex *l, syt *st) {
 	ast *sm = ast_init(); sm->k = AK_DECL;
 	sm->ln = T.ln; sm->cl = T.cl; sm->h = T.h; sm->s = T.s;
 
-	lex_kind(l, TK_ID); lex_kind(l, TK_COLON);
+	lex_kind(l, TK_ID);
+	if (T.k != TK_COLON) { return parse_stmt_assn(l, st, sm); }
+	lex_kind(l, TK_COLON);
 
 	/* Store the declaration's type if one is specified */
 	/* TODO store type when one is specified */
@@ -147,6 +152,22 @@ static ast *parse_stmt_decl(lex *l, syt *st) {
 	end:; syt_insert_h(st, sm->h, sm->s, sm); return sm;
 }
 
+/* Should only be called by parse_stmt_decl (?) */
+static ast *parse_stmt_assn(lex *l, syt *st, ast *a) {
+	switch (T.k) {
+	case TK_ASSIGN: { a->k = AK_ASSIGN; } goto expr;
+	case TK_AS_ADD: { a->k = AK_AS_ADD; } goto expr;
+	case TK_AS_SUB: { a->k = AK_AS_SUB; } goto expr;
+	case TK_AS_MUL: { a->k = AK_AS_MUL; } goto expr;
+	case TK_AS_DIV: { a->k = AK_AS_DIV; } goto expr;
+	case TK_AS_MOD: { a->k = AK_AS_MOD; } goto expr;
+	expr: { lex_next(l); ast_push(a, parse_expr(l, st)); } break;
+	default: { error(1, "%s:%zu:%zu: error: expected assignment operator", l->n, T.ln + 1, T.cl + 1); } break;
+	}
+	
+	lex_kind(l, TK_SCOLON); return a;
+}
+
 /* Parse an expression statement. */
 static ast *parse_stmt_expr(lex *l, syt *st) {
 	ast *a = NULL; if (T.k != TK_SCOLON) { a = parse_expr(l, st); }
diff --git a/src/parse.h b/src/parse.h
index fc7b5fd..b1e5a8d 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -14,6 +14,7 @@
 
 #include <llvm-c/Types.h>
 
+/* Remember to update ast_ks in parse.c */
 typedef enum {
 	AK_NULL, AK_PROG, AK_PROC, AK_TYPE,
 
@@ -22,10 +23,15 @@ typedef enum {
 	AK_OP_POS, AK_OP_NEG,
 	AK_OP_ADD, AK_OP_SUB, AK_OP_MUL, AK_OP_DIV, AK_OP_MOD,
 
+	AK_ASSIGN, AK_AS_ADD, AK_AS_SUB, AK_AS_MUL, AK_AS_DIV, AK_AS_MOD,
+	
 	AK_ID_VAR, AK_ID_PROC, AK_INT,
 } ast_k;
 
-/* k : Kind, ln : Line, cl : Column, t : Type, c : Children */
+/*
+	k : Kind, ln : Line, cl : Column, h : Hash, s : String, t : Type, v: Value
+	st : Symbol Table, p : Parent, c : Children
+*/
 typedef struct ast_s {
 	ast_k k; UINT ln, cl; u64 h; char *s; type *t; val v; syt st;
 	struct ast_s *p; struct { struct ast_s **a; UINT al; } c;