rsalz@uunet.uu.net (Rich Salz) (10/24/89)
Submitted-by: Eric S. Raymond <eric@snark.uu.net> Posting-number: Volume 20, Issue 48 Archive-name: plum-ansi-macros his is a tutorial program which illustrates how the Standard's macro-expansion algorithm works. First, look at some of the .out files to see the model of presentation of macro-expansion. Then, look at the file mac.c for notes on the implementation. This is not an elegant program. It was designed to illustrate the dynamics in the minimum amount of C code. Forget about "information-hiding"; everything is a string of chars. All of this directory is experimental, not intended to be authoritative, and in no way an official opinion of the ANSI X3J11 committee. Permissions: Permission is granted for reproduction and use of this mac program, provided that its enclosed authorship notice is reproduced entirely. Tom Plum, Plum Hall Inc, 609-927-3770, uunet!plumhall!plum . #!/bin/sh : "This is a shell archive, meaning: " : "1. Remove everything above the #! /bin/sh line. " : "2. Save the resulting test in a file. " : "3. Execute the file with /bin/sh (not csh) to create the files:" : " READ.ME" : " Makefile" : " mac.c" : " std1.in" : " std2.in" : " std3.in" : " std4.in" : " test1.in" : " test2.in" : " test5.in" : " test6.in" : " test7.in" : " test8.in" : " std1.out" : " std2.out" : " std3.out" : " std4.out" : " test1.out" : " test2.out" : " test5.out" : " test6.out" : " test7.out" : " test8.out" echo file: READ.ME sed 's/^X//' >READ.ME << 'END-of-READ.ME' XThe MAC demonstration program X XThis is a tutorial program which illustrates how the Standard's Xmacro-expansion algorithm works. First, look at some of the .out files Xto see the model of presentation of macro-expansion. X XThen, look at the file mac.c for notes on the implementation. This is Xnot an elegant program. It was designed to illustrate the dynamics in Xthe minimum amount of C code. Forget about "information-hiding"; Xeverything is a string of chars. X XAll of this directory is experimental, not intended to be authoritative, Xand in no way an official opinion of the ANSI X3J11 committee. X X----------------------- XPermissions: X X Permission is granted for reproduction and use of this mac program, X provided that its enclosed authorship notice is reproduced entirely. X X X Tom Plum, Plum Hall Inc, 609-927-3770, uunet!plumhall!plum . END-of-READ.ME echo file: Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# X# Makefile for the Plum-Hall X3J11 macro untangler X# XSRC = Makefile mac.c XIN = std[1234].in test[12345678].in XOUT = std[1234].out test[12345678].out X Xmac: mac.c X cc -g -o mac mac.c X XSUFFIXES: .out .in X X.in.out: mac X mac <$*.in >$*.out X Xshar: READ.ME $(SRC) $(IN) $(OUT) X shar READ.ME $(SRC) $(IN) $(OUT) >mac.shar X Xclean: X rm -f mac mac.shar *~ END-of-Makefile echo file: mac.c sed 's/^X//' >mac.c << 'END-of-mac.c' X/* macros - skeleton of macro expansion algorithm X * Each token is one char (letter a-z). X * Token-buffers are modeled by plain old char strings. X * Each such buffer has another same-size buffer printed just under it, X * which shows the "hide-set" associated with the token above it. X * (The "hide-set" contains all the tokens that are non-replaceable.) X * #define is #d (no space before or after #). X * No attempt to model details of whitespace handling. X * Two tokens, when catenated, produce "second token plus one". X * "Stringize" is crudely stubbed; two quotes "" replace the string. X * Does not handle empty actuals gracefully. X * Does not span newlines in matching actuals. X * Revisions: X * 88/10/01: Identify the "replacement" buffer as "R". X * 88/10/03: Handle the hide-set of actuals properly. X * 88/10/03: Indicate where to refine for the exact (unspecified) X * semantics of interactions of hide-sets in catenation X */ X/* X * First version written by Thomas Plum, Plum Hall Inc. X * Subsequently revised by members of X3J11, the X * ANSI C Standards Committee. X * Permission is granted to reproduce and use this program, X * for all purposes, provided that this notice is included. X */ X X/* First, 300+ lines of inelegant support routines, to about 363 ... */ X X#include <stdio.h> X#include <ctype.h> X#include <string.h> X#define TRACE(x) 0 /* or, printf x , if needed for debugging */ X#define OUT(x) printf x X#define cpy_nam(p, q) (p[0] = *(q), p[1] = '\0', ++(q)) X#define eobuf(p) (*(p) == '\0') X#define next(p, s) (strncmp(p, s, (length_matched = strlen(s))) == 0) X#define advance(p) (p += length_matched) X#define is_obj(p) in_set(obj.nam, *(p)) X#define is_fn(p) in_set(fn.nam, *(p)) X#define obj_def(p) obj.def[obj_num(p)][0] X#define obj_num(p) (strchr(obj.nam, *(p)) - obj.nam) X#define fn_def(p) fn.def[fn_num(p)][0] X#define fn_num(p) (strchr(fn.nam, *(p)) - fn.nam) X#define fn_parm_count(p) strlen(fn.parms[fn_num(p)]) X#define fn_parm_index(p, q) \ X (strchr(fn.parms[fn_num(p)], *(q)) - fn.parms[fn_num(p)]) X#define is_parm_name(p, q) in_set(fn.parms[fn_num(p)], *(q)) X#define in_set(p, c) (strchr(p, c) != 0) X#define hide_set(p) *((char*)p + L) X#define A 9 /* max # of macro args */ X#define D 26 /* max # of macro defs */ X#define L 100 /* max length of an input line or of a macro def */ Xint length_matched; Xvoid diagram(), expand(), expand_fn(), set_hide(), listcpy(); Xvoid add_hide(), lower_case(); Xchar *h_set(); Xchar arg_patterns[10][24] = X { X "()", X "(_)", X "(_,_)", X "(_,_,_)", X "(_,_,_,_)", X "(_,_,_,_,_)", X "(_,_,_,_,_,_)", X "(_,_,_,_,_,_,_)", X "(_,_,_,_,_,_,_,_)", X "(_,_,_,_,_,_,_,_,_)", X }; Xchar next_token(p) char *p; X { X length_matched = 0; X ++p; X for (;;) X { X if (*p == ' ') X ++p, ++length_matched; X else if (*p == '\0') X { X printf("treating end-of-buffer as end-of-file\n"); X return *p; X } X else X return *p; X } X } X Xvoid strip_blanks(p) char *p; X { X char *q = p; X X while (*p == ' ') X ++p; X /* now at first non-blank in p */ X while (*p != '\0') /* can't use strcpy because overlap */ X hide_set(q) = hide_set(p), *q++ = *p++; X while (*--q == ' ') X ; X *++q = '\0', hide_set(q) = '\0'; X } X Xstruct obj { int n; char nam[D]; char def[D][2][L]; } X obj = {0}; Xstruct fn { int n; char nam[D]; char def[D][2][L]; char parms[D][A]; } X fn = {0}; X Xvoid install_obj(nam, def) char *nam; char *def; X { X obj.nam[obj.n] = nam[0]; X strcpy(obj.def[obj.n][0], def); X strip_blanks(obj.def[obj.n][0]); X set_hide(obj.def[obj.n][0], nam); X printf("obj: nam=<%s> def=<%s>\n", nam, obj.def[obj.n][0]); X printf(" <%s>\n", obj.def[obj.n][1]); X ++obj.n; X } X Xvoid install_fn(nam, def, parms) char *nam; char *def; char *parms; X { X fn.nam[fn.n] = nam[0]; X strcpy(fn.def[fn.n][0], def); X strcpy(fn.parms[fn.n], parms); X strip_blanks(fn.def[fn.n][0]); X set_hide(fn.def[fn.n][0], nam); X printf("fn: nam=<%s> parms=<%s> def=<%s>\n", nam, parms, fn.def[fn.n][0]); X printf(" %*s <%s>\n", X strlen(parms), "", fn.def[fn.n][1]); X ++fn.n; X } X Xchar *parse_parms(p, parms) char *p; char *parms; X { X int i = 0; X X while (*p != ')') X { X if (*p != ' ' && *p != ',') X parms[i++] = *p; X ++p; X } X ++p; X parms[i] = '\0'; X return p; X } X X X Xvoid replace(level, suf, buf, p, p2, def) char *level, *suf, *buf, *p, *p2, *def; X { X char hold[2][L]; X char old_hide[2]; X X listcpy(hold[0], p2); X old_hide[0] = hide_set(p), old_hide[1] = '\0'; X listcpy(p, def); X add_hide(p, old_hide); X listcpy(p + strlen(def), hold[0]); X diagram(level, buf, suf); X } Xchar *match_actuals(p, actual, n) char *p; char actual[A][2][L]; int n; X { X int parens = 1; X int i = 0; X int j = 0; X X TRACE(("match_actuals(<%s>, actual)\n", p)); X p += 1; X /* past the '(' */ X X for ( ;; ) X { X if (*p == '(') X { X ++parens; X actual[i][1][j] = p[L]; X actual[i][0][j++] = *p++; X } X else if (*p == ')') X { X --parens; X if (parens == 0) X break; X actual[i][1][j] = p[L]; X actual[i][0][j++] = *p++; X } X else if (*p == ',' && parens == 1) X { X actual[i][1][j] = '\0'; X actual[i][0][j] = '\0'; X j = 0; X ++i; X ++p; X } X else X { X actual[i][1][j] = p[L]; X actual[i][0][j++] = *p++; X } X } X actual[i][1][j] = '\0'; X actual[i][0][j] = '\0'; X /* should strip blanks on each actual, to be sure non-empty */ X if (i == 0 && n == 0) X ; /* ok, no args */ X else if (i != n-1) X { X printf("wrong number of actuals\n"); X exit(2); X } X for (i = 0; i < n; ++i) X TRACE(("actual[%d] = <%s>\n", i, actual[i][0])); X return p+1; X } X Xchar *stringize(s) char *s; X { X static char string_buf[2][L] = {"\"\"", " "}; X X printf("string \"%s\" --> \"\"\n", s); X return string_buf[0]; X } X Xchar *catenate(p, q) char *p, *q; X { X static char cat_buf[2][L]; X char old_hide[2]; X X cat_buf[0][0] = q[0] + 1; X cat_buf[0][1] = '\0'; X set_hide(cat_buf[0], " "); X old_hide[0] = hide_set(p), old_hide[1] = '\0'; X add_hide(cat_buf[0], old_hide); X old_hide[0] = hide_set(q), old_hide[1] = '\0'; X add_hide(cat_buf[0], old_hide); /* NOTE: The other "unspecified" */ X /* choice is to intersect(!) the */ X /* two hide-sets, as in Prosser */ X /* 86-196. */ X printf("catenate %c%c --> %c\n", p[0], q[0], cat_buf[0][0]); X return cat_buf[0]; X } X Xvoid listcpy(p, q) char *p, *q; X { X strcpy(p, q); X strcpy(&hide_set(p), &hide_set(q)); X } X Xvoid diagram(level, s, suf) char *level, *s, *suf; X { X char prefix[L]; X X if (level[0] == '\0') X strcpy(prefix, "0"); X else X strcpy(prefix, level+1); X printf("%s%s: %s\n", prefix, suf, s); X printf("%*s%.*s\n", strlen(prefix)+strlen(suf)+2, ": ", X strlen(s), &hide_set(s)); X } X Xint charcmp(s, t) char *s, *t; X { X return *s - *t; X } X Xvoid set_hide(def, nam) char *def, *nam; X { X memset(&hide_set(def), nam[0], strlen(def)); X def[L+strlen(def)] = '\0'; X } Xchar hide_sets[10][10] = {0}; Xint n_hide_sets = 0; Xvoid add_hide(p, h) char *p, *h; X { X int i, lim; X X lim = strlen(p); X for (i = 0; i < lim; ++i) X { X char c = p[L+i]; X char old_h[2]; X X old_h[0] = c, old_h[1] = '\0'; X TRACE(("c=<%c>, h=<%c>\n", c, h[0])); X if (h[0] == ' ') X ; X else if (c == ' ') X p[L+i] = h[0]; X else if (h[0] == c) X ; X else if (in_set(h_set(old_h), h[0])) X ; X else X { X char new_hide[10]; X int n = n_hide_sets; X int j; X int found = 0; X X strcpy(new_hide, h_set(old_h)); X strcat(new_hide, h_set(h)); X qsort(new_hide, strlen(new_hide), 1, charcmp); X TRACE(("new_hide=<%s>\n", new_hide)); X for (j = 0; j < n_hide_sets; ++j) X { X if (strcmp(new_hide, hide_sets[j]) == 0) X { X p[L+i] = j + '0'; X found = 1; X } X } X if (!found) X { X if (n > 9) X { X printf("too many hide-sets\n"); X exit(2); X } X strcpy(hide_sets[n], new_hide); X p[L+i] = n + '0'; X qsort(hide_sets[n], strlen(hide_sets[n]), 1, charcmp); X printf("hide-set #%d = {%s}\n", n, hide_sets[n]); X ++n_hide_sets; X } X } X } X } X Xchar *h_set(s) char *s; X { X char c = s[0]; X X if (isdigit(c)) X return hide_sets[c - '0']; X else X return s; X } X Xint is_hidden(p) char *p; X { X if (!islower(*p)) X return 0; X else if (*p == p[L]) X return 1; X else if (isdigit(p[L]) && strchr(hide_sets[p[L] - '0'], *p) != 0) X return 1; X else X return 0; X } X Xvoid mark_non_replace(p) char *p; X { X *p = toupper(*p); X } X Xvoid lower_case(p) char *p; X { X for ( ; *p != '\0'; ++p) X *p = tolower(*p); X } X X X/* Now: Here's the actual macro algorithm ... */ X Xvoid preproc(p) char *p; X { X char nam[2]; X char parms[A]; X X if (next(p, "#d ")) X { /* starting a #define */ X advance(p); X TRACE(("p=<%s>\n", p)); X cpy_nam(nam, p); X if (next(p, "(")) /* a fn-like macro */ X { X advance(p); X p = parse_parms(p, parms); X install_fn(nam, p, parms); X } X else /* an object-like macro */ X install_obj(nam, p); X } /* end of #define */ X else if (next(p, "#u ")) X { /* starting a #undef */ X } /* stub */ X else X { X expand(p, ""); X lower_case(p); X set_hide(p, " "); X diagram("", p, ""); X } X } Xvoid expand(buf, level) char *buf; char *level; X { X char *p = buf; X X TRACE(("expand(<%s>, %s)\n", buf, level)); X diagram(level, buf, ""); X while (!eobuf(p)) X { X if (is_hidden(p)) X { X mark_non_replace(p); X ++p; X diagram(level, buf, ""); X } X else if (is_obj(p)) /* instance of object-like macro */ X replace(level, "", buf, p, p+1, obj_def(p)); X else if (is_fn(p) && next_token(p) == '(') X expand_fn(buf, p, level); /* instance of fn-like macro */ X else X ++p; /* ordinary token */ X } /* end while !eobuf */ X } /* end expand() */ X X X X X X Xvoid expand_fn(buf, p, level) char *buf, *p, *level; X { X char actual[A][2][L], expandeds[A][2][L]; X char repl[2][L]; X char nlevel[20]; X char fn_nam[2]; X char invocation[2][L]; X char *start_invok, *q; X int i_parm, num_parms; X X start_invok = p; X cpy_nam(fn_nam, p); X advance(p); /* past any blanks skipped in next_token */ X num_parms = fn_parm_count(fn_nam); X p = match_actuals(p, actual, num_parms); X for (i_parm = 0; i_parm < num_parms; ++i_parm) X { X listcpy(expandeds[i_parm][0], actual[i_parm][0]); X sprintf(nlevel, "%s.%d", level, i_parm+1); X expand(expandeds[i_parm][0], nlevel); X } X sprintf(invocation[0], "%s%s", fn_nam, arg_patterns[num_parms]); X set_hide(invocation[0], " "); X diagram(level, invocation[0], "R"); X listcpy(repl[0], fn_def(fn_nam)); X diagram(level, repl[0], "R"); X TRACE(("subst parms in repl:<%s>\n", repl)); X for (q = repl[0]; !eobuf(q); ) X { X TRACE(("repl-token <%c>\n", *q)); X if (q[1] == '#' && q[2] == '#' && !eobuf(q+3)) X { X replace(level, "R", repl[0], q, q+4, X catenate(q, q+3)); X q += 1; /* advance past new "token" */ X } X else if (q[0] == '#' && is_parm_name(fn_nam, q+1)) X { X i_parm = fn_parm_index(fn_nam, q+1); X replace(level, "R", repl[0], q, q+2, X stringize(actual[i_parm][0])); X q += 2; /* advance past "" */ X } X else if (is_parm_name(fn_nam, q)) X { X i_parm = fn_parm_index(fn_nam, q); X replace(level, "R", repl[0], q, q+1, X expandeds[i_parm][0]); X q += strlen(expandeds[i_parm][0]); /* advance past expansion */ X } X else /* ordinary token */ X ++q; X } X replace(level, "", buf, start_invok, p, repl[0]); X } X X X X Xmain() X { X char line[BUFSIZ]; X X while (gets(line)) X { X set_hide(line, " "); X preproc(line); X } X } /* end main */ END-of-mac.c echo file: std1.in sed 's/^X//' >std1.in << 'END-of-std1.in' X#d f(a) f( x * (a)) X#d z z[0] X#d x 2 Xf(y+1) + f(f(z)) % END-of-std1.in echo file: std2.in sed 's/^X//' >std2.in << 'END-of-std2.in' X#d f(a) f( x * (a)) X#d x 2 X#d g f X#d t(a) a Xt(t(g)(0) + t)(1); END-of-std2.in echo file: std3.in sed 's/^X//' >std3.in << 'END-of-std3.in' X#d f(a) f( x * (a)) X#d x 2 X#d g f X#d w 0,1 X#d h g(~ X Xg(x+(3,4)-w) | h 5) END-of-std3.in echo file: std4.in sed 's/^X//' >std4.in << 'END-of-std4.in' X#d f(a) f( x * (a)) X#d x 2 X#d m(a) a(w) X#d w 0,1 X Xm (f)^m(m) ; END-of-std4.in echo file: test1.in sed 's/^X//' >test1.in << 'END-of-test1.in' X#d x(c) (y(c,3)) X#d y(a, b) x(a+b) Xy(x(2),1) END-of-test1.in echo file: test2.in sed 's/^X//' >test2.in << 'END-of-test2.in' X#d f(a) i(x*(a)) X#d j(a) k(x*(a)) X#d z y[0] X#d x 2 Xf(j(z)) 3 4 z X X#d h(g) g X#d a() 0 X#d b () X#d c a b Xh(c) X X#d m(a) <<#a>> X#d n(a) m(a) Xm(1 2 3) Xm(z) Xn(z) X X#d e(a, b) [[a##b]] Xe(x,y) END-of-test2.in echo file: test5.in sed 's/^X//' >test5.in << 'END-of-test5.in' X#d h(g) g X#d a() 0 X#d b () X#d c a b Xh(c) END-of-test5.in echo file: test6.in sed 's/^X//' >test6.in << 'END-of-test6.in' X#d m(a) <<#a>> X#d n(a) m(a) Xm(1 2 3) Xm(z) Xn(z) END-of-test6.in echo file: test7.in sed 's/^X//' >test7.in << 'END-of-test7.in' X#d e(a, b) [[a##b]] Xe(x,y) END-of-test7.in echo file: test8.in sed 's/^X//' >test8.in << 'END-of-test8.in' X#d f(a) a * g X#d g(a) f(a) X Xf(2)(9) END-of-test8.in echo file: std1.out sed 's/^X//' >std1.out << 'END-of-std1.out' Xfn: nam=<f> parms=<a> def=<f( x * (a))> X <fffffffffff> Xobj: nam=<z> def=<z[0]> X <zzzz> Xobj: nam=<x> def=<2> X <x> X0: f(y+1) + f(f(z)) % X : X1: y+1 X : X0R: f(_) X : X0R: f( x * (a)) X : fffffffffff X0R: f( x * (y+1)) X : fffffffffffff X0: f( x * (y+1)) + f(f(z)) % X : fffffffffffff X0: F( x * (y+1)) + f(f(z)) % X : fffffffffffff Xhide-set #0 = {fx} X0: F( 2 * (y+1)) + f(f(z)) % X : fff0fffffffff X1: f(z) X : X1.1: z X : X1.1: z[0] X : zzzz X1.1: Z[0] X : zzzz X1R: f(_) X : X1R: f( x * (a)) X : fffffffffff Xhide-set #1 = {fz} X1R: f( x * (Z[0])) X : ffffffff1111ff X1: f( x * (Z[0])) X : ffffffff1111ff X1: F( x * (Z[0])) X : ffffffff1111ff X1: F( 2 * (Z[0])) X : fff0ffff1111ff X0R: f(_) X : X0R: f( x * (a)) X : fffffffffff X0R: f( x * (F( 2 * (Z[0])))) X : fffffffffff0ffff1111ffff X0: F( 2 * (y+1)) + f( x * (F( 2 * (Z[0])))) % X : fff0fffffffff fffffffffff0ffff1111ffff X0: F( 2 * (y+1)) + F( x * (F( 2 * (Z[0])))) % X : fff0fffffffff fffffffffff0ffff1111ffff X0: F( 2 * (y+1)) + F( 2 * (F( 2 * (Z[0])))) % X : fff0fffffffff fff0fffffff0ffff1111ffff X0: f( 2 * (y+1)) + f( 2 * (f( 2 * (z[0])))) % X : END-of-std1.out echo file: std2.out sed 's/^X//' >std2.out << 'END-of-std2.out' Xfn: nam=<f> parms=<a> def=<f( x * (a))> X <fffffffffff> Xobj: nam=<x> def=<2> X <x> Xobj: nam=<g> def=<f> X <g> Xfn: nam=<t> parms=<a> def=<a> X <t> X0: t(t(g)(0) + t)(1); X : X1: t(g)(0) + t X : X1.1: g X : X1.1: f X : g Xtreating end-of-buffer as end-of-file X1R: t(_) X : X1R: a X : t Xhide-set #0 = {gt} X1R: f X : 0 X1: f(0) + t X : 0 X1.1: 0 X : X1R: f(_) X : X1R: f( x * (a)) X : fffffffffff X1R: f( x * (0)) X : fffffffffff Xhide-set #1 = {fgt} X1: f( x * (0)) + t X : 11111111111 X1: F( x * (0)) + t X : 11111111111 Xhide-set #2 = {fgtx} X1: F( 2 * (0)) + t X : 11121111111 Xtreating end-of-buffer as end-of-file X0R: t(_) X : X0R: a X : t X0R: F( 2 * (0)) + t X : 11121111111tttt X0: F( 2 * (0)) + t(1); X : 11121111111tttt X0: F( 2 * (0)) + T(1); X : 11121111111tttt X0: f( 2 * (0)) + t(1); X : END-of-std2.out echo file: std3.out sed 's/^X//' >std3.out << 'END-of-std3.out' Xfn: nam=<f> parms=<a> def=<f( x * (a))> X <fffffffffff> Xobj: nam=<x> def=<2> X <x> Xobj: nam=<g> def=<f> X <g> Xobj: nam=<w> def=<0,1> X <www> Xobj: nam=<h> def=<g(~> X <hhh> X0: X : X0: X : X0: g(x+(3,4)-w) | h 5) X : X0: f(x+(3,4)-w) | h 5) X : g X1: x+(3,4)-w X : X1: 2+(3,4)-w X : x X1: 2+(3,4)-0,1 X : x www X0R: f(_) X : X0R: f( x * (a)) X : fffffffffff Xhide-set #0 = {fx} Xhide-set #1 = {fw} X0R: f( x * (2+(3,4)-0,1)) X : ffffffff0fffffff111ff Xhide-set #2 = {fg} Xhide-set #3 = {fgx} Xhide-set #4 = {fgw} X0: f( x * (2+(3,4)-0,1)) | h 5) X : 222222223222222244422 X0: F( x * (2+(3,4)-0,1)) | h 5) X : 222222223222222244422 X0: F( 2 * (2+(3,4)-0,1)) | h 5) X : 222322223222222244422 X0: F( 2 * (2+(3,4)-0,1)) | g(~ 5) X : 222322223222222244422 hhh Xhide-set #5 = {gh} X0: F( 2 * (2+(3,4)-0,1)) | f(~ 5) X : 222322223222222244422 5hh X1: ~ 5 X : h X0R: f(_) X : X0R: f( x * (a)) X : fffffffffff Xhide-set #6 = {fh} X0R: f( x * (~ 5)) X : ffffffff6ffff Xhide-set #7 = {fgh} Xhide-set #8 = {fghh} X0: F( 2 * (2+(3,4)-0,1)) | f( x * (~ 5)) X : 222322223222222244422 7777777787777 X0: F( 2 * (2+(3,4)-0,1)) | F( x * (~ 5)) X : 222322223222222244422 7777777787777 Xhide-set #9 = {fghx} X0: F( 2 * (2+(3,4)-0,1)) | F( 2 * (~ 5)) X : 222322223222222244422 7779777787777 X0: f( 2 * (2+(3,4)-0,1)) | f( 2 * (~ 5)) X : END-of-std3.out echo file: std4.out sed 's/^X//' >std4.out << 'END-of-std4.out' Xfn: nam=<f> parms=<a> def=<f( x * (a))> X <fffffffffff> Xobj: nam=<x> def=<2> X <x> Xfn: nam=<m> parms=<a> def=<a(w)> X <mmmm> Xobj: nam=<w> def=<0,1> X <www> X0: X : X0: X : X0: m (f)^m(m) ; X : X1: f X : Xtreating end-of-buffer as end-of-file X0R: m(_) X : X0R: a(w) X : mmmm X0R: f(w) X : mmmm X0: f(w)^m(m) ; X : mmmm X1: w X : m Xhide-set #0 = {mw} X1: 0,1 X : 000 X0R: f(_) X : X0R: f( x * (a)) X : fffffffffff Xhide-set #1 = {fmw} X0R: f( x * (0,1)) X : ffffffff111ff Xhide-set #2 = {fm} X0: f( x * (0,1))^m(m) ; X : 2222222211122 X0: F( x * (0,1))^m(m) ; X : 2222222211122 Xhide-set #3 = {fmx} X0: F( 2 * (0,1))^m(m) ; X : 2223222211122 X1: m X : Xtreating end-of-buffer as end-of-file X0R: m(_) X : X0R: a(w) X : mmmm X0R: m(w) X : mmmm X0: F( 2 * (0,1))^m(w) ; X : 2223222211122 mmmm X0: F( 2 * (0,1))^M(w) ; X : 2223222211122 mmmm X0: F( 2 * (0,1))^M(0,1) ; X : 2223222211122 mm000m X0: f( 2 * (0,1))^m(0,1) ; X : END-of-std4.out echo file: test1.out sed 's/^X//' >test1.out << 'END-of-test1.out' Xfn: nam=<x> parms=<c> def=<(y(c,3))> X <xxxxxxxx> Xfn: nam=<y> parms=<ab> def=<x(a+b)> X <yyyyyy> X0: y(x(2),1) X : X1: x(2) X : X1.1: 2 X : X1R: x(_) X : X1R: (y(c,3)) X : xxxxxxxx X1R: (y(2,3)) X : xxxxxxxx X1: (y(2,3)) X : xxxxxxxx X1.1: 2 X : x X1.2: 3 X : x X1R: y(_,_) X : X1R: x(a+b) X : yyyyyy Xhide-set #0 = {xy} X1R: x(2+b) X : yy0yyy X1R: x(2+3) X : yy0y0y X1: (x(2+3)) X : x000000x X1: (X(2+3)) X : x000000x X2: 1 X : X0R: y(_,_) X : X0R: x(a+b) X : yyyyyy X0R: x((X(2+3))+b) X : yy00000000yyy X0R: x((X(2+3))+1) X : yy00000000yyy X0: x((X(2+3))+1) X : yy00000000yyy X1: (X(2+3))+1 X : 00000000yy X0R: x(_) X : X0R: (y(c,3)) X : xxxxxxxx X0R: (y((X(2+3))+1,3)) X : xxx0000000000xxxx X0: (y((X(2+3))+1,3)) X : 00000000000000000 X0: (Y((X(2+3))+1,3)) X : 00000000000000000 X0: (y((x(2+3))+1,3)) X : END-of-test1.out echo file: test2.out sed 's/^X//' >test2.out << 'END-of-test2.out' Xfn: nam=<f> parms=<a> def=<i(x*(a))> X <ffffffff> Xfn: nam=<j> parms=<a> def=<k(x*(a))> X <jjjjjjjj> Xobj: nam=<z> def=<y[0]> X <zzzz> Xobj: nam=<x> def=<2> X <x> X0: f(j(z)) 3 4 z X : X1: j(z) X : X1.1: z X : X1.1: y[0] X : zzzz X1R: j(_) X : X1R: k(x*(a)) X : jjjjjjjj Xhide-set #0 = {jz} X1R: k(x*(y[0])) X : jjjjj0000jj X1: k(x*(y[0])) X : jjjjj0000jj Xhide-set #1 = {jx} X1: k(2*(y[0])) X : jj1jj0000jj X0R: f(_) X : X0R: i(x*(a)) X : ffffffff Xhide-set #2 = {fj} Xhide-set #3 = {fjx} Xhide-set #4 = {fjz} X0R: i(x*(k(2*(y[0])))) X : fffff22322444422ff X0: i(x*(k(2*(y[0])))) 3 4 z X : fffff22322444422ff Xhide-set #5 = {fx} X0: i(2*(k(2*(y[0])))) 3 4 z X : ff5ff22322444422ff X0: i(2*(k(2*(y[0])))) 3 4 y[0] X : ff5ff22322444422ff zzzz X0: i(2*(k(2*(y[0])))) 3 4 y[0] X : X0: X : X0: X : Xfn: nam=<h> parms=<g> def=<g> X <h> Xfn: nam=<a> parms=<> def=<0> X <a> Xobj: nam=<b> def=<()> X <bb> Xobj: nam=<c> def=<a b> X <ccc> X0: h(c) X : X1: c X : X1: a b X : ccc Xhide-set #6 = {bc} X1: a () X : cc66 X0R: h(_) X : X0R: g X : h Xhide-set #7 = {ch} Xhide-set #8 = {bch} X0R: a () X : 7788 X0: a () X : 7788 X0R: a() X : X0R: 0 X : a Xhide-set #9 = {ach} X0: 0 X : 9 X0: 0 X : X0: X : X0: X : Xfn: nam=<m> parms=<a> def=<<<#a>>> X <mmmmmm> Xfn: nam=<n> parms=<a> def=<m(a)> X <nnnn> X0: m(1 2 3) X : X1: 1 2 3 X : X0R: m(_) X : X0R: <<#a>> X : mmmmmm Xstring "1 2 3" --> "" X0R: <<"">> X : mmmmmm X0: <<"">> X : mmmmmm X0: <<"">> X : X0: m(z) X : X1: z X : X1: y[0] X : zzzz X0R: m(_) X : X0R: <<#a>> X : mmmmmm Xstring "z" --> "" X0R: <<"">> X : mmmmmm X0: <<"">> X : mmmmmm X0: <<"">> X : X0: n(z) X : X1: z X : X1: y[0] X : zzzz X0R: n(_) X : X0R: m(a) X : nnnn Xtoo many hide-sets END-of-test2.out echo file: test5.out sed 's/^X//' >test5.out << 'END-of-test5.out' Xfn: nam=<h> parms=<g> def=<g> X <h> Xfn: nam=<a> parms=<> def=<0> X <a> Xobj: nam=<b> def=<()> X <bb> Xobj: nam=<c> def=<a b> X <ccc> X0: h(c) X : X1: c X : X1: a b X : ccc Xhide-set #0 = {bc} X1: a () X : cc00 X0R: h(_) X : X0R: g X : h Xhide-set #1 = {ch} Xhide-set #2 = {bch} X0R: a () X : 1122 X0: a () X : 1122 X0R: a() X : X0R: 0 X : a Xhide-set #3 = {ach} X0: 0 X : 3 X0: 0 X : END-of-test5.out echo file: test6.out sed 's/^X//' >test6.out << 'END-of-test6.out' Xfn: nam=<m> parms=<a> def=<<<#a>>> X <mmmmmm> Xfn: nam=<n> parms=<a> def=<m(a)> X <nnnn> X0: m(1 2 3) X : X1: 1 2 3 X : X0R: m(_) X : X0R: <<#a>> X : mmmmmm Xstring "1 2 3" --> "" X0R: <<"">> X : mmmmmm X0: <<"">> X : mmmmmm X0: <<"">> X : X0: m(z) X : X1: z X : X0R: m(_) X : X0R: <<#a>> X : mmmmmm Xstring "z" --> "" X0R: <<"">> X : mmmmmm X0: <<"">> X : mmmmmm X0: <<"">> X : X0: n(z) X : X1: z X : X0R: n(_) X : X0R: m(a) X : nnnn X0R: m(z) X : nnnn X0: m(z) X : nnnn X1: z X : n X0R: m(_) X : X0R: <<#a>> X : mmmmmm Xstring "z" --> "" X0R: <<"">> X : mmmmmm Xhide-set #0 = {mn} X0: <<"">> X : 000000 X0: <<"">> X : END-of-test6.out echo file: test7.out sed 's/^X//' >test7.out << 'END-of-test7.out' Xfn: nam=<e> parms=<ab> def=<[[a##b]]> X <eeeeeeee> X0: e(x,y) X : X1: x X : X2: y X : X0R: e(_,_) X : X0R: [[a##b]] X : eeeeeeee Xcatenate ab --> c X0R: [[c]] X : eeeee X0: [[c]] X : eeeee X0: [[c]] X : END-of-test7.out echo file: test8.out sed 's/^X//' >test8.out << 'END-of-test8.out' Xfn: nam=<f> parms=<a> def=<a * g> X <fffff> Xfn: nam=<g> parms=<a> def=<f(a)> X <gggg> X0: X : X0: X : X0: f(2)(9) X : X1: 2 X : X0R: f(_) X : X0R: a * g X : fffff X0R: 2 * g X : fffff X0: 2 * g(9) X : fffff X1: 9 X : X0R: g(_) X : X0R: f(a) X : gggg X0R: f(9) X : gggg Xhide-set #0 = {fg} X0: 2 * f(9) X : ffff0000 X0: 2 * F(9) X : ffff0000 X0: 2 * f(9) X : END-of-test8.out exit -- Eric S. Raymond = eric@snark.uu.net (mad mastermind of TMN-Netnews) -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.