about summary refs log tree commit diff stats
path: root/wrapperhelper/src/parse.c
diff options
context:
space:
mode:
authorrajdakin <rajdakin@gmail.com>2024-09-30 12:31:45 +0200
committerGitHub <noreply@github.com>2024-09-30 12:31:45 +0200
commit4715ef2633534a0427a1e92006a09fde5c3faf44 (patch)
treeb3fe587555e1979d48df6666533f11496161b859 /wrapperhelper/src/parse.c
parent703d19b256bc533d73cf4f206e5c443579aaf4c1 (diff)
downloadbox64-4715ef2633534a0427a1e92006a09fde5c3faf44.tar.gz
box64-4715ef2633534a0427a1e92006a09fde5c3faf44.zip
[WRAPPERHELPER] Added box32 and line number support in the wrapperhelper (#1890)
Diffstat (limited to 'wrapperhelper/src/parse.c')
-rw-r--r--wrapperhelper/src/parse.c1064
1 files changed, 571 insertions, 493 deletions
diff --git a/wrapperhelper/src/parse.c b/wrapperhelper/src/parse.c
index 0254d8df..8f593f22 100644
--- a/wrapperhelper/src/parse.c
+++ b/wrapperhelper/src/parse.c
@@ -12,7 +12,7 @@
 void dump_prepare(const char *filename, FILE *file) {
 	prepare_t *prep = prepare_new_file(file, filename);
 	if (!prep) {
-		printf("Failed to create the prepare structure\n");
+		log_memory("failed to create the prepare structure\n");
 		return;
 	}
 	while (1) {
@@ -30,7 +30,7 @@ void dump_preproc(machine_t *target, const char *filename, FILE *file) {
 	char *dirname = strchr(filename, '/') ? strndup(filename, (size_t)(strrchr(filename, '/') - filename)) : NULL;
 	preproc_t *prep = preproc_new_file(target, file, dirname, filename);
 	if (!prep) {
-		printf("Failed to create the preproc structure\n");
+		log_memory("failed to create the preproc structure\n");
 		if (dirname) free(dirname);
 		return;
 	}
@@ -90,29 +90,31 @@ VECTOR_IMPL_STATIC(size_t, (void))
 #define VALIDATION_DECL 1
 #define VALIDATION_LAST_DECL 2
 #define VALIDATION_FUN 3
-static int validate_storage_type(machine_t *target, enum decl_storage storage,
+static int validate_storage_type(loginfo_t *loginfo, machine_t *target, enum decl_storage storage,
                                  type_t *typ, enum token_sym_type_e sym) {
 	// We may still do adjustments here
-	if (!validate_type(target, typ)) return 0;
+	if (!validate_type(loginfo, target, typ)) return 0;
 	if (typ->typ == TYPE_FUNCTION) {
 		if ((storage == TMPSTO_TLS) || (storage == TMPSTO_TLS_EXTERN) || (storage == TMPSTO_TLS_STATIC)) {
-			printf("Error: functions cannot be thread local\n");
+			log_error(loginfo, "functions cannot be thread local\n");
 			return 0;
 		}
 		if ((sym == SYM_COMMA) || (sym == SYM_RPAREN) || (sym == SYM_SEMICOLON)) {
 			return (sym == SYM_SEMICOLON) ? VALIDATION_LAST_DECL : VALIDATION_DECL;
 		} else if (sym == SYM_LBRACKET) {
 			return VALIDATION_FUN;
+		} else {
+			log_error(loginfo, "unexpected symbol %s (%u) after function declaration\n", sym2str[sym], sym);
+			return 0;
 		}
 	} else {
 		if ((sym == SYM_COMMA) || (sym == SYM_RPAREN) || (sym == SYM_SEMICOLON) || ((storage != TMPSTO_TYPEDEF) && (sym == SYM_EQ))) {
 			return (sym == SYM_SEMICOLON) ? VALIDATION_LAST_DECL : VALIDATION_DECL;
+		} else {
+			log_error(loginfo, "unexpected symbol %s (%u) after %s declaration\n", sym2str[sym], sym, (storage == TMPSTO_TYPEDEF) ? "type" : "variable");
+			return 0;
 		}
 	}
-	printf("TODO: validate_storage_type on storage %u, sym %s (%u), valid type ", storage, sym2str[sym], sym);
-	type_print(typ);
-	printf("\n");
-	return 0;
 }
 
 static void promote_csts(num_constant_t *v1, num_constant_t *v2) {
@@ -197,6 +199,8 @@ static void promote_csts(num_constant_t *v1, num_constant_t *v2) {
 	}
 }
 
+#define TOKEN_MATCH_ATTR(attr) (!strcmp(string_content(tok->tokv.str), #attr) || !strcmp(string_content(tok->tokv.str), "__" #attr "__"))
+
 VECTOR_DECLARE_STATIC(exprs, expr_t*)
 #define expr_del_ptr(p) expr_del(*(p))
 VECTOR_IMPL_STATIC(exprs, expr_del_ptr)
@@ -310,95 +314,6 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s
         type_t *(*builtins)[LAST_BUILTIN + 1], khash_t(const_map) *const_map,
         khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, enum decl_storage *storage, enum fun_spec *fspec, enum decl_spec *spec, type_t *typ);
 
-
-void expr_print(expr_t *e) {
-	switch (e->typ) {
-	case ETY_VAR: printf("%s", string_content(e->val.var)); break;
-	case ETY_CONST:
-		switch (e->val.cst.typ) {
-		case NCT_FLOAT: printf("%ff", e->val.cst.val.f); break;
-		case NCT_DOUBLE: printf("%f", e->val.cst.val.d); break;
-		case NCT_LDOUBLE: printf("%Lfl", e->val.cst.val.l); break;
-		case NCT_INT32: printf("%d", e->val.cst.val.i32); break;
-		case NCT_UINT32: printf("%uu", e->val.cst.val.u32); break;
-		case NCT_INT64: printf("%ldll", e->val.cst.val.i64); break;
-		case NCT_UINT64: printf("%lullu", e->val.cst.val.u64); break;
-		}
-		break;
-	case ETY_CALL: printf("(call)"); break;
-	case ETY_ACCESS: printf("(.)"); break;
-	case ETY_PTRACCESS: printf("(->)"); break;
-	case ETY_UNARY:
-		switch (e->val.unary.typ) {
-		case UOT_POSTINCR: printf("(++)"); expr_print(e->val.unary.e); break;
-		case UOT_POSTDECR: printf("(--)"); expr_print(e->val.unary.e); break;
-		case UOT_PREINCR: printf("++"); expr_print(e->val.unary.e); break;
-		case UOT_PREDECR: printf("--"); expr_print(e->val.unary.e); break;
-		case UOT_REF: printf("&"); expr_print(e->val.unary.e); break;
-		case UOT_POS: printf("(+)"); expr_print(e->val.unary.e); break;
-		case UOT_NEG: printf("(-)"); expr_print(e->val.unary.e); break;
-		case UOT_DEREF: printf("(*)"); expr_print(e->val.unary.e); break;
-		case UOT_ANOT: printf("~"); expr_print(e->val.unary.e); break;
-		case UOT_BNOT: printf("!"); expr_print(e->val.unary.e); break;
-		}
-		break;
-	case ETY_BINARY: {
-		printf("(");
-		expr_print(e->val.binary.e1);
-		switch (e->val.binary.typ) {
-		case BOT_ADD: printf(") + ("); break;
-		case BOT_SUB: printf(") - ("); break;
-		case BOT_MUL: printf(") * ("); break;
-		case BOT_DIV: printf(") / ("); break;
-		case BOT_MOD: printf(") %% ("); break;
-		case BOT_LSH: printf(") << ("); break;
-		case BOT_RSH: printf(") >> ("); break;
-		case BOT_LT: printf(") < ("); break;
-		case BOT_GT: printf(") > ("); break;
-		case BOT_LE: printf(") <= ("); break;
-		case BOT_GE: printf(") >= ("); break;
-		case BOT_EQ: printf(") == ("); break;
-		case BOT_NE: printf(") != ("); break;
-		case BOT_AAND: printf(") & ("); break;
-		case BOT_AXOR: printf(") ^ ("); break;
-		case BOT_AOR: printf(") | ("); break;
-		case BOT_BAND: printf(") && ("); break;
-		case BOT_BOR: printf(") || ("); break;
-		case BOT_ASSGN_EQ: printf(") = ("); break;
-		case BOT_ASSGN_ADD: printf(") += ("); break;
-		case BOT_ASSGN_SUB: printf(") -= ("); break;
-		case BOT_ASSGN_MUL: printf(") *= ("); break;
-		case BOT_ASSGN_DIV: printf(") /= ("); break;
-		case BOT_ASSGN_MOD: printf(") %%= ("); break;
-		case BOT_ASSGN_LSH: printf(") <<= ("); break;
-		case BOT_ASSGN_RSH: printf(") >>= ("); break;
-		case BOT_ASSGN_AAND: printf(") &= ("); break;
-		case BOT_ASSGN_AXOR: printf(") ^= ("); break;
-		case BOT_ASSGN_AOR: printf(") |= ("); break;
-		case BOT_COMMA: printf("), ("); break;
-		case BOT_ARRAY: printf(")["); break;
-		}
-		expr_print(e->val.binary.e2);
-		printf(e->val.binary.typ == BOT_ARRAY ? "]" : ")");
-		break; }
-	case ETY_TERNARY: {
-		printf("(");
-		expr_print(e->val.ternary.e1);
-		switch (e->val.ternary.typ) {
-		case TOT_COND: printf(") ? "); break;
-		}
-		expr_print(e->val.ternary.e2);
-		switch (e->val.ternary.typ) {
-		case TOT_COND: printf(" : ("); break;
-		}
-		expr_print(e->val.ternary.e3);
-		printf(")");
-		break; }
-	case ETY_CAST: printf("("); type_print(e->val.cast.typ); printf(")"); expr_print(e->val.cast.e); break;
-	}
-}
-
-
 static int is_type_spec_qual_kw(enum token_keyword_type_e kw) {
 	return
 		(kw == KW_ATOMIC)    ||
@@ -437,7 +352,7 @@ static int parse_type_name(machine_t *target, khash_t(struct_map) *struct_map, k
 	}
 	*typ = type_try_merge(*typ, type_set);
 	if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == end_sym)) {
-		return validate_type(target, *typ);
+		return validate_type(&tok->loginfo, target, *typ);
 	}
 	struct parse_declarator_dest_s dest2;
 	dest2.argt.dest = NULL;
@@ -454,18 +369,20 @@ static int parse_type_name(machine_t *target, khash_t(struct_map) *struct_map, k
 	}
 	type_del(*typ);
 	if (!dest2.argt.dest) {
-		printf("Internal error: argument type is NULL\n");
+		log_internal(&tok->loginfo, "parse_type_name: argument type is NULL\n");
 		// Empty destructor
 		goto failed;
 	}
 	if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != end_sym)) {
+		log_error(&tok->loginfo, "invalid token %s %u after type name\n",
+		            (tok->tokt == PTOK_SYM) ? "symbol" : "type", (tok->tokt == PTOK_SYM) ? tok->tokv.sym : tok->tokt);
 		type_del(dest2.argt.dest);
 		proc_token_del(tok);
 		goto failed;
 	}
 	*typ = dest2.argt.dest;
 	*typ = type_try_merge(*typ, type_set);
-	return validate_type(target, *typ);
+	return validate_type(&tok->loginfo, target, *typ);
 	
 failed:
 	return 0;
@@ -476,13 +393,13 @@ static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_m
         khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, int expr_level) {
 	// Note that expr_level >= 1; expr_level = 0 doesn't appear in the grammar
 	if ((expr_level < 1) || (expr_level > 16)) {
-		printf("Internal error: invalid expression level %d\n", expr_level);
+		log_internal(&tok->loginfo, "Internal error: invalid expression level %d\n", expr_level);
 		return NULL;
 	}
 	
 	VECTOR(expr_pops) *op_stack = vector_new(expr_pops);
 	if (!op_stack) {
-		printf("Error: failed to create operation stack");
+		log_memory("failed to create operation stack");
 		proc_token_del(tok);
 		return NULL;
 	}
@@ -494,18 +411,16 @@ pushed_expr:
 	e = NULL;
 	
 expr_new_token:
-	// printf("expr_new_token with level %d / %d\n", has_level, expr_level);
-	// proc_token_print(tok);
 	if (tok->tokt == PTOK_IDENT) {
 		if (has_level != -1) {
-			printf("Error: invalid expression: unexpected identifier '%s'\n", string_content(tok->tokv.str));
+			log_error(&tok->loginfo, "invalid expression: unexpected identifier '%s'\n", string_content(tok->tokv.str));
 			string_del(tok->tokv.str);
 			goto failed;
 		}
 		has_level = 0;
 		e = malloc(sizeof *e);
 		if (!e) {
-			printf("Error: failed to create new expression atom\n");
+			log_memory("failed to create new expression atom\n");
 			string_del(tok->tokv.str);
 			goto failed;
 		}
@@ -515,19 +430,19 @@ expr_new_token:
 		goto expr_new_token;
 	} else if (tok->tokt == PTOK_NUM) {
 		if (has_level != -1) {
-			printf("Error: invalid expression: unexpected number '%s'\n", string_content(tok->tokv.str));
+			log_error(&tok->loginfo, "invalid expression: unexpected number '%s'\n", string_content(tok->tokv.str));
 			string_del(tok->tokv.str);
 			goto failed;
 		}
 		has_level = 0;
 		e = malloc(sizeof *e);
 		if (!e) {
-			printf("Error: failed to create new expression atom\n");
+			log_memory("failed to create new expression atom\n");
 			string_del(tok->tokv.str);
 			goto failed;
 		}
 		e->typ = ETY_CONST;
-		if (!num_constant_convert(tok->tokv.str, &e->val.cst, target->size_long == 4)) {
+		if (!num_constant_convert(&tok->loginfo, tok->tokv.str, &e->val.cst, target->size_long == 4)) {
 			string_del(tok->tokv.str);
 			goto failed;
 		}
@@ -536,19 +451,19 @@ expr_new_token:
 		goto expr_new_token;
 	} else if ((tok->tokt == PTOK_STRING) && !tok->tokv.sisstr) {
 		if (has_level != -1) {
-			printf("Error: invalid expression: unexpected character constant '%s'\n", string_content(tok->tokv.sstr));
+			log_error(&tok->loginfo, "invalid expression: unexpected character constant '%s'\n", string_content(tok->tokv.sstr));
 			string_del(tok->tokv.sstr);
 			goto failed;
 		}
 		if (string_len(tok->tokv.sstr) != 1) {
-			printf("Error: TODO: invalid expression: multibyte character constant '%s'\n", string_content(tok->tokv.sstr));
+			log_TODO(&tok->loginfo, "invalid expression: multibyte character constant '%s'\n", string_content(tok->tokv.sstr));
 			string_del(tok->tokv.sstr);
 			goto failed;
 		}
 		has_level = 0;
 		e = malloc(sizeof *e);
 		if (!e) {
-			printf("Error: failed to create new expression atom\n");
+			log_memory("failed to create new expression atom\n");
 			string_del(tok->tokv.sstr);
 			goto failed;
 		}
@@ -570,7 +485,7 @@ expr_new_token:
 				.val.unop = opt                                                            \
 			};                                                                             \
 			if (!vector_push(expr_pops, op_stack, pop)) {                                  \
-				printf("Error: failed to add partial operation to operation stack\n");     \
+				log_memory("failed to add partial operation to operation stack\n");     \
 				/* Empty destructor */                                                     \
 				goto failed;                                                               \
 			}                                                                              \
@@ -589,7 +504,7 @@ expr_new_token:
 				.val.binop = {.op = opt, .e1 = e}                                          \
 			};                                                                             \
 			if (!vector_push(expr_pops, op_stack, pop)) {                                  \
-				printf("Error: failed to add partial operation to operation stack\n");     \
+				log_memory("failed to add partial operation to operation stack\n");     \
 				/* Empty destructor */                                                     \
 				goto failed;                                                               \
 			}                                                                              \
@@ -598,12 +513,13 @@ expr_new_token:
 			goto pushed_expr;                                                              \
 		}                                                                                  \
 	}
