#define RCSID4 "$Header$"

/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 *
 */

operation
	:
		prefix oper		
			{	address_long = 1; operand_long = 1; }
	|	prefix1		/* to allow for only prefixes on a line */
	;
prefix	:	/* empty */
	|	prefix1
	;
prefix1:	prefix PREFIX
			{	if ($2 == 0146) operand_long = ! operand_long;
				if ($2 == 0147) address_long = ! address_long;
				emit1($2);
			}
	;
oper	:	NOOP_1
			{	emit1($1);}
	|	NOOP_2
			{	emit2($1);}
	|	JOP expr
			{	branch($1,$2);}
	|	JOP2 expr
			{	ebranch($1,$2);}
	|	PUSHOP ea_1
			{	pushop($1);}
	|	IOOP absexp
			{	emit1($1);
				fit(ufitb($2));
				emit1((int)$2);
			}
	|	IOOP R32
			{	if ($2!=2) serror("register error");
				emit1($1+010);
			}
	|	BITTEST ea_ea
			{	bittestop($1);}
	|	BOUND R32 ',' mem
			{	emit1($1); ea_2($2<<3); }
	|	ADDOP ea_ea
			{	addop($1);}
	|	ROLOP ea_ea
			{	rolop($1);}
	|	INCOP ea_1
			{	incop($1);}
	|	NOTOP ea_1
			{	regsize($1); emit1(0366|($1&1)); ea_1($1&070);}
	|	CALLOP ea_1
			{	callop($1&0xFFFF);}
	|	CALFOP expr ':' expr
			{	emit1($1>>8);
#ifdef RELOCATION
				newrelo($4.typ, RELO4);
#endif
				emit4((long)($4.val));
#ifdef RELOCATION
				newrelo($2.typ, RELO2);
#endif
				emit2((int)($2.val));
			}
	|	CALFOP mem
			{	emit1(0377); ea_2($1&0xFF);}
	|	ENTER absexp ',' absexp
			{	fit(fitw($2)); fit(fitb($4));
				emit1($1); emit2((int)$2); emit1((int)$4);
			}
	|	LEAOP R32 ',' mem
			{	emit1($1); ea_2($2<<3);}
	|	LEAOP2 R32 ',' mem
			{	emit1(0xF); emit1($1); ea_2($2<<3);}
	|	LSHFT	ea_1 ',' R32 ',' ea_2
			{	extshft($1, $4);}
	|	EXTEND R32 ',' ea_2
			{	emit1(0xF); emit1($1|1); ea_2($2<<3);}
	|	EXTOP R32 ',' ea_2
			{	emit1(0xF); emit1($1); ea_2($2<<3);}
	|	EXTOP1 ea_1
			{	emit1(0xF); emit1($1&07); ea_1($1&070);}
	|	IMULB	ea_1
			{	regsize(0); emit1(0366); ea_1($1&070);}
	|	IMUL	ea_2
			{	reg_1 = IS_R32; imul(0); }
	|	IMUL	R32 ',' ea_2
			{	reg_1 = $2 | IS_R32; imul($2); }
	|	IMUL	R32 ',' ea_ea
			{	imul($2);}
	|	INT absexp
			{	if ($2==3)
					emit1(0314);
				else {
					fit(ufitb($2));
					emit1(0315); emit1((int)$2);
				}
			}
	|	RET
			{	emit1($1);}
	|	RET expr
			{	emit1($1-1);
#ifdef RELOCATION
				newrelo($2.typ, RELO2);
#endif
				emit2((int)($2.val));
			}
	|	SETCC ea_2
			{	emit1(0xF); emit1($1); ea_2(0);}
	|	XCHG ea_ea
			{	xchg($1);}
	|	TEST ea_ea
			{	test($1);}
	|	MOV ea_ea
			{	mov($1);}
	|	/*	What is really needed is just
			MOV R32 ',' RSYSCR
			but this gives a bad yacc conflict
		*/
		MOV ea_1 ',' RSYSCR
			{	
				if ($1 != 1 || !(reg_1 & IS_R32))
					serror("syntax error");
				emit1(0xF); emit1(042); emit1(0200|($4<<3)|(reg_1&07));}
	|	MOV ea_1 ',' RSYSDR
			{	
				if ($1 != 1 || !(reg_1 & IS_R32))
					serror("syntax error");
				emit1(0xF); emit1(043); emit1(0200|($4<<3)|(reg_1&07));}
	|	MOV ea_1 ',' RSYSTR
			{	
				if ($1 != 1 || !(reg_1 & IS_R32))
					serror("syntax error");
				emit1(0xF); emit1(046); emit1(0200|($4<<3)|(reg_1&07));}
	|	MOV RSYSCR ',' R32
			{	
				if ($1 != 1) serror("syntax error");
				emit1(0xF); emit1(040); emit1(0200|($4<<3)|$2);}
	|	MOV RSYSDR ',' R32
			{	
				if ($1 != 1) serror("syntax error");
				emit1(0xF); emit1(041); emit1(0200|($4<<3)|$2);}
	|	MOV RSYSTR ',' R32
			{	
				if ($1 != 1) serror("syntax error");
				emit1(0xF); emit1(044); emit1(0200|($4<<3)|$2);}
	;
mem	:	'(' expr ')'
			{	rm_2 = 05; exp_2 = $2; reg_2 = 05; mod_2 = 0;
				RELOMOVE(rel_2, relonami);
			}
	|	bases
			{	exp_2.val = 0; exp_2.typ = S_ABS; indexed();}
	|	expr bases
			{	exp_2 = $1; indexed();
				RELOMOVE(rel_2, relonami);
			}
	;
bases	:	'(' R32 ')'
			{	reg_2 = $2; sib_2 = 0; rm_2 = 0;}
	|	'(' R32 ')' '(' R32 scale ')'
			{	rm_2 = 04; sib_2 |= regindex_ind[$2][$5];
				reg_2 = $2;
			}
	|	'(' R32 '*' absexp ')'
			{	if ($4 == 1) {
					reg_2 = $2; sib_2 = 0; rm_2 = 0;
				}
				else {
					rm_2 = 04;
					sib_2 = checkscale($4) | regindex_ind[05][$2];
					reg_2 = 015;
				}
			}
	;
scale	:	/* empty */
			{	sib_2 = 0;}
	|	'*' absexp
			{	sib_2 = checkscale($2);}
	;
ea_2	:	mem
	|	R8
			{	reg_2 = $1 | IS_R8; rm_2 = 0;}
	|	R32
			{	reg_2 = $1 | IS_R32; rm_2 = 0;}
	|	RSEG
			{	reg_2 = $1 | IS_RSEG; rm_2 = 0;}
	|	expr
			{	reg_2 = IS_EXPR; exp_2 = $1; rm_2 = 0;
				RELOMOVE(rel_2, relonami);
			}
	;
ea_1	:	ea_2
			{	op_1 = op_2;
				RELOMOVE(rel_1, rel_2);
			}
	;
ea_ea	:	ea_1 ',' ea_2
	;