Esempio n. 1
0
static expression_t *gnu_get_oplist(asm86_t * a, int *pn, int deref)
/* Get a comma (or colon for jmpf and callf) separated list of instruction
 * operands.
 */
{
	expression_t *e, *o1, *o2;
	token_t *t;
	int sreg;

	if ((e= gnu_get_operand(a, pn, deref)) == nil) return nil;

	t = get_token(*pn);
	
	if (t->symbol == ':' && IS_REGSEG(sreg = isregister(e->name))) {
		a->seg = segreg2seg(sreg);
		del_expr(e);
		(*pn)++;
		e = gnu_get_oplist(a, pn, deref);
	}
	else if (t->symbol == ',' || t->symbol == ':') {
		o1= e;
		(*pn)++;
		if ((o2= gnu_get_oplist(a, pn, deref)) == nil) {
			del_expr(o1);
			return nil;
		}
		e= new_expr();
		e->operator= ',';
		e->left= o2;
		e->right= o1;
	}
	return e;
}
Esempio n. 2
0
void del_expr(expression_t *e)
/* Delete an expression tree. */
{
	if (e != nil) {
		assert(e->magic == 31624);
		e->magic= 0;
		deallocate(e->name);
		del_expr(e->left);
		del_expr(e->middle);
		del_expr(e->right);
		deallocate(e);
	}
}
Esempio n. 3
0
static void
unary_float(expr_t *expr, expr_t *uexp)
{
    int		iexp;
    long	ival;
    double	dval = uexp->data._unary.d;

    switch (expr->token) {
	case tok_plus:	iexp = 0;			break;
	case tok_neg:	iexp = 0; dval = -dval;		break;
	case tok_not:	iexp = 1; ival = !dval;		break;
	case tok_com:	error(expr, "not an integer");
	default:	error(expr, "internal error");
    }

    del_expr(uexp);
    if (iexp) {
	expr->data._unary.i = ival;
	expr->token = tok_int;
    }
    else {
	expr->data._unary.d = dval;
	expr->token = tok_float;
    }
}
Esempio n. 4
0
static void
unary_sizeof(expr_t *expr)
{
    tag_t	*tag;
    int		 size;
    expr_t	*uexp;

    eval(expr->data._unary.expr);
    uexp = expr->data._unary.expr;
    switch (uexp->token) {
	case tok_type:
	    tag = uexp->data._unary.vp;
	    size = tag->size;
	    break;
	case tok_int:
	    size = sizeof(int);
	    break;
	case tok_float:
	    size = sizeof(double);
	    break;
	case tok_string:
	    size = strlen(uexp->data._unary.cp) + 1;
	    break;
	default:
	    tag = eval_type(uexp);
	    size = tag->size;
	    break;
    }
    del_expr(uexp);
    expr->token = tok_int;
    expr->data._unary.i = size;
}
Esempio n. 5
0
static void
binary_int(expr_t *expr, expr_t *lexp, expr_t *rexp)
{
    long	lval = lexp->data._unary.i;
    long	rval = rexp->data._unary.i;

    switch (expr->token) {
	case tok_andand:	lval = lval && rval;	break;
	case tok_oror:		lval = lval || rval;	break;
	case tok_lt:		lval = lval <  rval;	break;
	case tok_le:		lval = lval <= rval;	break;
	case tok_eq:		lval = lval == rval;	break;
	case tok_ge:		lval = lval >= rval;	break;
	case tok_gt:		lval = lval >  rval;	break;
	case tok_ne:		lval = lval != rval;	break;
	case tok_and:		lval = lval &  rval;	break;
	case tok_or:		lval = lval |  rval;	break;
	case tok_xor:		lval = lval ^  rval;	break;
	case tok_lsh:		lval = lval << rval;	break;
	case tok_rsh:		lval = lval >> rval;	break;
	case tok_add:		lval = lval +  rval;	break;
	case tok_sub:		lval = lval -  rval;	break;
	case tok_mul:		lval = lval *  rval;	break;
	case tok_div:
	    if (rval == 0) {
		warn(expr, "divide by zero");
		return;
	    }
	    lval = lval / rval;
	    break;
	case tok_rem:
	    if (rval == 0) {
		warn(expr, "divide by zero");
		return;
	    }
	    lval = lval % rval;
	    break;
	default:
	    error(expr, "internal error");
    }

    del_expr(lexp);
    del_expr(rexp);
    expr->data._unary.i = lval;
    expr->token = tok_int;
}
Esempio n. 6
0
void
discard(void)
{
    expr_t	*expr = pop_expr();

    if (expr)
        del_expr(expr);
}
Esempio n. 7
0
static void
binary_float(expr_t *expr, expr_t *lexp, expr_t *rexp)
{
    int		iexp;
    long	ival;
    double	lval = lexp->data._unary.d;
    double	rval = rexp->data._unary.d;

    switch (expr->token) {
	case tok_andand:	iexp = 1; ival = lval && rval;	break;
	case tok_oror:		iexp = 1; ival = lval || rval;	break;
	case tok_lt:		iexp = 1; ival = lval <  rval;	break;
	case tok_le:		iexp = 1; ival = lval <= rval;	break;
	case tok_eq:		iexp = 1; ival = lval == rval;	break;
	case tok_ge:		iexp = 1; ival = lval >= rval;	break;
	case tok_gt:		iexp = 1; ival = lval >  rval;	break;
	case tok_ne:		iexp = 1; ival = lval != rval;	break;
	case tok_and:		case tok_or:		case tok_xor:
	case tok_lsh:		case tok_rsh:		case tok_rem:
	    error(expr, "not an integer");
	case tok_add:		iexp = 0; lval = lval +  rval;	break;
	case tok_sub:		iexp = 0; lval = lval -  rval;	break;
	case tok_mul:		iexp = 0; lval = lval *  rval;	break;
	case tok_div:
	    if (rval == 0.0) {
		warn(expr, "divide by zero");
		return;
	    }
	    lval = lval / rval;
	    break;
	default:
	    error(expr, "internal error");
    }

    del_expr(expr->data._binary.lvalue);
    del_expr(expr->data._binary.rvalue);
    if (iexp) {
	expr->data._unary.i = ival;
	expr->token = tok_int;
    }
    else {
	expr->data._unary.d = lval;
	expr->token = tok_float;
    }
}
Esempio n. 8
0
void del_asm86(asm86_t *a)
/* Delete an 80X86 instruction. */
{
	assert(a != nil);
	assert(a->magic == 37937);
	a->magic= 0;
	del_expr(a->args);
	deallocate(a);
}
Esempio n. 9
0
void
consume(void)
{
    if (ahead) {
        del_expr(ahead);
        ahead = NULL;
    }
    else
        error(NULL, "internal error");
}
Esempio n. 10
0
void
del_stat(expr_t *expr)
{
    expr_t	*next;

    while (expr) {
	next = expr->next;
	del_expr(expr);
	expr = next;
    }
}
Esempio n. 11
0
static void
unary_int(expr_t *expr, expr_t *uexp)
{
    long	uval = uexp->data._unary.i;

    switch (expr->token) {
	case tok_plus:					break;
	case tok_neg:		uval = -uval;		break;
	case tok_not:		uval = !uval;		break;
	case tok_com:		uval = ~uval;		break;
	default:	error(expr, "internal error");
    }

    del_expr(uexp);
    expr->data._unary.i = uval;
    expr->token = tok_int;
}
Esempio n. 12
0
static expression_t *ack_get_oplist(int *pn, int deref)
/* Get a comma (or colon for jmpf and callf) separated list of instruction
 * operands.
 */
{
	expression_t *e, *o1, *o2;
	token_t *t;

	if ((e= ack_get_operand(pn, deref)) == nil) return nil;

	if ((t= get_token(*pn))->symbol == ',' || t->symbol == ':') {
		o1= e;
		(*pn)++;
		if ((o2= ack_get_oplist(pn, deref)) == nil) {
			del_expr(o1);
			return nil;
		}
		e= new_expr();
		e->operator= ',';
		e->left= o1;
		e->right= o2;
	}
	return e;
}
Esempio n. 13
0
static expression_t *gnu_get_operand(asm86_t * a, int *pn, int deref)
/* Get something like: $immed, memory, offset(%base,%index,scale), or simpler. */
{
	expression_t *e, *offset, *base, *index;
	token_t *t;
	int c;

	if (get_token(*pn)->symbol == '$') {
		/* An immediate value. */
		(*pn)++;
		return gnu_get_C_expression(pn);
	}

	if (get_token(*pn)->symbol == '*') {
		(*pn)++;
		deref = 1;
#if 0
		if ((offset= gnu_get_operand(a, pn, deref)) == nil) return nil;
#if 0
		e= new_expr();
		e->operator= '(';
		e->middle= offset;
		return e;
#endif
		return offset;
#endif
	}

	if ((get_token(*pn)->symbol == '%')
		&& (t= get_token(*pn + 1))->type == T_WORD
		&& isregister(t->name)
	) {
		/* A register operand. */
		(*pn)+= 2;
		e= new_expr();
		e->operator= 'W';
		e->name= copystr(t->name);
		return e;
	}

	/* Offset? */
	if (get_token(*pn)->symbol != '('
				|| get_token(*pn + 1)->symbol != '%') {
		/* There is an offset. */
		if ((offset= gnu_get_C_expression(pn)) == nil) return nil;
	} else {
		/* No offset. */
		offset= nil;
	}

	/* (%base,%index,scale) ? */
	base= index= nil;
	if (get_token(*pn)->symbol == '(') {
		(*pn)++;

		/* %base ? */
		if (get_token(*pn)->symbol == '%'
			&& (t= get_token(*pn + 1))->type == T_WORD
			&& isregister(t->name)
		) {
			/* A base register expression. */
			base= new_expr();
			base->operator= 'B';
			base->name= copystr(t->name);
			(*pn)+= 2;
		}

		if (get_token(*pn)->symbol == ',') (*pn)++;

		/* %index ? */
		if (get_token(*pn)->symbol == '%'
			&& (t= get_token(*pn + 1))->type == T_WORD
			&& isregister(t->name)
		) {
			/* A index register expression. */
			index= new_expr();
			index->operator= '1';		/* for now */
			index->name= copystr(t->name);
			(*pn)+= 2;
		}

		if (get_token(*pn)->symbol == ',') (*pn)++;

		/* scale ? */
		if ((base != nil || index != nil)
			&& (t= get_token(*pn))->type == T_WORD
			&& strchr("1248", t->name[0]) != nil
			&& t->name[1] == 0
		) {		
			if (index == nil) {
				/* Base is really an index register. */
				index= base;
				base= nil;
			}
			index->operator= t->name[0];
			(*pn)++;
		}

		if (get_token(*pn)->symbol == ')') {
			/* Ending paren. */
			(*pn)++;
		} else {
			/* Alas. */
			parse_err(1, t, "operand syntax error\n");
			del_expr(offset);
			del_expr(base);
			del_expr(index);
			return nil;
		}
	}

	if (base == nil && index == nil) {
		if (deref) {
			/* Return a lone offset as (offset). */
			e= new_expr();
			e->operator= '(';
			e->middle= offset;
		} else {
			/* Return a lone offset as is. */
			e= offset;
		}
	} else {
		e= new_expr();
		e->operator= 'O';
		e->left= offset;

		e->middle= base;
		e->right= index;
	}
	return e;
}
Esempio n. 14
0
/*
 * Implementation
 */