+	
 	if ((expr_level >= 1) && (tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_PLUSPLUS)) {
 		if ((has_level != -1) && (has_level <= 1)) {
 			has_level = 1;
 			expr_t *new_e = malloc(sizeof *new_e);
 			if (!new_e) {
-				printf("Error: failed to create new expression atom\n");
+				log_memory("failed to create new expression atom\n");
 				string_del(tok->tokv.str);
 				goto failed;
 			}
@@ -620,7 +536,7 @@ expr_new_token:
 			has_level = 1;
 			expr_t *new_e = malloc(sizeof *new_e);
 			if (!new_e) {
-				printf("Error: failed to create new expression atom\n");
+				log_memory("failed to create new expression atom\n");
 				string_del(tok->tokv.str);
 				goto failed;
 			}
@@ -641,7 +557,7 @@ expr_new_token:
 				.val.binop = {.last_sym = SYM_RSQBRACKET, .op = BOT_ARRAY, .e1 = e}
 			};
 			if (!vector_push(expr_pops, op_stack, pop)) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				/* Empty destructor */
 				goto failed;
 			}
@@ -657,13 +573,13 @@ expr_new_token:
 			
 			*tok = proc_next_token(prep);
 			if (tok->tokt != PTOK_IDENT) {
-				printf("Error: invalid expression: unexpected token after access symbol\n");
+				log_error(&tok->loginfo, "invalid expression: unexpected token after access symbol\n");
 				proc_token_del(tok);
 				goto failed;
 			}
 			expr_t *new_e = malloc(sizeof *new_e);
 			if (!new_e) {
-				printf("Error: failed to create new expression atom\n");
+				log_memory("failed to create new expression atom\n");
 				string_del(tok->tokv.str);
 				goto failed;
 			}
@@ -683,24 +599,24 @@ expr_new_token:
 	UNOP(SYM_STAR,     UOT_DEREF,   2, 3)
 	UNOP(SYM_TILDE,    UOT_ANOT,    2, 3)
 	UNOP(SYM_EXCL,     UOT_BNOT,    2, 3)
-	BINOP(SYM_STAR,     BOT_MUL,    4,  4,  3)
-	BINOP(SYM_SLASH,    BOT_DIV,    4,  4,  3)
-	BINOP(SYM_PERCENT,  BOT_MOD,    4,  4,  3)
-	BINOP(SYM_PLUS,     BOT_ADD,    5,  5,  4)
-	BINOP(SYM_DASH,     BOT_SUB,    5,  5,  4)
-	BINOP(SYM_LTLT,     BOT_LSH,    6,  6,  5)
-	BINOP(SYM_GTGT,     BOT_RSH,    6,  6,  5)
-	BINOP(SYM_LT,       BOT_LT,     7,  7,  6)
-	BINOP(SYM_GT,       BOT_GT,     7,  7,  6)
-	BINOP(SYM_LTEQ,     BOT_LE,     7,  7,  6)
-	BINOP(SYM_GTEQ,     BOT_GE,     7,  7,  6)
-	BINOP(SYM_EQEQ,     BOT_EQ,     8,  8,  7)
-	BINOP(SYM_EXCLEQ,   BOT_NE,     8,  8,  7)
-	BINOP(SYM_AMP,      BOT_AAND,   9,  9,  8)
-	BINOP(SYM_HAT,      BOT_AXOR,  10, 10,  9)
-	BINOP(SYM_PIPE,     BOT_AOR,   11, 11, 10)
-	BINOP(SYM_AMPAMP,   BOT_BAND,  12, 12, 11)
-	BINOP(SYM_PIPEPIPE, BOT_BOR,   13, 13, 12)
+	BINOP(SYM_STAR,      BOT_MUL,         4,  4,  3)
+	BINOP(SYM_SLASH,     BOT_DIV,         4,  4,  3)
+	BINOP(SYM_PERCENT,   BOT_MOD,         4,  4,  3)
+	BINOP(SYM_PLUS,      BOT_ADD,         5,  5,  4)
+	BINOP(SYM_DASH,      BOT_SUB,         5,  5,  4)
+	BINOP(SYM_LTLT,      BOT_LSH,         6,  6,  5)
+	BINOP(SYM_GTGT,      BOT_RSH,         6,  6,  5)
+	BINOP(SYM_LT,        BOT_LT,          7,  7,  6)
+	BINOP(SYM_GT,        BOT_GT,          7,  7,  6)
+	BINOP(SYM_LTEQ,      BOT_LE,          7,  7,  6)
+	BINOP(SYM_GTEQ,      BOT_GE,          7,  7,  6)
+	BINOP(SYM_EQEQ,      BOT_EQ,          8,  8,  7)
+	BINOP(SYM_EXCLEQ,    BOT_NE,          8,  8,  7)
+	BINOP(SYM_AMP,       BOT_AAND,        9,  9,  8)
+	BINOP(SYM_HAT,       BOT_AXOR,       10, 10,  9)
+	BINOP(SYM_PIPE,      BOT_AOR,        11, 11, 10)
+	BINOP(SYM_AMPAMP,    BOT_BAND,       12, 12, 11)
+	BINOP(SYM_PIPEPIPE,  BOT_BOR,        13, 13, 12)
 	if ((expr_level >= 14) && (tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_QUESTION)) {
 		if ((has_level != -1) && (has_level <= 13)) {
 			struct expr_partial_op pop = {
@@ -710,7 +626,7 @@ expr_new_token:
 				.val.ternop = {.arg23_sep = SYM_COLON, .once_done2_want_level = 14, .op = TOT_COND, .e1 = e}
 			};
 			if (!vector_push(expr_pops, op_stack, pop)) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				// Empty destructor
 				goto failed;
 			}
@@ -719,18 +635,18 @@ expr_new_token:
 			goto pushed_expr;
 		}
 	}
-	BINOP(SYM_EQ,        BOT_ASSGN_EQ,   15, 2, 15)
-	BINOP(SYM_STAREQ,    BOT_ASSGN_MUL,  15, 2, 15)
-	BINOP(SYM_SLASHEQ,   BOT_ASSGN_DIV,  15, 2, 15)
-	BINOP(SYM_PERCENTEQ, BOT_ASSGN_MOD,  15, 2, 15)
-	BINOP(SYM_PLUSEQ,    BOT_ASSGN_ADD,  15, 2, 15)
-	BINOP(SYM_DASHEQ,    BOT_ASSGN_SUB,  15, 2, 15)
-	BINOP(SYM_LTLTEQ,    BOT_ASSGN_LSH,  15, 2, 15)
-	BINOP(SYM_GTGTEQ,    BOT_ASSGN_RSH,  15, 2, 15)
-	BINOP(SYM_AMPEQ,     BOT_ASSGN_AAND, 15, 2, 15)
-	BINOP(SYM_HATEQ,     BOT_ASSGN_AXOR, 15, 2, 15)
-	BINOP(SYM_PIPEEQ,    BOT_ASSGN_AOR,  15, 2, 15)
-	BINOP(SYM_COMMA,    BOT_COMMA, 16, 16, 15)
+	BINOP(SYM_EQ,        BOT_ASSGN_EQ,   15,  2, 15)
+	BINOP(SYM_STAREQ,    BOT_ASSGN_MUL,  15,  2, 15)
+	BINOP(SYM_SLASHEQ,   BOT_ASSGN_DIV,  15,  2, 15)
+	BINOP(SYM_PERCENTEQ, BOT_ASSGN_MOD,  15,  2, 15)
+	BINOP(SYM_PLUSEQ,    BOT_ASSGN_ADD,  15,  2, 15)
+	BINOP(SYM_DASHEQ,    BOT_ASSGN_SUB,  15,  2, 15)
+	BINOP(SYM_LTLTEQ,    BOT_ASSGN_LSH,  15,  2, 15)
+	BINOP(SYM_GTGTEQ,    BOT_ASSGN_RSH,  15,  2, 15)
+	BINOP(SYM_AMPEQ,     BOT_ASSGN_AAND, 15,  2, 15)
+	BINOP(SYM_HATEQ,     BOT_ASSGN_AXOR, 15,  2, 15)
+	BINOP(SYM_PIPEEQ,    BOT_ASSGN_AOR,  15,  2, 15)
+	BINOP(SYM_COMMA,     BOT_COMMA,      16, 16, 15)
 	
 	// expr2 ::= sizeof expr2
 	// which includes expr2 ::= sizeof ( expr16 )
@@ -745,7 +661,7 @@ expr_new_token:
 				.val.c = '\0'
 			};
 			if (!vector_push(expr_pops, op_stack, pop)) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -758,7 +674,7 @@ expr_new_token:
 		if (IS_BEGIN_TYPE_NAME) {
 			type_t *typ = type_new();
 			if (!typ) {
-				printf("Error: failed to create new type info structure\n");
+				log_memory("failed to create new type info structure\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -766,14 +682,14 @@ expr_new_token:
 				goto failed;
 			}
 			if (!typ->is_validated || typ->is_incomplete || (typ->typ == TYPE_FUNCTION)) {
-				printf("Error: cannot get the size of a function or incomplete type\n");
+				log_error(&tok->loginfo, "cannot get the size of a function or incomplete type\n");
 				type_del(typ);
 				proc_token_del(tok);
 				goto failed;
 			}
 			e = malloc(sizeof *e);
 			if (!e) {
-				printf("Error: failed to create new expression atom\n");
+				log_memory("failed to create new expression atom\n");
 				type_del(typ);
 				proc_token_del(tok);
 				goto failed;
@@ -784,6 +700,7 @@ expr_new_token:
 			has_level = 2;
 			type_del(typ);
 			if (!e->val.cst.val.u64) {
+				log_internal(&tok->loginfo, "size of type is 0\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -798,7 +715,7 @@ expr_new_token:
 				.val.c = 0
 			};
 			if (!vector_push(expr_pops, op_stack, pop)) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -809,7 +726,7 @@ expr_new_token:
 				.val.c = 0
 			};
 			if (!vector_push(expr_pops, op_stack, pop)) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -821,7 +738,7 @@ expr_new_token:
 	if ((has_level == -1) && (expr_level >= 2) && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ALIGNOF)) {
 		*tok = proc_next_token(prep);
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) {
-			printf("Error: invalid _Alignof expression\n");
+			log_error(&tok->loginfo, "unexpected token, expected symbol '('\n");
 			proc_token_del(tok);
 			goto failed;
 		}
@@ -829,7 +746,7 @@ expr_new_token:
 		*tok = proc_next_token(prep);
 		type_t *typ = type_new();
 		if (!typ) {
-			printf("Error: failed to create new type info structure\n");
+			log_memory("failed to create new type info structure\n");
 			proc_token_del(tok);
 			goto failed;
 		}
@@ -837,14 +754,14 @@ expr_new_token:
 			goto failed;
 		}
 		if (!typ->is_validated || typ->is_incomplete || (typ->typ == TYPE_FUNCTION)) {
-			printf("Error: cannot get the alignment of a function or incomplete type\n");
+			log_error(&tok->loginfo, "cannot get the alignment of a function or incomplete type\n");
 			type_del(typ);
 			proc_token_del(tok);
 			goto failed;
 		}
 		e = malloc(sizeof *e);
 		if (!e) {
-			printf("Error: failed to create new expression atom\n");
+			log_memory("failed to create new expression atom\n");
 			type_del(typ);
 			proc_token_del(tok);
 			goto failed;
@@ -855,6 +772,7 @@ expr_new_token:
 		has_level = 2;
 		type_del(typ);
 		if (!e->val.cst.val.u64) {
+			log_internal(&tok->loginfo, "alignment of type is 0\n");
 			proc_token_del(tok);
 			goto failed;
 		}
@@ -876,7 +794,7 @@ expr_new_token:
 				expr_t *new_e = malloc(sizeof *new_e);
 				new_e = malloc(sizeof *new_e);
 				if (!new_e) {
-					printf("Error: failed to create new expression atom\n");
+					log_memory("failed to create new expression atom\n");
 					// Empty destructor
 					goto failed;
 				}
@@ -891,7 +809,7 @@ expr_new_token:
 			// We want a function call with at least one argument
 			VECTOR(exprs) *exprs = vector_new_cap(exprs, 1);
 			if (!exprs) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -902,7 +820,7 @@ expr_new_token:
 				.val.funcall = {.f = e, .exprs = exprs}
 			};
 			if (!vector_push(expr_pops, op_stack, pop)) {
-				printf("Error: failed to add partial operation to operation stack\n");
+				log_memory("failed to add partial operation to operation stack\n");
 				vector_del(exprs, exprs);
 				proc_token_del(tok);
 				goto failed;
@@ -916,7 +834,7 @@ expr_new_token:
 			if ((expr_level >= 1) && IS_BEGIN_TYPE_NAME) {
 				type_t *typ = type_new();
 				if (!typ) {
-					printf("Error: failed to create new type info structure\n");
+					log_memory("failed to create new type info structure\n");
 					proc_token_del(tok);
 					goto failed;
 				}
@@ -926,12 +844,12 @@ expr_new_token:
 					goto failed;
 				}
 				if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_LBRACKET)) {
-					printf("Error: TODO: initializer-list\n");
+					log_TODO(&tok->loginfo, "initializer-list\n");
 					type_del(typ);
 					proc_token_del(tok);
 					goto failed;
 				} else if (expr_level < 3) {
-					printf("Error: cast expression (level 3) but the expression level is at most 2\n");
+					log_error(&tok->loginfo, "cast expression (level 3) but the required expression level is 1 or 2 (expected symbol '{')\n");
 					type_del(typ);
 					proc_token_del(tok);
 					goto failed;
@@ -943,7 +861,7 @@ expr_new_token:
 						.val.typ = typ
 					};
 					if (!vector_push(expr_pops, op_stack, pop)) {
-						printf("Error: failed to add partial operation to operation stack\n");
+						log_memory("failed to add partial operation to operation stack\n");
 						/* Empty destructor */
 						goto failed;
 					}
