// cmd/9a/lex.c from Vita Nuova.
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#define	EXTERN
#include <u.h>
#include <libc.h>
#include "a.h"
#include "y.tab.h"

enum
{
	Plan9	= 1<<0,
	Unix	= 1<<1,
	Windows	= 1<<2,
};

int
systemtype(int sys)
{
#ifdef _WIN32
	return sys&Windows;
#else
	return sys&Plan9;
#endif
}

int
pathchar(void)
{
	return '/';
}

int
Lconv(Fmt *fp)
{
	return linklinefmt(ctxt, fp);
}

void
dodef(char *p)
{
	if(nDlist%8 == 0)
		Dlist = allocn(Dlist, nDlist*sizeof(char *),
			8*sizeof(char *));
	Dlist[nDlist++] = p;
}

LinkArch*       thelinkarch = &linkpower64;

void
usage(void)
{
	print("usage: %ca [options] file.c...\n", thechar);
	flagprint(1);
	errorexit();
}

void
main(int argc, char *argv[])
{
	char *p;

	thechar = '9';
	thestring = "power64";

	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
	// but not other values.	
	p = getgoarch();
	if(strncmp(p, thestring, strlen(thestring)) != 0)
		sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
	if(strcmp(p, "power64le") == 0)
		thelinkarch = &linkpower64le;

	ctxt = linknew(thelinkarch);
	ctxt->diag = yyerror;
	ctxt->bso = &bstdout;
	ctxt->enforce_data_order = 1;
	Binit(&bstdout, 1, OWRITE);
	listinit9();
	fmtinstall('L', Lconv);

	ensuresymb(NSYMB);
	memset(debug, 0, sizeof(debug));
	cinit();
	outfile = 0;
	setinclude(".");

	flagfn1("D", "name[=value]: add #define", dodef);
	flagfn1("I", "dir: add dir to include path", setinclude);
	flagcount("S", "print assembly and machine code", &debug['S']);
	flagcount("m", "debug preprocessor macros", &debug['m']);
	flagstr("o", "file: set output file", &outfile);
	flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);

	flagparse(&argc, &argv, usage);
	ctxt->debugasm = debug['S'];

	if(argc < 1)
		usage();
	if(argc > 1){
		print("can't assemble multiple files\n");
		errorexit();
	}

	if(assemble(argv[0]))
		errorexit();
	Bflush(&bstdout);
	exits(0);
}

