G

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

AuthorJakob Wakeling <[email protected]>
Date2023-07-03 10:41:35
Commitcc58a1d3fcd21571a5d231359a3acbbe5564d97d
Parent3f9a543df8693f7ebeb7492e4077a716ed3cfdc0

Implement procedure arguments

Diffstat

M README.md | 2 +-
M examples/main.g | 10 ++++++----
M src/analyse.c | 8 +++++++-
M src/lex.c | 9 +++++----
M src/lex.h | 2 +-
M src/llvm.c | 42 +++++++++++++++++++++++++++---------------
M src/main.c | 8 --------
M src/parse.c | 38 +++++++++++++++++++++++++++++---------
M src/parse.h | 2 +-
M src/symbol.c | 9 +++++++++

10 files changed, 86 insertions, 44 deletions

diff --git a/README.md b/README.md
index 03b583b..831a715 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ command. The second command will output an executable file, *a.out* by default.
 
 - [x] Implement procedure declarations
 - [x] Implement procedure calls
-- [ ] Implement procedure arguments
+- [x] Implement procedure arguments
 - [x] Implement variables
 - [x] Implement booleans
 - [x] Implement integers
diff --git a/examples/main.g b/examples/main.g
index b4c85f3..61553d8 100644
--- a/examples/main.g
+++ b/examples/main.g
@@ -1,5 +1,7 @@
+add3 :: proc(x: u8, y: u8, z: u8) -> u8 {
+	return x + y + z;
+}
+
 main :: proc() -> u8 {
-	var : [1]u8;
-	var[0] = 1;
-	return var[0];
+	return add3(1, 2, 3);
 }
