/* variables globales */

# define MAXPAR 100
# include <stdio.h>
# define strend(s) ( (s) + strlen(s) )
		/* massive kludjj for kludjy motorola & jerome  */
#define hexdigit(c) ( (c>='0' && c<='9') || (c>='A' && c<='F') )

struct stligne
{
	char	*etiquette;
	char	*codop;
	char	*comment;
	int	nparam;
	char	*paramv [MAXPAR];
};

/* special directives */
int xop(), xalign(), dcop(), dsop(), equop(), multop(), sectop();
int condop(), errop(), arg1op(), dcbop(), bclrop();

struct descripm
{
	char	*nom;
	int	(*func)();

} pmac[] = {
	"xref", xop,
	"xdef", xop,
	"align", xalign,
	"dc.b", dcop,
	"dc.w", dcop,
	"dc.l", dcop,
	"ds.b", dsop,
	"ds.w", dsop,
	"ds.l", dsop,
	"equ",	equop,
	"set",	equop,
	"movem", multop,
	"movem.l", multop,
	"movem.w", multop,
	"section", sectop,
	"idnt",	NULL,
	"list", NULL,
	"nolist", NULL,
	"nol", NULL,
	"opt", NULL,
	"format", NULL,
	"page", NULL,
	"org", errop,
	"org.l", errop,
	"rorg", errop,
	"mexit", errop,
	"spc", NULL,
	"noobj", NULL,
	"fail", errop,
	"nopage", NULL,
	"ttl", NULL,
	"end", NULL,
	"ifeq", errop,
	"ifne", errop,
	"rts", arg1op,
	"nop", arg1op,
	"dcb.b", dcbop,
	"dcb.w", dcbop,
	"dcb.l", dcbop,
	"bclr.b", bclrop,
	"bclr.l", bclrop,
	"bset.b", bclrop,
	"bset.l", bclrop,
	"btst.b", bclrop,
	"btst.l", bclrop,
	NULL
};

struct stligne tchamp ;
char ligne [2048], copie [2048];
char *ptc, *pts;
int lnno;

char *readln(), *champ();
struct descripm *isspcl();


/* programme principal */
main ()
{
	int i;
	struct descripm *macp;

	while( readln() ) {
		if ((*ligne == ';') || (*ligne == '\n')) { 
			/* whole line is a comment */
			/* printf("|%s", ligne+1); */
			continue;
		}
		if ( (macp = isspcl ()) != NULL) {
			if (macp->func)
				(*macp->func)();
			else { /* null pseudo op -- echo as comment */
				/* printf("|%s", ligne); */
				continue;
			}
		}
		else {
			label();
			if (*tchamp.codop)
				outop(tchamp.codop);
			printargs();
		}
		if(*tchamp.comment!='\n')
	/*		printf("\t\t|\t%s", tchamp.comment);    */
			printf("\n");
		else
			printf("\n");
	}
}


/*  lit une ligne et la decompose en champs */
char *readln ()
{	register i, brac;
	register char *pit, c;
	/* lit une ligne d'un fichier */

	if (fgets (ligne, sizeof ligne, stdin) == NULL) return (NULL);

	lnno++;
	if (ligne[0]==';')
		return (ligne);
	ptc = ligne;
	pts = copie;
	tchamp.etiquette = champ ();
	tchamp.codop = champ ();
	pit = champ ();
	tchamp.comment = ptc;
	tchamp.nparam = *pit != '';
	for (i = 0; i < MAXPAR; i++) /* remplacer les , par des  */
	{
		tchamp.paramv[i] = pit;
		brac = 0;
		while (c = *pit) {
			switch (c) {
			case ',':
				if (!brac)
					goto out;
				break;
			case '(':
				brac++; break;
			case ')':
				brac--; break;
			}
			pit++;
		}
	out:
		if (c == ',') {
			*pit++ = '';
			tchamp.nparam++;
		}
	}
	return (ligne);
}

char *champ ()
{
	char c, *ptd = pts;
	while (*ptc != '\n')
	{
		if (*ptc == '\t' || *ptc == ' ')
		{
			/* remplacer les blancs et les tabulation
			   par des 0 */
			*pts++ = '';
			while (*++ptc == ' ' || *ptc == '\t')
				;
			return (ptd);
		}
		if ((c = *ptc++) == '\"') {
			*pts++ = '\"';
			while ( (c = getquote()) )
				*pts++ = c;
			*pts++ = '\"';
		} else {
			if (c=='$' && hexdigit(*ptc) ) {
				*pts++ = '0';
				*pts++ = 'x';
			} else {
				if (c>='A' && c<='Z')
					c += 'a' - 'A';
				*pts++ = c;
			}
		}
	}
	*pts++ = '';
	return (ptd);
}