@@ -959,7 +877,7 @@ expr_new_token:
 					.val.c = 0
 				};
 				if (!vector_push(expr_pops, op_stack, pop)) {
-					printf("Error: failed to add partial operation to operation stack\n");
+					log_memory("failed to add partial operation to operation stack\n");
 					proc_token_del(tok);
 					goto failed;
 				}
@@ -985,13 +903,13 @@ expr_new_token:
 				}
 				break;
 			case EPO_SIZEOF:
-				printf("Error: TODO: find type of expression\n");
+				log_TODO(&tok->loginfo, "find type of expression\n");
 				proc_token_del(tok);
 				goto failed;
 			case EPO_CAST:
 				new_e = malloc(sizeof *new_e);
 				if (!new_e) {
-					printf("Error: failed to create new expression atom\n");
+					log_memory("failed to create new expression atom\n");
 					proc_token_del(tok);
 					goto failed;
 				}
@@ -1009,13 +927,13 @@ expr_new_token:
 					has_level = pop->once_done_is_level;
 					expr_level = pop->once_done_want_level;
 					if (!vector_push(exprs, pop->val.funcall.exprs, e)) {
-						printf("Error: failed to add argument to argument stack\n");
+						log_memory("failed to add argument to argument stack\n");
 						// Empty destructor
 						goto failed;
 					}
 					e = malloc(sizeof *e);
 					if (!e) {
-						printf("Error: failed to create new expression atom\n");
+						log_memory("failed to create new expression atom\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -1029,7 +947,7 @@ expr_new_token:
 					goto expr_new_token;
 				} else if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_COMMA)) {
 					if (!vector_push(exprs, pop->val.funcall.exprs, e)) {
-						printf("Error: failed to add argument to argument stack\n");
+						log_memory("failed to add argument to argument stack\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -1042,7 +960,7 @@ expr_new_token:
 			case EPO_UNARY:
 				new_e = malloc(sizeof *new_e);
 				if (!new_e) {
-					printf("Error: failed to create new expression atom\n");
+					log_memory("failed to create new expression atom\n");
 					proc_token_del(tok);
 					goto failed;
 				}
@@ -1063,7 +981,7 @@ expr_new_token:
 			case EPO_BINARY_ARG:
 				new_e = malloc(sizeof *new_e);
 				if (!new_e) {
-					printf("Error: failed to create new expression atom\n");
+					log_memory("failed to create new expression atom\n");
 					proc_token_del(tok);
 					goto failed;
 				}
@@ -1090,7 +1008,7 @@ expr_new_token:
 			case EPO_TERNARY_ARG2:
 				new_e = malloc(sizeof *new_e);
 				if (!new_e) {
-					printf("Error: failed to create new expression atom\n");
+					log_memory("failed to create new expression atom\n");
 					proc_token_del(tok);
 					goto failed;
 				}
@@ -1113,15 +1031,14 @@ expr_new_token:
 		vector_del(expr_pops, op_stack);
 		return e;
 	}
-	printf("Error: invalid expression: unexpected token\n");
-	proc_token_print(tok);
+	log_error(&tok->loginfo, "invalid expression: unexpected token\n");
 	proc_token_del(tok);
 failed:
 	vector_del(expr_pops, op_stack);
 	if (e) expr_del(e);
 	return NULL;
 }
-static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constant_t *dest, int fatal) {
+static int eval_expression(loginfo_t *li, machine_t *target, expr_t *e, khash_t(const_map) *const_map, num_constant_t *dest, int fatal) {
 	// Evaluate the expression (we suppose it is constant)
 	switch (e->typ) {
 	case ETY_VAR: {
@@ -1130,7 +1047,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 			*dest = kh_val(const_map, it);
 			return 1;
 		}
-		if (fatal) printf("Error: failed to evaluate expression: expression is not constant (variable)\n");
+		if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (variable)\n");
 		return 0; }
 		
 	case ETY_CONST:
@@ -1140,18 +1057,16 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 	// case ETY_GENERIC:
 		
 	case ETY_CALL:
-		if (fatal) printf("Error: failed to evaluate expression: expression is not constant (function call)\n");
+		if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (function call)\n");
 		return 0;
 		
 	case ETY_ACCESS:
 	case ETY_PTRACCESS:
-		if (fatal) printf("Error: failed to evaluate expression: expression is not constant (member access)\n");
+		if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (member access)\n");
 		return 0;
 		
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wfloat-equal"
 	case ETY_UNARY:
-		if (!eval_expression(e->val.unary.e, const_map, dest, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.unary.e, const_map, dest, fatal)) return 0;
 		
 		switch (e->val.unary.typ) {
 		case UOT_POSTINCR:
@@ -1160,7 +1075,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 		case UOT_PREDECR:
 		case UOT_REF:
 		case UOT_DEREF:
-			if (fatal) printf("Error: failed to evaluate expression: expression is not constant (assignment or memory accesses)\n");
+			if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (assignment or memory accesses)\n");
 			return 0;
 		case UOT_POS:
 			return 1; // Nothing to do
@@ -1180,7 +1095,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 			case NCT_FLOAT:
 			case NCT_DOUBLE:
 			case NCT_LDOUBLE:
-				if (fatal) printf("Error: failed to evaluate expression: cannot bitwise-negate a floating point number\n");
+				if (fatal) log_error(li, "failed to evaluate expression: cannot bitwise-negate a floating point number\n");
 				return 0;
 			case NCT_INT32:  dest->val.i32 = ~dest->val.i32; return 1;
 			case NCT_UINT32: dest->val.u32 = ~dest->val.u32; return 1;
@@ -1190,9 +1105,12 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 			}
 		case UOT_BNOT:
 			switch (dest->typ) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
 			case NCT_FLOAT:   dest->typ = NCT_INT32; dest->val.i32 = !dest->val.f;   return 1;
 			case NCT_DOUBLE:  dest->typ = NCT_INT32; dest->val.i32 = !dest->val.d;   return 1;
 			case NCT_LDOUBLE: dest->typ = NCT_INT32; dest->val.i32 = !dest->val.l;   return 1;
+#pragma GCC diagnostic pop
 			case NCT_INT32:   dest->typ = NCT_INT32; dest->val.i32 = !dest->val.i32; return 1;
 			case NCT_UINT32:  dest->typ = NCT_INT32; dest->val.i32 = !dest->val.u32; return 1;
 			case NCT_INT64:   dest->typ = NCT_INT32; dest->val.i32 = !dest->val.i64; return 1;
@@ -1204,8 +1122,8 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 		
 	case ETY_BINARY: {
 		num_constant_t dest1, dest2;
-		if (!eval_expression(e->val.binary.e1, const_map, &dest1, fatal)) return 0;
-		if (!eval_expression(e->val.binary.e2, const_map, &dest2, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.binary.e1, const_map, &dest1, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.binary.e2, const_map, &dest2, fatal)) return 0;
 		
 		switch (e->val.binary.typ) {
 		case BOT_ASSGN_EQ:
@@ -1220,7 +1138,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 		case BOT_ASSGN_AXOR:
 		case BOT_ASSGN_AOR:
 		case BOT_ARRAY: // Is this possible?
-			if (fatal) printf("Error: failed to evaluate expression: expression is not constant (assignments)\n");
+			if (fatal) log_error(li, "failed to evaluate expression: expression is not constant (assignments)\n");
 			return 0;
 #define DOIT(op) \
 			promote_csts(&dest1, &dest2); \
@@ -1240,7 +1158,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 			case NCT_FLOAT: \
 			case NCT_DOUBLE: \
 			case NCT_LDOUBLE: \
-				if (fatal) printf("Error: failed to evaluate expression: binary operation %u incompatible with floating point numbers\n", e->val.binary.typ); \
+				if (fatal) log_error(li, "failed to evaluate expression: binary operation %u incompatible with floating point numbers\n", e->val.binary.typ); \
 				return 0; \
 			case NCT_INT32:   dest->val.i32 = dest1.val.i32 op dest2.val.i32; return 1; \
 			case NCT_UINT32:  dest->val.u32 = dest1.val.u32 op dest2.val.u32; return 1; \
@@ -1251,14 +1169,14 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 #define DOIT_BOOL(op) \
 			promote_csts(&dest1, &dest2); \
 			switch (dest1.typ) { \
-			case NCT_FLOAT:   dest->typ = NCT_INT32; dest->val.i32 = dest1.val.f   op dest2.val.f  ; return 1; \
-			case NCT_DOUBLE:  dest->typ = NCT_INT32; dest->val.i32 = dest1.val.d   op dest2.val.d  ; return 1; \
-			case NCT_LDOUBLE: dest->typ = NCT_INT32; dest->val.i32 = dest1.val.l   op dest2.val.l  ; return 1; \
-			case NCT_INT32:   dest->typ = NCT_INT32; dest->val.i32 = dest1.val.i32 op dest2.val.i32; return 1; \
-			case NCT_UINT32:  dest->typ = NCT_INT32; dest->val.i32 = dest1.val.u32 op dest2.val.u32; return 1; \
-			case NCT_INT64:   dest->typ = NCT_INT32; dest->val.i32 = dest1.val.i64 op dest2.val.i64; return 1; \
-			case NCT_UINT64:  dest->typ = NCT_INT32; dest->val.i32 = dest1.val.u64 op dest2.val.u64; return 1; \
-			default: return 0;                                                                                 \
+			case NCT_FLOAT:   dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.f   op dest2.val.f  ; return 1; \
+			case NCT_DOUBLE:  dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.d   op dest2.val.d  ; return 1; \
+			case NCT_LDOUBLE: dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.l   op dest2.val.l  ; return 1; \
+			case NCT_INT32:   dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.i32 op dest2.val.i32; return 1; \
+			case NCT_UINT32:  dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.u32 op dest2.val.u32; return 1; \
+			case NCT_INT64:   dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.i64 op dest2.val.i64; return 1; \
+			case NCT_UINT64:  dest->typ = NCT_UINT32; dest->val.u32 = dest1.val.u64 op dest2.val.u64; return 1; \
+			default: return 0;                                                                                  \
 			}
 		case BOT_ADD: DOIT(+)
 		case BOT_SUB: DOIT(-)
@@ -1271,13 +1189,19 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 		case BOT_GT: DOIT_BOOL(>)
 		case BOT_LE: DOIT_BOOL(<=)
 		case BOT_GE: DOIT_BOOL(>=)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
 		case BOT_EQ: DOIT_BOOL(==)
 		case BOT_NE: DOIT_BOOL(!=)
+#pragma GCC diagnostic pop
 		case BOT_AAND: DOIT_INT(&)
 		case BOT_AXOR: DOIT_INT(^)
 		case BOT_AOR: DOIT_INT(|)
-		case BOT_BAND: DOIT(&&)
-		case BOT_BOR: DOIT(||)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+		case BOT_BAND: DOIT_BOOL(&&)
+		case BOT_BOR: DOIT_BOOL(||)
+#pragma GCC diagnostic pop
 		case BOT_COMMA: *dest = dest2; return 1;
 #undef DOIT_BOOL
 #undef DOIT_INT
@@ -1287,17 +1211,20 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 		
 	case ETY_TERNARY: {
 		num_constant_t dest1, dest2, dest3;
-		if (!eval_expression(e->val.ternary.e1, const_map, &dest1, fatal)) return 0;
-		if (!eval_expression(e->val.ternary.e2, const_map, &dest2, fatal)) return 0;
-		if (!eval_expression(e->val.ternary.e3, const_map, &dest3, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.ternary.e1, const_map, &dest1, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.ternary.e2, const_map, &dest2, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.ternary.e3, const_map, &dest3, fatal)) return 0;
 		
 		switch (e->val.ternary.typ) {
 		case TOT_COND:
 			promote_csts(&dest2, &dest3);
 			switch (dest1.typ) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
 			case NCT_FLOAT:   *dest = dest1.val.f   ? dest2 : dest3; return 1;
 			case NCT_DOUBLE:  *dest = dest1.val.d   ? dest2 : dest3; return 1;
 			case NCT_LDOUBLE: *dest = dest1.val.l   ? dest2 : dest3; return 1;
+#pragma GCC diagnostic pop
 			case NCT_INT32:   *dest = dest1.val.i32 ? dest2 : dest3; return 1;
 			case NCT_UINT32:  *dest = dest1.val.u32 ? dest2 : dest3; return 1;
 			case NCT_INT64:   *dest = dest1.val.i64 ? dest2 : dest3; return 1;
@@ -1306,17 +1233,49 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 			}
 		default: return 0;
 		} }
-#pragma GCC diagnostic pop
 		
 	// case ETY_INIT_LIST:
 		
 	case ETY_CAST:
-		if (!eval_expression(e->val.cast.e, const_map, dest, fatal)) return 0;
+		if (!eval_expression(li, target, e->val.cast.e, const_map, dest, fatal)) return 0;
 		
 		if (e->val.cast.typ->typ == TYPE_BUILTIN) {
 			switch (e->val.cast.typ->val.builtin) {
+			case BTT_VOID:
+				if (fatal) log_error(li, "invalid cast to void\n");
+				return 0;
+			case BTT_BOOL:
+				switch (dest->typ) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+				case NCT_FLOAT:   dest->val.u32 = (_Bool)dest->val.f; break;
+				case NCT_DOUBLE:  dest->val.u32 = (_Bool)dest->val.d; break;
+				case NCT_LDOUBLE: dest->val.u32 = (_Bool)dest->val.l; break;
+#pragma GCC diagnostic pop
+				case NCT_INT32:   dest->val.u32 = (_Bool)dest->val.i32; break;
+				case NCT_UINT32:  dest->val.u32 = (_Bool)dest->val.u32; break;
+				case NCT_INT64:   dest->val.u32 = (_Bool)dest->val.i64; break;
+				case NCT_UINT64:  dest->val.u32 = (_Bool)dest->val.u64; break;
+				}
+				dest->typ = NCT_UINT32;
+				return 1;
+			case BTT_SCHAR:
+			case BTT_S8:
+			cast_s8:
+				switch (dest->typ) {
+				case NCT_FLOAT:   dest->val.i32 = (int8_t)dest->val.f; break;
+				case NCT_DOUBLE:  dest->val.i32 = (int8_t)dest->val.d; break;
+				case NCT_LDOUBLE: dest->val.i32 = (int8_t)dest->val.l; break;
+				case NCT_INT32:   dest->val.i32 = (int8_t)dest->val.i32; break;
+				case NCT_UINT32:  dest->val.i32 = (int8_t)dest->val.u32; break;
+				case NCT_INT64:   dest->val.i32 = (int8_t)dest->val.i64; break;
+				case NCT_UINT64:  dest->val.i32 = (int8_t)dest->val.u64; break;
+				}
+				dest->typ = NCT_INT32;
+				return 1;
 			case BTT_UCHAR:
 			case BTT_U8:
+			cast_u8:
 				switch (dest->typ) {
 				case NCT_FLOAT:   dest->val.u32 = (uint8_t)dest->val.f; break;
 				case NCT_DOUBLE:  dest->val.u32 = (uint8_t)dest->val.d; break;
@@ -1328,9 +1287,37 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 				}
 				dest->typ = NCT_UINT32;
 				return 1;
+			case BTT_SHORT:
+			case BTT_SSHORT:
+			case BTT_S16:
+				switch (dest->typ) {
+				case NCT_FLOAT:   dest->val.i32 = (int16_t)dest->val.f; break;
+				case NCT_DOUBLE:  dest->val.i32 = (int16_t)dest->val.d; break;
+				case NCT_LDOUBLE: dest->val.i32 = (int16_t)dest->val.l; break;
+				case NCT_INT32:   dest->val.i32 = (int16_t)dest->val.i32; break;
+				case NCT_UINT32:  dest->val.i32 = (int16_t)dest->val.u32; break;
+				case NCT_INT64:   dest->val.i32 = (int16_t)dest->val.i64; break;
+				case NCT_UINT64:  dest->val.i32 = (int16_t)dest->val.u64; break;
+				}
+				dest->typ = NCT_INT32;
+				return 1;
+			case BTT_USHORT:
+			case BTT_U16:
+				switch (dest->typ) {
+				case NCT_FLOAT:   dest->val.u32 = (uint16_t)dest->val.f; break;
+				case NCT_DOUBLE:  dest->val.u32 = (uint16_t)dest->val.d; break;
+				case NCT_LDOUBLE: dest->val.u32 = (uint16_t)dest->val.l; break;
+				case NCT_INT32:   dest->val.u32 = (uint16_t)dest->val.i32; break;
+				case NCT_UINT32:  dest->val.u32 = (uint16_t)dest->val.u32; break;
+				case NCT_INT64:   dest->val.u32 = (uint16_t)dest->val.i64; break;
+				case NCT_UINT64:  dest->val.u32 = (uint16_t)dest->val.u64; break;
+				}
+				dest->typ = NCT_UINT32;
+				return 1;
 			case BTT_INT:
 			case BTT_SINT:
 			case BTT_S32:
+			cast_s32:
 				switch (dest->typ) {
 				case NCT_FLOAT:   dest->val.i32 = (int32_t)dest->val.f; break;
 				case NCT_DOUBLE:  dest->val.i32 = (int32_t)dest->val.d; break;
@@ -1344,6 +1331,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 				return 1;
 			case BTT_UINT:
 			case BTT_U32:
+			cast_u32:
 				switch (dest->typ) {
 				case NCT_FLOAT:   dest->val.u32 = (uint32_t)dest->val.f; break;
 				case NCT_DOUBLE:  dest->val.u32 = (uint32_t)dest->val.d; break;
@@ -1355,10 +1343,24 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 				}
 				dest->typ = NCT_UINT32;
 				return 1;
-			case BTT_ULONG:
-				// Warning: assuming sizeof(long) == 8 on the current target
-				// TODO: use machine to select between U32 and U64
+			case BTT_LONGLONG:
+			case BTT_SLONGLONG:
+			case BTT_S64:
+			cast_s64:
+				switch (dest->typ) {
+				case NCT_FLOAT:   dest->val.i64 = (int64_t)dest->val.f; break;
+				case NCT_DOUBLE:  dest->val.i64 = (int64_t)dest->val.d; break;
+				case NCT_LDOUBLE: dest->val.i64 = (int64_t)dest->val.l; break;
+				case NCT_INT32:   dest->val.i64 = (int64_t)dest->val.i32; break;
+				case NCT_UINT32:  dest->val.i64 = (int64_t)dest->val.u32; break;
+				case NCT_INT64: break;
+				case NCT_UINT64:  dest->val.i64 = (int64_t)dest->val.u64; break;
+				}
+				dest->typ = NCT_INT64;
+				return 1;
+			case BTT_ULONGLONG:
 			case BTT_U64:
+			cast_u64:
 				switch (dest->typ) {
 				case NCT_FLOAT:   dest->val.u64 = (uint64_t)dest->val.f; break;
 				case NCT_DOUBLE:  dest->val.u64 = (uint64_t)dest->val.d; break;
@@ -1370,25 +1372,31 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 				}
 				dest->typ = NCT_UINT64;
 				return 1;
-			case BTT_VOID:
-			case BTT_BOOL:
-			case BTT_CHAR: // May be signed or unsigned depending on the machine
-			case BTT_SCHAR:
-			case BTT_SHORT:
-			case BTT_SSHORT:
-			case BTT_USHORT:
+			case BTT_CHAR:
+				if (target->unsigned_char) goto cast_u8;
+				else                       goto cast_s8;
 			case BTT_LONG:
 			case BTT_SLONG:
-			case BTT_LONGLONG:
-			case BTT_SLONGLONG:
-			case BTT_ULONGLONG:
+				if (target->size_long == 4) {
+					goto cast_s32;
+				} else if (target->size_long == 8) {
+					goto cast_s64;
+				} else {
+					log_internal(li, "unsupported cast to long with target sizeof(long) == %zu\n", target->size_long);
+					return 0;
+				}
+			case BTT_ULONG:
+				if (target->size_long == 4) {
+					goto cast_u32;
+				} else if (target->size_long == 8) {
+					goto cast_u64;
+				} else {
+					log_internal(li, "unsupported cast to unsigned long with target sizeof(long) == %zu\n", target->size_long);
+					return 0;
+				}
 			case BTT_INT128:
 			case BTT_SINT128:
 			case BTT_UINT128:
-			case BTT_S8:
-			case BTT_S16:
-			case BTT_U16:
-			case BTT_S64:
 			case BTT_FLOAT:
 			case BTT_CFLOAT:
 			case BTT_IFLOAT:
@@ -1403,11 +1411,11 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 			case BTT_IFLOAT128:
 			case BTT_VA_LIST:
 			default:
-				if (fatal) printf("Error: TODO: cast to builtin %s in constant expression\n", builtin2str[e->val.cast.typ->val.builtin]);
+				if (fatal) log_TODO(li, "unsupported cast to builtin %s in constant expression\n", builtin2str[e->val.cast.typ->val.builtin]);
 				return 0;
 			}
 		} else {
-			if (fatal) printf("Error: cast in constant expression\n");
+			if (fatal) log_TODO(li, "unsupported cast in constant expression\n");
 			return 0;
 		}
 		
@@ -1426,7 +1434,7 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s
 		// Empty destructor
 		*tok = proc_next_token(prep);
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) {
-			printf("Error: unexpected token in static assertion declaration\n");
+			log_error(&tok->loginfo, "unexpected token in static assertion declaration\n");
 			proc_token_del(tok);
 			goto failed;
 		}
@@ -1437,13 +1445,13 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s
 			goto failed;
 		}
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_COMMA)) {
-			printf("Error: unexpected token in static assertion expression\n");
+			log_error(&tok->loginfo, "unexpected token in static assertion expression\n");
 			expr_del(e);
 			proc_token_del(tok);
 			goto failed;
 		}
 		num_constant_t eval;
