/* * b u i l d 4 . c * * Process macro definitions and expansions * * define(model, flag) Define a macro * expand(arg, outfun, outarg) Expand macros * expout(arg) Expand macros, writing output to stdout */ #include #include "build.h" static char def_name[NAMESIZE]; /* Work area for define */ static char * defname(string) register char *string; /* * String points to the first byte of a macro name (the byte after the '$'). * Compile the name into static def_name, and return an updated argument * pointer (which now points to the first byte after the name -- possibly EOS). * Calling sequence: * arg = defname(arg); * sylookup(def_name); */ { register char *np; /* Name buffer pointer */ register int c; /* Working character */ register int closer; /* Terminator if (...) */ np = def_name; if ((c = *string) != EOS) { if (c == '(' || c == '{') { /* * $(FOO) or ${FOO} */ closer = (c == '(') ? ')' : '}'; ++string; /* Skip over '(' */ while (iswhite(*string)) string++; /* Leading whitespace */ while (!iswhite(*string) && *string != closer && *string != EOS && (np - def_name) < NAMESIZE - 1) *np++ = *string++; while (*string != closer && *string != EOS) string++; /* Trailing whitespace */ if (*string == closer) string++; /* and closing ')' */ } else { *np++ = c; /* $X */ string++; /* update string ptr */ } } *np = EOS; return (string); } define(model, flag) register char *model; /* Macro definition(s) */ int flag; /* Set in sy_flag */ /* * process model strings, building macro definitions. * continues until an EOS is passed from nextch. * * Macro definitions have the following format: * $X = Y * where X may be * a single character * (TEXT) or {TEXT} * and Y may be * a string up to the next blank. * { text } * */ { register int c; register char *tp; /* Random text pointer */ #define skip *(model = skipwhite(model)) if (debug) fprintf(stderr, "define(\"%s\")\n", model); while ((c = skip) != EOS) { model++; if (c == '#') { /* * Comment, skip to end of line */ while (c != EOS && c != '\n') c = *model++; continue; } if (c != '$') { fprintf(stderr, "expecting '$', got '%c'\n", c); continue; } model = defname(model); if ((c = skip) != '=') { fprintf(stderr, "definition of %s followed by '%c', '=' needed\n", def_name, c); continue; } model++; /* * Copy the definition into work[] */ tp = work; if ((c = skip) != '{') { /* * Just a word */ model++; while (c != EOS && !iswhite(c)) { if (tp - work >= WORKSIZE-1) fatal("work overflow in define", model); *tp++ = c; c = *model++; } } else { /* * { text } */ model++; c = skip; if (c != EOS) { model++; while (c != EOS && c != '}') { if (tp - work >= WORKSIZE-1) fatal("overflow in define {}", model); *tp++ = c; c = *model++; } } if (c != '}') { fprintf(stderr, "definition of %s not followed by '}'\n", def_name); continue; } } *tp = EOS; sysave(def_name, work, flag); } } expout(arg) char *arg; /* * Call expand, writing the output to stdout */ { expand(arg, out, stdout); } /* * Macro expansion */ static int ex_depth = 0; /* Catch recursion */ char * expand(arg, sfunc, sarg) register char *arg; /* What to expand */ char *(*sfunc)(); /* Output function */ char *sarg; /* Output argument */ /* * Output arg, expanding all macros. Sfunc is called with each character * as follows: * sarg = (*sfunc)(byte, sarg); * Thus, to output text to a file, you could execute expand as: * FILE *myfile; * myfile = stdout; * expand(arg, myfun, myfile); * Where myfun is defined as: * FILE * * myfun(byte, arg) * char byte; * FILE *arg; * { * if (byte != EOS) * putc(byte, arg); * return(arg); * * To output text to a buffer, do the following: * char *myarg; * myarg = buffer; * myarg = expand(arg, myfun, myarg); * On return, myarg will point to the EOS at the end of the string. * Myfun() is defined as: * char * * myfun(byte, arg) * char byte; * char *arg; * { * if (arg - buffer > sizeof buffer) * fatal("Overstuffed buffer", NULL); * *arg = byte; * if (byte != EOS) * arg++; * return (arg); * } */ { register char *np; /* Name pointer */ register SYMBOL *sy; /* Symbol table pointer */ if (++ex_depth > 50) fatal("Very recursive macro", NULL); if (arg != NULL) { if (debug) printf("`%d'[", ex_depth); while (*arg) { if (*arg != '$') { sarg = (*sfunc)(*arg++, sarg); } else if (*++arg == EOS || *arg == ' ') { /* * "$ " or "$" */ sarg = (*sfunc)('$', sarg); } else if (*arg == '$') { /* * "$$" => "$" */ sarg = (*sfunc)('$', sarg); arg++; } else { arg = defname(arg); sy = sylookup(def_name, FALSE); if (sy != NULL && sy->sy_value != NULL) { if (debug) printf("](%s)<", def_name); sarg = expand(sy->sy_value, sfunc, sarg); if (debug) printf(">["); sy->sy_flag |= USED; } } /* if macro found */ } /* arg while loop */ } /* if non-null arg */ sarg = (*sfunc)(EOS, sarg); --ex_depth; if (debug) printf("]"); return (sarg); }