diff options
| author | rajdakin <rajdakin@gmail.com> | 2024-09-07 15:20:17 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-07 15:20:17 +0200 |
| commit | f0d7582845e124ed61b86f43da30a7b3f3f0c3f5 (patch) | |
| tree | 2ee0c53821805b33ca47e0919fea95ccb920cd52 /wrapperhelper/src | |
| parent | 75bdb328284b8e5b6827eeb7d5cedef26222e7db (diff) | |
| download | box64-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.c | 55 | ||||
| -rw-r--r-- | wrapperhelper/src/cstring.h | 4 | ||||
| -rw-r--r-- | wrapperhelper/src/lang.c | 35 | ||||
| -rw-r--r-- | wrapperhelper/src/lang.h | 1 | ||||
| -rw-r--r-- | wrapperhelper/src/machine.c | 178 | ||||
| -rw-r--r-- | wrapperhelper/src/machine.h | 33 | ||||
| -rw-r--r-- | wrapperhelper/src/main.c | 114 | ||||
| -rw-r--r-- | wrapperhelper/src/parse.c | 9 | ||||
| -rw-r--r-- | wrapperhelper/src/parse.h | 5 | ||||
| -rw-r--r-- | wrapperhelper/src/prepare.c | 2 | ||||
| -rw-r--r-- | wrapperhelper/src/preproc.c | 496 | ||||
| -rw-r--r-- | wrapperhelper/src/preproc.h | 3 | ||||
| -rw-r--r-- | wrapperhelper/src/preproc_private.h | 39 | ||||
| -rw-r--r-- | wrapperhelper/src/vector.c | 1 |
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; |