diff --git a/src/analyse.c b/src/analyse.c
index 4f2a4a9..ed071f4 100644
--- a/src/analyse.c
+++ b/src/analyse.c
@@ -173,6 +173,11 @@ static void analyse_expr(ast *a, syt *st) {
 static void analyse_expr_proc(ast *a, syt *st) {
 	assert(A.k == AK_PROC);
 
+	/* Analyse the procedure arguments */
+	for (UINT i = 0; i < CL - 1; i += 1) {
+		/* TODO */
+	}
+	
 	/* Analyse the procedure body */
-	analyse_stmt_comp(C[0], st);
+	analyse_stmt_comp(C[CL - 1], st);
 }
diff --git a/src/lex.c b/src/lex.c
index 00352bc..2180e47 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -40,7 +40,7 @@ char *tok_ks[] = {
 #define is_digit_doz(c) ((c >= '0' && c <= '9') || (c == 'A' || c == 'B'))
 #define is_digit_hex(c) ((c >= '0' && c <= '9') || (c >= 'A' || c == 'F'))
 
-static inline u128 parse_int(char *s);
+static inline u64 parse_int(char *s);
 static inline f128 parse_flt(char *s);
 
 /* Push a token to a token array. */
@@ -138,6 +138,7 @@ tok lex_next(lex *l) {
 		switch (T.k) {
 		case TK_INT: { T.v_int = parse_int(T.s); } break;
 		case TK_FLT: { T.v_flt = parse_flt(T.s); } break;
+		default: { /* Unreachable */ } break;
 		}
 	}
 
@@ -307,8 +308,8 @@ void lex_debug(lex *l) {
 }
 
 /* Parse an integer string into a value. */
-static inline u128 parse_int(char *s) {
-	register u128 v = 0, c; register UINT b = 10;
+static inline u64 parse_int(char *s) {
+	register u64 v = 0; u64 c; register UINT b = 10;
 
 	if (s[0] == '0') switch (s[1]) {
 	case 'b': { s += 2; b = 2;  } break; case 'o': { s += 2; b = 8;  } break;
@@ -322,7 +323,7 @@ static inline u128 parse_int(char *s) {
 
 		/* TODO better error handling */
 		if (c >= b) { errno = EDOM; return 0; }
-		if (v > (U128_MAX - c) / b) { errno = ERANGE; return 0; }
+		if (v > (U64_MAX - c) / b) { errno = ERANGE; return 0; }
 
 		v = v * b + c;
 	}
diff --git a/src/lex.h b/src/lex.h
index 770d35a..6592620 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -30,7 +30,7 @@ typedef enum {
 	k : Kind, ln : Line, cl : Column, h : Hash, s : String,
 	v_int : Int Value, v_flt : Flt Value
 */
-typedef struct { tok_k k; UINT ln, cl; u64 h; char *s; union { u128 v_int; f128 v_flt; }; } tok;
+typedef struct { tok_k k; UINT ln, cl; u64 h; char *s; union { u64 v_int; f128 v_flt; }; } tok;
 typedef struct { tok *a; UINT al; } tok_a;
 
 /*
diff --git a/src/llvm.c b/src/llvm.c
index 77096a3..3be9794 100644
--- a/src/llvm.c
+++ b/src/llvm.c
@@ -30,7 +30,6 @@ 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_expr(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_return(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_if(ast *a, syt *st);
 static LLVMValueRef llvm_stmt_for(ast *a, syt *st);
@@ -138,14 +137,23 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) {
 	assert(a->k == AK_DECL);
 
 	if (CL && C[0]->k == AK_PROC) {
-		/* TODO handle procedure arguments if present */
-		LLVMTypeRef ft = LLVMFunctionType(llvm_type(C[0]->t), NULL, 0, 0);
+		LLVMTypeRef art[C[0]->c.al - 1];
+		for (UINT i = 0; i < C[0]->c.al - 1; i += 1) {
+			art[i] = llvm_type(ast_type(C[0]->c.a[i], st));
+		}
+		
+		LLVMTypeRef ft = LLVMFunctionType(llvm_type(C[0]->t), art, C[0]->c.al - 1, 0);
 		LLVMValueRef f = LLVMAddFunction(llvm_module, A.s, ft);
 
 		LLVMBasicBlockRef bb = LLVMAppendBasicBlock(f, "entry");
 		LLVMPositionBuilderAtEnd(llvm_builder, bb);
 
-		llvm_expr_proc(C[0], st); A.llvm_t = ft; A.llvm_v = f;
+		for (UINT i = 0; i < C[0]->c.al - 1; i += 1) {
+			C[0]->c.a[i]->llvm_v = LLVMGetParam(f, i);
+		}
+		
+		A.llvm_t = ft; A.llvm_v = f;
+		llvm_expr_proc(C[0], st);
 	}
 	else {
 		if (A.p->k == AK_PROG) { /* Global */
@@ -163,11 +171,6 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) {
 	return NULL;
 }
 
-/* Generate IR for an expression statement. */
-static LLVMValueRef llvm_stmt_expr(ast *a, syt *st) {
-	
-}
-
 /* Generate IR for a return statement. */
 static LLVMValueRef llvm_stmt_return(ast *a, syt *st) {
 	return LLVMBuildRet(llvm_builder, a->c.al > 0 ? llvm_expr(C[0], st, true) : NULL);
@@ -175,12 +178,12 @@ static LLVMValueRef llvm_stmt_return(ast *a, syt *st) {
 
 /* Generate IR for an if statement. */
 static LLVMValueRef llvm_stmt_if(ast *a, syt *st) {
-	
+	return NULL; /* TODO */
 }
 
 /* Generate IR for a for statement. */
 static LLVMValueRef llvm_stmt_for(ast *a, syt *st) {
-	
+	return NULL; /* TODO */
 }
 
 /* Generate IR for an expression. */
@@ -197,7 +200,9 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) {
 		if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined variable \"%s\"", A.s); }
 		if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Variable \"%s\" follows (llvm:llvm_expr)", A.s); }
 
-		if (!load || sym->t->k == TY_ARR) { return sym->llvm_v; }
+		/* TODO fix procedure argument handling, should be assignable */
+		/* TODO fix array variable handling */
+		if (!load || sym->k == AK_ID || sym->t->k == TY_ARR) { return sym->llvm_v; }
 		else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); }
 	} break;
 	case AK_CALL: {
@@ -205,9 +210,12 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) {
 		if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined procedure \"%s\" (llvm:llvm_expr)", C[0]->s); }
 		if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Procedure \"%s\" follows (llvm:llvm_expr)", C[0]->s); }
 
-		/* TODO procedure call arguments */
+		LLVMValueRef args[CL - 1];
+		for (UINT i = 1; i < CL; i += 1) {
+			args[i - 1] = llvm_expr(C[i], st, true);
+		}
 
