/* macro */
assert_preproc(
- " line p1 1 label01,2 3\n line p2 2\n line p3 3 p1, p2, p3\n", 0,
+ "\nline p1 1 label01,2 3\nline p2 2\nline p3 3 p1, p2, p3\n", 0,
"#macro test\n line $1 1 label$$$$,$$ $$\n line $2 2\n line $3 3 "
"$0\n#endmacro\ntest p1, p2, p3");
- assert_preproc("test macro with no args\n", 0,
+ assert_preproc("\ntest macro with no args\n", 0,
"#macro mtest\ntest macro with no args\n#endmacro\nmtest");
assert_preproc("", -1, "#macro test\n not terminated\n");
assert_preproc(
- "\ncontent macro t1\nt1\nafter\ncontent n1\n", 0,
+ "\n\ncontent macro t1\n\nt1\nafter\ncontent n1\n", 0,
"#macro test\nmnested macro $1\n$1\n#macro "
"mnested\ncontent $1\n#endmacro\nafter\nmnested n1\n#endmacro\ntest t1");
/* this macro caused a heap buffer overflow in production code */
- assert_preproc("ld a, verylongmacroinput & 0xFF\nld [hl+], a\nld a, "
+ assert_preproc("\nld a, verylongmacroinput & 0xFF\nld [hl+], a\nld a, "
"(verylongmacroinput >> 8) & 0xFF\nld [hl+], a\n",
0,
"#macro testlonginput\nld a, $1 & 0xFF\nld [hl+], a\nld a, "
ASSERT_FULL_ASM(0, "tests/t0.s", "tests/t0.bin");
ASSERT_FULL_ASM(0, "tests/multiline.s", "tests/multiline.bin");
+ ASSERT_FULL_ASM(0, "tests/macroexpandnested.s",
+ "tests/macroexpandnested.bin");
TESTEND("testfullasm");
}
}
}
-char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line,
- unsigned long *n, int recursive);
-void ulas_preprocexpand_rec(struct ulas_preproc *pp) {
+char *ulas_preprocexpand(struct ulas_preproc *pp, const char *raw_line,
+ unsigned long *n);
+void ulas_preprocexpand_rec(struct ulas_preproc *pp, int append_newline) {
+ struct ulas_str line2 = ulas_str(1);
+ struct ulas_str next_line = ulas_str(1);
+ struct ulas_str new_ppline = ulas_str(1);
+ const char *linep;
+ int lines_expanded = 0;
+
unsigned long n = 0;
/* expand macro result again to allow
* defines to appear in the macro
*/
- ulas_strensr(&pp->line2, strlen(pp->line.buf) + 1);
- sprintf(pp->line2.buf, "%s", pp->line.buf);
+ ulas_strensr(&line2, strlen(pp->line.buf) + 1);
+ sprintf(line2.buf, "%s", pp->line.buf);
n = strlen(pp->line.buf);
pp->exp_depth++;
if (pp->exp_depth > ULAS_PREPROC_MAX_MACRO_DEPTH) {
ULASERR("Max macro recursion depth reached\n");
+
+ ulas_strfree(&line2);
+ ulas_strfree(&next_line);
+ ulas_strfree(&new_ppline);
return;
}
- ulas_preprocexpand2(pp, pp->line2.buf, &n, 1);
+
+ linep = line2.buf;
+ new_ppline.buf[0] = '\0';
+ while (ulas_tokuntil(&next_line, '\n', &linep, strlen(linep))) {
+ n = strlen(next_line.buf);
+ ulas_preprocexpand(pp, next_line.buf, &n);
+
+ ulas_strensr(&new_ppline,
+ strlen(pp->line.buf) + strlen(new_ppline.buf) + 4);
+
+ if (lines_expanded == 0 && append_newline) {
+ sprintf(new_ppline.buf, "\n%s", pp->line.buf);
+ } else if (lines_expanded == 0) {
+ sprintf(new_ppline.buf, "%s", pp->line.buf);
+ } else {
+ sprintf(new_ppline.buf, "%s\n%s", new_ppline.buf, pp->line.buf);
+ }
+
+ lines_expanded++;
+ }
+
+ ulas_strensr(&pp->line, strlen(new_ppline.buf) + 4);
+
+ if (!append_newline) {
+ sprintf(pp->line.buf, "%s", new_ppline.buf);
+ } else {
+ sprintf(pp->line.buf, "%s\n", new_ppline.buf);
+ }
+
pp->exp_depth--;
+ ulas_strfree(&line2);
+ ulas_strfree(&next_line);
+ ulas_strfree(&new_ppline);
}
char *ulas_preprocexpand(struct ulas_preproc *pp, const char *raw_line,
unsigned long *n) {
- return ulas_preprocexpand2(pp, raw_line, n, 0);
-}
-
-char *ulas_preprocexpand2(struct ulas_preproc *pp, const char *raw_line,
- unsigned long *n, int recursive) {
const char *macro_argname[ULAS_MACROPARAMMAX] = {
"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
"$9", "$10", "$11", "$12", "$13", "$14", "$15"};
} else {
strncat(pp->line.buf, def->value, val_len);
}
- ulas_preprocexpand_rec(pp);
+ ulas_preprocexpand_rec(pp, 0);
}
break;
}
int paramc;
/* TODO: i am sure we can optimize the resize of line buffers here...
- * TODO: allow recursive macro calls
*/
/* get 9 comma separated values.
*/
tocat = NULL;
tocatlen = 0;
-
- /* always start an expanded macro with a new line
- * to ensure expansion are separated if we are in a recursive call
- * this fixes new lines in recursive macros being consumed
- */
- if (recursive) {
- int len = ulas_strnlen(pp->line.buf, pp->line.maxlen) + 1;
- ulas_strensr(&pp->line,
- len + 1);
- strncat(pp->line.buf, "\n", len);
- }
/* now tokenize the macro's value and look for $0-$9
strncat(pp->line.buf, tocat, tocatlen);
}
}
- ulas_preprocexpand_rec(pp);
+ ulas_preprocexpand_rec(pp, 1);
goto end;
}
}
pp.defslen = 0;
pp.tok = ulas_str(1);
pp.line = ulas_str(1);
- pp.line2 = ulas_str(1);
for (i = 0; i < ULAS_MACROPARAMMAX; i++) {
pp.macroparam[i] = ulas_str(8);
void ulas_preprocfree(struct ulas_preproc *pp) {
unsigned long i;
ulas_strfree(&pp->line);
- ulas_strfree(&pp->line2);
ulas_strfree(&pp->tok);
ulas_preprocclear(pp);