G

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

AuthorJakob Wakeling <[email protected]>
Date2021-09-07 09:36:23
Commit534efc4ea454ffe0ef4b995f035fea749ea07676
Parent272888243bd3c867399ae0423c0b33a9f8fc0008

llvm: Implement basic LLVM code generation

Diffstat

M CMakeLists.txt | 3 +++
M doc/g.ebnf | 13 ++++++++-----
M src/compile.c | 10 +++++-----
M src/compile.h | 1 +
M src/g.h | 10 +++-------
M src/lex.c | 3 ++-
A src/llvm/gen.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A src/llvm/llvm.h | 23 +++++++++++++++++++++++
A src/llvm/type.c | 28 ++++++++++++++++++++++++++++
M src/parse.c | 82 +++++++++++++++++++++++++++++--------------------------------------------------
M src/type.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------

11 files changed, 287 insertions, 84 deletions

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5fce0cf..dde9eb5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,9 @@ PROJECT(G VERSION 0.0.0 LANGUAGES C)
 SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
 ADD_COMPILE_DEFINITIONS(PROJECT_VERSION="${PROJECT_VERSION}")
 
+FIND_PACKAGE(LLVM REQUIRED)
+
 FILE(GLOB SRC ${PROJECT_SOURCE_DIR}/src/*.c ${PROJECT_SOURCE_DIR}/src/**/*.c)
 
 ADD_EXECUTABLE(g ${SRC})
+TARGET_LINK_LIBRARIES(g LLVM)
diff --git a/doc/g.ebnf b/doc/g.ebnf
index 259076d..9789983 100644
--- a/doc/g.ebnf
+++ b/doc/g.ebnf
@@ -13,15 +13,14 @@ decl            = iden, ":", decl_constant | decl_variable ;
 decl_constant   = [ type ], ":", expr, ";" ;
 decl_variable   = ( type, [ "=", expr ] ) | ( "=", expr ), ";" ;
 
-decl_procedure  = [ type ], ":", "proc", "(", [ parm_list ], ")" , "->", type
-                , "{", { decl | stmt | expr }, "}" ;
-
 (* Statements *)
-stmt            = "{", stmt, "}"
-                | [ expr ], ";"
+stmt            = stmt_compound
                 | "return", [ expr ], ";"
+                | [ expr ], ";"
                 ;
 
+stmt_compound   = "{", { stmt }, "}" ;
+
 (* Expressions *)
 expr            = "(", expr, ")" | iden | literal
                 | "+", expr | "-", expr (* Unary POS and NEG *)
@@ -47,6 +46,9 @@ expr            = "(", expr, ")" | iden | literal
                 | iden, "<<=", expr | iden, ">>=" expr
                 ;
 
+proc            = "proc", "(", [ parm_list ], ")", [ "->", type ]
+                , stmt_compound ;
+
 (* Identifiers and Parameters *)
 iden            = alpha_, { alpha_ | digit } ;
 type            = iden ;
diff --git a/src/compile.c b/src/compile.c
index 09933d7..7ff2691 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -5,9 +5,10 @@
 

 
+#include "cll/cll.h"
 #include "compile.h"
 #include "g.h"
-#include "cll/cll.h"
+#include "llvm/llvm.h"
 #include "util/ast.h"
 
 #include "cll/error.h"
@@ -17,7 +18,7 @@
 
 bool lflag = false, pflag = false;
 
