Category : C Source Code
Archive   : PH_MACRO.ZIP
Filename : MAC.C

 
Output of file : MAC.C contained in archive : PH_MACRO.ZIP
/* macros - skeleton of macro expansion algorithm
* Each token is one char (letter a-z).
* Token-buffers are modeled by plain old char strings.
* Each such buffer has another same-size buffer printed just under it,
* which shows the "hide-set" associated with the token above it.
* (The "hide-set" contains all the tokens that are non-replaceable.)
* #define is #d (no space before or after #).
* No attempt to model details of whitespace handling.
* Two tokens, when catenated, produce "second token plus one".
* "Stringize" is crudely stubbed; two quotes "" replace the string.
* Does not handle empty actuals gracefully.
* Does not span newlines in matching actuals.
* Revisions:
* 88/10/01: Identify the "replacement" buffer as "R".
* 88/10/03: Handle the hide-set of actuals properly.
* 88/10/03: Indicate where to refine for the exact (unspecified)
* semantics of interactions of hide-sets in catenation
*/
/*
* First version written by Thomas Plum, Plum Hall Inc.
* Subsequently revised by members of X3J11, the
* ANSI C Standards Committee.
* Permission is granted to reproduce and use this program,
* for all purposes, provided that this notice is included.
*/

/* First, 300+ lines of inelegant support routines, to about 363 ... */

#include
#include
#include
#define TRACE(x) 0 /* or, printf x , if needed for debugging */
#define OUT(x) printf x
#define cpy_nam(p, q) (p[0] = *(q), p[1] = '\0', ++(q))
#define eobuf(p) (*(p) == '\0')
#define next(p, s) (strncmp(p, s, (length_matched = strlen(s))) == 0)
#define advance(p) (p += length_matched)
#define is_obj(p) in_set(obj.nam, *(p))
#define is_fn(p) in_set(fn.nam, *(p))
#define obj_def(p) obj.def[obj_num(p)][0]
#define obj_num(p) (strchr(obj.nam, *(p)) - obj.nam)
#define fn_def(p) fn.def[fn_num(p)][0]
#define fn_num(p) (strchr(fn.nam, *(p)) - fn.nam)
#define fn_parm_count(p) strlen(fn.parms[fn_num(p)])
#define fn_parm_index(p, q) \
(strchr(fn.parms[fn_num(p)], *(q)) - fn.parms[fn_num(p)])
#define is_parm_name(p, q) in_set(fn.parms[fn_num(p)], *(q))
#define in_set(p, c) (strchr(p, c) != 0)
#define hide_set(p) *((char*)p + L)
#define A 9 /* max # of macro args */
#define D 26 /* max # of macro defs */
#define L 100 /* max length of an input line or of a macro def */
int length_matched;
void diagram(), expand(), expand_fn(), set_hide(), listcpy();
void add_hide(), lower_case();
char *h_set();
char arg_patterns[10][24] =
{
"()",
"(_)",
"(_,_)",
"(_,_,_)",
"(_,_,_,_)",
"(_,_,_,_,_)",
"(_,_,_,_,_,_)",
"(_,_,_,_,_,_,_)",
"(_,_,_,_,_,_,_,_)",
"(_,_,_,_,_,_,_,_,_)",
};
char next_token(p) char *p;
{
length_matched = 0;
++p;
for (;;)
{
if (*p == ' ')
++p, ++length_matched;
else if (*p == '\0')
{
printf("treating end-of-buffer as end-of-file\n");
return *p;
}
else
return *p;
}
}

void strip_blanks(p) char *p;
{
char *q = p;

while (*p == ' ')
++p;
/* now at first non-blank in p */
while (*p != '\0') /* can't use strcpy because overlap */
hide_set(q) = hide_set(p), *q++ = *p++;
while (*--q == ' ')
;
*++q = '\0', hide_set(q) = '\0';
}

struct obj { int n; char nam[D]; char def[D][2][L]; }
obj = {0};
struct fn { int n; char nam[D]; char def[D][2][L]; char parms[D][A]; }
fn = {0};

void install_obj(nam, def) char *nam; char *def;
{
obj.nam[obj.n] = nam[0];
strcpy(obj.def[obj.n][0], def);
strip_blanks(obj.def[obj.n][0]);
set_hide(obj.def[obj.n][0], nam);
printf("obj: nam=<%s> def=<%s>\n", nam, obj.def[obj.n][0]);
printf(" <%s>\n", obj.def[obj.n][1]);
++obj.n;
}