int
assemble(char *file)
{
	char *ofile, *p;
	int i, of;

	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
	strcpy(ofile, file);
	p = utfrrune(ofile, pathchar());
	if(p) {
		include[0] = ofile;
		*p++ = 0;
	} else
		p = ofile;
	if(outfile == 0) {
		outfile = p;
		if(outfile){
			p = utfrrune(outfile, '.');
			if(p)
				if(p[1] == 's' && p[2] == 0)
					p[0] = 0;
			p = utfrune(outfile, 0);
			p[0] = '.';
			p[1] = thechar;
			p[2] = 0;
		} else
			outfile = "/dev/null";
	}

	of = create(outfile, OWRITE, 0664);
	if(of < 0) {
		yyerror("%ca: cannot create %s", thechar, outfile);
		errorexit();
	}
	Binit(&obuf, of, OWRITE);
	Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
	Bprint(&obuf, "!\n");

	for(pass = 1; pass <= 2; pass++) {
		nosched = 0;
		pinit(file);
		for(i=0; i<nDlist; i++)
			dodefine(Dlist[i]);
		yyparse();
		cclean();
		if(nerrors)
			return nerrors;
	}

	writeobj(ctxt, &obuf);
	Bflush(&obuf);
	return 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,

	"LR",		LLR,	D_LR,
	"CTR",		LCTR,	D_CTR,

	"XER",		LSPREG,	D_XER,
	"MSR",		LMSR,	D_MSR,
	"FPSCR",	LFPSCR,	D_FPSCR,
	"SPR",		LSPR,	D_SPR,
	"DCR",		LSPR,	D_DCR,

	"CR",		LCR,	0,
	"CR0",		LCREG,	0,
	"CR1",		LCREG,	1,
	"CR2",		LCREG,	2,
	"CR3",		LCREG,	3,
	"CR4",		LCREG,	4,
	"CR5",		LCREG,	5,
	"CR6",		LCREG,	6,
	"CR7",		LCREG,	7,

	"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,

	"F",		LF,	0,
	"F0",		LFREG,	0,
	"F1",		LFREG,	1,
	"F2",		LFREG,	2,
	"F3",		LFREG,	3,
	"F4",		LFREG,	4,
	"F5",		LFREG,	5,
	"F6",		LFREG,	6,
	"F7",		LFREG,	7,
	"F8",		LFREG,	8,
	"F9",		LFREG,	9,
	"F10",		LFREG,	10,
	"F11",		LFREG,	11,
	"F12",		LFREG,	12,
	"F13",		LFREG,	13,
	"F14",		LFREG,	14,
	"F15",		LFREG,	15,
	"F16",		LFREG,	16,
	"F17",		LFREG,	17,
	"F18",		LFREG,	18,
	"F19",		LFREG,	19,
	"F20",		LFREG,	20,
	"F21",		LFREG,	21,
	"F22",		LFREG,	22,
	"F23",		LFREG,	23,
	"F24",		LFREG,	24,
	"F25",		LFREG,	25,
	"F26",		LFREG,	26,
	"F27",		LFREG,	27,
	"F28",		LFREG,	28,
	"F29",		LFREG,	29,
	"F30",		LFREG,	30,
	"F31",		LFREG,	31,

	"CREQV",	LCROP, ACREQV,
	"CRXOR",	LCROP, ACRXOR,
	"CRAND",	LCROP, ACRAND,
	"CROR",		LCROP, ACROR,
	"CRANDN",	LCROP, ACRANDN,
	"CRORN",	LCROP, ACRORN,
	"CRNAND",	LCROP, ACRNAND,
	"CRNOR",	LCROP, ACRNOR,

	"ADD",		LADDW, AADD,
	"ADDV",		LADDW, AADDV,
	"ADDCC",	LADDW, AADDCC,
	"ADDVCC",	LADDW, AADDVCC,
	"ADDC",		LADDW, AADDC,
	"ADDCV",	LADDW, AADDCV,
	"ADDCCC",	LADDW, AADDCCC,
	"ADDCVCC",	LADDW, AADDCVCC,
	"ADDE",		LLOGW, AADDE,
	"ADDEV",	LLOGW, AADDEV,
	"ADDECC",	LLOGW, AADDECC,
	"ADDEVCC",	LLOGW, AADDEVCC,

	"ADDME",	LABS, AADDME,
	"ADDMEV",	LABS, AADDMEV,
	"ADDMECC",	LABS, AADDMECC,
	"ADDMEVCC",	LABS, AADDMEVCC,
	"ADDZE",	LABS, AADDZE,
	"ADDZEV",	LABS, AADDZEV,
	"ADDZECC",	LABS, AADDZECC,
	"ADDZEVCC",	LABS, AADDZEVCC,

	"SUB",		LADDW, ASUB,
	"SUBV",		LADDW, ASUBV,
	"SUBCC",	LADDW, ASUBCC,
	"SUBVCC",	LADDW, ASUBVCC,
	"SUBE",		LLOGW, ASUBE,
	"SUBECC",	LLOGW, ASUBECC,
	"SUBEV",	LLOGW, ASUBEV,
	"SUBEVCC",	LLOGW, ASUBEVCC,
	"SUBC",		LADDW, ASUBC,
	"SUBCCC",	LADDW, ASUBCCC,
	"SUBCV",	LADDW, ASUBCV,
	"SUBCVCC",	LADDW, ASUBCVCC,

	"SUBME",	LABS, ASUBME,
	"SUBMEV",	LABS, ASUBMEV,
	"SUBMECC",	LABS, ASUBMECC,
	"SUBMEVCC",	LABS, ASUBMEVCC,
	"SUBZE",	LABS, ASUBZE,
	"SUBZEV",	LABS, ASUBZEV,
	"SUBZECC",	LABS, ASUBZECC,
	"SUBZEVCC",	LABS, ASUBZEVCC,

	"AND",		LADDW, AAND,
	"ANDCC",	LADDW, AANDCC,	/* includes andil & andiu */
	"ANDN",		LLOGW, AANDN,
	"ANDNCC",	LLOGW, AANDNCC,
	"EQV",		LLOGW, AEQV,
	"EQVCC",	LLOGW, AEQVCC,
	"NAND",		LLOGW, ANAND,
	"NANDCC",	LLOGW, ANANDCC,
	"NOR",		LLOGW, ANOR,
	"NORCC",	LLOGW, ANORCC,
	"OR",		LADDW, AOR,	/* includes oril & oriu */
	"ORCC",		LADDW, AORCC,
	"ORN",		LLOGW, AORN,
	"ORNCC",	LLOGW, AORNCC,
	"XOR",		LADDW, AXOR,	/* includes xoril & xoriu */
	"XORCC",	LLOGW, AXORCC,

	"EXTSB",	LABS,	AEXTSB,
	"EXTSBCC",	LABS,	AEXTSBCC,
	"EXTSH",	LABS, AEXTSH,
	"EXTSHCC",	LABS, AEXTSHCC,

	"CNTLZW",	LABS, ACNTLZW,
	"CNTLZWCC",	LABS, ACNTLZWCC,

	"RLWMI",	LRLWM, ARLWMI,
	"RLWMICC",	LRLWM, ARLWMICC,
	"RLWNM",	LRLWM, ARLWNM,
	"RLWNMCC", LRLWM, ARLWNMCC,

	"SLW",		LSHW, ASLW,
	"SLWCC",	LSHW, ASLWCC,
	"SRW",		LSHW, ASRW,
	"SRWCC",	LSHW, ASRWCC,
	"SRAW",		LSHW, ASRAW,
	"SRAWCC",	LSHW, ASRAWCC,

	"BR",		LBRA, ABR,
	"BC",		LBRA, ABC,
	"BCL",		LBRA, ABC,
	"BL",		LBRA, ABL,
	"BEQ",		LBRA, ABEQ,
	"BNE",		LBRA, ABNE,
	"BGT",		LBRA, ABGT,
	"BGE",		LBRA, ABGE,
	"BLT",		LBRA, ABLT,
	"BLE",		LBRA, ABLE,
	"BVC",		LBRA, ABVC,
	"BVS",		LBRA, ABVS,

	"CMP",		LCMP, ACMP,
	"CMPU",		LCMP, ACMPU,
	"CMPW",		LCMP, ACMPW,
	"CMPWU",	LCMP, ACMPWU,

	"DIVW",		LLOGW, ADIVW,
	"DIVWV",	LLOGW, ADIVWV,
	"DIVWCC",	LLOGW, ADIVWCC,
	"DIVWVCC",	LLOGW, ADIVWVCC,
	"DIVWU",	LLOGW, ADIVWU,
	"DIVWUV",	LLOGW, ADIVWUV,
	"DIVWUCC",	LLOGW, ADIVWUCC,
	"DIVWUVCC",	LLOGW, ADIVWUVCC,

	"FABS",		LFCONV,	AFABS,
	"FABSCC",	LFCONV,	AFABSCC,
	"FNEG",		LFCONV,	AFNEG,
	"FNEGCC",	LFCONV,	AFNEGCC,
	"FNABS",	LFCONV,	AFNABS,
	"FNABSCC",	LFCONV,	AFNABSCC,

	"FADD",		LFADD,	AFADD,
	"FADDCC",	LFADD,	AFADDCC,
	"FSUB",		LFADD,  AFSUB,
	"FSUBCC",	LFADD,	AFSUBCC,
	"FMUL",		LFADD,	AFMUL,
	"FMULCC",	LFADD,	AFMULCC,
	"FDIV",		LFADD,	AFDIV,
	"FDIVCC",	LFADD,	AFDIVCC,
	"FRSP",		LFCONV,	AFRSP,
	"FRSPCC",	LFCONV,	AFRSPCC,
	"FCTIW",	LFCONV,	AFCTIW,
	"FCTIWCC",	LFCONV,	AFCTIWCC,
	"FCTIWZ",	LFCONV,	AFCTIWZ,
	"FCTIWZCC",	LFCONV,	AFCTIWZCC,

	"FMADD",	LFMA, AFMADD,
	"FMADDCC",	LFMA, AFMADDCC,
	"FMSUB",	LFMA, AFMSUB,
	"FMSUBCC",	LFMA, AFMSUBCC,
	"FNMADD",	LFMA, AFNMADD,
	"FNMADDCC",	LFMA, AFNMADDCC,
	"FNMSUB",	LFMA, AFNMSUB,
	"FNMSUBCC",	LFMA, AFNMSUBCC,
	"FMADDS",	LFMA, AFMADDS,
	"FMADDSCC",	LFMA, AFMADDSCC,
	"FMSUBS",	LFMA, AFMSUBS,
	"FMSUBSCC",	LFMA, AFMSUBSCC,
	"FNMADDS",	LFMA, AFNMADDS,
	"FNMADDSCC",	LFMA, AFNMADDSCC,
	"FNMSUBS",	LFMA, AFNMSUBS,
	"FNMSUBSCC",	LFMA, AFNMSUBSCC,

	"FCMPU",	LFCMP, AFCMPU,
	"FCMPO",	LFCMP, AFCMPO,
	"MTFSB0",	LMTFSB, AMTFSB0,
	"MTFSB1",	LMTFSB,	AMTFSB1,

	"FMOVD",	LFMOV, AFMOVD,
	"FMOVS",	LFMOV, AFMOVS,
	"FMOVDCC",	LFCONV,	AFMOVDCC,	/* fmr. */

	"GLOBL",	LTEXT, AGLOBL,

	"MOVB",		LMOVB, AMOVB,
	"MOVBZ",	LMOVB, AMOVBZ,
	"MOVBU",	LMOVB, AMOVBU,
	"MOVBZU", LMOVB, AMOVBZU,
	"MOVH",		LMOVB, AMOVH,
	"MOVHZ",	LMOVB, AMOVHZ,
	"MOVHU",	LMOVB, AMOVHU,
	"MOVHZU", LMOVB, AMOVHZU,
	"MOVHBR", 	LXMV, AMOVHBR,
	"MOVWBR",	LXMV, AMOVWBR,
	"MOVW",		LMOVW, AMOVW,
	"MOVWU",	LMOVW, AMOVWU,
	"MOVMW",	LMOVMW, AMOVMW,
	"MOVFL",	LMOVW,	AMOVFL,

	"MULLW",	LADDW, AMULLW,		/* includes multiply immediate 10-139 */
	"MULLWV",	LLOGW, AMULLWV,
	"MULLWCC",	LLOGW, AMULLWCC,
	"MULLWVCC",	LLOGW, AMULLWVCC,

	"MULHW",	LLOGW, AMULHW,
	"MULHWCC",	LLOGW, AMULHWCC,
	"MULHWU",	LLOGW, AMULHWU,
	"MULHWUCC",	LLOGW, AMULHWUCC,

	"NEG",		LABS, ANEG,
	"NEGV",		LABS, ANEGV,
	"NEGCC",	LABS, ANEGCC,
	"NEGVCC",	LABS, ANEGVCC,

	"NOP",		LNOP, ANOP,	/* ori 0,0,0 */
	"SYSCALL",	LNOP, ASYSCALL,
	"UNDEF",	LNOP, AUNDEF,

	"RETURN",	LRETRN, ARETURN,
	"RFI",		LRETRN,	ARFI,
	"RFCI",		LRETRN,	ARFCI,

	"DATA",		LDATA, ADATA,
	"END",		LEND, AEND,
	"TEXT",		LTEXT, ATEXT,

	/* 64-bit instructions */
	"CNTLZD",	LABS,	ACNTLZD,
	"CNTLZDCC",	LABS,	ACNTLZDCC,
	"DIVD",	LLOGW,	ADIVD,
	"DIVDCC",	LLOGW,	ADIVDCC,
	"DIVDVCC",	LLOGW,	ADIVDVCC,
	"DIVDV",	LLOGW,	ADIVDV,
	"DIVDU",	LLOGW,	ADIVDU,
	"DIVDUCC",	LLOGW,	ADIVDUCC,
	"DIVDUVCC",	LLOGW,	ADIVDUVCC,
	"DIVDUV",	LLOGW,	ADIVDUV,
	"EXTSW",	LABS, AEXTSW,
	"EXTSWCC",	LABS, AEXTSWCC,
	"FCTID",	LFCONV,	AFCTID,
	"FCTIDCC",	LFCONV,	AFCTIDCC,
	"FCTIDZ",	LFCONV,	AFCTIDZ,
	"FCTIDZCC",	LFCONV,	AFCTIDZCC,
	"FCFID",	LFCONV,	AFCFID,
	"FCFIDCC",	LFCONV,	AFCFIDCC,
	"LDAR", LXLD, ALDAR,
	"MOVD",	LMOVW,	AMOVD,
	"MOVDU",	LMOVW,	AMOVDU,
	"MOVWZ",	LMOVW,	AMOVWZ,
	"MOVWZU",	LMOVW,	AMOVWZU,
	"MULHD",	LLOGW,	AMULHD,
	"MULHDCC",	LLOGW,	AMULHDCC,
	"MULHDU",	LLOGW,	AMULHDU,
	"MULHDUCC",	LLOGW,	AMULHDUCC,
	"MULLD",	LADDW,	AMULLD,	/* includes multiply immediate? */
	"MULLDCC",	LLOGW,	AMULLDCC,
	"MULLDVCC",	LLOGW,	AMULLDVCC,
	"MULLDV",	LLOGW,	AMULLDV,
	"RFID",	LRETRN,	ARFID,
	"HRFID", LRETRN, AHRFID,
	"RLDMI",	LRLWM,	ARLDMI,
	"RLDMICC",	LRLWM,	ARLDMICC,
	"RLDC",	LRLWM,	ARLDC,
	"RLDCCC",	LRLWM,	ARLDCCC,
	"RLDCR",	LRLWM,	ARLDCR,
	"RLDCRCC",	LRLWM,	ARLDCRCC,
	"RLDCL",	LRLWM,	ARLDCL,
	"RLDCLCC",	LRLWM,	ARLDCLCC,
	"SLBIA",	LNOP,	ASLBIA,
	"SLBIE",	LNOP,	ASLBIE,
	"SLBMFEE",	LABS,	ASLBMFEE,
	"SLBMFEV",	LABS,	ASLBMFEV,
	"SLBMTE",	LABS,	ASLBMTE,
	"SLD",	LSHW,	ASLD,
	"SLDCC",	LSHW,	ASLDCC,
	"SRD",	LSHW,	ASRD,
	"SRAD",	LSHW,	ASRAD,
	"SRADCC",	LSHW,	ASRADCC,
	"SRDCC",	LSHW,	ASRDCC,
	"STDCCC",	LXST,	ASTDCCC,
	"TD",	LADDW,	ATD,

	/* pseudo instructions */
	"REM",	LLOGW,	AREM,
	"REMCC",	LLOGW,	AREMCC,
	"REMV",	LLOGW,	AREMV,
	"REMVCC",	LLOGW,	AREMVCC,
	"REMU",	LLOGW,	AREMU,
	"REMUCC",	LLOGW,	AREMUCC,
	"REMUV",	LLOGW,	AREMUV,
	"REMUVCC",	LLOGW,	AREMUVCC,
	"REMD",	LLOGW,	AREMD,
	"REMDCC",	LLOGW,	AREMDCC,
	"REMDV",	LLOGW,	AREMDV,
	"REMDVCC",	LLOGW,	AREMDVCC,
	"REMDU",	LLOGW,	AREMDU,
	"REMDUCC",	LLOGW,	AREMDUCC,
	"REMDUV",	LLOGW,	AREMDUV,
	"REMDUVCC",	LLOGW,	AREMDUVCC,

/* special instructions */
	"DCBF",		LXOP,	ADCBF,
	"DCBI",		LXOP,	ADCBI,
	"DCBST",	LXOP,	ADCBST,
	"DCBT",		LXOP,	ADCBT,
	"DCBTST",	LXOP,	ADCBTST,
	"DCBZ",		LXOP,	ADCBZ,
	"ICBI",		LXOP,	AICBI,

	"ECIWX",	LXLD,	AECIWX,
	"ECOWX",	LXST,	AECOWX,
	"LWAR", LXLD, ALWAR,
	"LWAR", LXLD, ALWAR,
	"STWCCC", LXST, ASTWCCC,
	"EIEIO",	LRETRN,	AEIEIO,
	"TLBIE",	LNOP,	ATLBIE,
	"TLBIEL",	LNOP,	ATLBIEL,
	"LSW",	LXLD, ALSW,
	"STSW",	LXST, ASTSW,
	
	"ISYNC",	LRETRN, AISYNC,
	"SYNC",		LRETRN, ASYNC,
	"TLBSYNC",	LRETRN,	ATLBSYNC,
	"PTESYNC",	LRETRN,	APTESYNC,
/*	"TW",		LADDW,	ATW,*/

	"WORD",		LWORD, AWORD,
	"DWORD",	LWORD, ADWORD,
	"SCHED",	LSCHED, 0,
	"NOSCHED",	LSCHED,	0x80,

	"PCDATA",	LPCDAT,	APCDATA,
	"FUNCDATA",	LFUNCDAT,	AFUNCDATA,

	0
};

