about summary refs log tree commit diff stats
path: root/wrapperhelper/src
diff options
context:
space:
mode:
authorrajdakin <rajdakin@gmail.com>2024-09-07 15:20:17 +0200
committerGitHub <noreply@github.com>2024-09-07 15:20:17 +0200
commitf0d7582845e124ed61b86f43da30a7b3f3f0c3f5 (patch)
tree2ee0c53821805b33ca47e0919fea95ccb920cd52 /wrapperhelper/src
parent75bdb328284b8e5b6827eeb7d5cedef26222e7db (diff)
downloadbox64-f0d7582845e124ed61b86f43da30a7b3f3f0c3f5.tar.gz
box64-f0d7582845e124ed61b86f43da30a7b3f3f0c3f5.zip
Upgraded the wrapper helper (#1803)
* [WRAPPERHELPER] Fixed unsigned comparison in macros, added macro expanding in include commands, added -I option

* [WRAPPERHELPER] Forgot the README
Diffstat (limited to 'wrapperhelper/src')
-rw-r--r--wrapperhelper/src/cstring.c55
-rw-r--r--wrapperhelper/src/cstring.h4
-rw-r--r--wrapperhelper/src/lang.c35
-rw-r--r--wrapperhelper/src/lang.h1
-rw-r--r--wrapperhelper/src/machine.c178
-rw-r--r--wrapperhelper/src/machine.h33
-rw-r--r--wrapperhelper/src/main.c114
-rw-r--r--wrapperhelper/src/parse.c9
-rw-r--r--wrapperhelper/src/parse.h5
-rw-r--r--wrapperhelper/src/prepare.c2
-rw-r--r--wrapperhelper/src/preproc.c496
-rw-r--r--wrapperhelper/src/preproc.h3
-rw-r--r--wrapperhelper/src/preproc_private.h39
-rw-r--r--wrapperhelper/src/vector.c1
14 files changed, 798 insertions, 177 deletions
diff --git a/wrapperhelper/src/cstring.c b/wrapperhelper/src/cstring.c
index b38a43e6..aecfb52e 100644
--- a/wrapperhelper/src/cstring.c
+++ b/wrapperhelper/src/cstring.c
@@ -32,6 +32,22 @@ string_t *string_new_cap(size_t cap) {
 	return ret;
 }
 
+string_t *string_new_cstr(const char *s) {
+	string_t *ret = malloc(sizeof(*ret));
+	if (!ret) return NULL;
+	size_t len = strlen(s);
+	size_t cap = (len < STRING_MIN_CAP) ? STRING_MIN_CAP : len;
+	ret->buf = malloc((cap + 1) * sizeof(char));
+	if (!ret->buf) {
+		free(ret);
+		return NULL;
+	}
+	strcpy(ret->buf, s);
+	ret->scap = cap;
+	ret->ssize = len;
+	return ret;
+}
+
 int string_reserve(string_t *s, size_t cap) {
 	size_t new_cap = (cap < STRING_MIN_CAP) ? STRING_MIN_CAP : cap;
 	if (new_cap <= s->scap) return 1;
@@ -42,6 +58,18 @@ int string_reserve(string_t *s, size_t cap) {
 	s->scap = new_cap;
 	return 1;
 }
+int string_reserve_grow(string_t *s, size_t cap) {
+	cap = (cap < STRING_MIN_CAP) ? STRING_MIN_CAP : cap;
+	if (cap <= s->scap) return 1;
+	size_t new_cap = (s->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s->scap * 2;
+	while (new_cap < cap) new_cap *= 2;
+	
+	void *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
+	if (!new_buf) return 0;
+	s->buf = new_buf;
+	s->scap = new_cap;
+	return 1;
+}
 
 void string_del(string_t *s) {
 	if (s->buf) free(s->buf);
@@ -55,35 +83,28 @@ char *string_steal(string_t *s) {
 }
 
 int string_add_char(string_t *s, char elem) {
-	if (s->ssize >= s->scap) {
-		size_t new_cap = (s->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s->scap * 2;
-		char *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
-		if (!new_buf) return 0;
-		s->buf = new_buf;
-		s->scap = new_cap;
-	}
+	if (!string_reserve_grow(s, s->ssize + 1)) return 0;
 	s->buf[s->ssize++] = elem;
 	s->buf[s->ssize] = '\0';
 	return 1;
 }
 
 int string_add_string(string_t *s1, string_t *s2) {
-	if (s1->ssize + s2->ssize > s1->scap) {
-		size_t new_cap = (s1->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s1->scap * 2;
-		while (s1->ssize + s2->ssize > new_cap) {
-			new_cap = new_cap * 2;
-		}
-		char *new_buf = realloc(s1->buf, sizeof(char) * (new_cap + 1));
-		if (!new_buf) return 0;
-		s1->buf = new_buf;
-		s1->scap = new_cap;
-	}
+	if (!string_reserve_grow(s1, s1->ssize + s2->ssize)) return 0;
 	memcpy(s1->buf + s1->ssize, s2->buf, s2->ssize);
 	s1->ssize += s2->ssize;
 	s1->buf[s1->ssize] = '\0';
 	return 1;
 }
 
+int string_add_cstr(string_t *s1, const char *s2) {
+	size_t len = strlen(s2);
+	if (!string_reserve_grow(s1, s1->ssize + len)) return 0;
+	strcpy(s1->buf + s1->ssize, s2);
+	s1->ssize += len;
+	return 1;
+}
+
 void string_pop(string_t *s) {
 	if (!s->ssize) return;
 	s->buf[--s->ssize] = '\0';
diff --git a/wrapperhelper/src/cstring.h b/wrapperhelper/src/cstring.h
index 14032bd6..12c7df4c 100644
--- a/wrapperhelper/src/cstring.h
+++ b/wrapperhelper/src/cstring.h
@@ -13,11 +13,13 @@
  * string_t ------------ The string type.
  * string_new ---------- Creates a new string.
  * string_new_cap ------ Creates a new string with a given capacity. Takes the capacity.
+ * string_new_cstr ----- Creates a new string from a given C string. Takes the string.
  * string_reserve ------ Ensures a string has at least a given capacity. Takes the string and the capacity.
  * string_del ---------- Frees a string. Takes the string.
  * string_steal -------- Frees a string, keeping the content alive. Takes the string. The content (also returned) needs to be freed separately.
  * string_add_char ----- Add a character at the end. Takes the string and the new character. May increase the string capacity.
  * string_add_string --- Add a string at the end in-place. Takes both strings. May increase the string capacity.
+ * string_add_cstr ----- Add a C string at the end in-place. Takes both strings. May increase the string capacity.
  * string_pop ---------- Pops the last character. Takes the string. May reduce the string capacity.
  * string_dup ---------- Duplicate a string. Takes the string. Does not free the old string.
  * string_concat ------- Concatenate two strings. Takes both strings. Does not free any string.
@@ -58,11 +60,13 @@ typedef struct string_s {
 
 string_t *string_new(void);
 string_t *string_new_cap(size_t cap);
+string_t *string_new_cstr(const char *s);
 int       string_reserve(string_t *s, size_t cap);
 void      string_del(string_t *s);
 char     *string_steal(string_t *s);
 int       string_add_char(string_t *s, char elem);
 int       string_add_string(string_t *s1, string_t *s2);
+int       string_add_cstr(string_t *s1, const char *s2);
 void      string_pop(string_t *s);
 string_t *string_dup(string_t const *s);
 string_t *string_concat(string_t const *l, string_t const *r);
diff --git a/wrapperhelper/src/lang.c b/wrapperhelper/src/lang.c
index 9ca51b15..1c4cba6c 100644
--- a/wrapperhelper/src/lang.c
+++ b/wrapperhelper/src/lang.c
@@ -15,6 +15,41 @@
 #define DISP_ADDR_ARG(v) v,
 #endif
 
+preproc_token_t preproc_token_dup(preproc_token_t tok) {
+	preproc_token_t ret;
+	ret.tokt = tok.tokt;
+	switch (tok.tokt) {
+	case PPTOK_IDENT:
+	case PPTOK_IDENT_UNEXP:
+	case PPTOK_NUM:
+		ret.tokv.str = string_dup(tok.tokv.str);
+		if (!ret.tokv.str) {
+			ret.tokt = PPTOK_INVALID;
+			ret.tokv.c = '\0';
+		}
+		break;
+	case PPTOK_STRING:
+	case PPTOK_INCL:
+		ret.tokv.sisstr = tok.tokv.sisstr;
+		ret.tokv.sstr = string_dup(tok.tokv.sstr);
+		if (!ret.tokv.sstr) {
+			ret.tokt = PPTOK_INVALID;
+			ret.tokv.c = '\0';
+		}
+		string_del(tok.tokv.sstr);
+		break;
+	case PPTOK_INVALID:
+	case PPTOK_SYM:
+	case PPTOK_NEWLINE:
+	case PPTOK_BLANK:
+	case PPTOK_START_LINE_COMMENT:
+	case PPTOK_EOF:
+		ret.tokv.c = tok.tokv.c;
+		break;
+	}
+	return ret;
+}
+
 void preproc_token_del(preproc_token_t *tok) {
 	switch (tok->tokt) {
 	case PPTOK_IDENT:
diff --git a/wrapperhelper/src/lang.h b/wrapperhelper/src/lang.h
index 568ab855..2f1cf811 100644
--- a/wrapperhelper/src/lang.h
+++ b/wrapperhelper/src/lang.h
@@ -87,6 +87,7 @@ typedef struct preproc_token_s {
 	} tokv;
 } preproc_token_t;
 VECTOR_DECLARE(preproc, preproc_token_t)
+preproc_token_t preproc_token_dup(preproc_token_t tok);
 void preproc_token_del(preproc_token_t *tok);
 
 enum token_keyword_type_e {
diff --git a/wrapperhelper/src/machine.c b/wrapperhelper/src/machine.c
new file mode 100644
index 00000000..bd209bb6
--- /dev/null
+++ b/wrapperhelper/src/machine.c
@@ -0,0 +1,178 @@
+#include "machine.h"
+
+#include "preproc_private.h"
+
+machine_t machine_x86_64;
+// machine_t machine_x86;
+// machine_t machine_arm64;
+
+#define PASTE2(a, b) a ## b
+#define PASTE(a, b) PASTE2(a, b)
+#define STRINGIFY2(a) #a
+#define STRINGIFY(a) STRINGIFY2(a)
+#define MACHINE_STR STRINGIFY(CUR_MACHINE)
+#define EXTRA_PATHS \
+	PASTE(machine_, CUR_MACHINE).npaths = PASTE(CUR_MACHINE, _NPATHS) + npaths;                                  \
+	if (!(PASTE(machine_, CUR_MACHINE).include_path =                                                            \
+	      malloc((PASTE(CUR_MACHINE, _NPATHS) + npaths) * sizeof *PASTE(machine_, CUR_MACHINE).include_path))) { \
+		printf("Failed to add include path to " MACHINE_STR " platform\n");                                      \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _nopath));                                                        \
+	}                                                                                                            \
+	for (failure_id = 0; failure_id < npaths; ++failure_id) {                                                    \
+		if (!(PASTE(machine_, CUR_MACHINE).include_path[failure_id] = strdup(extra_include_path[failure_id]))) { \
+			printf("Failed to add include path to " MACHINE_STR " platform\n");                                  \
+			goto PASTE(failed_, PASTE(CUR_MACHINE, _paths));                                                     \
+		}                                                                                                        \
+	}
+#define ADD_PATH(path) \
+	if (!(PASTE(machine_, CUR_MACHINE).include_path[failure_id] = strdup(path))) { \
+		printf("Failed to add include path to " MACHINE_STR " platform\n");        \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _paths));                           \
+	}                                                                              \
+	++failure_id;
+#define EXTRA_MACROS \
+	PASTE(machine_, CUR_MACHINE).npredefs = PASTE(CUR_MACHINE, _NPREDEFS);                                       \
+	if (!(PASTE(machine_, CUR_MACHINE).predef_macros_name =                                                      \
+	      malloc((PASTE(CUR_MACHINE, _NPREDEFS)) * sizeof *PASTE(machine_, CUR_MACHINE).predef_macros_name))) {  \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");                                  \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _paths));                                                         \
+	}                                                                                                            \
+	if (!(PASTE(machine_, CUR_MACHINE).predef_macros =                                                           \
+	      malloc((PASTE(CUR_MACHINE, _NPREDEFS)) * sizeof *PASTE(machine_, CUR_MACHINE).predef_macros))) {       \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");                                  \
+		free(machine_x86_64.predef_macros_name);                                                                 \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _paths));                                                         \
+	}                                                                                                            \
+	failure_id = 0;
+#define ADD_NAME(mname) \
+	if (!(PASTE(machine_, CUR_MACHINE).predef_macros_name[failure_id] = strdup(#mname))) { \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");            \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _macros));                                  \
+	}
+#define ADD_MACRO(ntoks) \
+	if (!(PASTE(machine_, CUR_MACHINE).predef_macros[failure_id] =                   \
+	      malloc(sizeof *PASTE(machine_, CUR_MACHINE).predef_macros[failure_id]))) { \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");      \
+		free(machine_x86_64.predef_macros_name[failure_id]);                         \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _macros));                            \
+	}                                                                                \
+	*PASTE(machine_, CUR_MACHINE).predef_macros[failure_id] = (macro_t){             \
+		.is_funlike = 0,                                                             \
+		.has_varargs = 0,                                                            \
+		.nargs = 0,                                                                  \
+		.toks = vector_new_cap(mtoken, (ntoks)),                                     \
+	};                                                                               \
+	++failure_id;                                                                    \
+	if (!PASTE(machine_, CUR_MACHINE).predef_macros[failure_id - 1]->toks) {         \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");      \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _macros));                            \
+	}
+#define ADD_SYM(s) \
+	mtok = mtoken_new_token((preproc_token_t){.tokt = PPTOK_SYM, .tokv.sym = SYM_ ## s}); \
+	if (!mtok) {                                                                          \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");           \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _macros));                                 \
+	}                                                                                     \
+	vector_push(mtoken, PASTE(machine_, CUR_MACHINE).predef_macros[failure_id - 1]->toks, mtok);
+#define ADD_STR(typ, n) \
+	s = string_new_cstr(#n);                                                          \
+	if (!s) {                                                                         \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");       \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _macros));                             \
+	}                                                                                 \
+	mtok = mtoken_new_token((preproc_token_t){.tokt = PPTOK_ ## typ, .tokv.str = s}); \
+	if (!mtok) {                                                                      \
+		printf("Failed to add predefined macro to " MACHINE_STR " platform\n");       \
+		string_del(s);                                                                \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _macros));                             \
+	}                                                                                 \
+	vector_push(mtoken, PASTE(machine_, CUR_MACHINE).predef_macros[failure_id - 1]->toks, mtok);
+
+int init_machines(size_t npaths, const char *const *extra_include_path) {
+	size_t failure_id;
+	string_t *s;
+	mtoken_t *mtok;
+	
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
+#define CUR_MACHINE x86_64
+	machine_x86_64.size_long = 8;
+#define x86_64_NPATHS 5
+	EXTRA_PATHS
+	ADD_PATH("include-fixed")
+	ADD_PATH("/usr/lib/gcc/x86_64-pc-linux-gnu/14.2.1/include")
+	ADD_PATH("/usr/local/include")
+	ADD_PATH("/usr/lib/gcc/x86_64-pc-linux-gnu/14.2.1/include-fixed")
+	ADD_PATH("/usr/include")
+#define x86_64_NPREDEFS 9
+	EXTRA_MACROS
+	ADD_NAME(__x86_64__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 1)
+	ADD_NAME(__WCHAR_MAX__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 2147483647)
+	ADD_NAME(__WCHAR_MIN__)
+	ADD_MACRO(5)
+	ADD_SYM(LPAREN)
+	ADD_SYM(DASH)
+	ADD_STR(IDENT, __WCHAR_MAX__)
+	ADD_SYM(DASH)
+	ADD_STR(NUM, 1)
+	ADD_NAME(__CHAR_BIT__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 8)
+	ADD_NAME(__SCHAR_MAX__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 127)
+	ADD_NAME(__SHRT_MAX__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 32767)
+	ADD_NAME(__INT_MAX__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 2147483647)
+	ADD_NAME(__LONG_MAX__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 9223372036854775807L)
+	ADD_NAME(__LONG_LONG_MAX__)
+	ADD_MACRO(1)
+	ADD_STR(NUM, 9223372036854775807LL)
+#undef CUR_MACHINE
+#pragma GCC diagnostic pop
+	
+	return 1;
+	
+failed_x86_64_macros:
+	while (failure_id--) {
+		macro_del(machine_x86_64.predef_macros[failure_id]);
+		free(machine_x86_64.predef_macros[failure_id]);
+		free(machine_x86_64.predef_macros_name[failure_id]);
+	}
+	free(machine_x86_64.predef_macros);
+	free(machine_x86_64.predef_macros_name);
+	failure_id = machine_x86_64.npaths;
+failed_x86_64_paths:
+	while (failure_id--) {
+		free(machine_x86_64.include_path[failure_id]);
+	}
+	free(machine_x86_64.include_path);
+failed_x86_64_nopath:
+	return 0;
+}
+
+static void machine_del(machine_t *m) {
+	for (size_t predef_id = m->npredefs; predef_id--;) {
+		macro_del(m->predef_macros[predef_id]);
+		free(m->predef_macros[predef_id]);
+		free(m->predef_macros_name[predef_id]);
+	}
+	free(m->predef_macros);
+	free(m->predef_macros_name);
+	for (size_t path_no = m->npaths; path_no--;) {
+		free(m->include_path[path_no]);
+	}
+	free(machine_x86_64.include_path);
+}
+void del_machines(void) {
+	machine_del(&machine_x86_64);
+}
diff --git a/wrapperhelper/src/machine.h b/wrapperhelper/src/machine.h
new file mode 100644
index 00000000..0f850fef
--- /dev/null
+++ b/wrapperhelper/src/machine.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#ifndef MACHINE_H
+#define MACHINE_H
+
+#include "cstring.h"
+#include "khash.h"
+#include "vector.h"
+
+struct macro_s; // preproc_private.h
+
+typedef struct machine_s {
+	// Preprocessor
+	size_t npaths;
+	char **include_path;
+	
+	size_t npredefs;
+	char **predef_macros_name;
+	struct macro_s **predef_macros;
+	
+	// Parsing
+	size_t size_long;
+	// TODO: also have info on unnamed bitfields, etc
+} machine_t;
+
+extern machine_t machine_x86_64;
+// extern machine_t machine_x86;
+// extern machine_t machine_arm64;
+
+int init_machines(size_t npaths, const char *const *extra_include_path);
+void del_machines(void);
+
+#endif // MACHINE_H
diff --git a/wrapperhelper/src/main.c b/wrapperhelper/src/main.c
index 8a397b6b..ffe09146 100644
--- a/wrapperhelper/src/main.c
+++ b/wrapperhelper/src/main.c
@@ -6,6 +6,7 @@
 
 #include "generator.h"
 #include "lang.h"
+#include "machine.h"
 #include "parse.h"
 #include "khash.h"
 
@@ -38,59 +39,98 @@ int main(int argc, char **argv) {
 		return 2;
 	}
 	
-	enum main_state ms;
-	int off;
+	enum main_state ms = MAIN_RUN;
+	const char *in_file = NULL, *ref_file = NULL, *out_file = NULL;
+	VECTOR(charp) *paths = vector_new(charp);
 	
-	if ((argc == 2) && !strcmp(argv[1], "--help")) {
-		help(argv[0]);
-		return 0;
-	} else if (argc == 2) {
-		ms = MAIN_PROC;
-		off = 1;
-	} else if ((argc == 3) && !strcmp(argv[1], "--prepare")) {
-		ms = MAIN_PREPARE;
-		off = 2;
-	} else if ((argc == 3) && !strcmp(argv[1], "--preproc")) {
-		ms = MAIN_PREPROC;
-		off = 2;
-	} else if ((argc == 3) && !strcmp(argv[1], "--proc")) {
-		ms = MAIN_PROC;
-		off = 2;
-	} else if (argc == 4) {
-		ms = MAIN_RUN;
-		off = 1;
-	} else {
-		help(argv[0]);
-		return 2;
+	for (int i = 1; i < argc; ++i) {
+		if (!strcmp(argv[i], "--help")) {
+			help(argv[0]);
+			return 0;
+		} else if (!strcmp(argv[i], "--prepare")) {
+			ms = MAIN_PREPARE;
+		} else if (!strcmp(argv[i], "--preproc")) {
+			ms = MAIN_PREPROC;
+		} else if (!strcmp(argv[i], "--proc")) {
+			ms = MAIN_PROC;
+		} else if (!strcmp(argv[i], "-I") && (i + 1 < argc)) {
+			if (!vector_push(charp, paths, argv[i + 1])) {
+				printf("Error: failed to add path to buffer\n");
+				return 2;
+			}
+		} else if ((argv[i][0] == '-') && (argv[i][1] == 'I') && (argv[i][2] != '\0')) {
+			if (!vector_push(charp, paths, argv[i] + 2)) {
+				printf("Error: failed to add path to buffer\n");
+				return 2;
+			}
+		} else if (!in_file) {
+			in_file = argv[i];
+		} else if (!ref_file) {
+			ref_file = argv[i];
+		} else if (!out_file) {
+			out_file = argv[i];
+		} else {
+			printf("Error: too many unknown options considered as file\n");
+			help(argv[0]);
+			return 2;
+		}
+	}
+	switch (ms) {
+	case MAIN_PREPARE:
+	case MAIN_PREPROC:
+	case MAIN_PROC:
+		if (!in_file || ref_file || out_file) {
+			printf("Error: too many unknown options/not enough arguments\n");
+			help(argv[0]);
+			return 2;
+		}
+		break;
+	case MAIN_RUN:
+		if (in_file && !ref_file && !out_file) {
+			ms = MAIN_PROC;
+		} else if (!in_file || !ref_file || !out_file) {
+			printf("Error: too many unknown options/not enough arguments\n");
+			help(argv[0]);
+			return 2;
+		}
+		break;
 	}
 	
 	if (!init_str2kw()) {
 		return 2;
 	}
+	if (!init_machines(vector_size(charp, paths), (const char*const*)vector_content(charp, paths))) {
+		vector_del(charp, paths);
+		return 2;
+	}
+	vector_del(charp, paths);
 	
-	FILE *f = fopen(argv[off], "r");
+	FILE *f = fopen(in_file, "r");
 	if (!f) {
-		err(2, "Error: failed to open %s", argv[off]);
+		err(2, "Error: failed to open %s", in_file);
 		return 2;
 	}
 	switch (ms) {
 	case MAIN_RUN: {
-		file_t *content = parse_file(argv[off], f); // Takes ownership of f
+		file_t *content = parse_file(&machine_x86_64, in_file, f); // Takes ownership of f
 		if (!content) {
 			printf("Error: failed to parse the file\n");
+			del_machines();
 			del_str2kw();
 			return 0;
 		}
 		
-		FILE *ref = fopen(argv[off + 1], "r");
+		FILE *ref = fopen(ref_file, "r");
 		if (!ref) {
-			err(2, "Error: failed to open %s", argv[off + 1]);
+			err(2, "Error: failed to open %s", ref_file);
+			del_machines();
 			del_str2kw();
 			return 2;
 		}
-		VECTOR(requests) *reqs = requests_from_file(argv[off + 1], ref);
+		VECTOR(requests) *reqs = requests_from_file(ref_file, ref);
 		if (!reqs) {
 			file_del(content);
+			del_machines();
 			del_str2kw();
 			return 2;
 		}
@@ -100,11 +140,12 @@ int main(int argc, char **argv) {
 		}
 		// vector_for(requests, req, reqs) request_print(req);
 		//vector_for(requests, req, reqs) request_print_check(req);
-		FILE *out = fopen(argv[off + 2], "w");
+		FILE *out = fopen(out_file, "w");
 		if (!out) {
-			err(2, "Error: failed to open %s", argv[off + 1]);
+			err(2, "Error: failed to open %s", ref_file);
 			file_del(content);
 			vector_del(requests, reqs);
+			del_machines();
 			del_str2kw();
 			return 2;
 		}
@@ -112,12 +153,14 @@ int main(int argc, char **argv) {
 		fclose(out);
 		vector_del(requests, reqs);
 		file_del(content);
+		del_machines();
 		del_str2kw();
 		return 0; }
 	case MAIN_PROC: {
-		file_t *content = parse_file(argv[off], f); // Takes ownership of f
+		file_t *content = parse_file(&machine_x86_64, in_file, f); // Takes ownership of f
 		if (!content) {
 			printf("Error: failed to parse the file\n");
+			del_machines();
 			del_str2kw();
 			return 0;
 		}
@@ -165,16 +208,19 @@ int main(int argc, char **argv) {
 			printf("\n")
 		)
 		file_del(content);
+		del_machines();
 		del_str2kw();
 		return 0; }
 		
 	case MAIN_PREPARE:
-		dump_prepare(argv[off], f); // Takes ownership of f
+		dump_prepare(in_file, f); // Takes ownership of f
+		del_machines();
 		del_str2kw();
 		return 0;
 		
 	case MAIN_PREPROC:
-		dump_preproc(argv[off], f); // Takes ownership of f
+		dump_preproc(&machine_x86_64, in_file, f); // Takes ownership of f
+		del_machines();
 		del_str2kw();
 		return 0;
 	}
diff --git a/wrapperhelper/src/parse.c b/wrapperhelper/src/parse.c
index cba0d9de..83167bd9 100644
--- a/wrapperhelper/src/parse.c
+++ b/wrapperhelper/src/parse.c
@@ -5,6 +5,7 @@
 
 #include "cstring.h"
 #include "khash.h"
+#include "machine.h"
 #include "prepare.h"
 #include "preproc.h"
 
@@ -25,9 +26,9 @@ void dump_prepare(const char *filename, FILE *file) {
 		preproc_token_del(&tok);
 	}
 }
-void dump_preproc(const char *filename, FILE *file) {
+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(file, dirname, filename);
+	preproc_t *prep = preproc_new_file(target, file, dirname, filename);
 	if (!prep) {
 		printf("Failed to create the preproc structure\n");
 		if (dirname) free(dirname);
@@ -3051,9 +3052,9 @@ failed0:
 	return 0;
 }
 
-file_t *parse_file(const char *filename, FILE *file) {
+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(file, dirname, filename);
+	preproc_t *prep = preproc_new_file(target, file, dirname, filename);
 	if (!prep) {
 		printf("Failed to create the preproc structure\n");
 		if (dirname) free(dirname);
diff --git a/wrapperhelper/src/parse.h b/wrapperhelper/src/parse.h
index 8c7d54b3..e80f32d2 100644
--- a/wrapperhelper/src/parse.h
+++ b/wrapperhelper/src/parse.h
@@ -6,9 +6,10 @@
 #include <stdio.h>
 
 #include "lang.h"
+#include "machine.h"
 
 void dump_prepare(const char *filename, FILE *file);
-void dump_preproc(const char *filename, FILE *file);
-file_t *parse_file(const char *filename, FILE *file);
+void dump_preproc(machine_t *target, const char *filename, FILE *file);
+file_t *parse_file(machine_t *target, const char *filename, FILE *file);
 
 #endif // PARSE_H
diff --git a/wrapperhelper/src/prepare.c b/wrapperhelper/src/prepare.c
index 090da0b0..994d8292 100644
--- a/wrapperhelper/src/prepare.c
+++ b/wrapperhelper/src/prepare.c
@@ -99,7 +99,7 @@ static void fill_str(prepare_t *src, string_t *buf, char end_c, int can_esc) {
 			} else {
 				string_add_char(buf, '\\');
 			}
-		} else if ((c >= 0) && (c <= 0x7F) && (c != end_c)) {
+		} else if ((c >= 0) && (c <= 0x7F) && (c != '\n') && (c != end_c)) {
 			has_esc = 0;
 			string_add_char(buf, (char)c);
 		} else {
diff --git a/wrapperhelper/src/preproc.c b/wrapperhelper/src/preproc.c
index ba99f754..cdff0a4e 100644
--- a/wrapperhelper/src/preproc.c
+++ b/wrapperhelper/src/preproc.c
@@ -1,29 +1,18 @@
 // I think this file is too big for GCC to handle properly, there are curious false-positive analyzer warnings
 //  that didn't appear before adding preproc_eval
 #include "preproc.h"
+#include "preproc_private.h"
 
 #include <stdint.h>
 #include <string.h>
 
 #include "cstring.h"
 #include "khash.h"
+#include "machine.h"
 #include "prepare.h"
 
-typedef struct mtoken_s {
-	enum mtoken_e {
-		MTOK_TOKEN,
-		MTOK_ARG,
-		MTOK_STRINGIFY,
-		MTOK_CONCAT,
-	} typ;
-	union {
-		preproc_token_t tok;
-		unsigned argid;
-		struct { struct mtoken_s *l, *r; } concat;
-	} val;
-} mtoken_t;
 KHASH_MAP_INIT_STR(argid_map, unsigned)
-void argid_map_del(khash_t(argid_map) *args) {
+static void argid_map_del(khash_t(argid_map) *args) {
 	kh_cstr_t str;
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-qual"
@@ -31,47 +20,74 @@ void argid_map_del(khash_t(argid_map) *args) {
 #pragma GCC diagnostic pop
 	kh_destroy(argid_map, args);
 }
-static mtoken_t *mtoken_new_token(preproc_token_t tok) {
+mtoken_t *mtoken_new_token(preproc_token_t tok) {
 	mtoken_t *ret = malloc(sizeof *ret);
 	if (!ret) return NULL;
 	ret->typ = MTOK_TOKEN;
 	ret->val.tok = tok;
 	return ret;
 }
-static mtoken_t *mtoken_new_arg(unsigned argid, int as_string) {
+mtoken_t *mtoken_new_arg(unsigned argid, int as_string) {
 	mtoken_t *ret = malloc(sizeof *ret);
 	if (!ret) return NULL;
 	ret->typ = as_string ? MTOK_STRINGIFY : MTOK_ARG;
 	ret->val.argid = argid;
 	return ret;
 }
-static mtoken_t *mtoken_new_concat(mtoken_t *l, mtoken_t *r) { // Takes ownership of l and r
+mtoken_t *mtoken_new_concat(mtoken_t *l, mtoken_t *r) { // Takes ownership of l and r
 	mtoken_t *ret = malloc(sizeof *ret);
-	if (!ret) return NULL;
+	if (!ret) {
+		mtoken_del(l);
+		mtoken_del(r);
+		return NULL;
+	}
 	ret->typ = MTOK_CONCAT;
 	ret->val.concat.l = l;
 	ret->val.concat.r = r;
 	return ret;
 }
-static void mtoken_del(mtoken_t **tok) {
-	switch ((*tok)->typ) {
+void mtoken_del(mtoken_t *tok) {
+	switch (tok->typ) {
 	case MTOK_TOKEN:
-		preproc_token_del(&(*tok)->val.tok);
-		free(*tok);
+		preproc_token_del(&tok->val.tok);
+		free(tok);
 		return;
 		
 	case MTOK_CONCAT:
-		mtoken_del(&(*tok)->val.concat.l);
-		mtoken_del(&(*tok)->val.concat.r);
-		free(*tok);
+		mtoken_del(tok->val.concat.l);
+		mtoken_del(tok->val.concat.r);
+		free(tok);
 		return;
 		
 	case MTOK_ARG:
 	case MTOK_STRINGIFY:
-		free(*tok);
+		free(tok);
 		return;
 	}
 }
+mtoken_t *mtoken_dup(mtoken_t *src) {
+	switch (src->typ) {
+	case MTOK_TOKEN:
+		return mtoken_new_token(preproc_token_dup(src->val.tok));
+		
+	case MTOK_ARG:
+		return mtoken_new_arg(src->val.argid, 0);
+		
+	case MTOK_STRINGIFY:
+		return mtoken_new_arg(src->val.argid, 1);
+		
+	case MTOK_CONCAT: {
+		mtoken_t *l = mtoken_dup(src->val.concat.l);
+		if (!l) return NULL;
+		mtoken_t *r = mtoken_dup(src->val.concat.r);
+		if (!r) {
+			mtoken_del(l);
+			return NULL;
+		}
+		return mtoken_new_concat(l, r); }
+	}
+	return NULL;
+}
 
 static inline void print_macro_tok(mtoken_t *m) {
 	switch (m->typ) {
@@ -100,19 +116,13 @@ static inline void print_macro_tok(mtoken_t *m) {
 	}
 }
 
-VECTOR_DECLARE_STATIC(mtoken, mtoken_t*)
-VECTOR_IMPL_STATIC(mtoken, mtoken_del)
-
-typedef struct macro_s {
-	int is_funlike;
-	int has_varargs;
-	unsigned nargs;
-	VECTOR(mtoken) *toks;
-} macro_t;
+#define mtoken_ptr_del(m) mtoken_del(*(m))
+VECTOR_IMPL(mtoken, mtoken_ptr_del)
+#undef mtoken_ptr_del
 
 KHASH_MAP_INIT_STR(macros_map, macro_t)
 KHASH_SET_INIT_STR(string_set)
-static void macro_del(macro_t *m) {
+void macro_del(macro_t *m) {
 	vector_del(mtoken, m->toks);
 }
 static void macros_map_del(khash_t(macros_map) *args) {
@@ -133,6 +143,32 @@ static void macros_set_del(khash_t(string_set) *strset) {
 	kh_destroy(string_set, strset);
 }
 
+VECTOR(mtoken) *mtokens_dup(const VECTOR(mtoken) *src) {
+	VECTOR(mtoken) *ret = vector_new_cap(mtoken, vector_size(mtoken, src));
+	if (!ret) return NULL;
+	vector_for(mtoken, mtok, src) {
+		mtoken_t *mtok2 = mtoken_dup(*mtok);
+		if (!mtok2) {
+			vector_del(mtoken, ret);
+			return NULL;
+		}
+		if (!vector_push(mtoken, ret, mtok2)) {
+			mtoken_del(mtok2);
+			vector_del(mtoken, ret);
+			return NULL;
+		}
+	}
+	return ret;
+}
+int macro_dup(macro_t *dest, const macro_t *src) {
+	dest->is_funlike = src->is_funlike;
+	dest->has_varargs = src->has_varargs;
+	dest->nargs = src->nargs;
+	dest->toks = mtokens_dup(src->toks);
+	if (!dest->toks) return 0;
+	return 1;
+}
+
 typedef struct ppsource_s {
 	enum ppsrc_e {
 		PPSRC_PREPARE = 0,
@@ -189,6 +225,7 @@ VECTOR_DECLARE_STATIC(ppsource, ppsource_t)
 VECTOR_IMPL_STATIC(ppsource, ppsource_del)
 
 struct preproc_s {
+	machine_t *target;
 	VECTOR(ppsource) *prep;
 	enum preproc_state_e {
 		PPST_NONE,
@@ -237,12 +274,13 @@ static preproc_token_t ppsrc_next_token(preproc_t *src) {
 	}
 }
 
-preproc_t *preproc_new_file(FILE *f, char *dirname, const char *filename) {
+preproc_t *preproc_new_file(machine_t *target, FILE *f, char *dirname, const char *filename) {
 	preproc_t *ret = malloc(sizeof *ret);
 	if (!ret) {
 		fclose(f);
 		return NULL;
 	}
+	ret->target = target;
 	ret->macros_map = kh_init(macros_map);
 	if (!ret->macros_map) {
 		fclose(f);
@@ -274,7 +312,45 @@ preproc_t *preproc_new_file(FILE *f, char *dirname, const char *filename) {
 		return NULL;
 	}
 	ret->dirname = NULL;
+	ret->cur_file = NULL;
 	// ret can now be deleted by preproc_del
+	
+	// First add predefined macros
+	for (size_t i = 0; i < target->npredefs; ++i) {
+		// NL and EOF have empty destructors
+		khiter_t kh_k;
+		int iret;
+		char *mname_dup = strdup(target->predef_macros_name[i]);
+		if (!mname_dup) {
+			printf("Error: failed to initialize preprocessor (predefined macros), aborting\n");
+			preproc_del(ret);
+			return NULL;
+		}
+		kh_k = kh_put(string_set, ret->macros_defined, mname_dup, &iret);
+		// TODO: check iret?
+		if (iret >= 1) {
+			mname_dup = strdup(mname_dup);
+		}
+		kh_k = kh_put(macros_map, ret->macros_map, mname_dup, &iret);
+		if (iret < 0) {
+			printf("Error: failed to initialize preprocessor (predefined macros), aborting\n");
+			preproc_del(ret);
+			return NULL;
+		} else if (iret == 0) {
+			printf("Error: duplicated predefined macros, aborting\n");
+			preproc_del(ret);
+			return NULL;
+		}
+		if (!macro_dup(&kh_val(ret->macros_map, kh_k), target->predef_macros[i])) {
+			printf("Error: failed to initialize preprocessor (predefined macros), aborting\n");
+			free(mname_dup);
+			kh_del(macros_map, ret->macros_map, kh_k);
+			preproc_del(ret);
+			return NULL;
+		}
+	}
+	
+	// Next include the first file
 	if (!vector_push(ppsource, ret->prep, PREPARE_NEW_FILE(f, filename, NULL, NULL, 0, 0))) {
 		preproc_del(ret);
 		return NULL;
@@ -283,6 +359,7 @@ preproc_t *preproc_new_file(FILE *f, char *dirname, const char *filename) {
 		preproc_del(ret);
 		return NULL;
 	}
+	// Last finish setting up ret
 	ret->st = PPST_NL;
 	ret->is_sys = 0;
 	ret->dirname = dirname;
@@ -291,14 +368,6 @@ preproc_t *preproc_new_file(FILE *f, char *dirname, const char *filename) {
 	return ret;
 }
 
-const char *incl_paths[] = {
-	"include-fixed",
-	"/usr/lib/gcc/x86_64-pc-linux-gnu/14.2.1/include",
-	"/usr/local/include",
-	"/usr/lib/gcc/x86_64-pc-linux-gnu/14.2.1/include-fixed",
-	"/usr/include",
-	"/usr/include/tirpc",
-};
 static int try_open_dir(preproc_t *src, string_t *filename) {
 	size_t fnlen = string_len(filename);
 	size_t incl_len = src->dirname ? strlen(src->dirname) : 1;
@@ -332,11 +401,11 @@ static int try_open_dir(preproc_t *src, string_t *filename) {
 }
 static int try_open_sys(preproc_t *src, string_t *filename, size_t array_off) {
 	size_t fnlen = string_len(filename);
-	for (; array_off < sizeof incl_paths / sizeof *incl_paths; ++array_off) {
-		size_t incl_len = strlen(incl_paths[array_off]);
+	for (; array_off < src->target->npaths; ++array_off) {
+		size_t incl_len = strlen(src->target->include_path[array_off]);
 		char *fn = malloc(incl_len + fnlen + 2);
 		if (!fn) return 0;
-		memcpy(fn, incl_paths[array_off], incl_len);
+		memcpy(fn, src->target->include_path[array_off], incl_len);
 		fn[incl_len] = '/';
 		strcpy(fn + incl_len + 1, string_content(filename));
 		FILE *f = fopen(fn, "r");
@@ -1005,7 +1074,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 		return 0;
 	}
 	vector_push(ppeaux, stack, (preproc_eval_aux_t){0}); // vector_cap >= 1
-	int64_t acc;
+	int64_t acc; _Bool is_unsigned = 0;
 	vector_for(preproc, tok, cond) {
 		if (tok->tokt == PPTOK_NUM) {
 			// Evaluate token as an integer if st0 == 0, error otherwise
@@ -1015,10 +1084,10 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 					goto eval_fail;
 				}
 				switch (cst.typ) {
-				case NCT_INT32:  acc =          cst.val.i32; break;
-				case NCT_UINT32: acc =          cst.val.u32; break;
-				case NCT_INT64:  acc =          cst.val.i64; break;
-				case NCT_UINT64: acc = (int64_t)cst.val.u64; break;
+				case NCT_INT32:                   acc =          cst.val.i32; break;
+				case NCT_UINT32: is_unsigned = 1; acc =          cst.val.u32; break;
+				case NCT_INT64:                   acc =          cst.val.i64; break;
+				case NCT_UINT64: is_unsigned = 1; acc = (int64_t)cst.val.u64; break;
 				case NCT_FLOAT:
 				case NCT_DOUBLE:
 				case NCT_LDOUBLE:
@@ -1034,6 +1103,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 		} else if ((tok->tokt == PPTOK_IDENT) || (tok->tokt == PPTOK_IDENT_UNEXP)) {
 			// Evaluate token as 0 if st0 == 0, error otherwise
 			if (vector_last(ppeaux, stack).st0 == 0) {
+				is_unsigned = 0;
 				acc = 0;
 				goto push_acc_to_st0;
 			} else {
@@ -1284,6 +1354,10 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 					acc = vector_last(ppeaux, stack).v2 * acc;
 					vector_last(ppeaux, stack).st2 = 0;
 				} else if (vector_last(ppeaux, stack).st2 == OPTYP_DIV) {
+					if (!acc) {
+						printf("Error: division by zero\n");
+						goto eval_fail;
+					}
 					acc = vector_last(ppeaux, stack).v2 / acc;
 					vector_last(ppeaux, stack).st2 = 0;
 				} else if (vector_last(ppeaux, stack).st2) {
@@ -1304,23 +1378,27 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 					acc = vector_last(ppeaux, stack).v4 << acc;
 					vector_last(ppeaux, stack).st4 = 0;
 				} else if (vector_last(ppeaux, stack).st4 == OPTYP_LSR) {
-					acc = vector_last(ppeaux, stack).v4 >> acc;
+					acc = is_unsigned ? (int64_t)((uint64_t)vector_last(ppeaux, stack).v4 >> (uint64_t)acc) : (vector_last(ppeaux, stack).v4 >> acc);
 					vector_last(ppeaux, stack).st4 = 0;
 				} else if (vector_last(ppeaux, stack).st4) {
 					printf("<internal error> Unknown st4 %d during #if evaluation\n", vector_last(ppeaux, stack).st4);
 					goto eval_fail;
 				}
 				if (vector_last(ppeaux, stack).st5 == OPTYP_LET) {
-					acc = vector_last(ppeaux, stack).v5 < acc;
+					acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 < (uint64_t)acc) : (vector_last(ppeaux, stack).v5 < acc);
+					is_unsigned = 0;
 					vector_last(ppeaux, stack).st5 = 0;
 				} else if (vector_last(ppeaux, stack).st5 == OPTYP_LEE) {
-					acc = vector_last(ppeaux, stack).v5 <= acc;
+					acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 <= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 <= acc);
+					is_unsigned = 0;
 					vector_last(ppeaux, stack).st5 = 0;
 				} else if (vector_last(ppeaux, stack).st5 == OPTYP_GRT) {
-					acc = vector_last(ppeaux, stack).v5 > acc;
+					acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 > (uint64_t)acc) : (vector_last(ppeaux, stack).v5 > acc);
+					is_unsigned = 0;
 					vector_last(ppeaux, stack).st5 = 0;
 				} else if (vector_last(ppeaux, stack).st5 == OPTYP_GRE) {
-					acc = vector_last(ppeaux, stack).v5 >= acc;
+					acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 >= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 >= acc);
+					is_unsigned = 0;
 					vector_last(ppeaux, stack).st5 = 0;
 				} else if (vector_last(ppeaux, stack).st5) {
 					printf("<internal error> Unknown st5 %d during #if evaluation\n", vector_last(ppeaux, stack).st5);
@@ -1368,6 +1446,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 					goto push_acc_to_st0;
 				} else {
 				eval_question_acc:
+					is_unsigned = 0;
 					if (acc) {
 						// Increase n_colons
 						++vector_last(ppeaux, stack).n_colons;
@@ -1473,6 +1552,10 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 				acc = vector_last(ppeaux, stack).v2 * acc;
 				vector_last(ppeaux, stack).st2 = 0;
 			} else if (vector_last(ppeaux, stack).st2 == OPTYP_DIV) {
+				if (!acc) {
+					printf("Error: division by zero\n");
+					goto eval_fail;
+				}
 				acc = vector_last(ppeaux, stack).v2 / acc;
 				vector_last(ppeaux, stack).st2 = 0;
 			} else if (vector_last(ppeaux, stack).st2) {
@@ -1503,7 +1586,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 				acc = vector_last(ppeaux, stack).v4 << acc;
 				vector_last(ppeaux, stack).st4 = 0;
 			} else if (vector_last(ppeaux, stack).st4 == OPTYP_LSR) {
-				acc = vector_last(ppeaux, stack).v4 >> acc;
+				acc = is_unsigned ? (int64_t)((uint64_t)vector_last(ppeaux, stack).v4 >> (uint64_t)acc) : (vector_last(ppeaux, stack).v4 >> acc);
 				vector_last(ppeaux, stack).st4 = 0;
 			} else if (vector_last(ppeaux, stack).st4) {
 				printf("<internal error> Unknown st4 %d during #if evaluation\n", vector_last(ppeaux, stack).st4);
@@ -1515,16 +1598,20 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 				goto done_partial_eval;
 			}
 			if (vector_last(ppeaux, stack).st5 == OPTYP_LET) {
-				acc = vector_last(ppeaux, stack).v5 < acc;
+				acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 < (uint64_t)acc) : (vector_last(ppeaux, stack).v5 < acc);
+				is_unsigned = 0;
 				vector_last(ppeaux, stack).st5 = 0;
 			} else if (vector_last(ppeaux, stack).st5 == OPTYP_LEE) {
-				acc = vector_last(ppeaux, stack).v5 <= acc;
+				acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 <= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 <= acc);
+				is_unsigned = 0;
 				vector_last(ppeaux, stack).st5 = 0;
 			} else if (vector_last(ppeaux, stack).st5 == OPTYP_GRT) {
-				acc = vector_last(ppeaux, stack).v5 > acc;
+				acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 > (uint64_t)acc) : (vector_last(ppeaux, stack).v5 > acc);
+				is_unsigned = 0;
 				vector_last(ppeaux, stack).st5 = 0;
 			} else if (vector_last(ppeaux, stack).st5 == OPTYP_GRE) {
-				acc = vector_last(ppeaux, stack).v5 >= acc;
+				acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 >= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 >= acc);
+				is_unsigned = 0;
 				vector_last(ppeaux, stack).st5 = 0;
 			} else if (vector_last(ppeaux, stack).st5) {
 				printf("<internal error> Unknown st5 %d during #if evaluation\n", vector_last(ppeaux, stack).st5);
@@ -1589,6 +1676,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 			if (op_lvl == 10) {
 				// We know that sym == SYM_AMPAMP, so we need to skip evaluating the remainder if it equals 0
 				if (acc) goto done_partial_eval;
+				is_unsigned = 0;
 				unsigned nparens = 0;
 				// 0 && y ? z : w => w
 				// 0 && y || z => z
@@ -1622,6 +1710,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 			if (op_lvl == 11) {
 				// We know that sym == SYM_PIPEPIPE, so we need to skip evaluating the remainder if it equals 1
 				if (!acc) goto done_partial_eval;
+				is_unsigned = 0;
 				unsigned nparens = 0;
 				// 0 || y ? z : w => w
 				// Otherwise, keep skipping to the next token
@@ -1698,6 +1787,10 @@ done_complete_stack:
 		acc = vector_last(ppeaux, stack).v2 * acc;
 		vector_last(ppeaux, stack).st2 = 0;
 	} else if (vector_last(ppeaux, stack).st2 == OPTYP_DIV) {
+		if (!acc) {
+			printf("Error: division by zero\n");
+			goto eval_fail;
+		}
 		acc = vector_last(ppeaux, stack).v2 / acc;
 		vector_last(ppeaux, stack).st2 = 0;
 	} else if (vector_last(ppeaux, stack).st2) {
@@ -1718,23 +1811,27 @@ done_complete_stack:
 		acc = vector_last(ppeaux, stack).v4 << acc;
 		vector_last(ppeaux, stack).st4 = 0;
 	} else if (vector_last(ppeaux, stack).st4 == OPTYP_LSR) {
-		acc = vector_last(ppeaux, stack).v4 >> acc;
+		acc = is_unsigned ? (int64_t)((uint64_t)vector_last(ppeaux, stack).v4 >> (uint64_t)acc) : (vector_last(ppeaux, stack).v4 >> acc);
 		vector_last(ppeaux, stack).st4 = 0;
 	} else if (vector_last(ppeaux, stack).st4) {
 		printf("<internal error> Unknown st4 %d during #if evaluation\n", vector_last(ppeaux, stack).st4);
 		goto eval_fail;
 	}
 	if (vector_last(ppeaux, stack).st5 == OPTYP_LET) {
-		acc = vector_last(ppeaux, stack).v5 < acc;
+		acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 < (uint64_t)acc) : (vector_last(ppeaux, stack).v5 < acc);
+		is_unsigned = 0;
 		vector_last(ppeaux, stack).st5 = 0;
 	} else if (vector_last(ppeaux, stack).st5 == OPTYP_LEE) {
-		acc = vector_last(ppeaux, stack).v5 <= acc;
+		acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 <= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 <= acc);
+		is_unsigned = 0;
 		vector_last(ppeaux, stack).st5 = 0;
 	} else if (vector_last(ppeaux, stack).st5 == OPTYP_GRT) {
-		acc = vector_last(ppeaux, stack).v5 > acc;
+		acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 > (uint64_t)acc) : (vector_last(ppeaux, stack).v5 > acc);
+		is_unsigned = 0;
 		vector_last(ppeaux, stack).st5 = 0;
 	} else if (vector_last(ppeaux, stack).st5 == OPTYP_GRE) {
-		acc = vector_last(ppeaux, stack).v5 >= acc;
+		acc = is_unsigned ? ((uint64_t)vector_last(ppeaux, stack).v5 >= (uint64_t)acc) : (vector_last(ppeaux, stack).v5 >= acc);
+		is_unsigned = 0;
 		vector_last(ppeaux, stack).st5 = 0;
 	} else if (vector_last(ppeaux, stack).st5) {
 		printf("<internal error> Unknown st5 %d during #if evaluation\n", vector_last(ppeaux, stack).st5);
@@ -2191,49 +2288,155 @@ start_cur_token:
 				}
 			}
 			if ((tok.tokt != PPTOK_IDENT) && (tok.tokt != PPTOK_IDENT_UNEXP)) goto preproc_hash_err;
-			if (!strcmp(string_content(tok.tokv.str), "include")) {
-				string_del(tok.tokv.str);
-				tok = ppsrc_next_token(src);
-				if (tok.tokt != PPTOK_INCL) {
-					printf("Invalid token type %u after '#include' preprocessor command\n", tok.tokt);
-					goto preproc_hash_err;
-				}
-				string_t *incl_file = tok.tokv.sstr;
-				int is_sys = src->is_sys || !tok.tokv.sisstr;
-				tok = ppsrc_next_token(src); // Token was moved
-				while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) {
-					// TODO: Print warning 'ignored token(s)'
-					preproc_token_del(&tok);
-					tok = ppsrc_next_token(src);
-				}
-				if ((is_sys || !try_open_dir(src, incl_file)) && !try_open_sys(src, incl_file, 0)) {
-					printf("Failed to open %s\n", string_content(incl_file));
-					string_del(incl_file);
-					goto preproc_hash_err;
-				}
-				string_del(incl_file);
-				if (tok.tokt == PPTOK_NEWLINE) goto check_next_token;
-				else goto start_cur_token;
-			} else if (!strcmp(string_content(tok.tokv.str), "include_next")) {
+			if (!strcmp(string_content(tok.tokv.str), "include") || !strcmp(string_content(tok.tokv.str), "include_next")) {
+				int is_next = string_content(tok.tokv.str)[7] == '_';
 				string_del(tok.tokv.str);
 				tok = ppsrc_next_token(src);
-				if (tok.tokt != PPTOK_INCL) {
-					printf("Invalid token type %u after '#include_next' preprocessor command\n", tok.tokt);
-					goto preproc_hash_err;
-				}
-				string_t *incl_file = tok.tokv.sstr;
-				// Assume we only have one #include "..." path
-				tok = ppsrc_next_token(src); // Token was moved
-				while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) {
-					// TODO: Print warning 'ignored token(s)'
-					preproc_token_del(&tok);
-					tok = ppsrc_next_token(src);
+				string_t *incl_file;
+				int is_sys;
+				if (tok.tokt == PPTOK_INCL) {
+					incl_file = tok.tokv.sstr;
+					// Assume we only have one #include "..." path, so include_next is always a system include
+					is_sys = is_next || src->is_sys || !tok.tokv.sisstr;
+					tok = ppsrc_next_token(src); // Token was moved
+					while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) {
+						printf("Warning: ignored tokens after #include directive (%s)\n", src->cur_file);
+						preproc_token_del(&tok);
+						tok = ppsrc_next_token(src);
+					}
+				} else {
+					// Expand macro, then try again
+					VECTOR(preproc) *incl = vector_new(preproc);
+					if (!incl) {
+						printf("Error: failed to allocate #include tokens vector (%s)\n", src->cur_file);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.tokv = (union proc_token_val_u){.c = '\0'};
+						return ret;
+					}
+					while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) {
+						if (!vector_push(preproc, incl, tok)) {
+							printf("Error: failed to add token to #include tokens vector (%s)\n", src->cur_file);
+							vector_del(preproc, incl);
+							src->st = PPST_NONE;
+							ret.tokt = PTOK_INVALID;
+							ret.tokv = (union proc_token_val_u){.c = '\0'};
+							return ret;
+						}
+						tok = ppsrc_next_token(src);
+					}
+					vector_trim(preproc, incl);
+					khash_t(string_set) *solved_macros = kh_init(string_set);
+					if (!solved_macros) {
+						printf("Error: failed to allocate #include solved_macros set (%s)\n", src->cur_file);
+						vector_del(preproc, incl);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.tokv = (union proc_token_val_u){.c = '\0'};
+						return ret;
+					}
+					
+					VECTOR(preproc) *expanded = proc_do_expand(src->macros_map, incl, solved_macros, src->macros_used);
+					vector_del(preproc, incl);
+					macros_set_del(solved_macros);
+					if (!expanded) {
+						printf("Error: failed to expand #include tokens (%s)\n", src->cur_file);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.tokv = (union proc_token_val_u){.c = '\0'};
+						return ret;
+					}
+					
+					// Now we need to check what is pointed by expanded
+					if (!vector_size(preproc, expanded)) {
+						printf("Error: missing #include name (%s)\n", src->cur_file);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.tokv = (union proc_token_val_u){.c = '\0'};
+						return ret;
+					}
+					if (vector_content(preproc, expanded)[0].tokt == PPTOK_STRING) {
+						is_sys = is_next || src->is_sys;
+						preproc_token_t *exp = vector_content(preproc, expanded);
+						// TODO
+						printf("Error: TODO: #include <expanded, first is string '%s' (%d)> (%s)\n",
+							string_content(exp->tokv.sstr), exp->tokv.sisstr, src->cur_file);
+						vector_del(preproc, expanded);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.tokv = (union proc_token_val_u){.c = '\0'};
+						return ret;
+					} else if ((vector_content(preproc, expanded)[0].tokt == PPTOK_SYM) && (vector_content(preproc, expanded)[0].tokv.sym == SYM_LT)
+					        && (vector_last(preproc, expanded).tokt == PPTOK_SYM) && (vector_last(preproc, expanded).tokv.sym == SYM_GT)
+					        && (vector_size(preproc, expanded) >= 3)) {
+						printf("Warning: #include command with macro expansion, assuming no space is present in the file name\n");
+						is_sys = 0;
+						incl_file = string_new();
+						for (vector_preproc_elem *tok2 = expanded->content + 1; tok2 < expanded->content + expanded->vsize - 1; ++tok2) {
+							switch (tok2->tokt) {
+							case PPTOK_IDENT:
+							case PPTOK_IDENT_UNEXP:
+								if (!string_add_string(incl_file, tok2->tokv.str)) {
+									printf("Error: failed to add ident to include string (%s)\n", src->cur_file);
+									vector_del(preproc, expanded);
+									string_del(incl_file);
+									src->st = PPST_NONE;
+									ret.tokt = PTOK_INVALID;
+									ret.tokv = (union proc_token_val_u){.c = '\0'};
+									return ret;
+								}
+								break;
+							case PPTOK_SYM:
+								for (const char *s = sym2str[tok2->tokv.sym]; *s; ++s) {
+									if (!string_add_char(incl_file, *s)) {
+										printf("Error: failed to add symbol to include string (%s)\n", src->cur_file);
+										vector_del(preproc, expanded);
+										string_del(incl_file);
+										src->st = PPST_NONE;
+										ret.tokt = PTOK_INVALID;
+										ret.tokv = (union proc_token_val_u){.c = '\0'};
+										return ret;
+									}
+								}
+								break;
+								
+							case PPTOK_INVALID:
+							case PPTOK_NUM:
+							case PPTOK_STRING:
+							case PPTOK_INCL:
+							case PPTOK_NEWLINE:
+							case PPTOK_BLANK:
+							case PPTOK_START_LINE_COMMENT:
+							case PPTOK_EOF:
+							default:
+								printf("Error: TODO: add token type %u to include string (%s)\n", tok2->tokt, src->cur_file);
+								vector_del(preproc, expanded);
+								string_del(incl_file);
+								src->st = PPST_NONE;
+								ret.tokt = PTOK_INVALID;
+								ret.tokv = (union proc_token_val_u){.c = '\0'};
+								return ret;
+							}
+						}
+						vector_del(preproc, expanded);
+					} else {
+						printf("Error: invalid #include command (macro expansion does not result in string or <...>) (%s)\n", src->cur_file);
+						vector_del(preproc, expanded);
+						src->st = PPST_NONE;
+						ret.tokt = PTOK_INVALID;
+						ret.tokv = (union proc_token_val_u){.c = '\0'};
+						return ret;
+					}
 				}
 				// cur_pathno == 0 if cur_file was from an #include "...", otherwise idx + 1
-				if (!try_open_sys(src, incl_file, src->cur_pathno)) {
+				if ((is_sys || !try_open_dir(src, incl_file)) && !try_open_sys(src, incl_file, is_next ? src->cur_pathno : 0)) {
 					printf("Failed to open %s\n", string_content(incl_file));
 					string_del(incl_file);
-					goto preproc_hash_err;
+					src->st = PPST_NONE;
+					ret.tokt = PTOK_INVALID;
+					ret.tokv = (union proc_token_val_u){.c = tok.tokv.sisstr ? '<' : '"'};
+					string_del(tok.tokv.sstr);
+					return ret;
 				}
 				string_del(incl_file);
 				if (tok.tokt == PPTOK_NEWLINE) goto check_next_token;
@@ -2254,18 +2457,19 @@ start_cur_token:
 					ret.tokv = (union proc_token_val_u){.c = (char)EOF};
 					return ret;
 				}
-				khash_t(argid_map) *args = kh_init(argid_map);
-				if (!args) {
-					printf("Failed to allocate args map for macro %s, returning EOF\n", string_content(defname));
-					string_del(defname); // Token is now freed
-					vector_del(mtoken, m.toks);
-					ret.tokt = PTOK_EOF;
-					ret.tokv = (union proc_token_val_u){.c = (char)EOF};
-					return ret;
-				}
+				khash_t(argid_map) *args = NULL;
 				tok = ppsrc_next_token(src);
 				if ((tok.tokt == PPTOK_SYM) && (tok.tokv.sym == SYM_LPAREN)) {
 					m.is_funlike = 1;
+					args = kh_init(argid_map);
+					if (!args) {
+						printf("Failed to allocate args map for macro %s, returning EOF\n", string_content(defname));
+						string_del(defname); // Token is now freed
+						vector_del(mtoken, m.toks);
+						ret.tokt = PTOK_EOF;
+						ret.tokv = (union proc_token_val_u){.c = (char)EOF};
+						return ret;
+					}
 					m.nargs = 0;
 					tok = ppsrc_next_token(src);
 					int ok;
@@ -2449,7 +2653,7 @@ start_cur_token:
 				}
 #undef ST_CONCAT
 #undef ST_STR
-				argid_map_del(args);
+				if (args) argid_map_del(args);
 				if (tok.tokt == PPTOK_INVALID) {
 					// Abort
 					string_del(defname);
@@ -2522,12 +2726,68 @@ start_cur_token:
 				if (tok.tokt == PPTOK_NEWLINE) goto check_next_token;
 				else goto start_cur_token;
 			} else if (!strcmp(string_content(tok.tokv.str), "error")) {
-				printf("Error: #error command <TODO: add reason>\n");
+				printf("Error: #error command (%s):", src->cur_file);
 				string_del(tok.tokv.str);
+				tok = ppsrc_next_token(src);
+				while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) {
+					switch (tok.tokt) {
+					case PPTOK_IDENT:
+					case PPTOK_IDENT_UNEXP:
+						printf(" %s", string_content(tok.tokv.str));
+						break;
+					case PPTOK_SYM:
+						printf("%s%s", (tok.tokv.sym == SYM_COMMA) ? "" : " ", sym2str[tok.tokv.sym]);
+						break;
+					case PPTOK_STRING:
+						printf(" %c%s%c", tok.tokv.sisstr ? '"' : '\'', string_content(tok.tokv.sstr), tok.tokv.sisstr ? '"' : '\'');
+						break;
+						
+					case PPTOK_INVALID:
+					case PPTOK_NUM:
+					case PPTOK_INCL:
+					case PPTOK_NEWLINE:
+					case PPTOK_BLANK:
+					case PPTOK_START_LINE_COMMENT:
+					case PPTOK_EOF:
+					default:
+						printf(" <unknown token type %u>", tok.tokt);
+					}
+					preproc_token_del(&tok);
+					tok = ppsrc_next_token(src);
+				}
+				printf("\n");
 				vector_clear(ppsource, src->prep);
-				goto check_next_token; // Returns EOF
+				ret.tokt = PTOK_INVALID;
+				ret.tokv = (union proc_token_val_u){.c = (char)EOF};
+				return ret;
 			} else if (!strcmp(string_content(tok.tokv.str), "warning")) {
-				printf("Warning: #warning command <TODO: add reason>\n");
+				printf("Warning: #warning command (%s):", src->cur_file);
+				tok = ppsrc_next_token(src);
+				while ((tok.tokt != PPTOK_NEWLINE) && (tok.tokt != PPTOK_EOF) && (tok.tokt != PPTOK_INVALID)) {
+					switch (tok.tokt) {
+					case PPTOK_IDENT:
+					case PPTOK_IDENT_UNEXP:
+						printf(" %s", string_content(tok.tokv.str));
+						break;
+					case PPTOK_SYM:
+						printf("%s%s", (tok.tokv.sym == SYM_COMMA) ? "" : " ", sym2str[tok.tokv.sym]);
+						break;
+						
+					case PPTOK_INVALID:
+					case PPTOK_NUM:
+					case PPTOK_STRING:
+					case PPTOK_INCL:
+					case PPTOK_NEWLINE:
+					case PPTOK_BLANK:
+					case PPTOK_START_LINE_COMMENT:
+					case PPTOK_EOF:
+					default:
+						printf(" <unknown token type %u>", tok.tokt);
+					}
+					preproc_token_del(&tok);
+					tok = ppsrc_next_token(src);
+				}
+				printf("\n");
 				goto preproc_hash_err;
 			} else if (!strcmp(string_content(tok.tokv.str), "pragma")) {
 				string_del(tok.tokv.str);
diff --git a/wrapperhelper/src/preproc.h b/wrapperhelper/src/preproc.h
index 3ba2e06c..e76f450f 100644
--- a/wrapperhelper/src/preproc.h
+++ b/wrapperhelper/src/preproc.h
@@ -6,10 +6,11 @@
 #include <stdio.h>
 
 #include "lang.h"
+#include "machine.h"
 
 typedef struct preproc_s preproc_t;
 
-preproc_t *preproc_new_file(FILE *f, char *dirname, const char *filename); // Takes ownership of f and dirname
+preproc_t *preproc_new_file(machine_t *target, FILE *f, char *dirname, const char *filename); // Takes ownership of f and dirname
 proc_token_t proc_next_token(preproc_t *src);
 int proc_unget_token(preproc_t *src, proc_token_t *tok);
 void preproc_del(preproc_t *src);
diff --git a/wrapperhelper/src/preproc_private.h b/wrapperhelper/src/preproc_private.h
new file mode 100644
index 00000000..d1b5f804
--- /dev/null
+++ b/wrapperhelper/src/preproc_private.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#ifndef PREPROC_PRIVATE_H
+#define PREPROC_PRIVATE_H
+
+#include <stdio.h>
+
+#include "lang.h"
+
+typedef struct mtoken_s {
+	enum mtoken_e {
+		MTOK_TOKEN,
+		MTOK_ARG,
+		MTOK_STRINGIFY,
+		MTOK_CONCAT,
+	} typ;
+	union {
+		preproc_token_t tok;
+		unsigned argid;
+		struct { struct mtoken_s *l, *r; } concat;
+	} val;
+} mtoken_t;
+
+VECTOR_DECLARE(mtoken, mtoken_t*)
+
+typedef struct macro_s {
+	int is_funlike;
+	int has_varargs;
+	unsigned nargs;
+	VECTOR(mtoken) *toks;
+} macro_t;
+
+mtoken_t *mtoken_new_token(preproc_token_t tok);
+mtoken_t *mtoken_new_arg(unsigned argid, int as_string);
+mtoken_t *mtoken_new_concat(mtoken_t *l, mtoken_t *r);
+void mtoken_del(mtoken_t *tok);
+void macro_del(macro_t *m);
+
+#endif // PREPROC_PRIVATE_H
diff --git a/wrapperhelper/src/vector.c b/wrapperhelper/src/vector.c
index 2cccf09d..dffcb493 100644
--- a/wrapperhelper/src/vector.c
+++ b/wrapperhelper/src/vector.c
@@ -14,6 +14,7 @@ VECTOR(voidp) *vector_new_impl(void) {
 }
 
 VECTOR(voidp) *vector_new_cap_impl(size_t elem_size, size_t cap) {
+	if (!cap) return vector_new_impl();
 	VECTOR(voidp) *ret = malloc(sizeof(*ret));
 	if (!ret) return NULL;
 	cap = (cap < VECTOR_MIN_CAP) ? VECTOR_MIN_CAP : cap * 2;