getquote()
{
	char c;
	if ((c = *ptc++) == '\"') {
		if( *ptc=='\"' ) {
			ptc++;
			return (c);
		}
		return(NULL);
	}
	if (!c || c=='\n') {
		werr("newline or EOF in string");
		return(NULL);
	}
	return(c);
}

/* fonction recherchant le nom d'une macro dans le descrip. des macros */
struct descripm *isspcl ()
{
	struct descripm *macp;
	for (macp = pmac; macp->nom; macp++) {
		if (strcmp (tchamp.codop, macp->nom) == 0)
			return (macp);

	}
	return (NULL);
}

char *defops[] =
{
	"add", "addx", "and", "asl", "asr", "cmp", "clr", "ext", "lsl",
	"lsl", "move", "neg", "negx", "not", "or", "rol", "ror", "roxl",
	"roxr", "sub", "subq", "tst",
	"addq", "subx",
	NULL
};
outop(op)
register char *op;
{
	register char **opp;
	putchar('\t');
	opp = defops;
	while( *opp )
		if (strcmp(*(opp++), op)==0) {
			printf("%sw", strcmp(op, "move") ?op : "mov");
			return;
		}
	if (strncmp(op, "moveq", 5) == 0)
		printf("moveq");
	else if (strncmp(op, "move", 4) == 0)
		printf("mov");
	     else
		begop(op);
	restop(op);
}


substarg(arg)
register char *arg;
{
	/* first off, find the index register */
	register char *areg, *dreg, *offs, *offe, disp, incrdecr;
	char *end, isize;
	register brac;

	incrdecr = 0;
	end = strend(arg) - 1;
	areg = dreg = 0;
	disp = 0; isize = 0;
	if (*end == '+') {
		incrdecr = '+';
		end--;
	}
	if (arg[0] == '-' && arg[1] == '(') 
		incrdecr = '-';
	if( end>=arg && *end == ')') {
		brac = 1;
		while( brac && --end >= arg ) {
			if (*end == '(')
				brac--;
			else if (*end == ')')
				brac++;
		}
		offs = arg;
		offe = end;
		areg = end + 1;
		if (areg[2] == ',')  {
			dreg = areg + 3;
			if (areg[2+3] == '.')
				disp = areg[3+3];
			        if (areg[7] == '*')
					isize = areg[8];
		}
	} else {
		outoff(arg, strend(arg));
		return;
	}
	printf("%c%c\@", areg[0], areg[1]);
	if (incrdecr)
		putchar(incrdecr);
	else if (offs!=offe || dreg) {
		putchar('(');
		if (offs==offe)
			putchar('0');
		else
			outoff(offs, offe);
		if( dreg )
			printf(",%c%c", dreg[0], dreg[1]);
		if( disp )
			printf(":%c", disp);
		if ( isize )
			printf (":%c", isize);
		putchar(')');
	}
}

outoff(offs, offe)
register char *offs, *offe;
{
	register char c;
	register inquote = 0;
	int state;
	state = 0;
	while (offs<offe) {
		if ((c = *offs++) == '\'')
			inquote = !inquote;
		if (c=='*' && state==0)
			putchar('.');
		else
			putchar(c);
		state = alphanum(c);
	}
}

alphanum(c)
{
	if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' & c<='9') )
		return(1);
	return(0);
}

struct reg
{
	char	*rname;
	int	rno;
} regnames[] = {
	"d0", 0,
	"d1", 1,
	"d2", 2,
	"d3", 3,
	"d4", 4,
	"d5", 5,
	"d6", 6,
	"d7", 7,
	"a0", 8,
	"a1", 9,
	"a2", 10,
	"a3", 11,
	"a4", 12,
	"a5", 13,
	"a6", 14,
	"sp", 15,
	"a7", 15,
	"pc", -1,
	NULL
} ;

isreg(s)
{
	register struct reg *rp;
	for (rp=regnames; rp->rname; rp++)
		if (strncmp(rp->rname, s, 2) == 0)
			return(rp->rno);
	return(-1);
}


sectop()
{
	label();
	if( !strcmp(tchamp.paramv[0], "10") || !strcmp(tchamp.paramv[0],"9"))
		printf("\t.text");
	else if (strcmp(tchamp.paramv[0], "15") == 0)
		printf("\t.data");
	else if ( strcmp(tchamp.paramv[0], "14") == 0)
		printf("\t.bss");
	else
		werr("bad argument to section directive");
}

equop()
{
	printf("%s = ", tchamp.etiquette);
	substarg(tchamp.paramv[0]);
}

xop()
{
	printf("\t.globl");
	printargs();
}

xalign()
{
	printf("\t.align");
	printargs();
}