-		if (!eval_expression(e, const_map, &eval, 1)) {
+		if (!eval_expression(&tok->loginfo, target, e, const_map, &eval, 1)) {
 			expr_del(e);
 			// Empty destructor
 			goto failed;
@@ -1451,37 +1459,40 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s
 		expr_del(e);
 		*tok = proc_next_token(prep);
 		if ((tok->tokt != PTOK_STRING) || !tok->tokv.sisstr) {
-			printf("Error: unexpected token in static assertion message\n");
+			log_error(&tok->loginfo, "unexpected token in static assertion message\n");
 			proc_token_del(tok);
 			goto failed;
 		}
 		string_t *errmsg = tok->tokv.str;
 		*tok = proc_next_token(prep);
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) {
-			printf("Error: unexpected token in static assertion message\n");
+			log_error(&tok->loginfo, "unexpected token in static assertion message\n");
 			proc_token_del(tok);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_SEMICOLON)) {
-			printf("Error: unexpected token after static assertion\n");
+			log_error(&tok->loginfo, "unexpected token after static assertion\n");
 			proc_token_del(tok);
 			goto failed;
 		}
 		
 		int iserror;
 		switch (eval.typ) {
-		case NCT_FLOAT:   iserror = (int)eval.val.f == 0; break;
-		case NCT_DOUBLE:  iserror = (int)eval.val.d == 0; break;
-		case NCT_LDOUBLE: iserror = (int)eval.val.l == 0; break;
-		case NCT_INT32:   iserror = eval.val.i32    == 0; break;
-		case NCT_UINT32:  iserror = eval.val.u32    == 0; break;
-		case NCT_INT64:   iserror = eval.val.i64    == 0; break;
-		case NCT_UINT64:  iserror = eval.val.u64    == 0; break;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+		case NCT_FLOAT:   iserror = !eval.val.f;   break;
+		case NCT_DOUBLE:  iserror = !eval.val.d;   break;
+		case NCT_LDOUBLE: iserror = !eval.val.l;   break;
+#pragma GCC diagnostic pop
+		case NCT_INT32:   iserror = !eval.val.i32; break;
+		case NCT_UINT32:  iserror = !eval.val.u32; break;
+		case NCT_INT64:   iserror = !eval.val.i64; break;
+		case NCT_UINT64:  iserror = !eval.val.u64; break;
 		default: iserror = 1;
 		}
 		if (iserror) {
-			printf("Error: static assertion failed: %s\n", string_content(errmsg));
+			log_error(&tok->loginfo, "static assertion failed: %s\n", string_content(errmsg));
 			string_del(errmsg);
 			// Empty destructor
 			goto failed;
@@ -1493,15 +1504,14 @@ static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *s
 	
 parse_cur_token_decl:
 	if (tok->tokt == PTOK_EOF) {
-		printf("Error: unexpected end of file in declaration\n");
-		proc_token_print(tok);
+		log_error(&tok->loginfo, "unexpected end of file in declaration\n");
 		goto failed;
 	}
 	// Storage
 	if (storage && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_AUTO)) {
 		if (*storage == TMPSTO_NONE) *storage = TMPSTO_AUTO;
 		else {
-			printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1510,7 +1520,7 @@ parse_cur_token_decl:
 		if (*storage == TMPSTO_NONE) *storage = TMPSTO_EXTERN;
 		else if (*storage == TMPSTO_TLS) *storage = TMPSTO_TLS_EXTERN;
 		else {
-			printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1518,7 +1528,7 @@ parse_cur_token_decl:
 	} else if (storage && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_REGISTER)) {
 		if (*storage == TMPSTO_NONE) *storage = TMPSTO_REG;
 		else {
-			printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1527,7 +1537,7 @@ parse_cur_token_decl:
 		if (*storage == TMPSTO_NONE) *storage = TMPSTO_STATIC;
 		else if (*storage == TMPSTO_TLS) *storage = TMPSTO_TLS_STATIC;
 		else {
-			printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1537,7 +1547,7 @@ parse_cur_token_decl:
 		else if (*storage == TMPSTO_EXTERN) *storage = TMPSTO_TLS_EXTERN;
 		else if (*storage == TMPSTO_STATIC) *storage = TMPSTO_TLS_STATIC;
 		else {
-			printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1545,7 +1555,7 @@ parse_cur_token_decl:
 	} else if (storage && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_TYPEDEF)) {
 		if (*storage == TMPSTO_NONE) *storage = TMPSTO_TYPEDEF;
 		else {
-			printf("Error: unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected storage class specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1568,9 +1578,30 @@ parse_cur_token_decl:
 		// Empty destructor
 		*tok = proc_next_token(prep);
 		if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_LPAREN)) {
-			printf("Error: TODO: _Atomic(type-name)\n");
+			if (*spec != SPEC_NONE) {
+				log_error(&tok->loginfo, "unexpected symbol '('\n");
+				// Empty destructor
+				goto failed;
+			}
+			*spec = SPEC_TYPE;
+			if (!parse_type_name(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) {
+				goto failed;
+			}
+			if (!typ->is_validated) {
+				log_internal(&tok->loginfo, "_Atomic() type is not validated\n");
+				type_del(typ);
+				// Empty destructor
+				goto failed;
+			}
+			if ((typ->typ == TYPE_ARRAY) || (typ->typ == TYPE_FUNCTION) || typ->is_atomic || typ->is_const || typ->is_restrict || typ->is_volatile) {
+				log_error(&tok->loginfo, "the type name in an _Atomic() may not be an array, a function, atomic, or qualified\n");
+				type_del(typ);
+				// Empty destructor
+				goto failed;
+			}
 			// Empty destructor
-			goto failed;
+			*tok = proc_next_token(prep);
+			goto parse_cur_token_decl;
 		} else {
 			typ->is_atomic = 1;
 			goto parse_cur_token_decl;
@@ -1591,16 +1622,16 @@ parse_cur_token_decl:
 	
 	// Specifier
 #define SPEC(bt,post) \
-		if (*spec == SPEC_NONE) {                                                                   \
-			*spec = SPEC_BUILTIN;                                                                   \
-			typ->typ = TYPE_BUILTIN;                                                                \
-			typ->val.builtin = BTT_ ## bt;                                                          \
-			post                                                                                    \
-		} else {                                                                                    \
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); \
-			goto failed;                                                                            \
-		}                                                                                           \
-		*tok = proc_next_token(prep);                                                               \
+		if (*spec == SPEC_NONE) {                                                                              \
+			*spec = SPEC_BUILTIN;                                                                              \
+			typ->typ = TYPE_BUILTIN;                                                                           \
+			typ->val.builtin = BTT_ ## bt;                                                                     \
+			post                                                                                               \
+		} else {                                                                                               \
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]); \
+			goto failed;                                                                                       \
+		}                                                                                                      \
+		*tok = proc_next_token(prep);                                                                          \
 		goto parse_cur_token_decl;
 #define SPEC_SIGNED(bt, allow_int) \
 		if ((*spec == SPEC_NONE) || (allow_int && (*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_INT))) {                    \
@@ -1614,7 +1645,7 @@ parse_cur_token_decl:
 			*spec = allow_int ? *spec : SPEC_BUILTIN;                                                                             \
 			typ->val.builtin = BTT_U ## bt;                                                                                       \
 		} else {                                                                                                                  \
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);                               \
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);                    \
 			goto failed;                                                                                                          \
 		}                                                                                                                         \
 		*tok = proc_next_token(prep);                                                                                             \
@@ -1635,7 +1666,7 @@ parse_cur_token_decl:
 		} else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_LONGDOUBLE)) {
 			typ->val.builtin = BTT_CLONGDOUBLE;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1654,7 +1685,7 @@ parse_cur_token_decl:
 		} else if ((*spec == SPEC_BUILTIN) && (typ->val.builtin == BTT_LONGDOUBLE)) {
 			typ->val.builtin = BTT_ILONGDOUBLE;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1684,7 +1715,7 @@ parse_cur_token_decl:
 			*spec = SPEC_BUILTIN;
 			typ->val.builtin = BTT_LONGDOUBLE;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1703,7 +1734,7 @@ parse_cur_token_decl:
 			typ->typ = TYPE_BUILTIN;
 			typ->val.builtin = BTT_IFLOAT;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1722,7 +1753,7 @@ parse_cur_token_decl:
 			typ->typ = TYPE_BUILTIN;
 			typ->val.builtin = BTT_IFLOAT128;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1737,7 +1768,7 @@ parse_cur_token_decl:
 		} else if (*spec == SPEC_BUILTIN_NOINT) {
 			*spec = SPEC_BUILTIN;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1770,7 +1801,7 @@ parse_cur_token_decl:
 		} else if (*spec == SPEC_IMAGINARY) {
 			*spec = SPEC_LONGIMAGINARY;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1793,7 +1824,7 @@ parse_cur_token_decl:
 		} else if (((*spec == SPEC_BUILTIN_NOINT) || (*spec == SPEC_BUILTIN)) && (typ->val.builtin == BTT_SHORT)) {
 			typ->val.builtin = BTT_SSHORT;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1814,7 +1845,7 @@ parse_cur_token_decl:
 		} else if (((*spec == SPEC_BUILTIN_NOINT) || (*spec == SPEC_BUILTIN)) && (typ->val.builtin == BTT_SHORT)) {
 			typ->val.builtin = BTT_USHORT;
 		} else {
-			printf("Error: unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
+			log_error(&tok->loginfo, "unexpected type specifier '%s' in declaration\n", kw2str[tok->tokv.kw]);
 			goto failed;
 		}
 		*tok = proc_next_token(prep);
@@ -1828,19 +1859,13 @@ parse_cur_token_decl:
 		// The ident is the type-specifier
 		khiter_t it = kh_get(type_map, type_map, string_content(tok->tokv.str));
 		if (it == kh_end(type_map)) {
-			printf("Error: invalid type '%s' (ident is not a typedef)\n"
-					"Current state:\n"
-					"  storage: %p/%u\n"
-					"  spec: %u\n"
-					"  type: ", string_content(tok->tokv.str), storage, storage ? *storage : TMPSTO_NONE, *spec);
-			type_print(typ);
-			printf("\n");
+			log_error(&tok->loginfo, "invalid type '%s' (ident is not a typedef)\n", string_content(tok->tokv.str));
 			string_del(tok->tokv.str);
 			goto failed;
 		} else {
 			*spec = SPEC_TYPE;
 			if (!type_copy_into(typ, kh_val(type_map, it))) {
-				printf("Failed to duplicate type infos\n");
+				log_memory("failed to duplicate type infos\n");
 				string_del(tok->tokv.str);
 				goto failed;
 			}
@@ -1855,32 +1880,34 @@ parse_cur_token_decl:
 		
 		// Empty destructor
 		*tok = proc_next_token(prep);
-		khiter_t it = kh_end(struct_map); // Iterator into the struct_map
+		string_t *tag;
 		if (tok->tokt == PTOK_IDENT) {
-			string_t *tag = tok->tokv.str;
+			tag = tok->tokv.str;
 			// Token moved
 			*tok = proc_next_token(prep);
 			
+			khiter_t it; // Iterator into the struct_map
 			int iret;
 			it = kh_put(struct_map, struct_map, string_content(tag), &iret);
 			if (iret < 0) {
-				printf("Error: failed to add structure to struct map\n");
+				log_memory("failed to add structure to struct map\n");
 				proc_token_del(tok);
 				goto failed;
 			} else if (iret == 0) {
 				// Structure already declared or defined
 				if (kh_val(struct_map, it)->is_struct != is_struct) {
-					printf("Error: incoherent struct/union tagging of %s\n", string_content(tag));
+					log_error(&tok->loginfo, "incoherent struct/union tagging of %s\n", string_content(tag));
 					string_del(tag);
 					proc_token_del(tok);
 					goto failed;
 				}
 				++kh_val(struct_map, it)->nrefs;
 				string_del(tag);
+				tag = kh_val(struct_map, it)->tag;
 			} else {
 				kh_val(struct_map, it) = struct_new(is_struct, tag);
 				if (!kh_val(struct_map, it)) {
-					printf("Error: failed to create new structure metadata structure\n");
+					log_memory("failed to create new structure metadata structure\n");
 					string_del(tag);
 					proc_token_del(tok);
 					goto failed;
@@ -1890,10 +1917,11 @@ parse_cur_token_decl:
 			typ->val.st = kh_val(struct_map, it);
 			typ->is_incomplete = !typ->val.st->is_defined;
 		} else {
+			tag = NULL;
 			typ->typ = TYPE_STRUCT_UNION;
 			typ->val.st = struct_new(is_struct, NULL);
 			if (!typ->val.st) {
-				printf("Error: failed to create new structure metadata structure\n");
+				log_memory("failed to create new structure metadata structure\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -1901,24 +1929,18 @@ parse_cur_token_decl:
 		}
 		if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_LBRACKET)) {
 			if (typ->val.st->is_defined) {
-				printf("Error: TODO: struct redefinition\n"
-						"Current state:\n"
-						"  storage: %p/%u\n"
-						"  spec: %u\n"
-						"  type: ", storage, storage ? *storage : TMPSTO_NONE, *spec);
-				type_print(typ);
-				printf("\n");
+				log_TODO(&tok->loginfo, "struct redefinition (tag is %s)\n", typ->val.st->tag ? string_content(typ->val.st->tag) : "<no tag>");
 				goto failed;
 			}
 			
 			VECTOR(st_members) *members = vector_new(st_members);
 			if (!members) {
-				printf("Failed to create a members vector\n");
+				log_memory("failed to create a members vector\n");
 				goto failed;
 			}
 			type_t *typ2 = type_new();
 			if (!typ2) {
-				printf("Failed to create a type info structure\n");
+				log_memory("failed to create a type info structure\n");
 				vector_del(st_members, members);
 				goto failed;
 			}
@@ -1941,13 +1963,13 @@ parse_cur_token_decl:
 					// A struct-declaration that does not declare an anonymous structure or anonymous union
 					// shall contain a struct-declarator-list.
 					if ((typ2->typ != TYPE_STRUCT_UNION) || typ2->val.st->tag) {
-						printf("Error: missing struct-declarator-list\n");
+						log_error(&tok->loginfo, "missing struct-declarator-list\n");
 						vector_del(st_members, members);
 						type_del(typ2);
 						goto failed;
 					}
 					if (!vector_push(st_members, members, ((st_member_t){.name = NULL, .typ = typ2, .is_bitfield = 0}))) {
-						printf("Error: failed to add anonymous structure member\n");
+						log_memory("failed to add anonymous structure member\n");
 						vector_del(st_members, members);
 						type_del(typ2);
 						// Empty destructor
@@ -1955,7 +1977,7 @@ parse_cur_token_decl:
 					}
 					typ2 = type_new();
 					if (!typ2) {
-						printf("Failed to create a type info structure\n");
+						log_memory("failed to create a type info structure\n");
 						vector_del(st_members, members);
 						// Empty destructor
 						goto failed;
@@ -1974,7 +1996,7 @@ parse_cur_token_decl:
 				dest2.structms.const_map = const_map;
 				dest2.structms.dest = members;
 				if (!parse_declarator(target, &dest2, prep, tok, TMPSTO_NONE, FSPEC_NONE, typ2, 0, 1, 1, 1)) {
-					printf("Error parsing struct-declarator-list\n");
+					log_error(&tok->loginfo, "error parsing struct-declarator-list\n");
 					vector_del(st_members, members);
 					type_del(typ2);
 					// Token is deleted
@@ -1982,14 +2004,14 @@ parse_cur_token_decl:
 				}
 				type_del(typ2);
 				if ((tok->tokt != PTOK_SYM) && (tok->tokv.sym != SYM_SEMICOLON)) {
-					printf("Error parsing struct-declarator-list (invalid next token)\n");
+					log_error(&tok->loginfo, "error parsing struct-declarator-list (invalid next token)\n");
 					vector_del(st_members, members);
 					proc_token_del(tok);
 					goto failed;
 				}
 				typ2 = type_new();
 				if (!typ2) {
-					printf("Failed to create a type info structure\n");
+					log_memory("failed to create a type info structure\n");
 					vector_del(st_members, members);
 					// Empty destructor
 					goto failed;
@@ -1998,7 +2020,7 @@ parse_cur_token_decl:
 			}
 			type_del(typ2);
 			if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RBRACKET)) {
-				printf("Error parsing struct-declarator-list (invalid next token)\n");
+				log_error(&tok->loginfo, "error parsing struct-declarator-list (invalid next token)\n");
 				vector_del(st_members, members);
 				proc_token_del(tok);
 				goto failed;
@@ -2006,6 +2028,13 @@ parse_cur_token_decl:
 			
 			typ->is_incomplete = 0;
 			typ->is_validated = 0;
+			if (tag) {
+				khiter_t it = kh_get(type_set, type_set, typ);
+				if (it != kh_end(type_set)) {
+					kh_key(type_set, it)->is_incomplete = 0;
+					kh_key(type_set, it)->is_validated = 0;
+				}
+			}
 			typ->val.st->has_incomplete = 0; // Filled by the validate_type step
 			typ->val.st->nmembers = vector_size(st_members, members);
 			typ->val.st->members = vector_steal(st_members, members);
@@ -2013,8 +2042,8 @@ parse_cur_token_decl:
 			*tok = proc_next_token(prep);
 			goto parse_cur_token_decl;
 		} else {
-			if (it == kh_end(struct_map)) {
-				printf("Error: invalid structure declaration: missing tag and/or definition\n");
+			if (!tag) {
+				log_error(&tok->loginfo, "invalid structure declaration: missing tag and/or definition\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -2033,19 +2062,19 @@ parse_cur_token_decl:
 		}
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LBRACKET)) {
 			if (!tag) {
-				printf("Error: unexpected token after keyword 'enum'\n");
+				log_error(&tok->loginfo, "unexpected token after keyword 'enum'\n");
 				proc_token_del(tok);
 				goto failed;
 			}
 			khiter_t it = kh_get(type_map, enum_map, string_content(tag));
 			if (it == kh_end(enum_map)) {
-				printf("Error: enumeration %s has not been defined yet\n", string_content(tag)); // TODO?
+				log_error(&tok->loginfo, "enumeration %s has not been defined yet\n", string_content(tag)); // TODO?
 				string_del(tag);
 				proc_token_del(tok);
 				goto failed;
 			}
 			if (!type_copy_into(typ, kh_val(enum_map, it))) {
-				printf("Failed to duplicate enum type infos\n");
+				log_memory("failed to duplicate enum type infos\n");
 				string_del(tag);
 				proc_token_del(tok);
 				goto failed;
@@ -2068,25 +2097,93 @@ parse_cur_token_decl:
 		num_constant_t cst = { .typ = NCT_INT32, .val.i32 = -1 };
 		// Empty destructor
 		*tok = proc_next_token(prep);
+		if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_RBRACKET)) {
+			log_error(&tok->loginfo, "expected enum constant name before '}'\n");
+			proc_token_del(tok);
+			goto failed;
+		}
 		int iret;
 		while ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RBRACKET)) {
 			if (tok->tokt != PTOK_IDENT) {
-				printf("Error: invalid token in enumeration definition\n");
+				log_error(&tok->loginfo, "unexpected token in enumeration definition\n");
 				if (tag) string_del(tag);
 				proc_token_del(tok);
 				goto failed;
 			}
 			char *ident = string_steal(tok->tokv.str);
 			*tok = proc_next_token(prep);
+			while ((tok->tokt == PTOK_IDENT) && !strcmp(string_content(tok->tokv.str), "__attribute__")) {
+				// Attribute
+				string_del(tok->tokv.str);
+				*tok = proc_next_token(prep);
+				if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) {
+					log_error(&tok->loginfo, "unexpected token, expected '('\n");
+					free(ident);
+					if (tag) string_del(tag);
+					proc_token_del(tok);
+					goto failed;
+				}
+				// Empty destructor
+				*tok = proc_next_token(prep);
+				if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) {
+					log_error(&tok->loginfo, "unexpected token, expected '('\n");
+					free(ident);
+					if (tag) string_del(tag);
+					// Empty destructor
+					goto failed;
+				}
+				// Empty destructor
+				*tok = proc_next_token(prep);
+			enum_attribute_list:
+				if ((tok->tokt == PTOK_IDENT) && TOKEN_MATCH_ATTR(deprecated)) {
+					log_warning(&tok->loginfo, "ignoring enum constant attribute 'deprecated'\n");
+					string_del(tok->tokv.str);
+					*tok = proc_next_token(prep);
+					if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_COMMA)) {
+						// Empty destructor
+						*tok = proc_next_token(prep);
+						goto enum_attribute_list;
+					} else goto enum_attribute_list_end;
+				}
+				if ((tok->tokt == PTOK_IDENT) && TOKEN_MATCH_ATTR(unavailable)) {
+					log_warning(&tok->loginfo, "ignoring enum constant attribute 'unavailable'\n");
+					string_del(tok->tokv.str);
+					*tok = proc_next_token(prep);
+					if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_COMMA)) {
+						// Empty destructor
+						*tok = proc_next_token(prep);
+						goto enum_attribute_list;
+					} else goto enum_attribute_list_end;
+				}
+			enum_attribute_list_end:
+				if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) {
+					log_error(&tok->loginfo, "unexpected token, expected ident or ')'\n");
+					free(ident);
+					if (tag) string_del(tag);
+					// Empty destructor
+					goto failed;
+				}
+				// Empty destructor
+				*tok = proc_next_token(prep);
+				if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) {
+					log_error(&tok->loginfo, "unexpected token, expected ')'\n");
+					free(ident);
+					if (tag) string_del(tag);
+					// Empty destructor
+					goto failed;
+				}
+				// Empty destructor
+				*tok = proc_next_token(prep);
+			}
 			khiter_t it = kh_put(const_map, const_map, ident, &iret);
 			if (iret < 0) {
-				printf("Error: failed to add constant %s to the constants map\n", ident);
+				log_memory("failed to add constant %s to the constants map\n", ident);
 				free(ident);
 				if (tag) string_del(tag);
 				proc_token_del(tok);
 				goto failed;
 			} else if (iret == 0) {
-				printf("Error: constant %s is already in the constants map\n", ident);
+				log_error(&tok->loginfo, "constant %s is already defined\n", ident);
 				free(ident);
 				if (tag) string_del(tag);
 				proc_token_del(tok);
@@ -2114,7 +2211,7 @@ parse_cur_token_decl:
 					break;
 				case NCT_UINT64:
 					if (cst.val.u64 == UINT64_MAX) {
-						printf("Error: enum constant is too big\n");
+						log_error(&tok->loginfo, "enum constant is too big\n");
 						if (tag) string_del(tag);
 						proc_token_del(tok);
 						goto failed;
@@ -2124,7 +2221,7 @@ parse_cur_token_decl:
 				case NCT_DOUBLE:
 				case NCT_LDOUBLE:
 				default:
-					printf("Internal error: enum constant is a float/double/ldouble\n");
+					log_internal(&tok->loginfo, "enum constant is a float/double/ldouble\n");
 					if (tag) string_del(tag);
 					proc_token_del(tok);
 					goto failed;
@@ -2137,13 +2234,13 @@ parse_cur_token_decl:
 					goto failed;
 				}
 				if ((tok->tokt != PTOK_SYM) || ((tok->tokv.sym != SYM_COMMA) && (tok->tokv.sym != SYM_RBRACKET))) {
-					printf("Error: unexpected token during enumeration declaration\n");
+					log_error(&tok->loginfo, "unexpected token during enumeration declaration\n");
 					expr_del(e);
 					if (tag) string_del(tag);
 					proc_token_del(tok);
 					goto failed;
 				}
-				if (!eval_expression(e, const_map, &cst, 1)) {
+				if (!eval_expression(&tok->loginfo, target, e, const_map, &cst, 1)) {
 					expr_del(e);
 					if (tag) string_del(tag);
 					// Empty destructor
@@ -2156,7 +2253,7 @@ parse_cur_token_decl:
 				if (cst.val.i32 < 0) {
 					has_neg = 1;
 					if (btt == BTT_U64) {
-						printf("Error: enum constant is too big\n");
+						log_error(&tok->loginfo, "enum constant is too big\n");
 						if (tag) string_del(tag);
 						// Empty destructor
 						goto failed;
@@ -2177,7 +2274,7 @@ parse_cur_token_decl:
 						not_in_i32 = 1;
 					}
 					if (btt == BTT_U64) {
-						printf("Error: enum constant is too big\n");
+						log_error(&tok->loginfo, "enum constant is too big\n");
 						if (tag) string_del(tag);
 						// Empty destructor
 						goto failed;
@@ -2198,7 +2295,7 @@ parse_cur_token_decl:
 				if (cst.val.u64 > (uint32_t)INT32_MAX) {
 					not_in_i32 = 1;
 					if (has_neg && (cst.val.u64 > (uint64_t)INT64_MAX)) {
-						printf("Error: enum constant is too big\n");
+						log_error(&tok->loginfo, "enum constant is too big\n");
 						if (tag) string_del(tag);
 						// Empty destructor
 						goto failed;
@@ -2210,7 +2307,7 @@ parse_cur_token_decl:
 			case NCT_DOUBLE:
 			case NCT_LDOUBLE:
 			default:
-				printf("Error: invalid floating-point enumeration constant\n");
+				log_error(&tok->loginfo, "invalid floating-point enumeration constant\n");
 				if (tag) string_del(tag);
 				// Empty destructor
 				goto failed;
@@ -2224,19 +2321,19 @@ parse_cur_token_decl:
 			char *ctag = string_steal(tag);
 			khiter_t it = kh_put(type_map, enum_map, ctag, &iret);
 			if (iret < 0) {
-				printf("Error: failed to add enumeration %s to the type map\n", ctag);
+				log_memory("failed to add enumeration %s to the type map\n", ctag);
 				free(ctag);
 				// Empty destructor
 				goto failed;
 			} else if (iret == 0) {
-				printf("Error: enumeration %s already exists\n", ctag);
+				log_error(&tok->loginfo, "enumeration %s already exists\n", ctag);
 				free(ctag);
 				// Empty destructor
 				goto failed;
 			}
 			type_t *new_typ = type_new();
 			if (!new_typ) {
-				printf("Error: failed to create type info for enumeration %s\n", ctag);
+				log_memory("failed to create type info for enumeration %s\n", ctag);
 				free(ctag);
 				kh_del(type_map, enum_map, it);
 				// Empty destructor
@@ -2247,7 +2344,7 @@ parse_cur_token_decl:
 			typ->val.typ = new_typ->val.typ = (*builtins)[btt];
 			typ->val.typ->nrefs += 2;
 			new_typ = type_try_merge(new_typ, type_set);
-			validate_type(target, new_typ); // Assume it returns 1
+			validate_type(&tok->loginfo, target, new_typ); // Assume it returns 1
 			kh_val(enum_map, it) = new_typ;
 		} else {
 			typ->typ = TYPE_ENUM;
@@ -2269,14 +2366,7 @@ parse_cur_token_decl:
 	return 1;
 	
 invalid_token:
-	printf("Error: unexpected token (parse_declaration_specifier)\n"
-			"Current state:\n"
-			"  storage: %p/%u\n"
-			"  spec: %u\n"
-			"  type: ", storage, storage ? *storage : TMPSTO_NONE, *spec);
-	type_print(typ);
-	printf("\n");
-	proc_token_print(tok);
+	log_error(&tok->loginfo, "unexpected token (parse_declaration_specifier)\n");
 	proc_token_del(tok);
 	
 failed:
@@ -2294,7 +2384,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 	type_t *cur_bottom = NULL;
 	VECTOR(size_t) *nptr_stack = vector_new_cap(size_t, 1);
 	if (!nptr_stack) {
-		printf("Failed to parse init_declarator_list (allocate nptr_stack)\n");
+		log_memory("failed to allocate nptr stack\n");
 		proc_token_del(tok);
 		goto failed0;
 	}
@@ -2302,31 +2392,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 	while (1) {
 		switch (tok->tokt) {
 		case PTOK_IDENT:
-			if (!has_ident) {
-				if (allow_decl) {
-					cur_ident = tok->tokv.str;
-					has_ident = 1;
-					*tok = proc_next_token(prep);
-					break;
-				} else {
-					printf("Error: unexpected identifier: abstract declarator do not contain a name\n"
-					       "Current state:\n"
-					       "  storage: %u\n"
-					       "  type: ", storage);
-					type_print(typ);
-					printf("\n");
-					proc_token_print(tok);
-					proc_token_del(tok);
-					goto failed;
-				}
+			if (!has_ident && allow_decl) {
+				cur_ident = tok->tokv.str;
+				has_ident = 1;
+				*tok = proc_next_token(prep);
+				break;
 			} else {
-				printf("Error: unexpected identifier\n"
-				       "Current state:\n"
-				       "  storage: %u\n"
-				       "  type: ", storage);
-				type_print(typ);
-				printf("\n");
-				proc_token_print(tok);
+				log_error(&tok->loginfo, "unexpected identifier\n");
 				proc_token_del(tok);
 				goto failed;
 			}
@@ -2337,7 +2409,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					
 					VECTOR(types) *args = vector_new(types);
 					if (!args) {
-						printf("Error: failed to create new type (function argument)\n");
+						log_memory("failed to create new type (function argument)\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2350,7 +2422,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							vector_del(types, args);
 							new_typ = type_new();
 							if (!new_typ) {
-								printf("Error: failed to create new function type\n");
+								log_memory("failed to create new function type\n");
 								// Empty destructor
 								goto failed;
 							}
@@ -2362,7 +2434,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							goto end_fun;
 						}
 						if (!proc_unget_token(prep, tok)) {
-							printf("Error: failed to unget processor token\n");
+							log_memory("failed to unget processor token\n");
 							// Empty destructor
 							vector_del(types, args);
 							goto failed;
@@ -2378,7 +2450,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							// Empty destructor
 							*tok = proc_next_token(prep);
 							if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RPAREN)) {
-								printf("Error: invalid token after function variadic argument\n");
+								log_error(&tok->loginfo, "invalid token after function variadic argument\n");
 								proc_token_del(tok);
 								vector_del(types, args);
 								goto failed;
@@ -2387,7 +2459,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						} else {
 							type_t *typ2 = type_new();
 							if (!typ2) {
-								printf("Error: failed to create new type (function argument)\n");
+								log_memory("failed to create new type (function argument)\n");
 								// Empty destructor
 								vector_del(types, args);
 								goto failed;
@@ -2403,7 +2475,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							}
 							if (spec2 == SPEC_NONE) {
 								// _Static_assert declaration; empty destructor
-								printf("Invalid _Static_assert declaration\n");
+								log_error(&tok->loginfo, "unexpected _Static_assert declaration\n");
 								vector_del(types, args);
 								type_del(typ2);
 								goto failed;
@@ -2414,13 +2486,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 									// Need to convert type to a pointer
 									type_t *typ3 = type_new();
 									if (!typ3) {
-										printf("Error: failed to allocate new type\n");
+										log_memory("failed to allocate new type\n");
 										type_del(typ2);
 										// Empty destructor
 										goto failed;
 									}
 									if (!type_copy_into(typ3, typ2)) {
-										printf("Error: failed to duplicate array type to temporary type\n");
+										log_memory("failed to duplicate array type to temporary type\n");
 										type_del(typ3);
 										type_del(typ2);
 										// Empty destructor
@@ -2432,7 +2504,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 									typ2 = type_try_merge(typ3, PDECL_TYPE_SET);
 								}
 								if (!vector_push(types, args, typ2)) {
-									printf("Error: failed to add argument to argument vector\n");
+									log_memory("failed to add argument to argument vector\n");
 									vector_del(types, args);
 									type_del(typ2);
 									// Empty destructor
@@ -2445,13 +2517,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 									// Need to convert type to a pointer
 									type_t *typ3 = type_new();
 									if (!typ3) {
-										printf("Error: failed to allocate new type\n");
+										log_memory("failed to allocate new type\n");
 										type_del(typ2);
 										// Empty destructor
 										goto failed;
 									}
 									if (!type_copy_into(typ3, typ2)) {
-										printf("Error: failed to duplicate array type to temporary type\n");
+										log_memory("failed to duplicate array type to temporary type\n");
 										type_del(typ3);
 										type_del(typ2);
 										// Empty destructor
@@ -2463,7 +2535,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 									typ2 = type_try_merge(typ3, PDECL_TYPE_SET);
 								}
 								if (!vector_push(types, args, typ2)) {
-									printf("Error: failed to add argument to argument vector\n");
+									log_memory("failed to add argument to argument vector\n");
 									vector_del(types, args);
 									type_del(typ2);
 									// Empty destructor
@@ -2490,13 +2562,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							}
 							type_del(typ2);
 							if (!dest2.argt.dest) {
-								printf("Internal error: argument type is NULL\n");
+								log_internal(&tok->loginfo, "argument type is NULL\n");
 								vector_del(types, args);
 								// Empty destructor
 								goto failed;
 							}
 							if (!vector_push(types, args, dest2.argt.dest)) {
-								printf("Error: failed to add argument to argument vector\n");
+								log_memory("failed to add argument to argument vector\n");
 								vector_del(types, args);
 								type_del(dest2.argt.dest);
 								// Empty destructor
@@ -2509,7 +2581,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 								*tok = proc_next_token(prep);
 								continue;
 							}
-							printf("Error: invalid token after function argument\n");
+							log_error(&tok->loginfo, "invalid token after function argument\n");
 							vector_del(types, args);
 							proc_token_del(tok);
 							goto failed;
@@ -2518,7 +2590,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				no_arg:
 					new_typ = type_new();
 					if (!new_typ) {
-						printf("Error: failed to create new function type\n");
+						log_memory("failed to create new function type\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2547,7 +2619,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					break;
 				} else {
 					if (!vector_push(size_t, nptr_stack, 0)) {
-						printf("Failed to parse init_declarator_list (open parenthesis)\n");
+						log_memory("Failed to push 0 to the nptr stack for opening a parenthesis\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2556,13 +2628,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				}
 			} else if (tok->tokv.sym == SYM_STAR) {
 				if (has_ident) {
-					printf("Error: invalid token '*' after identifier in declaration\n");
+					log_error(&tok->loginfo, "invalid token '*' after identifier in declaration\n");
 					// Empty destructor
 					goto failed;
 				} else {
 					type_t *new_typ = type_new_ptr(typ);
 					if (!new_typ) {
-						printf("Failed to parse init_declarator_list (create new pointer typ)\n");
+						log_memory("failed to create a new pointer type info structure\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2574,14 +2646,14 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 			} else if (tok->tokv.sym == SYM_LSQBRACKET) {
 				if (!has_ident) {
 					if (!allow_abstract) {
-						printf("Error: invalid token '[' before identifier in declaration\n");
+						log_error(&tok->loginfo, "invalid token '[' before identifier in declaration\n");
 						// Empty destructor
 						goto failed;
 					}
 					has_ident = 1;
 				}
 				if (array_atomic || array_const || array_restrict || array_static || array_volatile) {
-					printf("Error: invalid array after array with type qualifier(s) and/or 'static'\n");
+					log_error(&tok->loginfo, "invalid array after array with type qualifier(s) and/or 'static'\n");
 					// Empty destructor
 					goto failed;
 				}
@@ -2598,10 +2670,10 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				size_t nelems; _Bool is_incomplete;
 				while (1) {
 #define DO_CHECKS \
-	if (is_init || is_list || !allow_decl || (cur_bottom && (typ->typ != TYPE_ARRAY))) {                         \
-		printf("Error: type qualifiers and 'static' may only appear in function argument array declarations\n"); \
-		/* Empty destructor */                                                                                   \
-		goto failed;                                                                                             \
+	if (is_init || is_list || !allow_decl || (cur_bottom && (typ->typ != TYPE_ARRAY))) {                                    \
+		log_error(&tok->loginfo, "type qualifiers and 'static' may only appear in function argument array declarations\n"); \
+		/* Empty destructor */                                                                                              \
+		goto failed;                                                                                                        \
 	}
 					if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ATOMIC)) {
 						DO_CHECKS
@@ -2629,7 +2701,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_RSQBRACKET)) {
 					if (array_static) {
 						// Missing expression
-						printf("Error: unexpected token ']' in static length array declaration\n");
+						log_error(&tok->loginfo, "unexpected token ']' in static length array declaration\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2639,7 +2711,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				} else if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_STAR)) {
 					if (array_static) {
 						// Missing expression
-						printf("Error: unexpected token '*' in static length array declaration\n");
+						log_error(&tok->loginfo, "unexpected token '*' in static length array declaration\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2650,7 +2722,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					*tok = proc_next_token(prep);
 					if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RSQBRACKET)) {
 						// TODO: ...[*expr]
-						printf("Error: unexpected token during variable length array declaration\n");
+						log_error(&tok->loginfo, "unexpected token during variable length array declaration\n");
 						proc_token_del(tok);
 						goto failed;
 					}
@@ -2663,13 +2735,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						goto failed;
 					}
 					if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RSQBRACKET)) {
-						printf("Error: unexpected token during array declaration\n");
+						log_error(&tok->loginfo, "unexpected token during array declaration\n");
 						expr_del(e);
 						proc_token_del(tok);
 						goto failed;
 					}
 					num_constant_t cst;
-					if (eval_expression(e, PDECL_CONST_MAP, &cst, is_init || is_list || !allow_decl)) {
+					if (eval_expression(&tok->loginfo, target, e, PDECL_CONST_MAP, &cst, is_init || is_list || !allow_decl)) {
 						expr_del(e);
 						int is_neg;
 						switch (cst.typ) {
@@ -2683,7 +2755,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						default: is_neg = 1;
 						}
 						if (is_neg) {
-							printf("Error: the size of an array must be nonnegative");
+							log_error(&tok->loginfo, "the size of an array must be nonnegative");
 							// Empty destructor
 							goto failed;
 						}
@@ -2702,7 +2774,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				if (cur_bottom) {
 					type_t *tmp = type_new();
 					if (!tmp) {
-						printf("Failed to parse init_declarator_list (create new array type)\n");
+						log_memory("failed to create new array type info\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2721,7 +2793,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				} else {
 					type_t *new_typ = type_new();
 					if (!new_typ) {
-						printf("Failed to parse init_declarator_list (create new array type)\n");
+						log_memory("failed to create new array type info\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2737,7 +2809,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 			} else if (tok->tokv.sym == SYM_RPAREN) {
 				if (!has_ident) {
 					if (!allow_abstract) {
-						printf("Error: invalid token ')' before identifier in declaration\n");
+						log_error(&tok->loginfo, "invalid token ')' before identifier in declaration\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2745,7 +2817,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				}
 				if (vector_size(size_t, nptr_stack) == 1) {
 					if (!is_init && !is_list) goto rparen_ok_ret;
-					printf("Error: closing unopened parenthesis in declaration\n");
+					log_error(&tok->loginfo, "closing unopened parenthesis in declaration\n");
 					// Empty destructor
 					goto failed;
 				}
@@ -2773,12 +2845,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 			        || (is_init && (tok->tokv.sym == SYM_LBRACKET))) {
 			rparen_ok_ret: // Last function argument
 				if (!allow_abstract && !has_ident) {
-					printf("Error: invalid symbol '%s' before identifier\n", sym2str[tok->tokv.sym]);
+					log_error(&tok->loginfo, "invalid symbol '%s' before identifier\n", sym2str[tok->tokv.sym]);
 					// Empty destructor
 					goto failed;
 				}
 				if (vector_size(size_t, nptr_stack) != 1) {
-					printf("Error: invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]);
+					log_error(&tok->loginfo, "invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]);
 					// Empty destructor
 					goto failed;
 				}
@@ -2786,7 +2858,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				// Try to free some redundant types
 				typ = type_try_merge(typ, PDECL_TYPE_SET);
 				
-				int validation = validate_storage_type(target, storage, typ, tok->tokv.sym);
+				int validation = validate_storage_type(&tok->loginfo, target, storage, typ, tok->tokv.sym);
 				if (!validation) {
 					// Empty destructor
 					goto failed;
@@ -2796,7 +2868,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					// Function definition; tok is '{'
 					if (!is_init || !is_list || has_list) {
 						// We are not at the top-level or we have an initialization list
-						printf("Error: invalid function definition\n");
+						log_error(&tok->loginfo, "invalid function definition\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2807,7 +2879,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					
 					declaration_t *decl = malloc(sizeof *decl);
 					if (!decl) {
-						printf("Failed to create new declaration\n");
+						log_memory("failed to create new declaration\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2819,7 +2891,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					char *cident = string_steal(cur_ident); cur_ident = NULL;
 					khiter_t it = kh_put(decl_map, dest->f->decl_map, cident, &iret);
 					if (iret < 0) {
-						printf("Failed to add function '%s' to the declaration map\n", cident);
+						log_memory("failed to add function '%s' to the declaration map\n", cident);
 						free(cident);
 						free(decl);
 						// Empty destructor
@@ -2827,7 +2899,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					} else if (iret == 0) {
 						free(decl);
 						if (kh_val(dest->f->decl_map, it)->defined) {
-							printf("Error: function '%s' is already in the declaration map\n", cident);
+							log_error(&tok->loginfo, "function '%s' is already in the declaration map\n", cident);
 							free(cident);
 							// Empty destructor
 							goto failed;
@@ -2850,11 +2922,11 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							else goto success;
 						}
 					} while (!proc_token_isend(tok));
-					printf("Error: unexpected token in function body\n");
+					log_error(&tok->loginfo, "unexpected token in function body\n");
 					goto failed;
 				}
 				if ((fspec != FSPEC_NONE) && (typ->typ != TYPE_FUNCTION)) {
-					printf("Error: unexpected function specifier\n");
+					log_error(&tok->loginfo, "unexpected function specifier\n");
 					// Empty destructor
 					goto failed;
 				}
@@ -2863,7 +2935,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				if (storage == TMPSTO_TYPEDEF) {
 					if (!is_init || !is_list) {
 						// We are not at the top-level (note that storage is set to NONE in function arguments)
-						printf("Error: invalid function definition\n");
+						log_error(&tok->loginfo, "invalid function definition\n");
 						// Empty destructor
 						goto failed;
 					}
@@ -2872,13 +2944,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					char *cident = string_steal(cur_ident); cur_ident = NULL;
 					khiter_t it = kh_put(type_map, dest->f->type_map, cident, &iret);
 					if (iret < 0) {
-						printf("Failed to add '%s' to the type map\n", cident);
+						log_memory("failed to add '%s' to the type map\n", cident);
 						free(cident);
 						// Empty destructor
 						goto failed;
 					} else if (iret == 0) {
 						if (!type_t_equal(typ, kh_val(dest->f->type_map, it))) {
-							printf("Error: '%s' is already in the type map with a different type\n", cident);
+							log_error(&tok->loginfo, "'%s' is already in the type map with a different type\n", cident);
 							free(cident);
 							type_del(typ);
 							// Empty destructor
@@ -2894,7 +2966,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					if (is_init && is_list) {
 						decl = malloc(sizeof *decl);
 						if (!decl) {
-							printf("Failed to create new declaration\n");
+							log_memory("failed to create new declaration\n");
 							// Empty destructor
 							goto failed;
 						}
@@ -2908,7 +2980,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						char *cident = string_steal(cur_ident); cur_ident = NULL;
 						khiter_t it = kh_put(decl_map, dest->f->decl_map, cident, &iret);
 						if (iret < 0) {
-							printf("Failed to add '%s' to the declaration map\n", cident);
+							log_memory("failed to add '%s' to the declaration map\n", cident);
 							free(cident);
 							free(decl);
 							// Empty destructor
@@ -2916,7 +2988,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						} else if (iret == 0) {
 							if (!type_t_equal(typ, kh_val(dest->f->decl_map, it)->typ)
 							 || ((storage == TMPSTO_NONE) && (kh_val(dest->f->decl_map, it)->storage == STORAGE_NONE))) {
-								printf("Error: '%s' is already in the declaration map (storage=%u)\n", cident, storage);
+								log_error(&tok->loginfo, "'%s' is already in the declaration map\n", cident);
 								free(cident);
 								free(decl);
 								type_del(typ);
@@ -2939,12 +3011,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 								if (typ == base_type) {
 									typ = type_new();
 									if (!typ) {
-										printf("Error: failed to allocate new type\n");
+										log_memory("failed to allocate new type\n");
 										// Empty destructor
 										goto failed;
 									}
 									if (!type_copy_into(typ, base_type)) {
-										printf("Error: failed to allocate new type\n");
+										log_memory("failed to allocate new type\n");
 										// Empty destructor
 										goto failed;
 									}
@@ -2963,13 +3035,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						goto success;
 					} else if (!is_init && is_list) {
 						if (!vector_push(st_members, dest->structms.dest, ((st_member_t){.name = cur_ident, .typ = typ, .is_bitfield = 0}))) {
-							printf("Error: failed to add structure member %s\n", string_content(cur_ident));
+							log_memory("failed to add structure member %s\n", string_content(cur_ident));
 							string_del(cur_ident);
 							// Empty destructor
 							goto failed;
 						}
 					} else {
-						printf("Internal error: unknown is_init/is_list combination %d%d\n", is_init, is_list);
+						log_internal(&tok->loginfo, "unknown is_init/is_list combination %d%d\n", is_init, is_list);
 						// Empty destructor
 						goto failed;
 					}
@@ -2977,12 +3049,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_EQ)) {
 					// Initialization
 					if (!is_init) {
-						printf("Error: unexpected initializer\n");
+						log_error(&tok->loginfo, "unexpected initializer\n");
 						goto failed;
 					}
 					if (decl) {
 						if (decl->defined) {
-							printf("Error: invalid declaration initializer: variable was already declared\n");
+							log_error(&tok->loginfo, "invalid declaration initializer: variable was already declared\n");
 							goto failed;
 						}
 						decl->defined = 1;
@@ -3001,7 +3073,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 							}
 						} while (!proc_token_isend(tok));
 						if (proc_token_isend(tok)) {
-							printf("Error: unexpected token in declaration initializer\n");
+							log_error(&tok->loginfo, "unexpected token in declaration initializer\n");
 							proc_token_del(tok);
 							goto failed;
 						}
@@ -3009,13 +3081,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 						expr_t *e = parse_expression(target, PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS,
 						                             PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, 15);
 						if (!e) {
-							printf("Error: invalid declaration initializer\n");
+							log_error(&tok->loginfo, "invalid declaration initializer\n");
 							goto failed;
 						}
 						expr_del(e);
 					}
 					if ((tok->tokt != PTOK_SYM) || ((tok->tokv.sym != SYM_COMMA) && (tok->tokv.sym != SYM_SEMICOLON))) {
-						printf("Error: unexpected token in declaration initializer\n");
+						log_error(&tok->loginfo, "unexpected token in declaration initializer\n");
 						proc_token_del(tok);
 						goto failed;
 					}
@@ -3032,7 +3104,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				}
 			} else if (!is_init && is_list && (tok->tokv.sym == SYM_COLON)) {
 				if (vector_size(size_t, nptr_stack) != 1) {
-					printf("Error: invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]);
+					log_error(&tok->loginfo, "invalid symbol '%s' (missing parenthesis?)\n", sym2str[tok->tokv.sym]);
 					// Empty destructor
 					goto failed;
 				}
@@ -3048,20 +3120,20 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					goto failed;
 				}
 				if ((tok->tokt != PTOK_SYM) || ((tok->tokv.sym != SYM_COMMA) && (tok->tokv.sym != SYM_SEMICOLON))) {
-					printf("Error: unexpected token in bitfield width\n");
+					log_error(&tok->loginfo, "unexpected token in bitfield width\n");
 					expr_del(e);
 					proc_token_del(tok);
 					goto failed;
 				}
 				num_constant_t eval;
-				if (!eval_expression(e, dest->structms.const_map, &eval, 1)) {
+				if (!eval_expression(&tok->loginfo, target, e, dest->structms.const_map, &eval, 1)) {
 					expr_del(e);
 					// Empty destructor
 					goto failed;
 				}
 				expr_del(e);
 				
-				int validation = validate_storage_type(target, storage, typ, tok->tokv.sym);
+				int validation = validate_storage_type(&tok->loginfo, target, storage, typ, tok->tokv.sym);
 				if (!validation) {
 					// Empty destructor
 					goto failed;
@@ -3070,12 +3142,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				if (validation == VALIDATION_FUN) {
 					// We are not at the top-level or we have an initialization list
 					// Should never happen
-					printf("Error: invalid function definition in structure definition\n");
+					log_error(&tok->loginfo, "invalid function definition in structure definition\n");
 					// Empty destructor
 					goto failed;
 				}
 				if ((fspec != FSPEC_NONE) && (typ->typ != TYPE_FUNCTION)) {
-					printf("Error: unexpected function specifier\n");
+					log_error(&tok->loginfo, "unexpected function specifier\n");
 					// Empty destructor
 					goto failed;
 				}
@@ -3084,7 +3156,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				switch (eval.typ) {
 				case NCT_INT32:
 					if (eval.val.i32 < 0) {
-						printf("Error: invalid negative bitfield width\n");
+						log_error(&tok->loginfo, "invalid negative bitfield width\n");
 						goto failed;
 					}
 					width = (size_t)eval.val.i32;
@@ -3094,7 +3166,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 					break;
 				case NCT_INT64:
 					if (eval.val.i64 < 0) {
-						printf("Error: invalid negative bitfield width\n");
+						log_error(&tok->loginfo, "invalid negative bitfield width\n");
 						goto failed;
 					}
 					width = (size_t)eval.val.i64;
@@ -3106,13 +3178,13 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				case NCT_DOUBLE:
 				case NCT_LDOUBLE:
 				default:
-					printf("Error: invalid non-integer bitfield width\n");
+					log_error(&tok->loginfo, "invalid non-integer bitfield width\n");
 					goto failed;
 				}
 				
 				if (!vector_push(st_members, dest->structms.dest,
 				        ((st_member_t){.name = cur_ident, .typ = typ, .is_bitfield = 1, .bitfield_width = width}))) {
-					printf("Error: failed to add structure member %s\n", string_content(cur_ident));
+					log_memory("failed to add structure member %s\n", string_content(cur_ident));
 					string_del(cur_ident);
 					// Empty destructor
 					goto failed;
@@ -3131,12 +3203,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 		case PTOK_KEYWORD:
 			if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ATOMIC)) {
 				if (has_ident) {
-					printf("Error: invalid keyword '_Atomic' after identifier\n");
+					log_error(&tok->loginfo, "invalid keyword '_Atomic' after identifier\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
 				} else if (!vector_last(size_t, nptr_stack)) {
-					printf("Error: invalid keyword '_Atomic' before symbol '*'\n");
+					log_error(&tok->loginfo, "invalid keyword '_Atomic' before symbol '*'\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
@@ -3147,12 +3219,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				}
 			} else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_CONST)) {
 				if (has_ident) {
-					printf("Error: invalid keyword 'const' after identifier\n");
+					log_error(&tok->loginfo, "invalid keyword 'const' after identifier\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
 				} else if (!vector_last(size_t, nptr_stack)) {
-					printf("Error: invalid keyword 'const' before symbol '*'\n");
+					log_error(&tok->loginfo, "invalid keyword 'const' before symbol '*'\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
@@ -3163,12 +3235,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				}
 			} else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_RESTRICT)) {
 				if (has_ident) {
-					printf("Error: invalid keyword 'restrict' after identifier\n");
+					log_error(&tok->loginfo, "invalid keyword 'restrict' after identifier\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
 				} else if (!vector_last(size_t, nptr_stack)) {
-					printf("Error: invalid keyword 'restrict' before symbol '*'\n");
+					log_error(&tok->loginfo, "invalid keyword 'restrict' before symbol '*'\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
@@ -3179,12 +3251,12 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 				}
 			} else if ((tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_VOLATILE)) {
 				if (has_ident) {
-					printf("Error: invalid keyword 'volatile' after identifier\n");
+					log_error(&tok->loginfo, "invalid keyword 'volatile' after identifier\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
 				} else if (!vector_last(size_t, nptr_stack)) {
-					printf("Error: invalid keyword 'volatile' before symbol '*'\n");
+					log_error(&tok->loginfo, "invalid keyword 'volatile' before symbol '*'\n");
 					proc_token_print(tok);
 					// Empty destructor
 					goto failed;
@@ -3200,13 +3272,7 @@ static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *d
 		case PTOK_STRING:
 		case PTOK_PRAGMA:
 		case PTOK_EOF:
-			printf("Error: unexpected token (parse_declarator %d%d%d%d)\n"
-			       "Current state:\n"
-			       "  storage: %u\n"
-			       "  type: ", is_init, is_list, allow_decl, allow_abstract, storage);
-			type_print(typ);
-			printf("\n");
-			proc_token_print(tok);
+			log_error(&tok->loginfo, "unexpected token (in parse_declarator %d%d%d%d)\n", is_init, is_list, allow_decl, allow_abstract);
 			proc_token_del(tok);
 			goto failed;
 		}
@@ -3226,44 +3292,44 @@ failed0:
 
 static int finalize_file(machine_t *target, file_t *file) {
 #define MARK_SIMPLE(sname) \
-	it = kh_get(struct_map, file->struct_map, #sname);                          \
-	if (it != kh_end(file->struct_map)) {                                       \
-		kh_val(file->struct_map, it)->is_simple = 1;                            \
-	} else {                                                                    \
-		it = kh_get(type_map, file->type_map, #sname);                          \
-		if (it != kh_end(file->type_map)) {                                     \
-			type_t *typ2 = kh_val(file->type_map, it);                          \
-			if (typ2->typ != TYPE_STRUCT_UNION) {                               \
-				printf("Error: invalid typedef " #sname ": not a structure\n"); \
-				return 0;                                                       \
-			}                                                                   \
-			typ2->val.st->is_simple = 1;                                        \
-		}                                                                       \
+	it = kh_get(struct_map, file->struct_map, #sname);                            \
+	if (it != kh_end(file->struct_map)) {                                         \
+		kh_val(file->struct_map, it)->is_simple = 1;                              \
+	} else {                                                                      \
+		it = kh_get(type_map, file->type_map, #sname);                            \
+		if (it != kh_end(file->type_map)) {                                       \
+			type_t *typ2 = kh_val(file->type_map, it);                            \
+			if (typ2->typ != TYPE_STRUCT_UNION) {                                 \
+				log_error_nopos("invalid typedef " #sname ": not a structure\n"); \
+				return 0;                                                         \
+			}                                                                     \
+			typ2->val.st->is_simple = 1;                                          \
+		}                                                                         \
 	}
 #define SET_WEAK(converted) \
-	validate_type(target, typ);                                              \
-	typ = type_try_merge(typ, file->type_set);                               \
-	it = kh_put(conv_map, file->relaxed_type_conversion, typ, &iret);        \
-	if (iret < 0) {                                                          \
-		printf("Error: failed to add relaxed conversion to type map\n");     \
-		type_del(typ);                                                       \
-		return 0;                                                            \
-	} else if (iret == 0) {                                                  \
-		printf("Error: type already has a relaxed conversion\n");            \
-		type_del(typ);                                                       \
-		return 0;                                                            \
-	}                                                                        \
+	validate_type(&(loginfo_t){0}, target, typ);                      \
+	typ = type_try_merge(typ, file->type_set);                        \
+	it = kh_put(conv_map, file->relaxed_type_conversion, typ, &iret); \
+	if (iret < 0) {                                                   \
+		log_memory("failed to add relaxed conversion to type map\n"); \
+		type_del(typ);                                                \
+		return 0;                                                     \
+	} else if (iret == 0) {                                           \
+		log_error_nopos("type already has a relaxed conversion\n");   \
+		type_del(typ);                                                \
+		return 0;                                                     \
+	}                                                                 \
 	kh_val(file->relaxed_type_conversion, it) = string_new_cstr(#converted);
 #define SET_WEAK_PTR_TO(to_typ, converted) \
-	it = kh_get(type_map, file->type_map, #to_typ);         \
-	if (it != kh_end(file->type_map)) {                     \
-		typ = type_new_ptr(kh_val(file->type_map, it));     \
-		if (!typ) {                                         \
-			printf("Failed to create type " #to_typ "*\n"); \
-			return 0;                                       \
-		}                                                   \
-		++kh_val(file->type_map, it)->nrefs;                \
-		SET_WEAK(converted)                                 \
+	it = kh_get(type_map, file->type_map, #to_typ);             \
+	if (it != kh_end(file->type_map)) {                         \
+		typ = type_new_ptr(kh_val(file->type_map, it));         \
+		if (!typ) {                                             \
+			log_memory("failed to create type " #to_typ "*\n"); \
+			return 0;                                           \
+		}                                                       \
+		++kh_val(file->type_map, it)->nrefs;                    \
+		SET_WEAK(converted)                                     \
 	}
 	
 	type_t *typ;
@@ -3273,13 +3339,25 @@ static int finalize_file(machine_t *target, file_t *file) {
 	SET_WEAK_PTR_TO(FILE, S)
 	// #pragma type_letters b xcb_connection_t*
 	SET_WEAK_PTR_TO(xcb_connection_t, S)
+	if (target->size_long == 4) {
+		// Only on x86, not on x86_64
+		it = kh_get(type_map, file->type_map, "locale_t");
+		if (it != kh_end(file->type_map)) {
+			typ = kh_val(file->type_map, it);
+			SET_WEAK(a)
+		}
+	}
 	// #pragma mark_simple ...
-	MARK_SIMPLE(FTS)
-	MARK_SIMPLE(FTS64)
-	MARK_SIMPLE(glob_t)
-	MARK_SIMPLE(glob64_t)
+	if (target->size_long == 8) {
+		// Only on x86_64, not on x86
+		MARK_SIMPLE(FTS)
+		MARK_SIMPLE(FTS64)
+		MARK_SIMPLE(glob_t)
+		MARK_SIMPLE(glob64_t)
+	}
 #undef MARK_SIMPLE
 #undef SET_WEAK
+#undef SET_WEAK_PTR_TO
 	return 1;
 }
 
@@ -3287,20 +3365,20 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 	char *dirname = strchr(filename, '/') ? strndup(filename, (size_t)(strrchr(filename, '/') - filename)) : NULL;
 	preproc_t *prep = preproc_new_file(target, file, dirname, filename);
 	if (!prep) {
-		printf("Failed to create the preproc structure\n");
+		log_memory("failed to create the preproc structure\n");
 		if (dirname) free(dirname);
 		return NULL;
 	}
 	file_t *ret = file_new(target);
 	if (!ret) {
-		printf("Failed to create the file structure\n");
+		log_memory("failed to create the file structure\n");
 		preproc_del(prep);
 		return NULL;
 	}
 	
 	type_t *typ = type_new();
 	if (!typ) {
-		printf("Failed to create a type info structure\n");
+		log_memory("failed to create a type info structure\n");
 		goto failed;
 	}
 	while (1) {
@@ -3315,17 +3393,17 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 					int iret;
 					char *dup = strdup(typenames[i]);
 					if (!dup) {
-						printf("Failed to create a type info structure\n");
+						log_memory("failed to create a type info structure\n");
 						goto failed;
 					}
 					type_t *t = ret->builtins[BTT_START_INT_EXT + i];
 					khiter_t it = kh_put(type_map, ret->type_map, dup, &iret);
 					if (iret < 0) {
-						printf("Failed to add an intrinsic to the type map\n");
+						log_memory("failed to add an intrinsic to the type map\n");
 						goto failed;
 					} else if (iret == 0) {
 						if (!type_t_equal(t, kh_val(ret->type_map, it))) {
-							printf("Error: %s is already defined\n", dup);
+							log_error(&tok.loginfo, "%s is already defined\n", dup);
 							free(dup);
 							goto failed;
 						}
@@ -3347,13 +3425,13 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 					if (it != kh_end(ret->struct_map)) {
 						type_t *typ2 = kh_val(ret->type_map, it);
 						if (typ2->typ != TYPE_STRUCT_UNION) {
-							printf("Error: failed to find struct/union named %s\n", string_content(sutag));
+							log_error(&tok.loginfo, "failed to find struct/union named %s\n", string_content(sutag));
 							string_del(sutag);
 							goto failed;
 						}
 						su = typ2->val.st;
 					} else {
-						printf("Error: failed to find struct/union named %s\n", string_content(sutag));
+						log_error(&tok.loginfo, "failed to find struct/union named %s\n", string_content(sutag));
 						string_del(sutag);
 						goto failed;
 					}
@@ -3366,7 +3444,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 				string_t *converted = tok.tokv.pragma.val;
 				type_t *typ2 = type_new();
 				if (!typ2) {
-					printf("Error: failed to create new type info structure\n");
+					log_memory("failed to create new type info structure\n");
 					string_del(converted);
 					type_del(typ2);
 					goto failed;
@@ -3380,13 +3458,13 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 				int iret;
 				khiter_t it = kh_put(conv_map, ret->relaxed_type_conversion, typ2, &iret);
 				if (iret < 0) {
-					printf("Error: failed to add relaxed conversion to type map\n");
+					log_memory("failed to add relaxed conversion to type map\n");
 					string_del(converted);
 					type_del(typ2);
 					// Empty destructor
 					goto failed;
 				} else if (iret == 0) {
-					printf("Error: type already has a relaxed conversion\n");
+					log_error(&tok.loginfo, "type already has a relaxed conversion\n");
 					string_del(converted);
 					type_del(typ2);
 					// Empty destructor
@@ -3400,7 +3478,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 				string_t *converted = tok.tokv.pragma.val;
 				type_t *typ2 = type_new();
 				if (!typ2) {
-					printf("Error: failed to create new type info structure\n");
+					log_memory("failed to create new type info structure\n");
 					string_del(converted);
 					type_del(typ2);
 					goto failed;
@@ -3413,7 +3491,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 				}
 				type_del(typ2); // typ2 is in the type set, so it is already used
 				if (typ2->converted) {
-					printf("Error: type already has a strict conversion\n");
+					log_error(&tok.loginfo, "type already has a strict conversion\n");
 					string_del(converted);
 					// Empty destructor
 					goto failed;
@@ -3424,7 +3502,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 				break; }
 			}
 		} else if (proc_token_iserror(&tok)) {
-			printf("Error: unexpected error token\n");
+			log_error(&tok.loginfo, "unexpected error token\n");
 			proc_token_del(&tok);
 			goto failed;
 		} else {
@@ -3442,11 +3520,11 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 					goto failed;
 				}
 			} else {
-				if (validate_storage_type(target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) {
+				if (validate_storage_type(&tok.loginfo, target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) {
 					goto failed;
 				}
 				if (fspec != FSPEC_NONE) {
-					printf("Error: unexpected function specifier\n");
+					log_error(&tok.loginfo, "unexpected function specifier\n");
 					// Empty destructor
 					goto failed;
 				}
@@ -3455,7 +3533,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 			type_del(typ);
 			typ = type_new();
 			if (!typ) {
-				printf("Failed to create a type info structure\n");
+				log_memory("failed to create a type info structure\n");
 				goto failed;
 			}
 		}
@@ -3465,7 +3543,7 @@ success:
 	preproc_del(prep);
 	type_del(typ);
 	if (!finalize_file(target, ret)) {
-		printf("Error: failed to add builtin aliases\n");
+		log_memory("failed to add builtin aliases\n");
 		file_del(ret);
 		return NULL;
 	}