-		return LLVMBuildCall2(llvm_builder, sym->llvm_t, sym->llvm_v, NULL, 0, "");
+		return LLVMBuildCall2(llvm_builder, sym->llvm_t, sym->llvm_v, args, CL - 1, "");
 	} break;
 	case AK_SUBS: {
 		ast *sym = syt_search_h(st, C[0]->h, C[0]->s);
@@ -298,11 +306,13 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) {
 	} break;
 	default: { note(file_name, A.ln, A.cl, -1, "Unhandled AST kind %s (llvm:llvm_expr)", ast_ks[a->k]); } break;
 	}
+	
+	return NULL;
 }
 
 /* Generate IR for a procedure. */
 static LLVMValueRef llvm_expr_proc(ast *a, syt *st) {
-	return llvm_stmt_compound(C[0], st);
+	return llvm_stmt_compound(C[CL - 1], st);
 }
 
 /* Generate IR for a type cast. */
@@ -356,6 +366,8 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) {
 	}
 
 	note(file_name, A.ln, A.cl, -1, "Unhandled cast \"%s\" -> \"%s\" (llvm:llvm_expr_cast)", expr_type->s, A.t->s);
+	
+	return NULL;
 }
 
 /* Generate IR for an array. */
diff --git a/src/main.c b/src/main.c
index 4aa5271..bfba797 100644
--- a/src/main.c
+++ b/src/main.c
@@ -23,10 +23,6 @@ static struct lop lops[] = {
 	{ NULL, 0, 0 }
 };
 
-static char *aw[] = {
-	"g", "/home/deus/Workspace/G/examples/main.g", NULL
-};
-
 static bool bflag = false, Bflag = false, cflag = false;
 static bool Eflag = false, pflag = false, Pflag = false;
 static bool qflag = false;