void install_fn(nam, def, parms) char *nam; char *def; char *parms;
{
fn.nam[fn.n] = nam[0];
strcpy(fn.def[fn.n][0], def);
strcpy(fn.parms[fn.n], parms);
strip_blanks(fn.def[fn.n][0]);
set_hide(fn.def[fn.n][0], nam);
printf("fn: nam=<%s> parms=<%s> def=<%s>\n", nam, parms, fn.def[fn.n][0]);
printf(" %*s <%s>\n",
strlen(parms), "", fn.def[fn.n][1]);
++fn.n;
}

char *parse_parms(p, parms) char *p; char *parms;
{
int i = 0;

while (*p != ')')
{
if (*p != ' ' && *p != ',')
parms[i++] = *p;
++p;
}
++p;
parms[i] = '\0';
return p;
}



void replace(level, suf, buf, p, p2, def) char *level, *suf, *buf, *p, *p2, *def;
{
char hold[2][L];
char old_hide[2];

listcpy(hold[0], p2);
old_hide[0] = hide_set(p), old_hide[1] = '\0';
listcpy(p, def);
add_hide(p, old_hide);
listcpy(p + strlen(def), hold[0]);
diagram(level, buf, suf);
}
char *match_actuals(p, actual, n) char *p; char actual[A][2][L]; int n;
{
int parens = 1;
int i = 0;
int j = 0;

TRACE(("match_actuals(<%s>, actual)\n", p));
p += 1;
/* past the '(' */

for ( ;; )
{
if (*p == '(')
{
++parens;
actual[i][1][j] = p[L];
actual[i][0][j++] = *p++;
}
else if (*p == ')')
{
--parens;
if (parens == 0)
break;
actual[i][1][j] = p[L];
actual[i][0][j++] = *p++;
}
else if (*p == ',' && parens == 1)
{
actual[i][1][j] = '\0';
actual[i][0][j] = '\0';
j = 0;
++i;
++p;
}
else
{
actual[i][1][j] = p[L];
actual[i][0][j++] = *p++;
}
}
actual[i][1][j] = '\0';
actual[i][0][j] = '\0';
/* should strip blanks on each actual, to be sure non-empty */
if (i == 0 && n == 0)
; /* ok, no args */
else if (i != n-1)
{
printf("wrong number of actuals\n");
exit(2);
}
for (i = 0; i < n; ++i)
TRACE(("actual[%d] = <%s>\n", i, actual[i][0]));
return p+1;
}

char *stringize(s) char *s;
{
static char string_buf[2][L] = {"\"\"", " "};

printf("string \"%s\" --> \"\"\n", s);
return string_buf[0];
}

char *catenate(p, q) char *p, *q;
{
static char cat_buf[2][L];
char old_hide[2];

cat_buf[0][0] = q[0] + 1;
cat_buf[0][1] = '\0';
set_hide(cat_buf[0], " ");
old_hide[0] = hide_set(p), old_hide[1] = '\0';
add_hide(cat_buf[0], old_hide);
old_hide[0] = hide_set(q), old_hide[1] = '\0';
add_hide(cat_buf[0], old_hide); /* NOTE: The other "unspecified" */
/* choice is to intersect(!) the */
/* two hide-sets, as in Prosser */
/* 86-196. */
printf("catenate %c%c --> %c\n", p[0], q[0], cat_buf[0][0]);
return cat_buf[0];
}

void listcpy(p, q) char *p, *q;
{
strcpy(p, q);
strcpy(&hide_set(p), &hide_set(q));
}

void diagram(level, s, suf) char *level, *s, *suf;
{
char prefix[L];

if (level[0] == '\0')
strcpy(prefix, "0");
else
strcpy(prefix, level+1);
printf("%s%s: %s\n", prefix, suf, s);
printf("%*s%.*s\n", strlen(prefix)+strlen(suf)+2, ": ",
strlen(s), &hide_set(s));
}

int charcmp(s, t) char *s, *t;
{
return *s - *t;
}

void set_hide(def, nam) char *def, *nam;
{
memset(&hide_set(def), nam[0], strlen(def));
def[L+strlen(def)] = '\0';
}
char hide_sets[10][10] = {0};
int n_hide_sets = 0;
void add_hide(p, h) char *p, *h;
{
int i, lim;

lim = strlen(p);
for (i = 0; i < lim; ++i)
{
char c = p[L+i];
char old_h[2];

old_h[0] = c, old_h[1] = '\0';
TRACE(("c=<%c>, h=<%c>\n", c, h[0]));
if (h[0] == ' ')
;
else if (c == ' ')
p[L+i] = h[0];
else if (h[0] == c)
;
else if (in_set(h_set(old_h), h[0]))
;
else
{
char new_hide[10];
int n = n_hide_sets;
int j;
int found = 0;

strcpy(new_hide, h_set(old_h));
strcat(new_hide, h_set(h));
qsort(new_hide, strlen(new_hide), 1, charcmp);
TRACE(("new_hide=<%s>\n", new_hide));
for (j = 0; j < n_hide_sets; ++j)
{
if (strcmp(new_hide, hide_sets[j]) == 0)
{
p[L+i] = j + '0';
found = 1;
}
}
if (!found)
{
if (n > 9)
{
printf("too many hide-sets\n");
exit(2);
}
strcpy(hide_sets[n], new_hide);
p[L+i] = n + '0';
qsort(hide_sets[n], strlen(hide_sets[n]), 1, charcmp);
printf("hide-set #%d = {%s}\n", n, hide_sets[n]);
++n_hide_sets;
}
}
}
}

