[comp.sources.unix] v20i048: Plum-Hall X3J11 macro explainer

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.