text: #include <time.h>
  #include <ctype.h>
  #include "c.h"
  
  #define I(f) s_##f
  
  static Node *tail;
  static int off, maxoff, uid = 0, verbose = 0, html = 0;
  
  static const char *yyBEGIN(const char *tag) {
  	if (html)
  		print("<%s>", tag);
  	return tag;
  }
  
  static void yyEND(const char *tag) {
  	if (html)
  		print("</%s>", tag);
  	if (isupper(*tag))
  		print("\n");
  }
  
  #define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag)
  #define END yyEND(yytag); } while (0)
  #define ITEM BEGIN(li)
  #define START BEGIN(LI)
  #define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); }
  #define NEWLINE print(html ? "<br>\n" : "\n")
  
  static void emitCoord(Coordinate src) {
  	if (src.file && *src.file) {
  		ANCHOR(href,print("%s", src.file)); print("%s", src.file); END;
  		print(":");
  	}
  	print("%d.%d", src.y, src.x);
  }
  
  static void emitString(int len, const char *s) {
  	for ( ; len-- > 0; s++)
  		if (*s == '&' && html)
  			print("&amp;");
  		else if (*s == '<' && html)
  			print("&lt;");
  		else if (*s == '>' && html)
  			print("&lt;");
  		else if (*s == '"' || *s == '\\')
  			print("\\%c", *s);
  		else if (*s >= ' ' && *s < 0177)
  			print("%c", *s);
  		else
  			print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7);
  }
  
  static void emitSymRef(Symbol p) {
  	(*IR->defsymbol)(p);
  	ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
  }
  
  static void emitSymbol(Symbol p) {
  	(*IR->defsymbol)(p);
  	ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END;
  	BEGIN(ul);
  #define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END
  	if (verbose && (src.y || src.x))
  		xx(src,emitCoord(p->src));
  	xx(type,print("%t", p->type));
  	xx(sclass,print("%k", p->sclass));
  	switch (p->scope) {
  	case CONSTANTS: xx(scope,print("CONSTANTS")); break;
  	case LABELS:    xx(scope,print("LABELS"));    break;
  	case GLOBAL:    xx(scope,print("GLOBAL"));    break;
  	case PARAM:     xx(scope,print("PARAM"));     break;
  	case LOCAL:     xx(scope,print("LOCAL"));     break;
  	default:
  		if (p->scope > LOCAL)
  			xx(scope,print("LOCAL+%d", p->scope-LOCAL));
  		else
  			xx(scope,print("%d", p->scope));
  	}
  	ITEM;
  	int n = 0;
  	if (!html)
  		print(" ");
  	print("flags=");
  #define yy(f) if (p->f) { if (n++) print("|"); print(#f); }
  	yy(structarg)
  	yy(addressed)
  	yy(computed)
  	yy(temporary)
  	yy(generated)
  #undef yy
  	if (n == 0)
  		print("0");
  	END;
  	if (p->scope >= PARAM && p->sclass != STATIC)
  		xx(offset,print("%d", p->x.offset));
  	xx(ref,print("%f", p->ref));
  	if (p->temporary && p->u.t.cse)
  		xx(u.t.cse,print("%p", p->u.t.cse));
  	END;
  #undef xx
  }
  
  /* address - initialize q for addressing expression p+n */
  static void I(address)(Symbol q, Symbol p, long n) {
  	q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n);
  	(*IR->defsymbol)(q);
  	START; print("address "); emitSymbol(q); END;
  }
  
  /* blockbeg - start a block */
  static void I(blockbeg)(Env *e) {
  	e->offset = off;
  	START; print("blockbeg off=%d", off); END;
  }
  
  /* blockend - start a block */
  static void I(blockend)(Env *e) {
  	if (off > maxoff)
  		maxoff = off;
  	START; print("blockend off=%d", off); END;
  	off = e->offset;
  }
  
  /* defaddress - initialize an address */
  static void I(defaddress)(Symbol p){
  	START; print("defaddress "); emitSymRef(p); END;
  }
  
  /* defconst - define a constant */
  static void I(defconst)(int suffix, int size, Value v) {
  	START;
  	print("defconst ");
  	switch (suffix) {
  	case I:
  		print("int.%d ", size);
  		BEGIN(code);
  		if (size > sizeof (int))
  			print("%D", v.i);
  		else
  			print("%d", (int)v.i);
  		END;
  		break;
  	case U:
  		print("unsigned.%d ", size);
  		BEGIN(code);
  		if (size > sizeof (unsigned))
  			print("%U", v.u);
  		else
  			print("%u", (unsigned)v.u);
  		END;
  		break;
  	case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break;
  	case F:
  		print("float.%d ", size);
  		BEGIN(code);
  			double d = v.d;
  			if (d == 0.0) {
  				static union { int x; char endian; } little = { 1 };
  				signed char *b = (signed char *)&d;
  				if ((!little.endian && b[0] < 0)
  				||   (little.endian && b[sizeof (d)-1] < 0))
  					print("-0.0");
  				else
  					print("0.0");
  			} else
  				print("%g", d);
  		END;
  		break;
  	default: assert(0);
  	}
  	END;
  }
  
  /* defstring - emit a string constant */
  static void I(defstring)(int len, char *s) {
  	START; print("defstring ");
  	BEGIN(code); print("\""); emitString(len, s); print("\""); END;
  	END;
  }
  
  /* defsymbol - define a symbol: initialize p->x */
  static void I(defsymbol)(Symbol p) {
  	if (p->x.name == NULL)
  		p->x.name = stringd(++uid);
  }
  
  /* emit - emit the dags on list p */
  static void I(emit)(Node p){
  	ITEM;
  	if (!html)
  		print(" ");
  	for (; p; p = p->x.next) {
  		if (p->op == LABEL+V) {
  			assert(p->syms[0]);
  			ANCHOR(name,print("%s", p->syms[0]->x.name));
  			BEGIN(code); print("%s", p->syms[0]->name); END;
  			END;
  			print(":");
  		} else {
  			int i;
  			if (p->x.listed) {
  				BEGIN(strong); print("%d", p->x.inst); END; print("'");
  				print(" %s", opname(p->op));
  			} else
  				print("%d. %s", p->x.inst, opname(p->op));
  			if (p->count > 1)
  				print(" count=%d", p->count);
  			for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++)
  				print(" #%d", p->kids[i]->x.inst);
  			if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type)
  				print(" {%t}", p->syms[0]->type);
  			else
  				for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) {
  					print(" ");
  					if (p->syms[i]->scope == CONSTANTS)
  						print(p->syms[i]->name);
  					else
  						emitSymRef(p->syms[i]);
  				}
  		}
  		NEWLINE;
  	}
  	END;
  }
  
  /* export - announce p as exported */
  static void I(export)(Symbol p) {
  	START; print("export "); emitSymRef(p); END;
  }
  
  /* function - generate code for a function */
  static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {
  	int i;
  
  	(*IR->defsymbol)(f);
  	off = 0;
  	for (i = 0; caller[i] && callee[i]; i++) {
  		off = roundup(off, caller[i]->type->align);
  		caller[i]->x.offset = callee[i]->x.offset = off;
  		off += caller[i]->type->size;
  	}
  	if (!html) {
  		print("function ");
  		emitSymbol(f);
  		print(" ncalls=%d\n", ncalls);
  		for (i = 0; caller[i]; i++)
  			START; print("caller "); emitSymbol(caller[i]); END;
  		for (i = 0; callee[i]; i++)
  			START; print("callee "); emitSymbol(callee[i]); END;
  	} else {
  		START;
  		print("function");
  		BEGIN(UL);
  #define xx(field,code) ITEM; print(#field "="); code; END
  		xx(f,emitSymbol(f));
  		xx(ncalls,print("%d", ncalls));
  		if (caller[0]) {
  			ITEM; print("caller"); BEGIN(OL);
  			for (i = 0; caller[i]; i++)
  				ITEM; emitSymbol(caller[i]); END;
  			END; END;
  			ITEM; print("callee"); BEGIN(OL);
  			for (i = 0; callee[i]; i++)
  				ITEM; emitSymbol(callee[i]); END;
  			END; END;
  		} else {
  			xx(caller,BEGIN(em); print("empty"); END);
  			xx(callee,BEGIN(em); print("empty"); END);
  		}
  		END;
  		END;
  	}
  	maxoff = off = 0;
  	gencode(caller, callee);
  	if (html)
  		START; print("emitcode"); BEGIN(ul); emitcode(); END; END;
  	else
  		emitcode();
  	START; print("maxoff=%d", maxoff); END;
  #undef xx
  }
  
  /* visit - generate code for *p */
  static int visit(Node p, int n) {
  	if (p && p->x.inst == 0) {
  		p->x.inst = ++n;
  		n = visit(p->kids[0], n);
  		n = visit(p->kids[1], n);
  		*tail = p;
  		tail = &p->x.next;
  	}
  	return n;
  }
  
  /* gen0 - generate code for the dags on list p */
  static Node I(gen)(Node p) {
  	int n;
  	Node nodelist;
  
  	tail = &nodelist;
  	for (n = 0; p; p = p->link) {
  		switch (generic(p->op)) {	/* check for valid forest */
  		case CALL:
  			assert(IR->wants_dag || p->count == 0);
  			break;
  		case ARG:
  		case ASGN: case JUMP: case LABEL: case RET:
  		case EQ: case GE: case GT: case LE: case LT: case NE:
  			assert(p->count == 0);
  			break;
  		case INDIR:
  			assert(IR->wants_dag && p->count > 0);
  			break;
  		default:
  			assert(0);
  		}
  		check(p);
  		p->x.listed = 1;
  		n = visit(p, n);
  	}
  	*tail = 0;
  	return nodelist;
  }
  
  /* global - announce a global */
  static void I(global)(Symbol p) {
  	START; print("global "); emitSymbol(p); END;
  }
  
  /* import - import a symbol */
  static void I(import)(Symbol p) {
  	START; print("import "); emitSymRef(p); END;
  }
  
  /* local - local variable */
  static void I(local)(Symbol p) {
  	if (p->temporary)
  		p->name = stringf("t%s", p->name);
  	(*IR->defsymbol)(p);
  	off = roundup(off, p->type->align);
  	p->x.offset = off;
  	off += p->type->size;
  	START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END;
  }
  
  /* progbeg - beginning of program */
  static void I(progbeg)(int argc, char *argv[]) {
  	int i;
  
  	for (i = 1; i < argc; i++)
  		if (strcmp(argv[i], "-v") == 0)
  			verbose++;
  		else if (strcmp(argv[i], "-html") == 0)
  			html++;
  	if (html) {
  		print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n");
  		print("<html>");
  		BEGIN(head);
  		if (firstfile && *firstfile)
  			BEGIN(title); emitString(strlen(firstfile), firstfile);	END;
  		print("<link rev=made href=\"mailto:drh@microsoft.com\">\n");
  		END;
  		print("<body>\n");
  		if (firstfile && *firstfile)
  			BEGIN(h1); emitString(strlen(firstfile), firstfile); END;
  		BEGIN(P); BEGIN(em);
  		print("Links lead from uses of identifiers and labels to their definitions.");
  		END; END;
  		print("<ul>\n");
  		START;
  		print("progbeg");
  		BEGIN(ol);
  		for (i = 1; i < argc; i++) {
  			ITEM;
  			BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END;
  			END;
  		}
  		END;
  		END;
  	}
  }
  
  /* progend - end of program */
  static void I(progend)(void) {
  	START; print("progend"); END;
  	if (html) {
  		time_t t;
  		print("</ul>\n");
  		time(&t);
  		print("<hr><address>%s</address>\n", ctime(&t));
  		print("</body></html>\n");
  	}
  }
  
  /* segment - switch to segment s */
  static void I(segment)(int s) {
  	START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END;
  }
  
  /* space - initialize n bytes of space */
  static void I(space)(int n) {
  	START; print("space %d", n); END;
  }
  
  static void I(stabblock)(int brace, int lev, Symbol *p) {}
  
  /* stabend - finalize stab output */
  static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {
  	int i;
  
  	if (p)
  		emitSymRef(p);
  	print("\n");
  	if (cpp && sp)
  		for (i = 0; cpp[i] && sp[i]; i++) {
  			print("%w.%d: ", cpp[i], cpp[i]->x);
  			emitSymRef(sp[i]);
  			print("\n");
  		}
  }
  
  static void I(stabfend)(Symbol p, int lineno) {}
  static void I(stabinit)(char *file, int argc, char *argv[]) {}
  
  /* stabline - emit line number information for source coordinate *cp */
  static void I(stabline)(Coordinate *cp) {
  	if (cp->file)
  		print("%s:", cp->file);
  	print("%d.%d:\n", cp->y, cp->x);
  }
  
  static void I(stabsym)(Symbol p) {}
  static void I(stabtype)(Symbol p) {}
  
  Interface symbolicIR = {
  	{ 1, 1, 0 },	/* char */
  	{ 2, 2, 0 },	/* short */
  	{ 4, 4, 0 },	/* int */
  	{ 4, 4, 0 },	/* long */
  	{ 4, 4, 0 },	/* long long */
  	{ 4, 4, 1 },	/* float */
  	{ 8, 8, 1 },	/* double */
  	{ 8, 8, 1 },	/* long double */
  	{ 4, 4, 0 },	/* T* */
  	{ 0, 4, 0 },	/* struct */
  	0,		/* little_endian */
  	0,		/* mulops_calls */
  	0,		/* wants_callb */
  	1,		/* wants_argb */
  	1,		/* left_to_right */
  	1,		/* wants_dag */
  	0,		/* unsigned_char */
  	I(address),
  	I(blockbeg),
  	I(blockend),
  	I(defaddress),
  	I(defconst),
  	I(defstring),
  	I(defsymbol),
  	I(emit),
  	I(export),
  	I(function),
  	I(gen),
  	I(global),
  	I(import),
  	I(local),
  	I(progbeg),
  	I(progend),
  	I(segment),
  	I(space),
  	I(stabblock),
  	I(stabend),
  	I(stabfend),
  	I(stabinit),
  	I(stabline),
  	I(stabsym),
  	I(stabtype)
  };
  
  Interface symbolic64IR = {
  	{ 1, 1, 0 },	/* char */
  	{ 2, 2, 0 },	/* short */
  	{ 4, 4, 0 },	/* int */
  	{ 8, 8, 0 },	/* long */
  	{ 8, 8, 0 },	/* long long */
  	{ 4, 4, 1 },	/* float */
  	{ 8, 8, 1 },	/* double */
  	{ 8, 8, 1 },	/* long double */
  	{ 8, 8, 0 },	/* T* */
  	{ 0, 1, 0 },	/* struct */
  	1,		/* little_endian */
  	0,		/* mulops_calls */
  	0,		/* wants_callb */
  	1,		/* wants_argb */
  	1,		/* left_to_right */
  	1,		/* wants_dag */
  	0,		/* unsigned_char */
  	I(address),
  	I(blockbeg),
  	I(blockend),
  	I(defaddress),
  	I(defconst),
  	I(defstring),
  	I(defsymbol),
  	I(emit),
  	I(export),
  	I(function),
  	I(gen),
  	I(global),
  	I(import),
  	I(local),
  	I(progbeg),
  	I(progend),
  	I(segment),
  	I(space),
  	I(stabblock),
  	I(stabend),
  	I(stabfend),
  	I(stabinit),
  	I(stabline),
  	I(stabsym),
  	I(stabtype)
  };
  