int
eval(expr_t *expr)
{
    int		 test;
    expr_t	*prev;
    expr_t	*temp;
    symbol_t	*symbol;

    switch (expr->token) {
	case tok_set:		case tok_andset:
	case tok_orset:		case tok_xorset:
	case tok_lshset:	case tok_rshset:
	case tok_addset:	case tok_subset:
	case tok_mulset:	case tok_divset:
	case tok_remset:	case tok_dot:
	case tok_arrow:
	    eval(expr->data._binary.lvalue);
	    eval(expr->data._binary.rvalue);
	    break;
	case tok_vector:
	    eval(expr->data._binary.lvalue);
	    if (expr->data._binary.rvalue)
		eval(expr->data._binary.rvalue);
	    break;
	case tok_andand:	case tok_oror:
	case tok_lt:		case tok_le:
	case tok_eq:		case tok_ge:
	case tok_gt:		case tok_ne:
	case tok_and:		case tok_or:
	case tok_xor:		case tok_lsh:
	case tok_rsh:		case tok_add:
	case tok_sub:		case tok_mul:
	case tok_div:		case tok_rem:
	    binary(expr);
	    break;
	case tok_inc:		case tok_dec:
	case tok_postinc:	case tok_postdec:
	case tok_pointer:	case tok_elemref:
	case tok_fieldref:
	    eval(expr->data._unary.expr);
	    break;
	case tok_address:
	    eval(expr->data._unary.expr);
	    /* Remember address was taken, and only useful if argument
	     * is a register, otherwise, unused information */
	    /* FIXME if a symbol is declared as register, this should
	     * be an error, but register keyword not yet implemented */
	    temp = expr->data._unary.expr;
	    if (temp->token == tok_symbol) {
		symbol = get_symbol(temp->data._unary.cp);
		if (symbol && symbol->arg)
		    symbol->mem = 1;
	    }
	    break;
	case tok_plus:		case tok_neg:
	case tok_not:		case tok_com:
	    unary(expr);
	    break;
	case tok_sizeof:
	    unary_sizeof(expr);
	    break;
	case tok_question:	case tok_if:
	    eval_stat(expr->data._if.test);
	    eval_stat(expr->data._if.tcode);
	    eval_stat(expr->data._if.fcode);
	    temp = prev = expr->data._if.test;
	    for (; temp->next; prev = temp, temp = temp->next)
		;
	    switch (temp->token) {
		case tok_int:
		    test = temp->data._unary.i != 0;
		    break;
		case tok_float:
		    test = temp->data._unary.d != 0.0;
		    break;
		default:
		    return (0);
	    }
	    if (test) {
		del_expr(expr->data._if.fcode);
		expr->data._if.fcode = NULL;
	    }
	    else {
		del_expr(expr->data._if.tcode);
		expr->data._if.tcode = expr->data._if.fcode;
		expr->data._if.fcode = NULL;
	    }
	    if (prev != temp) {
		prev->next = expr->data._if.tcode;
		expr->data._unary.expr = expr->data._if.test;
	    }
	    else
		expr->data._unary.expr = expr->data._if.tcode;
	    del_expr(temp);
	    expr->token = tok_stat;
	    break;
	case tok_return:
	    if (expr->data._unary.expr)
		eval(expr->data._unary.expr);
	    break;
	case tok_switch:
	    eval_stat(expr->data._switch.test);
	    eval_stat(expr->data._switch.code);
	    break;
	case tok_for:
	    eval_stat(expr->data._for.init);
	    eval_stat(expr->data._for.test);
	    eval_stat(expr->data._for.incr);
	    eval_stat(expr->data._for.code);
	    temp = prev = expr->data._do.test;
	    for (; temp->next; prev = temp, temp = temp->next)
		;
	    switch (temp->token) {
		case tok_int:
		    test = temp->data._unary.i != 0;
		    break;
		case tok_float:
		    test = temp->data._unary.d != 0.0;
		    break;
		default:
		    return (0);
	    }
	    if (test == 0) {
		del_expr(expr->data._for.incr);
		del_expr(expr->data._for.code);
		if ((temp = expr->data._for.init)) {
		    for (; temp->next; temp = temp->next)
			;
		    temp->next = expr->data._for.test;
		    expr->data._unary.expr = expr->data._for.init;
		}
		else
		    expr->data._unary.expr = expr->data._for.test;
		expr->token = tok_stat;
	    }
	    break;
	case tok_do:
	    eval_stat(expr->data._do.code);
	    eval_stat(expr->data._do.test);
	    temp = prev = expr->data._do.test;
	    for (; temp->next; prev = temp, temp = temp->next)
		;
	    switch (temp->token) {
		case tok_int:
		    test = temp->data._unary.i != 0;
		    break;
		case tok_float:
		    test = temp->data._unary.d != 0.0;
		    break;
		default:
		    return (0);
	    }
	    if (test == 0) {
		for (temp = expr->data._do.code; temp->next; temp = temp->next)
		    ;
		temp->next = expr->data._do.test;
		expr->data._unary.expr = expr->data._do.code;
		expr->token = tok_stat;
	    }
	    break;
	case tok_while:
	    eval_stat(expr->data._while.test);
	    eval_stat(expr->data._while.code);
	    temp = prev = expr->data._while.test;
	    for (; temp->next; prev = temp, temp = temp->next)
		;
	    switch (temp->token) {
		case tok_int:
		    test = temp->data._unary.i != 0;
		    break;
		case tok_float:
		    test = temp->data._unary.d != 0.0;
		    break;
		default:
		    return (0);
	    }
	    if (test == 0) {
		del_expr(expr->data._while.code);
		expr->data._unary.expr = expr->data._while.test;
		expr->token = tok_stat;
	    }
	    break;
	case tok_list:
	    temp = expr->data._unary.expr;
	    eval_stat(temp);
	    if (temp->next == NULL) {
		memcpy(expr, temp, sizeof(expr_t));
		temp->token = tok_none;
		del_expr(temp);
	    }
	    break;
	case tok_stat:
	    eval_stat(expr->data._unary.expr);
	    break;
	case tok_call:
	    eval(expr->data._binary.lvalue);
	    eval_stat(expr->data._binary.rvalue);
	    break;
	case tok_code:		case tok_data:
	    eval_stat(expr->data._unary.expr);
	    break;
	case tok_decl:
	    eval(expr->data._binary.lvalue);
	    eval_stat(expr->data._binary.rvalue);
	    break;
	case tok_function:
	    current = expr->data._function.function->table;
	    eval(expr->data._function.type);
	    eval(expr->data._function.call);
	    eval(expr->data._function.body);
	    current = globals;
	    break;
	default:
	    break;
    }

    return (0);
}
Esempio n. 15
0
static asm86_t *ack_get_statement(void)
/* Get a pseudo op or machine instruction with arguments. */
{
	token_t *t= get_token(0);
	asm86_t *a;
	mnemonic_t *m;
	int n;
	int prefix_seen;
	int oaz_prefix;
	int deref;

	assert(t->type == T_WORD);

	if (strcmp(t->name, ".sect") == 0) {
		/* .sect .text etc.  Accept only four segment names. */
		skip_token(1);
		t= get_token(0);
		if (t->type != T_WORD || (
			strcmp(t->name, ".text") != 0
			&& strcmp(t->name, ".rom") != 0
			&& strcmp(t->name, ".data") != 0
			&& strcmp(t->name, ".bss") != 0
			&& strcmp(t->name, ".end") != 0
		)) {
			parse_err(1, t, "weird section name to .sect\n");
			return nil;
		}
	}
	a= new_asm86();

	/* Process instruction prefixes. */
	oaz_prefix= 0;
	for (prefix_seen= 0;; prefix_seen= 1) {
		if (strcmp(t->name, "o16") == 0) {
			if (use16()) {
				parse_err(1, t, "o16 in an 8086 section\n");
			}
			oaz_prefix|= OPZ;
		} else
		if (strcmp(t->name, "o32") == 0) {
			if (use32()) {
				parse_err(1, t, "o32 in an 80386 section\n");
			}
			oaz_prefix|= OPZ;
		} else
		if (strcmp(t->name, "a16") == 0) {
			if (use16()) {
				parse_err(1, t, "a16 in an 8086 section\n");
			}
			oaz_prefix|= ADZ;
		} else
		if (strcmp(t->name, "a32") == 0) {
			if (use32()) {
				parse_err(1, t, "a32 in an 80386 section\n");
			}
			oaz_prefix|= ADZ;
		} else
		if (strcmp(t->name, "rep") == 0
			|| strcmp(t->name, "repe") == 0
			|| strcmp(t->name, "repne") == 0
			|| strcmp(t->name, "repz") == 0
			|| strcmp(t->name, "repnz") == 0
		) {
			if (a->rep != ONCE) {
				parse_err(1, t,
					"can't have more than one rep\n");
			}
			switch (t->name[3]) {
			case 0:		a->rep= REP;	break;
			case 'e':
			case 'z':	a->rep= REPE;	break;
			case 'n':	a->rep= REPNE;	break;
			}
		} else
		if (strchr("cdefgs", t->name[0]) != nil
					&& strcmp(t->name+1, "seg") == 0) {
			if (a->seg != DEFSEG) {
				parse_err(1, t,
				"can't have more than one segment prefix\n");
			}
			switch (t->name[0]) {
			case 'c':	a->seg= CSEG;	break;
			case 'd':	a->seg= DSEG;	break;
			case 'e':	a->seg= ESEG;	break;
			case 'f':	a->seg= FSEG;	break;
			case 'g':	a->seg= GSEG;	break;
			case 's':	a->seg= SSEG;	break;
			}
		} else
		if (!prefix_seen) {
			/* No prefix here, get out! */
			break;
		} else {
			/* No more prefixes, next must be an instruction. */
			if (t->type != T_WORD
				|| (m= search_mnem(t->name)) == nil
				|| m->optype == PSEUDO
			) {
				parse_err(1, t,
		"machine instruction expected after instruction prefix\n");
				del_asm86(a);
				return nil;
			}
			if (oaz_prefix != 0 && m->optype != JUMP
						&& m->optype != WORD) {
				parse_err(1, t,
			"'%s' can't have an operand size prefix\n", m->name);
			}
			break;
		}

		/* Skip the prefix and extra newlines. */
		do {
			skip_token(1);
		} while ((t= get_token(0))->symbol == ';');
	}

	/* All the readahead being done upsets the line counter. */
	a->line= t->line;

	/* Read a machine instruction or pseudo op. */
	if ((m= search_mnem(t->name)) == nil) {
		parse_err(1, t, "unknown instruction '%s'\n", t->name);
		del_asm86(a);
		return nil;
	}
	a->opcode= m->opcode;
	a->optype= m->optype;
	a->oaz= oaz_prefix;

	switch (a->opcode) {
	case IN:
	case OUT:
	case INT:
		deref= 0;
		break;
	default:
		deref= (a->optype >= BYTE);
	}
	n= 1;
	if (get_token(1)->symbol != ';'
			&& (a->args= ack_get_oplist(&n, deref)) == nil) {
		del_asm86(a);
		return nil;
	}
	if (get_token(n)->symbol != ';') {
		parse_err(1, t, "garbage at end of instruction\n");
		del_asm86(a);
		return nil;
	}
	switch (a->opcode) {
	case DOT_ALIGN:
		/* Restrict .align to have a single numeric argument, some
		 * assemblers think of the argument as a power of two, so
		 * we need to be able to change the value.
		 */
		if (a->args == nil || a->args->operator != 'W'
					|| !isanumber(a->args->name)) {
			parse_err(1, t,
			  ".align is restricted to one numeric argument\n");
			del_asm86(a);
			return nil;
		}
		break;
	case JMPF:
	case CALLF:
		/* NCC jmpf off,seg  ->  ACK jmpf seg:off */
		if (dialect == NCC && a->args != nil
						&& a->args->operator == ',') {
			expression_t *t;

			t= a->args->left;
			a->args->left= a->args->right;
			a->args->right= t;
			break;
		}
		/*FALL THROUGH*/
	case JMP:
	case CALL:
		/* NCC jmp @(reg)  ->  ACK jmp (reg) */
		if (dialect == NCC && a->args != nil && (
			(a->args->operator == '('
				&& a->args->middle != nil
				&& a->args->middle->operator == 'O')
			|| (a->args->operator == 'O'
				&& a->args->left == nil
				&& a->args->middle != nil
				&& a->args->right == nil)
		)) {
			expression_t *t;

			t= a->args;
			a->args= a->args->middle;
			t->middle= nil;
			del_expr(t);
			if (a->args->operator == 'B') a->args->operator= 'W';
		}
		break;
	default:;
	}
	skip_token(n+1);
	return a;
}
Esempio n. 16
0
static expression_t *ack_get_operand(int *pn, int deref)
/* Get something like: (memory), offset(base)(index*scale), or simpler. */
{
	expression_t *e, *offset, *base, *index;
	token_t *t;
	int c;

	/* Is it (memory)? */
	if (get_token(*pn)->symbol == '('
		&& ((t= get_token(*pn + 1))->type != T_WORD
			|| !isregister(t->name))
	) {
		/* A memory dereference. */
		(*pn)++;
		if ((offset= ack_get_C_expression(pn)) == nil) return nil;
		if (get_token(*pn)->symbol != ')') {
			parse_err(1, t, "operand syntax error\n");
			del_expr(offset);
			return nil;
		}
		(*pn)++;
		e= new_expr();
		e->operator= '(';
		e->middle= offset;
		return e;
	}

	/* #constant? */
	if (dialect == NCC && deref
			&& ((c= get_token(*pn)->symbol) == '#' || c == '*')) {
		/* NCC: mov ax,#constant  ->  ACK: mov ax,constant */
		(*pn)++;
		return ack_get_C_expression(pn);
	}

	/* @address? */
	if (dialect == NCC && get_token(*pn)->symbol == '@') {
		/* NCC: jmp @address  ->  ACK: jmp (address) */
		(*pn)++;
		if ((offset= ack_get_operand(pn, deref)) == nil) return nil;
		e= new_expr();
		e->operator= '(';
		e->middle= offset;
		return e;
	}

	/* Offset? */
	if (get_token(*pn)->symbol != '(') {
		/* There is an offset. */
		if ((offset= ack_get_C_expression(pn)) == nil) return nil;
	} else {
		/* No offset. */
		offset= nil;
	}

	/* (base)? */
	if (get_token(*pn)->symbol == '('
		&& (t= get_token(*pn + 1))->type == T_WORD
		&& isregister(t->name)
		&& get_token(*pn + 2)->symbol == ')'
	) {
		/* A base register expression. */
		base= new_expr();
		base->operator= 'B';
		base->name= copystr(t->name);
		(*pn)+= 3;
	} else {
		/* No base register expression. */
		base= nil;
	}

	/* (index*scale)? */
	if (get_token(*pn)->symbol == '(') {
		/* An index most likely. */
		token_t *m= nil;

		if (!(		/* This must be true: */
			(t= get_token(*pn + 1))->type == T_WORD
			&& isregister(t->name)
			&& (get_token(*pn + 2)->symbol == ')' || (
				get_token(*pn + 2)->symbol == '*'
				&& (m= get_token(*pn + 3))->type == T_WORD
				&& strchr("1248", m->name[0]) != nil
				&& m->name[1] == 0
				&& get_token(*pn + 4)->symbol == ')'
			))
		)) {
			/* Alas it isn't */
			parse_err(1, t, "operand syntax error\n");
			del_expr(offset);
			del_expr(base);
			return nil;
		}
		/* Found an index. */
		index= new_expr();
		index->operator= m == nil ? '1' : m->name[0];
		index->name= copystr(t->name);
		(*pn)+= (m == nil ? 3 : 5);
	} else {
		/* No index. */
		index= nil;
	}

	if (dialect == NCC && deref && base == nil && index == nil
		&& !(offset != nil && offset->operator == 'W'
					&& isregister(offset->name))
	) {
		/* NCC: mov ax,thing  ->  ACK mov ax,(thing) */
		e= new_expr();
		e->operator= '(';
		e->middle= offset;
		return e;
	}

	if (base == nil && index == nil) {
		/* Return a lone offset as is. */
		e= offset;
	} else {
		e= new_expr();
		e->operator= 'O';
		e->left= offset;
		e->middle= base;
		e->right= index;
	}
	return e;
}
Esempio n. 17
0
static expression_t *ack_get_C_expression(int *pn)
/* Read a "C-like" expression.  Note that we don't worry about precedence,
 * the expression is printed later like it is read.  If the target language
 * does not have all the operators (like ~) then this has to be repaired by
 * changing the source file.  (No problem, you still have one source file
 * to maintain, not two.)
 */
{
	expression_t *e, *a1, *a2;
	token_t *t;

	if ((t= get_token(*pn))->symbol == '[') {
		/* [ expr ]: grouping. */
		(*pn)++;
		if ((a1= ack_get_C_expression(pn)) == nil) return nil;
		if (get_token(*pn)->symbol != ']') {
			parse_err(1, t, "missing ]\n");
			del_expr(a1);
			return nil;
		}
		(*pn)++;
		e= new_expr();
		e->operator= '[';
		e->middle= a1;
	} else
	if (t->type == T_WORD || t->type == T_STRING) {
		/* Label, number, or string. */
		e= new_expr();
		e->operator= t->type == T_WORD ? 'W' : 'S';
		e->name= allocate(nil, (t->len+1) * sizeof(e->name[0]));
		memcpy(e->name, t->name, t->len+1);
		e->len= t->len;
		(*pn)++;
	} else
	if (t->symbol == '+' || t->symbol == '-' || t->symbol == '~') {
		/* Unary operator. */
		(*pn)++;
		if ((a1= ack_get_C_expression(pn)) == nil) return nil;
		e= new_expr();
		e->operator= t->symbol;
		e->middle= a1;
	} else {
		parse_err(1, t, "expression syntax error\n");
		return nil;
	}

	switch ((t= get_token(*pn))->symbol) {
	case '+':
	case '-':
	case '*':
	case '/':
	case '%':
	case '&':
	case '|':
	case '^':
	case S_LEFTSHIFT:
	case S_RIGHTSHIFT:
		(*pn)++;
		a1= e;
		if ((a2= ack_get_C_expression(pn)) == nil) {
			del_expr(a1);
			return nil;
		}
		e= new_expr();
		e->operator= t->symbol;
		e->left= a1;
		e->right= a2;
	}
	return e;
}