void
cinit(void)
{
	Sym *s;
	int i;

	nullgen.type = D_NONE;
	nullgen.name = D_NONE;
	nullgen.reg = NREG;
	nullgen.scale = NREG; // replaced Gen.xreg with Prog.scale

	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;
	}
}

void
syminit(Sym *s)
{

	s->type = LNAME;
	s->value = 0;
}

void
cclean(void)
{

	outcode(AEND, &nullgen, NREG, &nullgen);
}

static Prog *lastpc;

void
outcode(int a, Addr *g1, int reg, Addr *g2)
{
	Prog *p;
	Plist *pl;

	if(pass == 1)
		goto out;

	if(g1->scale != NREG) {
		if(reg != NREG || g2->scale != NREG)
			yyerror("bad addressing modes");
		reg = g1->scale;
	} else
	if(g2->scale != NREG) {
		if(reg != NREG)
			yyerror("bad addressing modes");
		reg = g2->scale;
	}

	p = ctxt->arch->prg();
	p->as = a;
	p->lineno = lineno;
	if(nosched)
		p->mark |= NOSCHED;
	p->from = *g1;
	p->reg = reg;
	p->to = *g2;
	p->pc = pc;

	if(lastpc == nil) {
		pl = linknewplist(ctxt);
		pl->firstpc = p;
	} else
		lastpc->link = p;
	lastpc = p;
out:
	if(a != AGLOBL && a != ADATA)
		pc++;
}

void
outgcode(int a, Addr *g1, int reg, Addr *g2, Addr *g3)
{
	Prog *p;
	Plist *pl;

	if(pass == 1)
		goto out;

	p = ctxt->arch->prg();
	p->as = a;
	p->lineno = lineno;
	if(nosched)
		p->mark |= NOSCHED;
	p->from = *g1;
	p->reg = reg;
	p->to = *g2;
	p->from3 = *g3;
	p->pc = pc;
	print("oc: %P\n", p);

	if(lastpc == nil) {
		pl = linknewplist(ctxt);
		pl->firstpc = p;
	} else
		lastpc->link = p;
	lastpc = p;
out:
	if(a != AGLOBL && a != ADATA)
		pc++;
}

#include "../cc/lexbody"
#include "../cc/macbody"