dcop()
{
	register i;
	label();
	for (i=0; i<tchamp.nparam; i++) {
		if (*tchamp.paramv[i] == '\"') {
			strop(tchamp.paramv[i]);
		} else {
			switch(tchamp.codop[3]) { /* DC.[BWD] */
			case 'b':
				printf("\t.byte\t");
				break;
			case 'l':
				printf("\t.long\t");
				break;
			case 'w':
			default:
				printf("\t.word\t");
				break;
			}
			substarg(tchamp.paramv[i]);
			if (i < (tchamp.nparam -1)) {putchar('\n');}
		}
	}
}

dcbop()
{
	register char *w, *init;
	register count;
	label();
	switch(tchamp.codop[4]) {
	case 'b':
		w = ".byte"; break;
	case 'l':
		w = ".long"; break;
	default: case 'w':
		w = ".word"; break;
	}
	init = tchamp.nparam<2 ? "0" : tchamp.paramv[1];
	if (!strcmp(init, "0") && tchamp.codop[3]=='l')
		printf("\t.zerol\t%s\n", tchamp.paramv[0]);
	count = atoi(tchamp.paramv[0]);
	while(count-- >0)
		printf("\t%s\t%s\n", w, init);
}


strop(s)
register char *s;
{
	register char *start, *end, c;
	align(tchamp.codop[3]);
	printf("\t.ascii\t");
	start = s + 1;
	end = strend(start) - 1;
	putchar('"');
	while (start < end) {
		if ( (c = *start++) == '"' || c == '\\' )
			putchar('\\');
		putchar(c);
	}
	printf("\"\n");
	align(tchamp.codop[3]);
}

dsop()
{
	label();
	align(tchamp.codop[3]);
	printf(". = ");
	switch(tchamp.codop[3]) {
	default:
	case 'b': printf("1"); break;
	case 'w': printf("2"); break;
	case 'l': printf("4"); break;
	}
	printf("*");
	substarg(tchamp.paramv[0]);
	printf(" + .");
}

multop()
{
	unsigned short mask, flipbits(), multbits();
	register regs, mem;
	label();
	if (strcmp(tchamp.codop, "movem.l")==0)
		printf("\tmoveml");
	else
		printf("\tmovemw");
	printf("\t");
	regs = isreg(tchamp.paramv[1]) >= 0;
	mem = !regs;
	mask = multbits(tchamp.paramv[regs]);
	if (tchamp.paramv[mem][0] == '-' )
		mask = flipbits(mask);
	if (regs==0)
		printf("#0x%04x", mask);
	else
		substarg(tchamp.paramv[0]);
	putchar(',');
	if (regs==0)
		substarg(tchamp.paramv[1]);
	else
		printf("#0x%04x", mask);
}

unsigned short  multbits(s)
register char *s;
{
	register unsigned short mask;
	register rn, r2n;
	int temp;

	mask = 0;
	while ((rn = isreg(s)) >= 0) {
		if (s[2]=='-') {
			if ((r2n = isreg(s+=3)) < 0)
				break;
			if (r2n<rn ) {
				temp =rn;
				rn = r2n;
				r2n = temp;
			}
			mask |= ((1<<(r2n+1)) - 1) - ((1<<rn) - 1);
		} else
			mask |= 1 << rn;
		if ( *(s+=2) != '/' )
			break;
		s++;
	}
	return(mask);
}

unsigned short flipbits(word)
{
	register unsigned short test, rev, val;
	val = 0;
	for(test=1, rev=0x8000; rev; test<<=1, rev >>= 1)
		if (word&test)
			val |= rev;
	return (val);
}



errop()
{
	char s[80];
	sprintf(s, "unknown directive %s", tchamp.codop);
	werr(s);
}

werr(s)
char *s;
{
	fprintf(stderr, "motmit: line %d: %s\n", lnno, s);
}


begop(op)
register char *op;
{
	register char c;
	while ( (c = *op++) && c!='.' )
		putchar(c);
}

restop(op)
register char *op;
{
	register char c;
	while ( (c = *op++) && c!='.' )
		;
	if (c)
		while( c = *op++ )
			putchar(c);
}

align(c)
{
	if (c != 'b')
		printf("\t.even\n");
}

printargs()
{
	register i;
	if (tchamp.nparam==0)
		return;
	putchar('\t');
	for(i=0; i<tchamp.nparam; i++) {
		substarg(tchamp.paramv[i]);
		if(i<tchamp.nparam-1)
			printf(",");
	}
}

label()
{
	if (*tchamp.etiquette)
		printf("%s:", tchamp.etiquette);
}


arg1op()
{
	label();
	putchar('\t');
	printf("%s", tchamp.codop);
}

bclrop()
{
	label();
	putchar('\t');
	begop(tchamp.codop);
	printargs();
}