void dobuiltin(const char *argv[], int argc) { ndptr p; argv[1] = NULL; p = macro_getbuiltin(argv[2]); if (p != NULL) eval(argv+1, argc-1, macro_builtin_type(p), is_traced(p)); else m4errx(1, "unknown builtin %s.", argv[2]); }
void doindir(const char *argv[], int argc) { ndptr n; struct macro_definition *p; n = lookup(argv[2]); if (n == NULL || (p = macro_getdef(n)) == NULL) m4errx(1, "indir: undefined macro %s.", argv[2]); argv[1] = p->defn; eval(argv+1, argc-1, p->type, is_traced(n)); }
/* * eval - eval all macros and builtins calls * argc - number of elements in argv. * argv - element vector : * argv[0] = definition of a user * macro or nil if built-in. * argv[1] = name of the macro or * built-in. * argv[2] = parameters to user-defined * . macro or built-in. * . * * A call in the form of macro-or-builtin() will result in: * argv[0] = nullstr * argv[1] = macro-or-builtin * argv[2] = nullstr * * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin */ void eval(const char *argv[], int argc, int td) { ssize_t mark = -1; expansion_id++; if (td & RECDEF) errx(1, "%s at line %lu: expanding recursive definition for %s", CURRENT_NAME, CURRENT_LINE, argv[1]); if (traced_macros && is_traced(argv[1])) mark = trace(argv, argc, infile+ilevel); if (td == MACRTYPE) expand_macro(argv, argc); else expand_builtin(argv, argc, td); if (mark != -1) finish_trace(mark); }
/* * macro - the work horse.. */ static void macro(void) { char token[MAXTOK+1]; int t, l; ndptr p; int nlpar; cycle { t = gpbc(); if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ nlpar = 0; record(quotes, nlpar++); /* * Opening quote: scan forward until matching * closing quote has been found. */ do { l = gpbc(); if (LOOK_AHEAD(l,rquote)) { if (--nlpar > 0) outputstr(rquote); } else if (LOOK_AHEAD(l,lquote)) { record(quotes, nlpar++); outputstr(lquote); } else if (l == EOF) { if (nlpar == 1) warnx("unclosed quote:"); else warnx("%d unclosed quotes:", nlpar); dump_stack(quotes, nlpar); exit(1); } else { if (nlpar > 0) { if (sp < 0) reallyputchar(l); else CHRSAVE(l); } } } while (nlpar != 0); } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { reallyoutputstr(scommt); for(;;) { t = gpbc(); if (LOOK_AHEAD(t, ecommt)) { reallyoutputstr(ecommt); break; } if (t == EOF) break; reallyputchar(t); } } else if (t == '_' || isalpha(t)) { p = inspect(t, token); if (p != NULL) pushback(l = gpbc()); if (p == NULL || (l != LPAREN && (macro_getdef(p)->type & NEEDARGS) != 0)) outputstr(token); else { /* * real thing.. First build a call frame: */ pushf(fp); /* previous call frm */ pushf(macro_getdef(p)->type); /* type of the call */ pushf(is_traced(p)); pushf(0); /* parenthesis level */ fp = sp; /* new frame pointer */ /* * now push the string arguments: */ pushs1(macro_getdef(p)->defn); /* defn string */ pushs1((char *)macro_name(p)); /* macro name */ pushs(ep); /* start next..*/ if (l != LPAREN && PARLEV == 0) { /* no bracks */ chrsave(EOS); if (sp == (int)STACKMAX) errx(1, "internal stack overflow"); eval((const char **) mstack+fp+1, 2, CALTYP, TRACESTATUS); ep = PREVEP; /* flush strspace */ sp = PREVSP; /* previous sp.. */ fp = PREVFP; /* rewind stack...*/ } } } else if (t == EOF) { if (!mimic_gnu /* you can puke right there */ && sp > -1 && ilevel <= 0) { warnx( "unexpected end of input, unclosed parenthesis:"); dump_stack(paren, PARLEV); exit(1); } if (ilevel <= 0) break; /* all done thanks.. */ release_input(infile+ilevel--); emit_synchline(); bufbase = bbase[ilevel]; continue; } else if (sp < 0) { /* not in a macro at all */ reallyputchar(t); /* output directly.. */ } else switch(t) { case LPAREN: if (PARLEV > 0) chrsave(t); while (isspace(l = gpbc())) /* skip blank, tab, nl.. */ if (PARLEV > 0) chrsave(l); pushback(l); record(paren, PARLEV++); break; case RPAREN: if (--PARLEV > 0) chrsave(t); else { /* end of argument list */ chrsave(EOS); if (sp == (int)STACKMAX) errx(1, "internal stack overflow"); eval((const char **) mstack+fp+1, sp-fp, CALTYP, TRACESTATUS); ep = PREVEP; /* flush strspace */ sp = PREVSP; /* previous sp.. */ fp = PREVFP; /* rewind stack...*/ } break; case COMMA: if (PARLEV == 1) { chrsave(EOS); /* new argument */ while (isspace(l = gpbc())) ; pushback(l); pushs(ep); } else chrsave(t); break; default: if (LOOK_AHEAD(t, scommt)) { char *cp; for (cp = scommt; *cp; cp++) chrsave(*cp); for(;;) { t = gpbc(); if (LOOK_AHEAD(t, ecommt)) { for (cp = ecommt; *cp; cp++) chrsave(*cp); break; } if (t == EOF) break; CHRSAVE(t); } } else CHRSAVE(t); /* stack the char */ break; } } }