WIP: macros expansion
authorLukas Krickl <lukas@krickl.dev>
Wed, 8 Nov 2023 19:22:37 +0000 (20:22 +0100)
committerLukas Krickl <lukas@krickl.dev>
Wed, 8 Nov 2023 19:22:37 +0000 (20:22 +0100)
src/test.c
src/ulas.c

index 52c004d7cfc5fd6377db55eaf86ef52ebd6e8c41..5975de766918e14a39441213bed5d97799c9be74 100644 (file)
@@ -75,6 +75,8 @@ void test_preproc(void) {
   assert_preproc("", -1, "  #define 1test 123\n");
   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");
 
   TESTEND("preproc");
 }
index 43477e045abdecb8e0b96b93259c4e81c9d07151..51a92ed2c8b222d4d649af4264614800ba57d302 100644 (file)
@@ -207,6 +207,27 @@ int ulas_preprocdef(struct ulas_preproc *pp, struct ulas_ppdef def) {
   return 0;
 }
 
+int ulas_preprochasstray(struct ulas_preproc *pp, const char *pline, size_t n) {
+
+  // the end of a directive should have no further tokens!
+  if (ulas_tok(&pp->tok, &pline, n) != 0) {
+    ULASERR("Stray tokens '%s' at end of preprocessor directive\n",
+            pp->tok.buf);
+    return 1;
+  }
+
+  return 0;
+}
+
+void ulas_trimend(char c, char *buf, size_t n) {
+  size_t buflen = strnlen(buf, n);
+  // remove trailing new line if present
+  while (buf[buflen - 1] == '\n') {
+    buf[buflen - 1] = '\0';
+    buflen--;
+  }
+}
+
 int ulas_preprocline(struct ulas_preproc *pp, FILE *dst, FILE *src,
                      const char *raw_line, size_t n) {
   char *line = ulas_preprocexpand(pp, raw_line, &n);
@@ -244,6 +265,8 @@ int ulas_preprocline(struct ulas_preproc *pp, FILE *dst, FILE *src,
 found:
 
   if (found_dir != ULAS_PPDIR_NONE) {
+    ulas_trimend('\n', line, strlen(line));
+
     switch (found_dir) {
     case ULAS_PPDIR_DEF: {
       // next token is a name
@@ -278,14 +301,36 @@ found:
         return -1;
       }
 
+      if (ulas_preprochasstray(pp, pline, n)) {
+        return -1;
+      }
+
       struct ulas_str val = ulas_str(32);
+      memset(val.buf, 0, 32);
+
+      char buf[ULAS_LINEMAX];
+      memset(buf, 0, ULAS_LINEMAX);
+
+      // consume lines until #endmacro is read
+      // if reaching end of input without #endmacro we have an unterminated
+      // macro. pass NULL as dst to consume lines that are being read instead of
+      // echoing them back
+      int rc = 0;
+      while ((rc = ulas_preprocnext(pp, NULL, src, buf, ULAS_LINEMAX)) > 0) {
+        if (rc == ULAS_PPDIR_ENDMACRO) {
+          break;
+        }
+      }
 
-      // TODO: handle lines here
+      if (rc != ULAS_PPDIR_ENDMACRO) {
+        ULASERR("Unterminated macro directive\n");
+        ulas_strfree(&val);
+        return -1;
+      }
 
       // we leak the str's buffer into the def now
       // this is ok because we call free for it later anyway
-      struct ulas_ppdef def = {ULAS_PPDEF, strdup(pp->tok.buf), strdup(val.buf),
-                               false};
+      struct ulas_ppdef def = {ULAS_PPDEF, strdup(pp->tok.buf), val.buf, false};
       ulas_preprocdef(pp, def);
 
       goto dirdone;
@@ -304,14 +349,12 @@ found:
     }
 
     // the end of a directive should have no further tokens!
-    if (ulas_tok(&pp->tok, &pline, n) != 0) {
-      ULASERR("Stray tokens '%s' at end of preprocessor directive\n",
-              pp->tok.buf);
+    if (ulas_preprochasstray(pp, pline, n)) {
       return -1;
     }
   dirdone:
     return found_dir;
-  } else {
+  } else if (dst) {
     fwrite(line, 1, n, dst);
   }
 
@@ -326,11 +369,6 @@ int ulas_preprocnext(struct ulas_preproc *pp, FILE *dst, FILE *src, char *buf,
 
     size_t buflen = strlen(buf);
 
-    // remove trailing new line if present
-    if (buf[buflen - 1] == '\n') {
-      buf[buflen - 1] = '\0';
-    }
-
     rc = ulas_preprocline(pp, dst, src, buf, buflen);
   } else {
     rc = 0;