WIP: macro expansion
authorLukas Krickl <lukas@krickl.dev>
Fri, 10 Nov 2023 17:18:38 +0000 (18:18 +0100)
committerLukas Krickl <lukas@krickl.dev>
Fri, 10 Nov 2023 17:18:38 +0000 (18:18 +0100)
include/ulas.h
src/test.c
src/ulas.c

index 24b9c2c77ed028d34b54fea21f2a7d11485b591c..8d4ac7850536f84fac4a68e1da236a687e65d2dd 100644 (file)
@@ -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
index 8b219a1acc5fa0bf113d58c60af52b8426f76746..6a32d2690b5099def381a824a3c1ce6d30fd89d1 100644 (file)
     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");
 }
index 618e78e2bf3aa91594d0d21906d2884ebd5808d0..f9a7b4c4ceb8c4ceb8f9895f3ad064b289661e7d 100644 (file)
@@ -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);
   }