@@ -42,9 +38,6 @@ static void hlp(void);
 static void ver(void);
 
 int main(int ac, char *av[]) { A0 = av[0];
-	/* DEBUG */
-	if (ac == 1) { ac = (sizeof (aw) / sizeof (*aw)) - 1; av = aw; }
-	
 	struct opt opt = OPTGET_INIT; opt.str = "bBcEf:O:pPqW:"; opt.lops = lops;
 	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
 	case 'b': { bflag = true; } break; /* Output LLVM IR files */
diff --git a/src/parse.c b/src/parse.c
index 923ac7c..bf81581 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -96,10 +96,10 @@ void ast_displace(ast *a, ast *c) {
 type *ast_type(ast *a, syt *st) {
 	/* Search the symbol table for a type first */
 	if (a->s) {
-		ast *v = syt_search(st, a->s);
-		if (v != NULL) {
-			if (v->c.al != 0 && v->c.a[0]->k == AK_PROC) { return v->c.a[0]->t; }
-			else { return v->t; }
+		ast *sym = syt_search(st, a->s);
+		if (sym != NULL) {
+			if (sym->c.al != 0 && sym->c.a[0]->k == AK_PROC) { return sym->c.a[0]->t; }
+			else { return sym->t; }
 		}
 	}
 
@@ -315,6 +315,7 @@ static ast *parse_expr(lex *l, syt *st, s32 o) {
 	case TK_OP_DIV: { a = ast_init(AK_OP_DIV, T.ln, T.cl); } goto infix;
 	case TK_OP_MOD: { a = ast_init(AK_OP_MOD, T.ln, T.cl); } goto infix;
 	infix: { lex_next(l); ast_push(a, left); ast_push(a, parse_expr(l, st, ast_precedence(a->k))); } break;
+	default: { /* Ignored */ } break;
 	}
 
 	return left;
@@ -339,10 +340,23 @@ static ast *parse_expr_proc(lex *l, syt *st) {
 	assert(T.k == TK_PROC);
 
 	ast *a = ast_init(AK_PROC, T.ln, T.cl);
-	lex_next(l); lex_kind(l, TK_LPAREN);
+	lex_next(l); lex_kind(l, TK_LPAREN); a->st.pt = st;
 
 	/* Parse optional procedure parameter(s) */
-	/* TODO */ lex_kind(l, TK_RPAREN);
+	if (T.k != TK_RPAREN) for (;;) {
+		ast *arg = ast_init(AK_ID, T.ln, T.cl);
+		arg->h = T.h; arg->s = strdup_or_fail(T.s);
+		
+		lex_kind(l, TK_ID); lex_kind(l, TK_COLON);
+		
+		ta_pair ta = parse_type(l, st);
+		arg->t = ta.t; /* TODO handle AST component */
+		
+		ast_push(a, arg); syt_insert_h(&a->st, arg->h, arg->s, arg);
+		if (T.k == TK_COMMA) { lex_next(l); } else { break; }
+	}
+	
+	lex_kind(l, TK_RPAREN);
 
 	/* Parse optional procedure return type */
 	if (T.k == TK_RARROW) {
@@ -353,7 +367,7 @@ static ast *parse_expr_proc(lex *l, syt *st) {
 	}
 	else { a->t = &TYPE(TY_VOID); }
 
-	ast_push(a, parse_stmt_compound(l, st)); return a;
+	ast_push(a, parse_stmt_compound(l, &a->st)); return a;
 }
 
 /* Parse a type identifier. */
@@ -386,7 +400,7 @@ static inline ta_pair parse_type(lex *l, syt *st) {
 	if (s == NULL) { note(l->n, t.ln, t.cl, 0, "Use of undeclared identifier \"%s\"", t.s); }
 	else if (s->k != AK_TYPE) { note(l->n, t.ln, t.cl, 0, "Expected type identifier"); }
 
-	if (r == NULL) { (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; }
+	if (r == NULL) { return (ta_pair){ s->t, a }; } else { c->base = s->t; return (ta_pair){ r, a }; }
 }
 
 /* Parse an integer. */
@@ -404,7 +418,7 @@ static ast *parse_int(lex *l, syt *st) {
 	else if (a->v_int <= U16_MAX) { a->t = &TYPE(TY_U16); }
 	else if (a->v_int <= U32_MAX) { a->t = &TYPE(TY_U32); }
 	else if (a->v_int <= U64_MAX) { a->t = &TYPE(TY_U64); }
-	else if (a->v_int <= U128_MAX) { a->t = &TYPE(TY_U128); }
+	// else if (a->v_int <= U128_MAX) { a->t = &TYPE(TY_U128); }
 
 	return a;
 }
@@ -495,7 +509,8 @@ void ast_print(ast *a, UINT indent) {
 	switch (a->k) {
 	case AK_BOOL: { printf(a->v_bool ? " = true" : " = false"); } break;
 	case AK_INT:  { printf(" = %lu", a->v_int); } break;
-	case AK_FLT:  { printf(" = %lf", a->v_flt); } break;
+	case AK_FLT:  { printf(" = %Lf", a->v_flt); } break;
+	default: { /* Ignored */ } break;
 	}
 
 	/* Indicate if the AST node has no parent */
diff --git a/src/parse.h b/src/parse.h
index d0f7da0..5b489f5 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -37,7 +37,7 @@ typedef enum {
 typedef struct ast_s {
 	ast_k k; UINT ln, cl; u64 h; char *s; type *t; syt st;
 	struct ast_s *p; struct { struct ast_s **a; UINT al; } c;
-	union { bool v_bool; u128 v_int; f128 v_flt; };
+	union { bool v_bool; u64 v_int; f128 v_flt; };
 
 	LLVMTypeRef llvm_t; LLVMValueRef llvm_v;
 } ast;
diff --git a/src/symbol.c b/src/symbol.c
index 43838b7..8ef3b2d 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -160,7 +160,15 @@ ast *syt_search_h(syt *st, u64 h, char *k) {
 /* Print a basic representation of a map to stdout. */
 void syt_print(syt *st) {
 	for (UINT i = 0; i < st->ac; i += 1) if (st->a[i].h != 0) {
-		fputs(st->a[i].k, stdout);
+		printf("%s %s", ast_ks[st->a[i].v->k], st->a[i].k);
+		
+		if (st->a[i].v->k == AK_DECL && st->a[i].v->c.al > 0 && st->a[i].v->c.a[0]->k == AK_PROC) {
+			fputc('(', stdout);
+			for (UINT j = 0; j < st->a[i].v->c.al - 1; j += 1) {
+				/* TODO */
+			}
+			fputc(')', stdout);
+		}
 
 		if (st->a[i].v->t != NULL) { fputs(" -> ", stdout); }
 		for (type *t = st->a[i].v->t; t != NULL; t = t->base) switch (t->k) {