From 6246fbe10749ce171c5b47bf2906c8e854da5dc2 Mon Sep 17 00:00:00 2001 From: Lukas Krickl Date: Fri, 10 Nov 2023 18:18:38 +0100 Subject: [PATCH] WIP: macro expansion --- include/ulas.h | 9 ++++++ src/test.c | 25 +++++++++++++++- src/ulas.c | 77 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 101 insertions(+), 10 deletions(-) diff --git a/include/ulas.h b/include/ulas.h index 24b9c2c..8d4ac78 100644 --- a/include/ulas.h +++ b/include/ulas.h @@ -128,12 +128,19 @@ struct ulas_ppdef { bool undef; }; +#define ULAS_MACROPARAMMAX 9 + struct ulas_preproc { struct ulas_ppdef *defs; size_t defslen; struct ulas_str tok; struct ulas_str line; + + // macro parameter buffers + struct ulas_str macroparam[ULAS_MACROPARAMMAX]; + // macro expansion buffer + struct ulas_str macrobuf; }; /** @@ -221,6 +228,8 @@ char *ulas_strndup(const char *src, size_t n); // consumed or -1 on error // returns 0 when no more tokens can be read int ulas_tok(struct ulas_str *dst, const char **out_line, size_t n); +int ulas_tokuntil(struct ulas_str *dst, char c, const char **out_line, + size_t n); /** * str diff --git a/src/test.c b/src/test.c index 8b219a1..6a32d26 100644 --- a/src/test.c +++ b/src/test.c @@ -28,6 +28,26 @@ ulas_strfree(&dst); \ } +#define assert_tokuntil(line, c, ...) \ + { \ + const char *expect[] = __VA_ARGS__; \ + size_t n = strlen(line); \ + struct ulas_str dst = ulas_str(n); \ + memset(dst.buf, 0, n); \ + int i = 0; \ + const char *pline = line; \ + while (ulas_tokuntil(&dst, c, &pline, n)) { \ + assert(expect[i]); \ + assert(strcmp(dst.buf, expect[i]) == 0); \ + i++; \ + } \ + size_t expect_n = 0; \ + for (expect_n = 0; expect[expect_n]; expect_n++) { \ + } \ + assert(i == expect_n); \ + ulas_strfree(&dst); \ + } + void test_tok(void) { TESTBEGIN("tok"); @@ -35,6 +55,9 @@ void test_tok(void) { {"test", "tokens", "with", ",", "line", "/", "*", "+", "-", ",", ";", "$1", NULL}); + assert_tokuntil(" this is a, test for tok , until", ',', + {" this is a", " test for tok ", " until", NULL}); + TESTEND("tok"); } @@ -76,7 +99,7 @@ void test_preproc(void) { assert_preproc("this is a 123 for defs", 0, " #define test 123\nthis is a test for defs"); assert_preproc(" line 1\n line 2\n line 3\n", 0, - "#macro test\n line 1\n line 2\n line 3\n#endmacro\ntest"); + "#macro test\n line $1 1\n line $2 2\n line $3 3 $0\n#endmacro\ntest p1, p2, p3"); TESTEND("preproc"); } diff --git a/src/ulas.c b/src/ulas.c index 618e78e..f9a7b4c 100644 --- a/src/ulas.c +++ b/src/ulas.c @@ -72,6 +72,9 @@ int ulas_isname(const char *tok, size_t n) { return 1; } +#define WELD_TOKISTERM write +#define WELD_TOKCOND (i < n && write < n && line[i]) + int ulas_tok(struct ulas_str *dst, const char **out_line, size_t n) { const char *line = *out_line; ulas_strensr(dst, n + 1); @@ -79,9 +82,6 @@ int ulas_tok(struct ulas_str *dst, const char **out_line, size_t n) { int i = 0; int write = 0; -#define WELD_TOKISTERM write -#define WELD_TOKCOND (i < n && write < n && line[i]) - // always skip leading terminators while (WELD_TOKCOND && isspace(line[i])) { i++; @@ -126,8 +126,6 @@ int ulas_tok(struct ulas_str *dst, const char **out_line, size_t n) { i++; } tokdone: -#undef WELD_TOKCOND -#undef WLED_TOKISTERM dst->buf[write] = '\0'; @@ -135,6 +133,35 @@ tokdone: return i; } +// tokenize until the char c is seen +// this will also consume c and out_line will point to the next valid char +// this is useful if the next expected token is well defined and we want to +// capture everything between +int ulas_tokuntil(struct ulas_str *dst, char c, const char **out_line, + size_t n) { + const char *line = *out_line; + ulas_strensr(dst, n + 1); + + int i = 0; + int write = 0; + + while (WELD_TOKCOND && line[i] != c) { + dst->buf[write++] = line[i++]; + } + + if (line[i] == c) { + i++; + } + + dst->buf[write] = '\0'; + + *out_line += i; + return i; +} + +#undef WELD_TOKCOND +#undef WLED_TOKISTERM + struct ulas_str ulas_str(size_t n) { struct ulas_str str = {malloc(n), n}; return str; @@ -187,11 +214,32 @@ char *ulas_preprocexpand(struct ulas_preproc *pp, const char *raw_line, ulas_strensr(&pp->line, (*n) + 1); strncat(pp->line.buf, def->value, val_len); break; - case ULAS_PPMACRO: - // TODO: Implement - ULASPANIC("PPMACRO is not implemented!\n"); + case ULAS_PPMACRO: { + // get 9 comma separated values. + // $1-$9 will reference the respective arg + // $0 will reference the entire line after the macro name + // there can be more than 9 args, but anything after the 9th arg can + // only be accessed via $0 + const char *line = praw_line; + size_t linelne = strlen(praw_line); + // clear all params from previous attempt + for (size_t i = 0; i < ULAS_MACROPARAMMAX; i++) { + pp->macroparam[i].buf[0] = '\0'; + } - break; + // loop until 9 args are found or the line ends + int paramc = 0; + while (paramc < ULAS_MACROPARAMMAX && + ulas_tokuntil(&pp->macroparam[i], ',', &praw_line, *n) > 0) { + paramc++; + } + + // now tokenize the macro's value and look for $0-$9 + // and replace those instances + // eveyrthing else will just be copied as is + + goto end; + } } goto found; @@ -206,6 +254,7 @@ char *ulas_preprocexpand(struct ulas_preproc *pp, const char *raw_line, continue; } +end: *n = strlen(pp->line.buf); return pp->line.buf; } @@ -404,6 +453,10 @@ int ulas_preproc(FILE *dst, FILE *src) { int rc = 0; struct ulas_preproc pp = {NULL, 0, ulas_str(1), ulas_str(1)}; + for (size_t i = 0; i < ULAS_MACROPARAMMAX; i++) { + pp.macroparam[i] = ulas_str(8); + } + pp.macrobuf = ulas_str(8); while ((rc = ulas_preprocnext(&pp, dst, src, buf, ULAS_LINEMAX)) > 0) { } @@ -419,6 +472,12 @@ int ulas_preproc(FILE *dst, FILE *src) { free(pp.defs[i].value); } } + + for (size_t i = 0; i < ULAS_MACROPARAMMAX; i++) { + ulas_strfree(&pp.macroparam[i]); + } + ulas_strfree(&pp.macrobuf); + if (pp.defs) { free(pp.defs); } -- 2.30.2