-void compile(char *src, UINT len) {
+void compile(u8 *src, UINT len) {
 	if (lflag) {
 		lex l = lex_init(src, len);
 
@@ -37,14 +38,13 @@ compile:;
 
 	ast_print(a, 0);
 
-	// code generation
-	// linking
+	llvm_test(a);
 
 	return;
 }
 
 void compile_file(const char *file) {
-	FILE *fi; char *fb; size_t fl;
+	FILE *fi; u8 *fb; size_t fl;
 
 	if (!(fi = fopen(file, "r"))) { error(1, "%s: %s", file, serr()); }
 	fseek(fi, 0, SEEK_END); fl = ftell(fi); rewind(fi);
diff --git a/src/compile.h b/src/compile.h
index bb61672..6693c0b 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -12,7 +12,7 @@
 
 extern bool lflag, pflag;
 
-extern void compile(char *src, UINT len);
+extern void compile(u8 *src, UINT len);
 extern void compile_file(const char *file);
 
 #endif // OMKOV_G_COMPILE_H_DSDZQ0ZM
diff --git a/src/g.h b/src/g.h
index d79947b..8372aa2 100644
--- a/src/g.h
+++ b/src/g.h
@@ -30,15 +30,11 @@ typedef enum {
 typedef enum {
 	AK_NIL,
 
-	AK_DECL, AK_ASSN, AK_COMP,
+	AK_DECL, AK_COMPOUND,
 
 	AK_INT, AK_FLT,
 
-	AK_VARIABLE,
-	AK_CONSTANT,
-	AK_PROCEDURE,
-	
-	AK_RETURN,
+	AK_PROC, AK_RETURN,
 } ast_k;
 
 typedef struct { UINT ln, cl; } pos;
diff --git a/src/lex.c b/src/lex.c
index e325515..0f7a496 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -1,4 +1,4 @@
-// lexer.c
+// lex.c
 // Lexer source file for G
 // Copyright (C) 2021, Jakob Wakeling
 // All rights reserved.
@@ -9,6 +9,7 @@
 #include "keyword.h"
 #include "type.h"
 
+#include "cll/cll.h"
 #include "cll/error.h"
 #include "cll/fnv.h"
 
diff --git a/src/llvm/gen.c b/src/llvm/gen.c
new file mode 100644
index 0000000..62e1129
--- /dev/null
+++ b/src/llvm/gen.c
@@ -0,0 +1,126 @@
+// llvm/gen.c
+// LLVM generator source file for G
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#include "../g.h"
+#include "../type.h"
+#include "llvm.h"
+
+#include "../cll/cll.h"
+#include "../cll/error.h"
+
+#include <llvm-c/Analysis.h>
+#include <llvm-c/BitWriter.h>
+#include <llvm-c/Core.h>
+#include <llvm-c/Target.h>
+#include <llvm-c/TargetMachine.h>
+#include <llvm-c/Types.h>
+
+#include <stdio.h>
+
+static LLVMContextRef llvm_context;
+static LLVMModuleRef  llvm_module;
+static LLVMBuilderRef llvm_builder;
+
+static LLVMValueRef gen_decl(ast *a);
+
+static LLVMValueRef gen_compound(ast *a);
+
+static LLVMValueRef gen_proc(ast *a);
+
+static LLVMValueRef gen_return(ast *a);
+
+static LLVMValueRef gen_int(ast *a);
+
+void llvm_init(void) {
+	llvm_context = LLVMGetGlobalContext();
+	llvm_module  = LLVMModuleCreateWithName("G");
+	llvm_builder = LLVMCreateBuilder();
+}
+
+void llvm_free(void) {
+	LLVMDisposeBuilder(llvm_builder);
+	LLVMDisposeModule(llvm_module);
+}
+
+void llvm_test(ast *a) {
+	llvm_init(); gen_decl(a);
+	
+	if (LLVMWriteBitcodeToFile(llvm_module, "llvm.bc")) {
+		error(11, "LLVMWriteBitcodeToFile failure!");
+	}
+	
+	char *err;
+	LLVMVerifyModule(llvm_module, LLVMAbortProcessAction, &err);
+	LLVMDisposeMessage(err);
+	
+	char *triple = LLVMGetDefaultTargetTriple();
+	LLVMSetTarget(llvm_module, triple);
+	
+	LLVMInitializeAllTargetInfos();
+	LLVMInitializeAllTargets();
+	LLVMInitializeAllTargetMCs();
+	LLVMInitializeAllAsmParsers();
+	LLVMInitializeAllAsmPrinters();
+	
+	LLVMTargetRef target; LLVMGetTargetFromTriple(triple, &target, &err);
+	if (!target) { error(11, "LLVMGetTargetFromName failure!"); }
+	
+	LLVMTargetMachineRef machine = LLVMCreateTargetMachine(
+		target, triple, "generic", "",
+		LLVMCodeGenLevelNone, LLVMRelocDefault, LLVMCodeModelDefault
+	);
+	
+	LLVMTargetMachineEmitToFile(
+		machine, llvm_module, "llvm.o", LLVMObjectFile, &err
+	);
+	
+	LLVMDisposeTargetMachine(machine); llvm_free();
+}
+
+/* Generate IR for a declaration. */
+static LLVMValueRef gen_decl(ast *a) {
+	/* TODO actually implement this properly. */
+	if (a->k == AK_DECL && a->c->k == AK_PROC) {
+		return gen_proc(a->c);
+	}
+	else { error(1, "gen_decl else!"); }
+	
+	return NULL;
+}
+
+/* Generate IR for a compound statement. */
+static LLVMValueRef gen_compound(ast *a) {
+	/* TODO actually implement this properly. */
+	if (((ast *)a->cs->a[0])->k == AK_RETURN) {
+		return gen_int(((ast *)a->cs->a[0])->c);
+	}
+	else { error(1, "gen_compound else!"); }
+	
+	return NULL;
+}
+
+/* Generate IR for a procedure. */
+static LLVMValueRef gen_proc(ast *a) {
+	LLVMTypeRef ft = LLVMFunctionType(llvm_type(a->t), NULL, 0, 0);
+	LLVMValueRef f = LLVMAddFunction(llvm_module, (char *)a->s, ft);
+	
+	LLVMBasicBlockRef bb = LLVMAppendBasicBlock(f, "entry");
+	LLVMPositionBuilderAtEnd(llvm_builder, bb);
+	
+	LLVMValueRef r = gen_compound(a->c); if (!r) { return NULL; }
+	LLVMBuildRet(llvm_builder, r); return f;
+}
+
+/* Generate IR for a return statement. */
+static LLVMValueRef gen_return(ast *a) {
+	return NULL;
+}
+
+/* Generate IR for an integer. */
+static LLVMValueRef gen_int(ast *a) {
+	return LLVMConstInt(LLVMInt64Type(), a->v.v_int, false);
+}
diff --git a/src/llvm/llvm.h b/src/llvm/llvm.h
new file mode 100644
index 0000000..69d026f
--- /dev/null
+++ b/src/llvm/llvm.h
@@ -0,0 +1,23 @@
+// llvm/llvm.h
+// LLVM header file for G
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#ifndef G_LLVM_LLVM_H_CZUMSHFW
+#define G_LLVM_LLVM_H_CZUMSHFW
+
+#include "../g.h"
+#include "../type.h"
+
+#include "../cll/cll.h"
+
+#include <llvm-c/Types.h>
+
+extern void llvm_init(void);
+void llvm_test(ast *a);
+
+extern LLVMTypeRef llvm_type(type *t);
+
+#endif // G_LLVM_LLVM_H_CZUMSHFW
diff --git a/src/llvm/type.c b/src/llvm/type.c
new file mode 100644
index 0000000..091036c
--- /dev/null
+++ b/src/llvm/type.c
@@ -0,0 +1,28 @@
+// llvm/type.c
+// LLVM type source file for G
+// Copyright (C) 2021, Jakob Wakeling
+// All rights reserved.
+
+
+
+#include "../type.h"
+
+#include <llvm-c/Core.h>
+#include <llvm-c/Types.h>
+
+/* Return the appropriate LLVMTypeRef for a G type. */
+LLVMTypeRef llvm_type(type *t) {
+	switch (t->k) {
+	case TK_UINT: case TK_SINT: { return LLVMIntType(64);  } break;
+	case TK_U8:   case TK_S8:   { return LLVMIntType(8);   } break;
+	case TK_U16:  case TK_S16:  { return LLVMIntType(16);  } break;
+	case TK_U32:  case TK_S32:  { return LLVMIntType(32);  } break;
+	case TK_U64:  case TK_S64:  { return LLVMIntType(64);  } break;
+	case TK_U128: case TK_S128: { return LLVMIntType(128); } break;
+	case TK_F16:  { return LLVMHalfType();   } break;
+	case TK_F32:  { return LLVMFloatType();  } break;
+	case TK_F64:  { return LLVMDoubleType(); } break;
+	case TK_F128: { return LLVMFP128Type();  } break;
+	default: { return NULL; } break;
+	}
+}
diff --git a/src/parse.c b/src/parse.c
index f394045..a8b7676 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1,16 +1,16 @@
-// parser.c
+// parse.c
 // Parser source file for G
 // Copyright (C) 2021, Jakob Wakeling
 // All rights reserved.
 

 
-#include "cll/cll.h"
 #include "g.h"
 #include "type.h"
 #include "util/stack.h"
 #include "value.h"
 
+#include "cll/cll.h"
 #include "cll/error.h"
 
 #include <stdio.h>
@@ -20,41 +20,33 @@
 char *ast_ks[] = {
 	"AK_NIL",
 
-	"AK_DECL", "AK_ASSN", "AK_COMP",
+	"AK_DECL", "AK_COMPOUND",
 
 	"AK_INT", "AK_FLT",
 
-	"AK_VARIABLE",
-	"AK_CONSTANT",
-	"AK_PROCEDURE",
-	
-	"AK_RETURN",
+	"AK_PROC", "AK_RETURN",
 };
 
 static ast *parse_decl(lex *l);
 
 static ast *parse_stmt(lex *l);
-static ast *parse_stmt_comp(lex *l);
+static ast *parse_stmt_compound(lex *l);
 
 static ast *parse_expr(lex *l);
 
 static ast *parse_proc(lex *l);
-static ast *parse_proc_parm(lex *l);
-static ast *parse_proc_rett(lex *l);
 
 static ast *parse_int(lex *l);
 
 ast *ast_init() { return calloc(1, sizeof (ast)); }
 void ast_free(ast *a) { stack_free(a->cs); free(a); return; }
 
-/* prog            = { decl } ; */
+/* Parse a program. */
 ast *parse(lex *l) {
 	return parse_decl(l);
 }
 
-/* decl            = iden, ":", decl_variable | decl_constant ; */
-/* decl_constant   = [ type ], ":", expr, ";" ; */
-/* decl_variable   = ( type, [ "=", expr ] ) | ( "=", expr ), ";" ; */
+/* Parse a declaration. */
 static ast *parse_decl(lex *l) {
 	ast *a = ast_init();
 
@@ -65,45 +57,43 @@ static ast *parse_decl(lex *l) {
 	switch (lex_peek(l).k) {
 	case LK_COLON:  { lex_kind(l, LK_COLON);  a->k = AK_DECL; } goto decl_expr;
 	case LK_EQUALS: { lex_kind(l, LK_EQUALS); a->k = AK_DECL; } goto decl_expr;
-	decl_expr: { a->cl = parse_expr(l); } break;
+	decl_expr: { a->c = parse_expr(l); } break;
 	default: { error(
-		1, "%zu:%zu: Unexpected: \"%s\" (parser_parse_decl)",
+		1, "%zu:%zu: Unexpected: \"%s\" (parse_decl)",
 		lex_peek(l).p.ln, lex_peek(l).p.cl, tok_ks[lex_peek(l).k]
 	); } break;
 	}
 
-	return a;
+	if (a->c->k == AK_PROC) { a->c->s = a->s; } return a;
 }
 
 /* Parse a statement. */
 static ast *parse_stmt(lex *l) {
+	if (lex_peek(l).k == LK_LBRACE) { return parse_stmt_compound(l); }
+	
 	ast *a = ast_init();
 
 	switch (lex_peek(l).k) {
-	case LK_RETURN: { a->k = AK_RETURN; lex_kind(l, LK_RETURN); a->c = parse_expr(l); } break;
+	case LK_RETURN: { lex_kind(l, LK_RETURN); a->k = AK_RETURN; a->c = parse_expr(l); } break;
 	default: { error(
-		1, "%zu:%zu: Unexpected: \"%s\" (parser_parse_stmt)",
+		1, "%zu:%zu: Unexpected: \"%s\" (parse_stmt)",
 		lex_peek(l).p.ln, lex_peek(l).p.cl, tok_ks[lex_peek(l).k]
 	); } break;
 	}
 
-	return a;
+	lex_kind(l, LK_SCOLON); return a;
 }
 
 /* Parse a compound statement. */
-static ast *parse_stmt_comp(lex *l) {
+static ast *parse_stmt_compound(lex *l) {
 	lex_kind(l, LK_LBRACE);
-	ast *a = ast_init(); a->k = AK_COMP;
+	ast *a = ast_init(); a->k = AK_COMPOUND;
+	
 	a->cs = stack_init();
 
-	/* Parse statements and expressions until EOF or closing brace */
+	/* Parse statements until EOF or closing brace */
 	for (; lex_peek(l).k != LK_EOF && lex_peek(l).k != LK_RBRACE;) {
-		switch (lex_peek(l).k) {
-		case LK_RETURN: { stack_push(a->cs, parse_stmt(l)); } break;
-		default: { stack_push(a->cs, parse_expr(l)); } break;
-		}
-		
-		if (lex_peek(l).k == LK_SCOLON) { lex_kind(l, LK_SCOLON); }
+		stack_push(a->cs, parse_stmt(l));
 	}
 
 	lex_kind(l, LK_RBRACE); return a;
@@ -117,7 +107,7 @@ static ast *parse_expr(lex *l) {
 	case LK_PROC: { return parse_proc(l); } break;
 	case LK_INT: { return parse_int(l); } break;
 	default: { error(
-		1, "%zu:%zu: Unexpected: \"%s\" (parser_parse_expr_fact)",
+		1, "%zu:%zu: Unexpected: \"%s\" (parse_expr)",
 		lex_peek(l).p.ln, lex_peek(l).p.cl, tok_ks[lex_peek(l).k]
 	); } break;
 	}
@@ -127,20 +117,15 @@ static ast *parse_expr(lex *l) {
 
 /* Parse a procedure. */
 static ast *parse_proc(lex *l) {
-	lex_kind(l, LK_PROC);
-	ast *a = ast_init(); a->k = AK_PROCEDURE;
+	lex_kind(l, LK_PROC); lex_kind(l, LK_LPAREN);
+	ast *a = ast_init(); a->k = AK_PROC;
 
-	lex_kind(l, LK_LPAREN);
 	a->cs = stack_init();
 
 	/* Parse optional procedure parameter(s) */
+	/* TODO parse parameters(s) */
 	if (lex_peek(l).k != LK_RPAREN) {
-		stack_push(a->cs, parse_proc_parm(l));
-		
-		while (lex_peek(l).k == LK_COMMA) {
-			lex_kind(l, LK_COMMA);
-			stack_push(a->cs, parse_proc_parm(l));
-		}
+		error(1, "UNIMPLEMENTED (parse_proc)");
 	}
 
 	lex_kind(l, LK_RPAREN);
@@ -154,19 +139,7 @@ static ast *parse_proc(lex *l) {
 		lex_kind(l, LK_IDN); a->t = t_s64;
 	}
 
-	a->c = parse_stmt_comp(l);
-	
-	return a;
-}
-
-/* Parse a procedure parameter. */
-static ast *parse_proc_parm(lex *l) {
-	return NULL; /* TODO */
-}
-
-/* Parse a procedure return type. */
-static ast *parse_proc_rett(lex *l) {
-	return NULL; /* TODO */
+	a->c = parse_stmt_compound(l); return a;
 }
 
 static ast *parse_int(lex *l) {
diff --git a/src/type.c b/src/type.c
index c15934b..18c6225 100644
--- a/src/type.c
+++ b/src/type.c
@@ -10,71 +10,71 @@
 #include <stdlib.h>
 
 static type types[] = {
-	{ TK_VOID, 0,       0, "void" },
-	{ TK_PTR,  TF_PTR, -1, "ptr"  },
-	{ TK_TYPE, 0,      -1, "type" },
-	{ TK_ANY,  0,      -1, "any"  },
+	{ TK_VOID, 0,       0, (u8 *)"void" },
+	{ TK_PTR,  TF_PTR, -1, (u8 *)"ptr"  },
+	{ TK_TYPE, 0,      -1, (u8 *)"type" },
+	{ TK_ANY,  0,      -1, (u8 *)"any"  },
 
-	{ TK_BOOL, TF_BOOL, 1, "bool" },
-	{ TK_B8,   TF_BOOL, 1, "b8"   },
-	{ TK_B16,  TF_BOOL, 2, "b16"  },
-	{ TK_B32,  TF_BOOL, 4, "b32"  },
-	{ TK_B64,  TF_BOOL, 8, "b64"  },
+	{ TK_BOOL, TF_BOOL, 1, (u8 *)"bool" },
+	{ TK_B8,   TF_BOOL, 1, (u8 *)"b8"   },
+	{ TK_B16,  TF_BOOL, 2, (u8 *)"b16"  },
+	{ TK_B32,  TF_BOOL, 4, (u8 *)"b32"  },
+	{ TK_B64,  TF_BOOL, 8, (u8 *)"b64"  },
 
-	{ TK_UINT, TF_INT, -1, "unt"  },
-	{ TK_U8,   TF_INT,  1, "u8"   },
-	{ TK_U16,  TF_INT,  2, "u16"  },
-	{ TK_U32,  TF_INT,  4, "u32"  },
-	{ TK_U64,  TF_INT,  8, "u64"  },
-	{ TK_U128, TF_INT, 16, "u128" },
+	{ TK_UINT, TF_INT, -1, (u8 *)"unt"  },
+	{ TK_U8,   TF_INT,  1, (u8 *)"u8"   },
+	{ TK_U16,  TF_INT,  2, (u8 *)"u16"  },
+	{ TK_U32,  TF_INT,  4, (u8 *)"u32"  },
+	{ TK_U64,  TF_INT,  8, (u8 *)"u64"  },
+	{ TK_U128, TF_INT, 16, (u8 *)"u128" },
 
-	{ TK_SINT, TF_INT | TF_SIGN, -1, "int"  },
-	{ TK_S8,   TF_INT | TF_SIGN,  1, "i8"   },
-	{ TK_S16,  TF_INT | TF_SIGN,  2, "i16"  },
-	{ TK_S32,  TF_INT | TF_SIGN,  4, "i32"  },
-	{ TK_S64,  TF_INT | TF_SIGN,  8, "i64"  },
-	{ TK_S128, TF_INT | TF_SIGN, 16, "i128" },
+	{ TK_SINT, TF_INT | TF_SIGN, -1, (u8 *)"int"  },
+	{ TK_S8,   TF_INT | TF_SIGN,  1, (u8 *)"i8"   },
+	{ TK_S16,  TF_INT | TF_SIGN,  2, (u8 *)"i16"  },
+	{ TK_S32,  TF_INT | TF_SIGN,  4, (u8 *)"i32"  },
+	{ TK_S64,  TF_INT | TF_SIGN,  8, (u8 *)"i64"  },
+	{ TK_S128, TF_INT | TF_SIGN, 16, (u8 *)"i128" },
 
-	{ TK_F16,  TF_FLT | TF_SIGN,  2, "f16"  },
-	{ TK_F32,  TF_FLT | TF_SIGN,  4, "f32"  },
-	{ TK_F64,  TF_FLT | TF_SIGN,  8, "f64"  },
-	{ TK_F128, TF_FLT | TF_SIGN, 16, "f128" },
+	{ TK_F16,  TF_FLT | TF_SIGN,  2, (u8 *)"f16"  },
+	{ TK_F32,  TF_FLT | TF_SIGN,  4, (u8 *)"f32"  },
+	{ TK_F64,  TF_FLT | TF_SIGN,  8, (u8 *)"f64"  },
+	{ TK_F128, TF_FLT | TF_SIGN, 16, (u8 *)"f128" },
 
-	{ TK_C32,  TF_FLT | TF_SIGN,  4, "c32"  },
-	{ TK_C64,  TF_FLT | TF_SIGN,  8, "c64"  },
-	{ TK_C128, TF_FLT | TF_SIGN, 16, "c128" },
-	{ TK_C256, TF_FLT | TF_SIGN, 32, "c256" },
+	{ TK_C32,  TF_FLT | TF_SIGN,  4, (u8 *)"c32"  },
+	{ TK_C64,  TF_FLT | TF_SIGN,  8, (u8 *)"c64"  },
+	{ TK_C128, TF_FLT | TF_SIGN, 16, (u8 *)"c128" },
+	{ TK_C256, TF_FLT | TF_SIGN, 32, (u8 *)"c256" },
 
-	{ TK_I16LE,  TF_INT | TF_SIGN | TF_LE,  2, "i16le"  },
-	{ TK_I32LE,  TF_INT | TF_SIGN | TF_LE,  4, "i32le"  },
-	{ TK_I64LE,  TF_INT | TF_SIGN | TF_LE,  8, "i64le"  },
-	{ TK_I128LE, TF_INT | TF_SIGN | TF_LE, 16, "i128le" },
-	{ TK_I16BE,  TF_INT | TF_SIGN | TF_BE,  2, "i16be"  },
-	{ TK_I32BE,  TF_INT | TF_SIGN | TF_BE,  4, "i32be"  },
-	{ TK_I64BE,  TF_INT | TF_SIGN | TF_BE,  8, "i64be"  },
-	{ TK_I128BE, TF_INT | TF_SIGN | TF_BE, 16, "i128be" },
+	{ TK_I16LE,  TF_INT | TF_SIGN | TF_LE,  2, (u8 *)"i16le"  },
+	{ TK_I32LE,  TF_INT | TF_SIGN | TF_LE,  4, (u8 *)"i32le"  },
+	{ TK_I64LE,  TF_INT | TF_SIGN | TF_LE,  8, (u8 *)"i64le"  },
+	{ TK_I128LE, TF_INT | TF_SIGN | TF_LE, 16, (u8 *)"i128le" },
+	{ TK_I16BE,  TF_INT | TF_SIGN | TF_BE,  2, (u8 *)"i16be"  },
+	{ TK_I32BE,  TF_INT | TF_SIGN | TF_BE,  4, (u8 *)"i32be"  },
+	{ TK_I64BE,  TF_INT | TF_SIGN | TF_BE,  8, (u8 *)"i64be"  },
+	{ TK_I128BE, TF_INT | TF_SIGN | TF_BE, 16, (u8 *)"i128be" },
 
-	{ TK_U16LE,  TF_INT | TF_LE,  2, "u16le"  },
-	{ TK_U32LE,  TF_INT | TF_LE,  4, "u32le"  },
-	{ TK_U64LE,  TF_INT | TF_LE,  8, "u64le"  },
-	{ TK_U128LE, TF_INT | TF_LE, 16, "u128le" },
-	{ TK_U16BE,  TF_INT | TF_BE,  2, "u16be"  },
-	{ TK_U32BE,  TF_INT | TF_BE,  4, "u32be"  },
-	{ TK_U64BE,  TF_INT | TF_BE,  8, "u64be"  },
-	{ TK_U128BE, TF_INT | TF_BE, 16, "u128be" },
+	{ TK_U16LE,  TF_INT | TF_LE,  2, (u8 *)"u16le"  },
+	{ TK_U32LE,  TF_INT | TF_LE,  4, (u8 *)"u32le"  },
+	{ TK_U64LE,  TF_INT | TF_LE,  8, (u8 *)"u64le"  },
+	{ TK_U128LE, TF_INT | TF_LE, 16, (u8 *)"u128le" },
+	{ TK_U16BE,  TF_INT | TF_BE,  2, (u8 *)"u16be"  },
+	{ TK_U32BE,  TF_INT | TF_BE,  4, (u8 *)"u32be"  },
+	{ TK_U64BE,  TF_INT | TF_BE,  8, (u8 *)"u64be"  },
+	{ TK_U128BE, TF_INT | TF_BE, 16, (u8 *)"u128be" },
 
-	{ TK_F16LE,  TF_FLT | TF_SIGN | TF_LE,  2, "f16le"  },
-	{ TK_F32LE,  TF_FLT | TF_SIGN | TF_LE,  4, "f32le"  },
-	{ TK_F64LE,  TF_FLT | TF_SIGN | TF_LE,  8, "f64le"  },
-	{ TK_F128LE, TF_FLT | TF_SIGN | TF_LE, 16, "f128le" },
-	{ TK_F16BE,  TF_FLT | TF_SIGN | TF_BE,  2, "f16be"  },
-	{ TK_F32BE,  TF_FLT | TF_SIGN | TF_BE,  4, "f32be"  },
-	{ TK_F64BE,  TF_FLT | TF_SIGN | TF_BE,  8, "f64be"  },
-	{ TK_F128BE, TF_FLT | TF_SIGN | TF_BE, 16, "f128be" },
+	{ TK_F16LE,  TF_FLT | TF_SIGN | TF_LE,  2, (u8 *)"f16le"  },
+	{ TK_F32LE,  TF_FLT | TF_SIGN | TF_LE,  4, (u8 *)"f32le"  },
+	{ TK_F64LE,  TF_FLT | TF_SIGN | TF_LE,  8, (u8 *)"f64le"  },
+	{ TK_F128LE, TF_FLT | TF_SIGN | TF_LE, 16, (u8 *)"f128le" },
+	{ TK_F16BE,  TF_FLT | TF_SIGN | TF_BE,  2, (u8 *)"f16be"  },
+	{ TK_F32BE,  TF_FLT | TF_SIGN | TF_BE,  4, (u8 *)"f32be"  },
+	{ TK_F64BE,  TF_FLT | TF_SIGN | TF_BE,  8, (u8 *)"f64be"  },
+	{ TK_F128BE, TF_FLT | TF_SIGN | TF_BE, 16, (u8 *)"f128be" },
 
-	{ TK_CHAR, TF_INT | TF_CHAR,  1, "char" },
-	{ TK_RUNE, TF_INT | TF_CHAR,  4, "rune" },
-	{ TK_STR,  TF_STR,           -1, "str"  },
+	{ TK_CHAR, TF_INT | TF_CHAR,  1, (u8 *)"char" },
+	{ TK_RUNE, TF_INT | TF_CHAR,  4, (u8 *)"rune" },
+	{ TK_STR,  TF_STR,           -1, (u8 *)"str"  },
 };
 
 type *t_void = &types[TK_VOID]; type *t_ptr  = &types[TK_PTR];