char *h_set(s) char *s;
{
char c = s[0];

if (isdigit(c))
return hide_sets[c - '0'];
else
return s;
}

int is_hidden(p) char *p;
{
if (!islower(*p))
return 0;
else if (*p == p[L])
return 1;
else if (isdigit(p[L]) && strchr(hide_sets[p[L] - '0'], *p) != 0)
return 1;
else
return 0;
}

void mark_non_replace(p) char *p;
{
*p = toupper(*p);
}

void lower_case(p) char *p;
{
for ( ; *p != '\0'; ++p)
*p = tolower(*p);
}


/* Now: Here's the actual macro algorithm ... */

void preproc(p) char *p;
{
char nam[2];
char parms[A];

if (next(p, "#d "))
{ /* starting a #define */
advance(p);
TRACE(("p=<%s>\n", p));
cpy_nam(nam, p);
if (next(p, "(")) /* a fn-like macro */
{
advance(p);
p = parse_parms(p, parms);
install_fn(nam, p, parms);
}
else /* an object-like macro */
install_obj(nam, p);
} /* end of #define */
else if (next(p, "#u "))
{ /* starting a #undef */
} /* stub */
else
{
expand(p, "");
lower_case(p);
set_hide(p, " ");
diagram("", p, "");
}
}
void expand(buf, level) char *buf; char *level;
{
char *p = buf;

TRACE(("expand(<%s>, %s)\n", buf, level));
diagram(level, buf, "");
while (!eobuf(p))
{
if (is_hidden(p))
{
mark_non_replace(p);
++p;
diagram(level, buf, "");
}
else if (is_obj(p)) /* instance of object-like macro */
replace(level, "", buf, p, p+1, obj_def(p));
else if (is_fn(p) && next_token(p) == '(')
expand_fn(buf, p, level); /* instance of fn-like macro */
else
++p; /* ordinary token */
} /* end while !eobuf */
} /* end expand() */






void expand_fn(buf, p, level) char *buf, *p, *level;
{
char actual[A][2][L], expandeds[A][2][L];
char repl[2][L];
char nlevel[20];
char fn_nam[2];
char invocation[2][L];
char *start_invok, *q;
int i_parm, num_parms;

start_invok = p;
cpy_nam(fn_nam, p);
advance(p); /* past any blanks skipped in next_token */
num_parms = fn_parm_count(fn_nam);
p = match_actuals(p, actual, num_parms);
for (i_parm = 0; i_parm < num_parms; ++i_parm)
{
listcpy(expandeds[i_parm][0], actual[i_parm][0]);
sprintf(nlevel, "%s.%d", level, i_parm+1);
expand(expandeds[i_parm][0], nlevel);
}
sprintf(invocation[0], "%s%s", fn_nam, arg_patterns[num_parms]);
set_hide(invocation[0], " ");
diagram(level, invocation[0], "R");
listcpy(repl[0], fn_def(fn_nam));
diagram(level, repl[0], "R");
TRACE(("subst parms in repl:<%s>\n", repl));
for (q = repl[0]; !eobuf(q); )
{
TRACE(("repl-token <%c>\n", *q));
if (q[1] == '#' && q[2] == '#' && !eobuf(q+3))
{
replace(level, "R", repl[0], q, q+4,
catenate(q, q+3));
q += 1; /* advance past new "token" */
}
else if (q[0] == '#' && is_parm_name(fn_nam, q+1))
{
i_parm = fn_parm_index(fn_nam, q+1);
replace(level, "R", repl[0], q, q+2,
stringize(actual[i_parm][0]));
q += 2; /* advance past "" */
}
else if (is_parm_name(fn_nam, q))
{
i_parm = fn_parm_index(fn_nam, q);
replace(level, "R", repl[0], q, q+1,
expandeds[i_parm][0]);
q += strlen(expandeds[i_parm][0]); /* advance past expansion */
}
else /* ordinary token */
++q;
}
replace(level, "", buf, start_invok, p, repl[0]);
}




main()
{
char line[BUFSIZ];

while (gets(line))
{
set_hide(line, " ");
preproc(line);
}
} /* end main */


  3 Responses to “Category : C Source Code
Archive   : PH_MACRO.ZIP
Filename : MAC.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/