* Preprocessor
*/
+enum ulas_ppdirs {
+ ULAS_PPDIR_NONE = 0,
+ ULAS_PPDIR_DEF,
+ ULAS_PPDIR_MACRO,
+ ULAS_PPDIR_ENDMACRO,
+ ULAS_PPDIR_IFDEF,
+ ULAS_PPDIR_IFNDEF,
+ ULAS_PPDIR_ENDIF
+};
+
enum ulas_ppdefs {
ULAS_PP_DEF,
ULAS_PP_MACRO,
/**
* Tokenize and apply the preprocessor
*/
-int ulas_preproc(FILE *dst, const char *dstname, FILE *src, const char *srcname);
+int ulas_preproc(FILE *dst, const char *dstname, FILE *src,
+ const char *srcname);
+
+// expand preproc into dst line
+char *ulas_preprocexpand(char *line, size_t linemax, const char *raw_line, size_t *n);
#endif
#define ULAS_PATHMAX 4096
#define ULAS_LINEMAX 4096
-#define ULAS_TOKMAX 512
+#define ULAS_TOKMAX 64
+
+// max tokens per line...
+#define ULAS_TOKSMAX 64
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
// returns 0 when no more tokens can be read
int ulas_tok(char *dst, const char *line, size_t n, ulas_tokrule rule);
-// tokenizes an entire line
-char **ulas_tokline(const char *line, size_t *n, ulas_tokrule rule);
-
-void ulas_toklinefree(char **data, size_t n);
+// smae as ulas_tok but modifies line
+int ulas_tokline(char *dst, const char **line, size_t n, ulas_tokrule rule);
#endif
cfg->verbose = true;
break;
case 'o':
- cfg->output_path = ulas_strndup(optarg, ULAS_PATHMAX);
+ cfg->output_path = strndup(optarg, ULAS_PATHMAX);
break;
case '?':
break;
#include "preproc.h"
#include "ulas.h"
+#include <ctype.h>
+#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
+bool ulas_tokpreproc(char c) { return !isalnum(c); }
-int ulas_preprocline(struct ulas_preproc *pp, FILE *dst, const char *line,
+char *ulas_preprocexpand(char *line, size_t linemax, const char *raw_line,
+ size_t *n) {
+ assert(*n <= linemax);
+ const char *praw_line = raw_line;
+
+ char tok[ULAS_TOKMAX];
+
+ // go through all tokens, see if a define matches the token,
+ // if so expand it
+ // only expand macros if they match toks[0] though!
+ // otherwise memcpy the read bytes 1:1 into the new string
+ while (ulas_tokline(tok, &praw_line, ULAS_TOKMAX, ulas_tokpreproc)) {
+ }
+
+ // TODO: actually expand here...
+ strncpy(line, raw_line, *n);
+ *n = strlen(line);
+ return line;
+}
+
+int ulas_preprocline(struct ulas_preproc *pp, FILE *dst, const char *raw_line,
size_t n) {
+ if (n > ULAS_LINEMAX) {
+ ULASERR("%s: line exceeds %d (LINEMAX)\n", raw_line, ULAS_LINEMAX);
+ return -1;
+ }
+ assert(n <= ULAS_LINEMAX);
+ char line[ULAS_LINEMAX];
+ const char *pline = line;
+
+ ulas_preprocexpand(line, ULAS_LINEMAX, raw_line, &n);
+ const char *dirstrs[] = {"#define", "#macro", "#ifdef", "#ifndef",
+ "#endif", "#endmacro", NULL};
+ enum ulas_ppdirs dirs[] = {ULAS_PPDIR_DEF, ULAS_PPDIR_MACRO,
+ ULAS_PPDIR_IFDEF, ULAS_PPDIR_IFNDEF,
+ ULAS_PPDIR_ENDIF, ULAS_PPDIR_ENDMACRO};
+
+ enum ulas_ppdirs found_dir = ULAS_PPDIR_NONE;
+
+ char tok[ULAS_TOKMAX];
// check if the first token is any of the valid preproc directives
+ if (ulas_tokline(tok, &pline, ULAS_TOKMAX, ulas_tokpreproc)) {
+ for (size_t i = 0; dirstrs[i]; i++) {
+ if (strncmp(dirstrs[i], tok, ULAS_TOKMAX) == 0) {
+ found_dir = dirs[i];
+ goto found;
+ }
+ }
+ }
+found:
- assert(fwrite(line, 1, n, dst) == n);
+ if (found_dir) {
+ // TODO: process directive
+ } else {
+ assert(fwrite(line, 1, n, dst) == n);
+ }
return 0;
}
#define assert_tokline(expected_n, line, rule, ...) \
{ \
- char *expect[] = __VA_ARGS__; \
- size_t n = 0; \
- char **toks = ulas_tokline(line, &n, rule); \
- assert(toks); \
- assert(n == expected_n); \
- for (size_t i = 0; i < n; i++) { \
- assert(strcmp(toks[i], expect[i]) == 0); \
+ const char *expect[] = __VA_ARGS__; \
+ size_t n = ULAS_TOKMAX; \
+ char buf[n]; \
+ memset(buf, 0, n); \
+ int i = 0; \
+ const char *pline = line; \
+ while (ulas_tokline(buf, &pline, n, rule)) { \
+ assert(strcmp(buf, expect[i]) == 0); \
+ i++; \
} \
- ulas_toklinefree(toks, n); \
+ assert(i == expected_n); \
}
void test_tok(void) {
void test_preproc(void) {
TESTBEGIN("preproc");
- assert_preproc("test", 0, "test");
+ // should just echo back line as is
+ assert_preproc(" test line", 0, " test line");
TESTEND("preproc");
}
return cfg;
}
-char *ulas_strndup(const char *src, size_t n) {
- size_t len = MIN(strlen(src), n);
- char *dst = malloc(len);
- strncpy(dst, src, len);
- return dst;
-}
-
int ulas_main(struct ulas_config cfg) {
if (cfg.output_path) {
ulasout = fopen(cfg.output_path, "we");
return i;
}
-char **ulas_tokline(const char *line, size_t *n, ulas_tokrule rule) {
- char buf[ULAS_TOKMAX];
-
- char **dst = NULL;
- *n = 0;
-
- int tokrc = 0;
- int read = 0;
- while ((tokrc = ulas_tok(buf, line + read, ULAS_TOKMAX, rule)) > 0) {
- if (tokrc == -1) {
- goto fail;
- }
- read += tokrc;
-
- *n = *n + 1;
- char **newdst = realloc(dst, sizeof(char *) * (*n));
- if (!newdst) {
- goto fail;
- }
- dst = newdst;
-
- dst[(*n) - 1] = strndup(buf, ULAS_TOKMAX);
- }
-
- return dst;
-fail:
- ulas_toklinefree(dst, *n);
- *n = 0;
- return NULL;
-}
-
-void ulas_toklinefree(char **data, size_t n) {
- if (!data) {
- return;
- }
- for (size_t i = 0; i < n; i++) {
- free(data[i]);
+int ulas_tokline(char *dst, const char **line, size_t n, ulas_tokrule rule) {
+ int rc = ulas_tok(dst, *line, n, rule);
+ if (rc == -1) {
+ return -1;
}
-
- free(data);
+ *line += rc;
+ return rc;
}