text: #include <u.h>
  #include <libc.h>
  #include <ctype.h>
  #include <bio.h>
  #include "../kc/k.out.h"
  #include "a.h"
  #include "y.tab.h"
  
  void
  main(int argc, char *argv[])
  {
  	char ofile[100], incfile[20], *p;
  	int nout, nproc, status, i, c, of;
  
  	thechar = 'k';
  	thestring = "sparc";
  	memset(debug, 0, sizeof(debug));
  	cinit();
  	outfile = 0;
  	include[ninclude++] = ".";
  	ARGBEGIN {
  	default:
  		c = ARGC();
  		if(c >= 0 || c < sizeof(debug))
  			debug[c] = 1;
  		break;
  
  	case 'o':
  		outfile = ARGF();
  		break;
  
  	case 'D':
  		p = ARGF();
  		if(p)
  			Dlist[nDlist++] = p;
  		break;
  
  	case 'I':
  		p = ARGF();
  		if(p)
  			include[ninclude++] = p;
  		break;
  	} ARGEND
  	if(*argv == 0) {
  		print("usage: %ca [-options] file.s\n", thechar);
  		errorexit();
  	}
  	nproc = 3;
  	if(p = getenv("NPROC"))
  		nproc = atol(p);
  	if(argc > 1) {
  		c = 0;
  		nout = 0;
  		for(;;) {
  			while(nout < nproc && argc > 0) {
  				i = fork();
  				if(i < 0) {
  					i = mywait(&status);
  					if(i < 0)
  						errorexit();
  					if(status)
  						c++;
  					nout--;
  					continue;
  				}
  				if(i == 0) {
  					print("%s:\n", *argv);
  					goto child;
  				}
  				nout++;
  				argc--;
  				argv++;
  			}
  			i = mywait(&status);
  			if(i < 0) {
  				if(c)
  					errorexit();
  				exits(0);
  			}
  			if(status)
  				c++;
  			nout--;
  		}
  	}
  
  child:
  	strcpy(ofile, *argv);
  	if(p = strrchr(ofile, '/')) {
  		include[0] = ofile;
  		*p++ = 0;
  	} else
  		p = ofile;
  	if(outfile == 0) {
  		outfile = p;
  		if(p = strrchr(outfile, '.'))
  			if(p[1] == 's' && p[2] == 0)
  				p[0] = 0;
  		p = strrchr(outfile, 0);
  		p[0] = '.';
  		p[1] = thechar;
  		p[2] = 0;
  	}
  	if(unix()) {
  		strcpy(incfile, "/usr/%include");
  		p = strrchr(incfile, '%');
  		if(p)
  			*p = thechar;
  	} else {
  		strcpy(incfile, "/");
  		strcat(incfile, thestring);
  		strcat(incfile, "/include");
  	}
  	include[ninclude++] = incfile;
  	if(p = getenv("INCLUDE"))
  		include[ninclude-1] = p;	/* */
  	of = mycreat(outfile, 0664);
  	if(of < 0) {
  		yyerror("%ca: cannot create %s", thechar, outfile);
  		errorexit();
  	}
  	Binit(&obuf, of, OWRITE);
  
  	pass = 1;
  	nosched = 0;
  	pinit(*argv);
  	for(i=0; i<nDlist; i++)
  		dodefine(Dlist[i]);
  	yyparse();
  	if(nerrors) {
  		cclean();
  		errorexit();
  	}
  
  	pass = 2;
  	nosched = 0;
  	outhist();
  	pinit(*argv);
  	for(i=0; i<nDlist; i++)
  		dodefine(Dlist[i]);
  	yyparse();
  	cclean();
  	if(nerrors)
  		errorexit();
  	exits(0);
  }
  
  struct
  {
  	char	*name;
  	ushort	type;
  	ushort	value;
  } itab[] =
  {
  	"SP",		LSP,	D_AUTO,
  	"SB",		LSB,	D_EXTERN,
  	"FP",		LFP,	D_PARAM,
  	"PC",		LPC,	D_BRANCH,
  
  	"FSR",		LFSR,	D_FSR,
  	"CSR",		LFSR,	D_CSR,
  
  	"FQ",		LFPQ,	D_FPQ,
  	"CQ",		LFPQ,	D_CPQ,
  
  	"Y",		LPSR,	D_Y,
  	"PSR",		LPSR,	D_PSR,
  	"WIM",		LPSR,	D_WIM,
  	"TBR",		LPSR,	D_TBR,
  
  	"R",		LR,	0,
  	"R0",		LREG,	0,
  	"R1",		LREG,	1,
  	"R2",		LREG,	2,
  	"R3",		LREG,	3,
  	"R4",		LREG,	4,
  	"R5",		LREG,	5,
  	"R6",		LREG,	6,
  	"R7",		LREG,	7,
  	"R8",		LREG,	8,
  	"R9",		LREG,	9,
  	"R10",		LREG,	10,
  	"R11",		LREG,	11,
  	"R12",		LREG,	12,
  	"R13",		LREG,	13,
  	"R14",		LREG,	14,
  	"R15",		LREG,	15,
  	"R16",		LREG,	16,
  	"R17",		LREG,	17,
  	"R18",		LREG,	18,
  	"R19",		LREG,	19,
  	"R20",		LREG,	20,
  	"R21",		LREG,	21,
  	"R22",		LREG,	22,
  	"R23",		LREG,	23,
  	"R24",		LREG,	24,
  	"R25",		LREG,	25,
  	"R26",		LREG,	26,
  	"R27",		LREG,	27,
  	"R28",		LREG,	28,
  	"R29",		LREG,	29,
  	"R30",		LREG,	30,
  	"R31",		LREG,	31,
  
  	"C",		LC,	0,
  	"C0",		LCREG,	0,
  	"C1",		LCREG,	1,
  	"C2",		LCREG,	2,
  	"C3",		LCREG,	3,
  	"C4",		LCREG,	4,
  	"C5",		LCREG,	5,
  	"C6",		LCREG,	6,
  	"C7",		LCREG,	7,
  	"C8",		LCREG,	8,
  	"C9",		LCREG,	9,
  	"C10",		LCREG,	10,
  	"C11",		LCREG,	11,
  	"C12",		LCREG,	12,
  	"C13",		LCREG,	13,
  	"C14",		LCREG,	14,
  	"C15",		LCREG,	15,
  	"C16",		LCREG,	16,
  	"C17",		LCREG,	17,
  	"C18",		LCREG,	18,
  	"C19",		LCREG,	19,
  	"C20",		LCREG,	20,
  	"C21",		LCREG,	21,
  	"C22",		LCREG,	22,
  	"C23",		LCREG,	23,
  	"C24",		LCREG,	24,
  	"C25",		LCREG,	25,
  	"C26",		LCREG,	26,
  	"C27",		LCREG,	27,
  	"C28",		LCREG,	28,
  	"C29",		LCREG,	29,
  	"C30",		LCREG,	30,
  	"C31",		LCREG,	31,
  
  	"F",		LF,	0,
  	"F0",		LFREG,	0,
  	"F2",		LFREG,	2,
  	"F4",		LFREG,	4,
  	"F6",		LFREG,	6,
  	"F8",		LFREG,	8,
  	"F10",		LFREG,	10,
  	"F12",		LFREG,	12,
  	"F14",		LFREG,	14,
  	"F16",		LFREG,	16,
  	"F18",		LFREG,	18,
  	"F20",		LFREG,	20,
  	"F22",		LFREG,	22,
  	"F24",		LFREG,	24,
  	"F26",		LFREG,	26,
  	"F28",		LFREG,	28,
  	"F30",		LFREG,	30,
  	"F1",		LFREG,	1,
  	"F3",		LFREG,	3,
  	"F5",		LFREG,	5,
  	"F7",		LFREG,	7,
  	"F9",		LFREG,	9,
  	"F11",		LFREG,	11,
  	"F13",		LFREG,	13,
  	"F15",		LFREG,	15,
  	"F17",		LFREG,	17,
  	"F19",		LFREG,	19,
  	"F21",		LFREG,	21,
  	"F23",		LFREG,	23,
  	"F25",		LFREG,	25,
  	"F27",		LFREG,	27,
  	"F29",		LFREG,	29,
  	"F31",		LFREG,	31,
  
  	"ADD",		LADDW, AADD,
  	"ADDCC",	LADDW, AADDCC,
  	"ADDX",		LADDW, AADDX,
  	"ADDXCC",	LADDW, AADDXCC,
  	"AND",		LADDW, AAND,
  	"ANDCC",	LADDW, AANDCC,
  	"ANDN",		LADDW, AANDN,
  	"ANDNCC",	LADDW, AANDNCC,
  	"BA",		LBRA, ABA,
  	"BCC",		LBRA, ABCC,
  	"BCS",		LBRA, ABCS,
  	"BE",		LBRA, ABE,
  	"BG",		LBRA, ABG,
  	"BGE",		LBRA, ABGE,
  	"BGU",		LBRA, ABGU,
  	"BL",		LBRA, ABL,
  	"BLE",		LBRA, ABLE,
  	"BLEU",		LBRA, ABLEU,
  	"BN",		LBRA, ABN,
  	"BNE",		LBRA, ABNE,
  	"BNEG",		LBRA, ABNEG,
  	"BPOS",		LBRA, ABPOS,
  	"BVC",		LBRA, ABVC,
  	"BVS",		LBRA, ABVS,
  	"CB0",		LBRA, ACB0,
  	"CB01",		LBRA, ACB01,
  	"CB012",	LBRA, ACB012,
  	"CB013",	LBRA, ACB013,
  	"CB02",		LBRA, ACB02,
  	"CB023",	LBRA, ACB023,
  	"CB03",		LBRA, ACB03,
  	"CB1",		LBRA, ACB1,
  	"CB12",		LBRA, ACB12,
  	"CB123",	LBRA, ACB123,
  	"CB13",		LBRA, ACB13,
  	"CB2",		LBRA, ACB2,
  	"CB23",		LBRA, ACB23,
  	"CB3",		LBRA, ACB3,
  	"CBA",		LBRA, ACBA,
  	"CBN",		LBRA, ACBN,
  	"CMP",		LCMP, ACMP,
  	"CPOP1",	LCPOP, ACPOP1,
  	"CPOP2",	LCPOP, ACPOP2,
  	"DATA",		LDATA, ADATA,
  	"DIV",		LADDW, ADIV,
  	"DIVL",		LADDW, ADIVL,
  	"END",		LEND, AEND,
  	"FABSD",	LFCONV, AFABSD,
  	"FABSF",	LFCONV, AFABSF,
  	"FABSX",	LFCONV, AFABSX,
  	"FADDD",	LFADD, AFADDD,
  	"FADDF",	LFADD, AFADDF,
  	"FADDX",	LFADD, AFADDX,
  	"FBA",		LBRA, AFBA,
  	"FBE",		LBRA, AFBE,
  	"FBG",		LBRA, AFBG,
  	"FBGE",		LBRA, AFBGE,
  	"FBL",		LBRA, AFBL,
  	"FBLE",		LBRA, AFBLE,
  	"FBLG",		LBRA, AFBLG,
  	"FBN",		LBRA, AFBN,
  	"FBNE",		LBRA, AFBNE,
  	"FBO",		LBRA, AFBO,
  	"FBU",		LBRA, AFBU,
  	"FBUE",		LBRA, AFBUE,
  	"FBUG",		LBRA, AFBUG,
  	"FBUGE",	LBRA, AFBUGE,
  	"FBUL",		LBRA, AFBUL,
  	"FBULE",	LBRA, AFBULE,
  	"FCMPD",	LFADD, AFCMPD,
  	"FCMPED",	LFADD, AFCMPED,
  	"FCMPEF",	LFADD, AFCMPEF,
  	"FCMPEX",	LFADD, AFCMPEX,
  	"FCMPF",	LFADD, AFCMPF,
  	"FCMPX",	LFADD, AFCMPX,
  	"FDIVD",	LFADD, AFDIVD,
  	"FDIVF",	LFADD, AFDIVF,
  	"FDIVX",	LFADD, AFDIVX,
  	"FMOVD",	LFMOV, AFMOVD,
  	"FMOVDF",	LFCONV, AFMOVDF,
  	"FMOVDW",	LFCONV, AFMOVDW,
  	"FMOVDX",	LFCONV, AFMOVDX,
  	"FMOVF",	LFMOV, AFMOVF,
  	"FMOVFD",	LFCONV, AFMOVFD,
  	"FMOVFW",	LFCONV, AFMOVFW,
  	"FMOVFX",	LFCONV, AFMOVFX,
  	"FMOVWD",	LFCONV, AFMOVWD,
  	"FMOVWF",	LFCONV, AFMOVWF,
  	"FMOVWX",	LFCONV, AFMOVWX,
  	"FMOVX",	LFCONV, AFMOVX,
  	"FMOVXD",	LFCONV, AFMOVXD,
  	"FMOVXF",	LFCONV, AFMOVXF,
  	"FMOVXW",	LFCONV, AFMOVXW,
  	"FMULD",	LFADD, AFMULD,
  	"FMULF",	LFADD, AFMULF,
  	"FMULX",	LFADD, AFMULX,
  	"FNEGD",	LFCONV, AFNEGD,
  	"FNEGF",	LFCONV, AFNEGF,
  	"FNEGX",	LFCONV, AFNEGX,
  	"FSQRTD",	LFCONV, AFSQRTD,
  	"FSQRTF",	LFCONV, AFSQRTF,
  	"FSQRTX",	LFCONV, AFSQRTX,
  	"FSUBD",	LFADD, AFSUBD,
  	"FSUBF",	LFADD, AFSUBF,
  	"FSUBX",	LFADD, AFSUBX,
  	"GLOBL",	LTEXT, AGLOBL,
  	"IFLUSH",	LFLUSH, AIFLUSH,
  	"JMPL",		LJMPL, AJMPL,
  	"JMP",		LJMPL, AJMP,
  	"MOD",		LADDW, AMOD,
  	"MODL",		LADDW, AMODL,
  	"MOVB",		LMOVB, AMOVB,
  	"MOVBU",	LMOVB, AMOVBU,
  	"MOVD",		LMOVD, AMOVD,
  	"MOVH",		LMOVB, AMOVH,
  	"MOVHU",	LMOVB, AMOVHU,
  	"MOVW",		LMOVW, AMOVW,
  	"MUL",		LADDW, AMUL,
  	"MULSCC",	LADDW, AMULSCC,
  	"NOP",		LNOP, ANOP,
  	"OR",		LADDW, AOR,
  	"ORCC",		LADDW, AORCC,
  	"ORN",		LADDW, AORN,
  	"ORNCC",	LADDW, AORNCC,
  	"RESTORE",	LADDW, ARESTORE,
  	"RETT",		LRETT, ARETT,
  	"RETURN",	LRETRN, ARETURN,
  	"SAVE",		LADDW, ASAVE,
  	"SLL",		LADDW, ASLL,
  	"SRA",		LADDW, ASRA,
  	"SRL",		LADDW, ASRL,
  	"SUB",		LADDW, ASUB,
  	"SUBCC",	LADDW, ASUBCC,
  	"SUBX",		LADDW, ASUBX,
  	"SUBXCC",	LADDW, ASUBXCC,
  	"SWAP",		LSWAP, ASWAP,
  	"TA",		LTRAP, ATA,
  	"TADDCC",	LADDW, ATADDCC,
  	"TADDCCTV",	LADDW, ATADDCCTV,
  	"TAS",		LSWAP, ATAS,
  	"TCC",		LTRAP, ATCC,
  	"TCS",		LTRAP, ATCS,
  	"TE",		LTRAP, ATE,
  	"TEXT",		LTEXT, ATEXT,
  	"TG",		LTRAP, ATG,
  	"TGE",		LTRAP, ATGE,
  	"TGU",		LTRAP, ATGU,
  	"TL",		LTRAP, ATL,
  	"TLE",		LTRAP, ATLE,
  	"TLEU",		LTRAP, ATLEU,
  	"TN",		LTRAP, ATN,
  	"TNE",		LTRAP, ATNE,
  	"TNEG",		LTRAP, ATNEG,
  	"TPOS",		LTRAP, ATPOS,
  	"TSUBCC",	LADDW, ATSUBCC,
  	"TSUBCCTV",	LADDW, ATSUBCCTV,
  	"TVC",		LTRAP, ATVC,
  	"TVS",		LTRAP, ATVS,
  	"UNIMP",	LUNIMP, AUNIMP,
  	"WORD",		LUNIMP, AWORD,
  	"XNOR",		LADDW, AXNOR,
  	"XNORCC",	LADDW, AXNORCC,
  	"XOR",		LXORW, AXOR,
  	"XORCC",	LADDW, AXORCC,
  
  	"SCHED",	LSCHED, 0,
  	"NOSCHED",	LSCHED, 0x80,
  
  	0
  };
  
  void
  cinit(void)
  {
  	Sym *s;
  	int i;
  
  	nullgen.sym = S;
  	nullgen.offset = 0;
  	nullgen.type = D_NONE;
  	nullgen.name = D_NONE;
  	nullgen.reg = NREG;
  	nullgen.xreg = NREG;
  	if(FPCHIP)
  		nullgen.dval = 0;
  	for(i=0; i<sizeof(nullgen.sval); i++)
  		nullgen.sval[i] = 0;
  
  	nerrors = 0;
  	iostack = I;
  	iofree = I;
  	peekc = IGN;
  	nhunk = 0;
  	for(i=0; i<NHASH; i++)
  		hash[i] = S;
  	for(i=0; itab[i].name; i++) {
  		s = slookup(itab[i].name);
  		s->type = itab[i].type;
  		s->value = itab[i].value;
  	}
  
  	ALLOCN(pathname, 0, 100);
  	if(getwd(pathname, 99) == 0) {
  		ALLOCN(pathname, 100, 900);
  		if(getwd(pathname, 999) == 0)
  			strcpy(pathname, "/???");
  	}
  }
  
  void
  syminit(Sym *s)
  {
  
  	s->type = LNAME;
  	s->value = 0;
  }
  
  void
  cclean(void)
  {
  
  	outcode(AEND, &nullgen, NREG, &nullgen);
  	Bflush(&obuf);
  }
  
  void
  zname(char *n, int t, int s)
  {
  
  	Bputc(&obuf, ANAME);
  	Bputc(&obuf, t);	/* type */
  	Bputc(&obuf, s);	/* sym */
  	while(*n) {
  		Bputc(&obuf, *n);
  		n++;
  	}
  	Bputc(&obuf, 0);
  }
  
  void
  zaddr(Gen *a, int s)
  {
  	long l;
  	int i;
  	char *n;
  	Ieee e;
  
  	Bputc(&obuf, a->type);
  	Bputc(&obuf, a->reg);
  	Bputc(&obuf, s);
  	Bputc(&obuf, a->name);
  	switch(a->type) {
  	default:
  		print("unknown type %d\n", a->type);
  		exits("arg");
  
  	case D_NONE:
  	case D_REG:
  	case D_FREG:
  	case D_CREG:
  	case D_PREG:
  		break;
  
  	case D_OREG:
  	case D_ASI:
  	case D_CONST:
  	case D_BRANCH:
  		l = a->offset;
  		Bputc(&obuf, l);
  		Bputc(&obuf, l>>8);
  		Bputc(&obuf, l>>16);
  		Bputc(&obuf, l>>24);
  		break;
  
  	case D_SCONST:
  		n = a->sval;
  		for(i=0; i<NSNAME; i++) {
  			Bputc(&obuf, *n);
  			n++;
  		}
  		break;
  
  	case D_FCONST:
  		ieeedtod(&e, a->dval);
  		Bputc(&obuf, e.l);
  		Bputc(&obuf, e.l>>8);
  		Bputc(&obuf, e.l>>16);
  		Bputc(&obuf, e.l>>24);
  		Bputc(&obuf, e.h);
  		Bputc(&obuf, e.h>>8);
  		Bputc(&obuf, e.h>>16);
  		Bputc(&obuf, e.h>>24);
  		break;
  	}
  }
  
  void
  outcode(int a, Gen *g1, int reg, Gen *g2)
  {
  	int sf, st, t;
  	Sym *s;
  
  	if(pass == 1)
  		goto out;
  	if(g1->xreg != NREG) {
  		if(reg != NREG || g2->xreg != NREG)
  			yyerror("bad addressing modes");
  		reg = g1->xreg;
  	} else
  	if(g2->xreg != NREG) {
  		if(reg != NREG)
  			yyerror("bad addressing modes");
  		reg = g2->xreg;
  	}
  jackpot:
  	sf = 0;
  	s = g1->sym;
  	while(s != S) {
  		sf = s->sym;
  		if(sf < 0 || sf >= NSYM)
  			sf = 0;
  		t = g1->name;
  		if(h[sf].type == t)
  		if(h[sf].sym == s)
  			break;
  		zname(s->name, t, sym);
  		s->sym = sym;
  		h[sym].sym = s;
  		h[sym].type = t;
  		sf = sym;
  		sym++;
  		if(sym >= NSYM)
  			sym = 1;
  		break;
  	}
  	st = 0;
  	s = g2->sym;
  	while(s != S) {
  		st = s->sym;
  		if(st < 0 || st >= NSYM)
  			st = 0;
  		t = g2->name;
  		if(h[st].type == t)
  		if(h[st].sym == s)
  			break;
  		zname(s->name, t, sym);
  		s->sym = sym;
  		h[sym].sym = s;
  		h[sym].type = t;
  		st = sym;
  		sym++;
  		if(sym >= NSYM)
  			sym = 1;
  		if(st == sf)
  			goto jackpot;
  		break;
  	}
  	Bputc(&obuf, a);
  	Bputc(&obuf, reg|nosched);
  	Bputc(&obuf, lineno);
  	Bputc(&obuf, lineno>>8);
  	Bputc(&obuf, lineno>>16);
  	Bputc(&obuf, lineno>>24);
  	zaddr(g1, sf);
  	zaddr(g2, st);
  
  out:
  	if(a != AGLOBL && a != ADATA)
  		pc++;
  }
  
  void
  outhist(void)
  {
  	Gen g;
  	Hist *h;
  	char *p, *q, *op;
  	int n;
  
  	g = nullgen;
  	for(h = hist; h != H; h = h->link) {
  		p = h->name;
  		op = 0;
  		if(p && p[0] != '/' && h->offset == 0 && pathname && pathname[0] == '/') {
  			op = p;
  			p = pathname;
  		}
  		while(p) {
  			q = strchr(p, '/');
  			if(q) {
  				n = q-p;
  				if(n == 0)
  					n = 1;	/* leading "/" */
  				q++;
  			} else {
  				n = strlen(p);
  				q = 0;
  			}
  			if(n) {
  				Bputc(&obuf, ANAME);
  				Bputc(&obuf, D_FILE);	/* type */
  				Bputc(&obuf, 1);	/* sym */
  				Bputc(&obuf, '<');
  				Bwrite(&obuf, p, n);
  				Bputc(&obuf, 0);
  			}
  			p = q;
  			if(p == 0 && op) {
  				p = op;
  				op = 0;
  			}
  		}
  		g.offset = h->offset;
  
  		Bputc(&obuf, AHISTORY);
  		Bputc(&obuf, 0);
  		Bputc(&obuf, h->line);
  		Bputc(&obuf, h->line>>8);
  		Bputc(&obuf, h->line>>16);
  		Bputc(&obuf, h->line>>24);
  		zaddr(&nullgen, 0);
  		zaddr(&g, 0);
  	}
  }
  
  #include "../cc/lexbody"
  #include "../cc/macbody"
  