cleaned up expression handler, it's now able to handle more than just ints/floats

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@158 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2020-05-13 23:26:40 +00:00
parent 3300c9d468
commit 40afd3311a
10 changed files with 462 additions and 340 deletions

515
src/alu.c
View File

@ -167,7 +167,7 @@ static struct op **op_stack = NULL;
static int opstack_size = HALF_INITIAL_STACK_SIZE;
static int op_sp;
// argument stack, current size and stack pointer:
static struct number *arg_stack = NULL;
static struct object *arg_stack = NULL;
static int argstack_size = HALF_INITIAL_STACK_SIZE;
static int arg_sp;
enum alu_state {
@ -211,17 +211,19 @@ static struct ronode function_list[] = {
#define PUSH_OP(x) op_stack[op_sp++] = (x)
#define PUSH_INT_ARG(i, f, r) \
do { \
arg_stack[arg_sp].flags = (f); \
arg_stack[arg_sp].val.intval = (i); \
arg_stack[arg_sp++].addr_refs = (r); \
#define PUSH_INT_ARG(i, f, r) \
do { \
arg_stack[arg_sp].type = &type_int; \
arg_stack[arg_sp].u.number.flags = (f); \
arg_stack[arg_sp].u.number.val.intval = (i); \
arg_stack[arg_sp++].u.number.addr_refs = (r); \
} while (0)
#define PUSH_FP_ARG(fp, f) \
do { \
arg_stack[arg_sp].flags = (f) | NUMBER_IS_FLOAT; \
arg_stack[arg_sp].val.fpval = (fp); \
arg_stack[arg_sp++].addr_refs = 0; \
#define PUSH_FP_ARG(fp, f) \
do { \
arg_stack[arg_sp].type = &type_float; \
arg_stack[arg_sp].u.number.flags = (f); \
arg_stack[arg_sp].u.number.val.fpval = (fp); \
arg_stack[arg_sp++].u.number.addr_refs = 0; \
} while (0)
@ -296,14 +298,11 @@ static intval_t my_asr(intval_t left, intval_t right)
}
// if needed, throw "Value not defined" error
// if wanted, throw "Value not defined" error
// This function is not allowed to change DynaBuf because the symbol's name
// might be stored there!
static void check_for_def(struct symbol *optional_symbol, int flags, char optional_prefix_char, char *name, size_t length)
static void is_not_defined(struct symbol *optional_symbol, char optional_prefix_char, char *name, size_t length)
{
if (flags & NUMBER_IS_DEFINED)
return;
if (!pass.complain_about_undefined)
return;
@ -349,7 +348,8 @@ static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t na
// if the symbol gets created now, mark it as unsure
symbol = symbol_find(scope, NUMBER_EVER_UNDEFINED);
// if needed, output "value not defined" error
check_for_def(symbol, symbol->result.flags, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
if (!(symbol->result.type->is_defined(&symbol->result)))
is_not_defined(symbol, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
// in first pass, count usage
if (FIRST_PASS)
symbol->usage++;
@ -366,7 +366,8 @@ static void parse_program_counter(void) // Now GotByte = "*"
GetByte();
vcpu_read_pc(&pc);
// if needed, output "value not defined" error
check_for_def(NULL, pc.flags, 0, "*", 1);
if (!(pc.flags & NUMBER_IS_DEFINED))
is_not_defined(NULL, 0, "*", 1);
PUSH_INT_ARG(pc.val.intval, pc.flags, pc.addr_refs);
}
@ -956,59 +957,25 @@ push_dyadic_op:
// int:
// convert to float
inline static void int_to_float(struct number *self)
inline static void int_to_float(struct object *self)
{
self->val.fpval = self->val.intval;
self->flags |= NUMBER_IS_FLOAT;
self->type = &type_float;
self->u.number.val.fpval = self->u.number.val.intval;
}
// float:
// convert to int
inline static void float_to_int(struct number *self)
inline static void float_to_int(struct object *self)
{
self->val.intval = self->val.fpval;
self->flags &= ~NUMBER_IS_FLOAT;
self->type = &type_int;
self->u.number.val.intval = self->u.number.val.fpval;
}
// int/float:
// set flags according to result
static void number_fixresult(struct number *self)
// return DEFINED flag
static boolean number_is_defined(struct object *self)
{
// only allow a single force bit
if (self->flags & NUMBER_FORCES_24)
self->flags &= ~(NUMBER_FORCES_16 | NUMBER_FORCES_8);
else if (self->flags & NUMBER_FORCES_16)
self->flags &= ~NUMBER_FORCES_8;
}
// int:
// set flags according to result
static void int_fixresult(struct number *self)
{
number_fixresult(self);
// if undefined, return zero
if (!(self->flags & NUMBER_IS_DEFINED))
self->val.intval = 0;
// if value is sure, check to set FITS BYTE
else if ((!(self->flags & NUMBER_EVER_UNDEFINED))
&& (self->val.intval <= 255)
&& (self->val.intval >= -128))
self->flags |= NUMBER_FITS_BYTE;
}
// float:
// set flags according to result
static void float_fixresult(struct number *self)
{
number_fixresult(self);
// if undefined, return zero
if (!(self->flags & NUMBER_IS_DEFINED))
self->val.fpval = 0;
// if value is sure, check to set FITS BYTE
else if ((!(self->flags & NUMBER_EVER_UNDEFINED))
&& (self->val.fpval <= 255.0)
&& (self->val.fpval >= -128.0))
self->flags |= NUMBER_FITS_BYTE;
return !!(self->u.number.flags & NUMBER_IS_DEFINED);
}
// this gets called for LSR, AND, OR, XOR with float args
@ -1018,14 +985,9 @@ static void warn_float_to_int(void)
Throw_first_pass_warning("Converted to integer for binary logic operator.");
}
// prototypes needed because int and float handlers reference each other.
// FIXME - remove when handlers are put as pointers into proper "type" structures.
static void float_handle_monadic_operator(struct number *self, enum op_handle op);
static void float_handle_dyadic_operator(struct number *self, enum op_handle op, struct number *other);
// int:
// handle monadic operator (includes functions)
static void int_handle_monadic_operator(struct number *self, enum op_handle op)
static void int_handle_monadic_operator(struct object *self, enum op_handle op)
{
int refs = 0; // default for "addr_refs", shortens this fn
@ -1046,33 +1008,33 @@ static void int_handle_monadic_operator(struct number *self, enum op_handle op)
case OPHANDLE_ARCTAN:
// convert int to fp and ask fp handler to do the work
int_to_float(self);
float_handle_monadic_operator(self, op); // TODO - put recursion check around this?
type_float.handle_monadic_operator(self, op); // TODO - put recursion check around this?
return; // float handler has done everything
case OPHANDLE_NOT:
self->val.intval = ~(self->val.intval);
self->flags &= ~NUMBER_FITS_BYTE;
refs = -(self->addr_refs); // negate address ref count
self->u.number.val.intval = ~(self->u.number.val.intval);
self->u.number.flags &= ~NUMBER_FITS_BYTE;
refs = -(self->u.number.addr_refs); // negate address ref count
break;
case OPHANDLE_NEGATE:
self->val.intval = -(self->val.intval);
self->flags &= ~NUMBER_FITS_BYTE;
refs = -(self->addr_refs); // negate address ref count as well
self->u.number.val.intval = -(self->u.number.val.intval);
self->u.number.flags &= ~NUMBER_FITS_BYTE;
refs = -(self->u.number.addr_refs); // negate address ref count as well
break;
case OPHANDLE_LOWBYTEOF:
self->val.intval = (self->val.intval) & 255;
self->flags |= NUMBER_FITS_BYTE;
self->flags &= ~NUMBER_FORCEBITS;
self->u.number.val.intval = (self->u.number.val.intval) & 255;
self->u.number.flags |= NUMBER_FITS_BYTE;
self->u.number.flags &= ~NUMBER_FORCEBITS;
break;
case OPHANDLE_HIGHBYTEOF:
self->val.intval = ((self->val.intval) >> 8) & 255;
self->flags |= NUMBER_FITS_BYTE;
self->flags &= ~NUMBER_FORCEBITS;
self->u.number.val.intval = ((self->u.number.val.intval) >> 8) & 255;
self->u.number.flags |= NUMBER_FITS_BYTE;
self->u.number.flags &= ~NUMBER_FORCEBITS;
break;
case OPHANDLE_BANKBYTEOF:
self->val.intval = ((self->val.intval) >> 16) & 255;
self->flags |= NUMBER_FITS_BYTE;
self->flags &= ~NUMBER_FORCEBITS;
self->u.number.val.intval = ((self->u.number.val.intval) >> 16) & 255;
self->u.number.flags |= NUMBER_FITS_BYTE;
self->u.number.flags &= ~NUMBER_FORCEBITS;
break;
// add new monadic operators here
// case OPHANDLE_:
@ -1081,26 +1043,26 @@ static void int_handle_monadic_operator(struct number *self, enum op_handle op)
default:
Bug_found("IllegalOperatorHandleIM", op);
}
self->addr_refs = refs; // update address refs with local copy
self->u.number.addr_refs = refs; // update address refs with local copy
}
// float:
// helper function for asin/acos:
// make sure arg is in [-1, 1] range before calling function
static void float_ranged_fn(double (*fn)(double), struct number *self)
static void float_ranged_fn(double (*fn)(double), struct object *self)
{
if ((self->val.fpval >= -1) && (self->val.fpval <= 1)) {
self->val.fpval = fn(self->val.fpval);
if ((self->u.number.val.fpval >= -1) && (self->u.number.val.fpval <= 1)) {
self->u.number.val.fpval = fn(self->u.number.val.fpval);
} else {
if (self->flags & NUMBER_IS_DEFINED)
if (self->u.number.flags & NUMBER_IS_DEFINED)
Throw_error("Argument out of range."); // TODO - add number output to error message
self->val.fpval = 0;
self->u.number.val.fpval = 0;
}
}
// float:
// handle monadic operator (includes functions)
static void float_handle_monadic_operator(struct number *self, enum op_handle op)
static void float_handle_monadic_operator(struct object *self, enum op_handle op)
{
int refs = 0; // default for "addr_refs", shortens this fn
@ -1114,13 +1076,13 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
case OPHANDLE_FLOAT:
break;
case OPHANDLE_SIN:
self->val.fpval = sin(self->val.fpval);
self->u.number.val.fpval = sin(self->u.number.val.fpval);
break;
case OPHANDLE_COS:
self->val.fpval = cos(self->val.fpval);
self->u.number.val.fpval = cos(self->u.number.val.fpval);
break;
case OPHANDLE_TAN:
self->val.fpval = tan(self->val.fpval);
self->u.number.val.fpval = tan(self->u.number.val.fpval);
break;
case OPHANDLE_ARCSIN:
float_ranged_fn(asin, self);
@ -1129,12 +1091,12 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
float_ranged_fn(acos, self);
break;
case OPHANDLE_ARCTAN:
self->val.fpval = atan(self->val.fpval);
self->u.number.val.fpval = atan(self->u.number.val.fpval);
break;
case OPHANDLE_NEGATE:
self->val.fpval = -(self->val.fpval);
self->flags &= ~NUMBER_FITS_BYTE;
refs = -(self->addr_refs); // negate address ref count as well
self->u.number.val.fpval = -(self->u.number.val.fpval);
self->u.number.flags &= ~NUMBER_FITS_BYTE;
refs = -(self->u.number.addr_refs); // negate address ref count as well
break;
case OPHANDLE_NOT:
case OPHANDLE_LOWBYTEOF:
@ -1142,7 +1104,7 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
case OPHANDLE_BANKBYTEOF:
// convert fp to int and ask int handler to do the work
float_to_int(self);
int_handle_monadic_operator(self, op); // TODO - put recursion check around this?
type_int.handle_monadic_operator(self, op); // TODO - put recursion check around this?
return; // int handler has done everything
// add new monadic operators here
@ -1152,30 +1114,40 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
default:
Bug_found("IllegalOperatorHandleFM", op);
}
self->addr_refs = refs; // update address refs with local copy
self->u.number.addr_refs = refs; // update address refs with local copy
}
// int/float:
// merge result flags
// (used by both int and float handlers for dyadic operators)
static void number_fix_result_after_dyadic(struct number *self, struct number *other)
static void number_fix_result_after_dyadic(struct object *self, struct object *other)
{
// EVER_UNDEFINED and FORCEBIT flags are ORd together
self->flags |= other->flags & (NUMBER_EVER_UNDEFINED | NUMBER_FORCEBITS);
self->u.number.flags |= other->u.number.flags & (NUMBER_EVER_UNDEFINED | NUMBER_FORCEBITS);
// DEFINED flags are ANDed together
self->flags &= (other->flags | ~NUMBER_IS_DEFINED);
self->u.number.flags &= (other->u.number.flags | ~NUMBER_IS_DEFINED);
// FITS_BYTE is cleared
self->flags &= ~NUMBER_FITS_BYTE;
self->u.number.flags &= ~NUMBER_FITS_BYTE;
}
// helper function: don't know how to handle that ARG1 OP ARG2 combination
static void unsupported_dyadic(struct object *self, enum op_handle op, struct object *other)
{
Throw_error("Unsupported combination of argument(s) and operator"); // FIXME - make dynamic, add type names of self/other, add to docs
}
// int:
// handle dyadic operator
static void int_handle_dyadic_operator(struct number *self, enum op_handle op, struct number *other)
static void int_handle_dyadic_operator(struct object *self, enum op_handle op, struct object *other)
{
int refs = 0; // default for "addr_refs", shortens this fn
// first check type of second arg:
if (other->flags & NUMBER_IS_FLOAT) {
if (other->type == &type_int) {
// ok
} else if (other->type == &type_float) {
// handle according to operation
switch (op) {
case OPHANDLE_POWEROF:
@ -1192,7 +1164,7 @@ static void int_handle_dyadic_operator(struct number *self, enum op_handle op, s
case OPHANDLE_NOTEQUAL:
// become float, delegate to float handler
int_to_float(self);
float_handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
type_float.handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
return; // float handler has done everything
case OPHANDLE_MODULO:
@ -1210,97 +1182,105 @@ static void int_handle_dyadic_operator(struct number *self, enum op_handle op, s
float_to_int(other);
warn_float_to_int();
break;
// add new dyadic operators here
// add new dyadic operators here:
// case OPHANDLE_:
// break;
default:
break;
unsupported_dyadic(self, op, other);
return;
}
// add new types here:
// } else if (other->type == &type_) {
// ...
} else {
unsupported_dyadic(self, op, other);
return;
}
// sanity check, now "other" can no longer be a float
if (other->flags & NUMBER_IS_FLOAT)
Bug_found("SecondArgIsStillFloatForOp", op); // FIXME - rename? then add to docs!
// maybe put this into an extra "int_dyadic_int" function?
// sanity check, now "other" must be an int
if (other->type != &type_int)
Bug_found("SecondArgIsNotAnInt", op); // FIXME - rename? then add to docs!
// part 2: now we got rid of floats, perform actual operation:
switch (op) {
case OPHANDLE_POWEROF:
if (other->val.intval >= 0) {
self->val.intval = my_pow(self->val.intval, other->val.intval);
if (other->u.number.val.intval >= 0) {
self->u.number.val.intval = my_pow(self->u.number.val.intval, other->u.number.val.intval);
} else {
if (other->flags & NUMBER_IS_DEFINED)
if (other->u.number.flags & NUMBER_IS_DEFINED)
Throw_error("Exponent is negative.");
self->val.intval = 0;
self->u.number.val.intval = 0;
}
break;
case OPHANDLE_MULTIPLY:
self->val.intval *= other->val.intval;
self->u.number.val.intval *= other->u.number.val.intval;
break;
case OPHANDLE_DIVIDE:
case OPHANDLE_INTDIV:
if (other->val.intval) {
self->val.intval /= other->val.intval;
if (other->u.number.val.intval) {
self->u.number.val.intval /= other->u.number.val.intval;
break;
}
// "division by zero" output is below
/*FALLTHROUGH*/
case OPHANDLE_MODULO:
if (other->val.intval) {
self->val.intval %= other->val.intval;
if (other->u.number.val.intval) {
self->u.number.val.intval %= other->u.number.val.intval;
} else {
if (other->flags & NUMBER_IS_DEFINED)
if (other->u.number.flags & NUMBER_IS_DEFINED)
Throw_error(exception_div_by_zero);
self->val.intval = 0;
self->u.number.val.intval = 0;
}
break;
case OPHANDLE_ADD:
self->val.intval += other->val.intval;
refs = self->addr_refs + other->addr_refs; // add address references
self->u.number.val.intval += other->u.number.val.intval;
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
break;
case OPHANDLE_SUBTRACT:
self->val.intval -= other->val.intval;
refs = self->addr_refs - other->addr_refs; // subtract address references
self->u.number.val.intval -= other->u.number.val.intval;
refs = self->u.number.addr_refs - other->u.number.addr_refs; // subtract address references
break;
case OPHANDLE_SL:
self->val.intval <<= other->val.intval;
self->u.number.val.intval <<= other->u.number.val.intval;
break;
case OPHANDLE_ASR:
self->val.intval = my_asr(self->val.intval, other->val.intval);
self->u.number.val.intval = my_asr(self->u.number.val.intval, other->u.number.val.intval);
break;
case OPHANDLE_LSR:
self->val.intval = ((uintval_t) (self->val.intval)) >> other->val.intval;
self->u.number.val.intval = ((uintval_t) (self->u.number.val.intval)) >> other->u.number.val.intval;
break;
case OPHANDLE_LE:
self->val.intval = (self->val.intval <= other->val.intval);
self->u.number.val.intval = (self->u.number.val.intval <= other->u.number.val.intval);
break;
case OPHANDLE_LESSTHAN:
self->val.intval = (self->val.intval < other->val.intval);
self->u.number.val.intval = (self->u.number.val.intval < other->u.number.val.intval);
break;
case OPHANDLE_GE:
self->val.intval = (self->val.intval >= other->val.intval);
self->u.number.val.intval = (self->u.number.val.intval >= other->u.number.val.intval);
break;
case OPHANDLE_GREATERTHAN:
self->val.intval = (self->val.intval > other->val.intval);
self->u.number.val.intval = (self->u.number.val.intval > other->u.number.val.intval);
break;
case OPHANDLE_NOTEQUAL:
self->val.intval = (self->val.intval != other->val.intval);
self->u.number.val.intval = (self->u.number.val.intval != other->u.number.val.intval);
break;
case OPHANDLE_EQUALS:
self->val.intval = (self->val.intval == other->val.intval);
self->u.number.val.intval = (self->u.number.val.intval == other->u.number.val.intval);
break;
case OPHANDLE_AND:
self->val.intval &= other->val.intval;
refs = self->addr_refs + other->addr_refs; // add address references
self->u.number.val.intval &= other->u.number.val.intval;
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
break;
case OPHANDLE_OR:
self->val.intval |= other->val.intval;
refs = self->addr_refs + other->addr_refs; // add address references
self->u.number.val.intval |= other->u.number.val.intval;
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
break;
case OPHANDLE_EOR:
Throw_first_pass_warning("\"EOR\" is deprecated; use \"XOR\" instead.");
/*FALLTHROUGH*/
case OPHANDLE_XOR:
self->val.intval ^= other->val.intval;
refs = self->addr_refs + other->addr_refs; // add address references
self->u.number.val.intval ^= other->u.number.val.intval;
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
break;
// add new dyadic operators here
// case OPHANDLE_:
@ -1309,18 +1289,20 @@ static void int_handle_dyadic_operator(struct number *self, enum op_handle op, s
default:
Bug_found("IllegalOperatorHandleID", op);
}
self->addr_refs = refs; // update address refs with local copy
self->u.number.addr_refs = refs; // update address refs with local copy
number_fix_result_after_dyadic(self, other); // fix result flags
}
// float:
// handle dyadic operator
static void float_handle_dyadic_operator(struct number *self, enum op_handle op, struct number *other)
static void float_handle_dyadic_operator(struct object *self, enum op_handle op, struct object *other)
{
int refs = 0; // default for "addr_refs", shortens this fn
// first check type of second arg:
if (!(other->flags & NUMBER_IS_FLOAT)) {
if (other->type == &type_float) {
// ok
} else if (other->type == &type_int) {
// handle according to operation
switch (op) {
// these want two floats
@ -1354,35 +1336,42 @@ static void float_handle_dyadic_operator(struct number *self, enum op_handle op,
// case OPHANDLE_:
// break;
default:
break;
unsupported_dyadic(self, op, other);
return;
}
// add new types here
// } else if (other->type == &type_) {
// ...
} else {
unsupported_dyadic(self, op, other);
return;
}
switch (op) {
case OPHANDLE_POWEROF:
self->val.fpval = pow(self->val.fpval, other->val.fpval);
self->u.number.val.fpval = pow(self->u.number.val.fpval, other->u.number.val.fpval);
break;
case OPHANDLE_MULTIPLY:
self->val.fpval *= other->val.fpval;
self->u.number.val.fpval *= other->u.number.val.fpval;
break;
case OPHANDLE_DIVIDE:
if (other->val.fpval) {
self->val.fpval /= other->val.fpval;
if (other->u.number.val.fpval) {
self->u.number.val.fpval /= other->u.number.val.fpval;
} else {
if (other->flags & NUMBER_IS_DEFINED)
if (other->u.number.flags & NUMBER_IS_DEFINED)
Throw_error(exception_div_by_zero);
self->val.fpval = 0;
self->u.number.val.fpval = 0;
}
break;
case OPHANDLE_INTDIV:
if (other->val.fpval) {
self->val.intval = self->val.fpval / other->val.fpval;
if (other->u.number.val.fpval) {
self->u.number.val.intval = self->u.number.val.fpval / other->u.number.val.fpval; // fp becomes int!
} else {
if (other->flags & NUMBER_IS_DEFINED)
if (other->u.number.flags & NUMBER_IS_DEFINED)
Throw_error(exception_div_by_zero);
self->val.intval = 0;
self->u.number.val.intval = 0;
}
self->flags &= ~NUMBER_IS_FLOAT; // result is int
self->type = &type_int; // result is int
break;
case OPHANDLE_LSR:
case OPHANDLE_AND:
@ -1394,50 +1383,50 @@ static void float_handle_dyadic_operator(struct number *self, enum op_handle op,
case OPHANDLE_MODULO:
float_to_int(self);
// int handler will check other and, if needed, convert to int
int_handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
type_int.handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
return; // int handler has done everything
case OPHANDLE_ADD:
self->val.fpval += other->val.fpval;
refs = self->addr_refs + other->addr_refs; // add address references
self->u.number.val.fpval += other->u.number.val.fpval;
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
break;
case OPHANDLE_SUBTRACT:
self->val.fpval -= other->val.fpval;
refs = self->addr_refs - other->addr_refs; // subtract address references
self->u.number.val.fpval -= other->u.number.val.fpval;
refs = self->u.number.addr_refs - other->u.number.addr_refs; // subtract address references
break;
case OPHANDLE_SL:
if (other->flags & NUMBER_IS_FLOAT)
if (other->type == &type_float)
float_to_int(other);
self->val.fpval *= pow(2.0, other->val.intval);
self->u.number.val.fpval *= pow(2.0, other->u.number.val.intval);
break;
case OPHANDLE_ASR:
if (other->flags & NUMBER_IS_FLOAT)
if (other->type == &type_float)
float_to_int(other);
self->val.fpval /= (1 << other->val.intval); // FIXME - why not use pow() as in SL above?
self->u.number.val.fpval /= (1 << other->u.number.val.intval); // FIXME - why not use pow() as in SL above?
break;
case OPHANDLE_LE:
self->val.intval = (self->val.fpval <= other->val.fpval);
self->flags &= ~NUMBER_IS_FLOAT;
self->u.number.val.intval = (self->u.number.val.fpval <= other->u.number.val.fpval);
self->type = &type_int; // result is int
break;
case OPHANDLE_LESSTHAN:
self->val.intval = (self->val.fpval < other->val.fpval);
self->flags &= ~NUMBER_IS_FLOAT;
self->u.number.val.intval = (self->u.number.val.fpval < other->u.number.val.fpval);
self->type = &type_int; // result is int
break;
case OPHANDLE_GE:
self->val.intval = (self->val.fpval >= other->val.fpval);
self->flags &= ~NUMBER_IS_FLOAT;
self->u.number.val.intval = (self->u.number.val.fpval >= other->u.number.val.fpval);
self->type = &type_int; // result is int
break;
case OPHANDLE_GREATERTHAN:
self->val.intval = (self->val.fpval > other->val.fpval);
self->flags &= ~NUMBER_IS_FLOAT;
self->u.number.val.intval = (self->u.number.val.fpval > other->u.number.val.fpval);
self->type = &type_int; // result is int
break;
case OPHANDLE_NOTEQUAL:
self->val.intval = (self->val.fpval != other->val.fpval);
self->flags &= ~NUMBER_IS_FLOAT;
self->u.number.val.intval = (self->u.number.val.fpval != other->u.number.val.fpval);
self->type = &type_int; // result is int
break;
case OPHANDLE_EQUALS:
self->val.intval = (self->val.fpval == other->val.fpval);
self->flags &= ~NUMBER_IS_FLOAT;
self->u.number.val.intval = (self->u.number.val.fpval == other->u.number.val.fpval);
self->type = &type_int; // result is int
break;
// add new dyadic operators here
// case OPHANDLE_:
@ -1446,10 +1435,107 @@ static void float_handle_dyadic_operator(struct number *self, enum op_handle op,
default:
Bug_found("IllegalOperatorHandleFD", op);
}
self->addr_refs = refs; // update address refs with local copy
self->u.number.addr_refs = refs; // update address refs with local copy
number_fix_result_after_dyadic(self, other); // fix result flags
}
// int/float:
// set flags according to result
static void number_fix_result(struct object *self)
{
// only allow a single force bit
if (self->u.number.flags & NUMBER_FORCES_24)
self->u.number.flags &= ~(NUMBER_FORCES_16 | NUMBER_FORCES_8);
else if (self->u.number.flags & NUMBER_FORCES_16)
self->u.number.flags &= ~NUMBER_FORCES_8;
}
// int:
// set flags according to result
static void int_fix_result(struct object *self)
{
number_fix_result(self);
// if undefined, return zero
if (!(self->u.number.flags & NUMBER_IS_DEFINED))
self->u.number.val.intval = 0;
// if value is sure, check to set FITS BYTE
else if ((!(self->u.number.flags & NUMBER_EVER_UNDEFINED))
&& (self->u.number.val.intval <= 255)
&& (self->u.number.val.intval >= -128))
self->u.number.flags |= NUMBER_FITS_BYTE;
}
// float:
// set flags according to result
static void float_fix_result(struct object *self)
{
number_fix_result(self);
// if undefined, return zero
if (!(self->u.number.flags & NUMBER_IS_DEFINED))
self->u.number.val.fpval = 0;
// if value is sure, check to set FITS BYTE
else if ((!(self->u.number.flags & NUMBER_EVER_UNDEFINED))
&& (self->u.number.val.fpval <= 255.0)
&& (self->u.number.val.fpval >= -128.0))
self->u.number.flags |= NUMBER_FITS_BYTE;
}
// int:
// print value for user message
static void int_print(struct object *self, struct dynabuf *db)
{
char buffer[32]; // 11 for dec, 8 for hex
if (self->u.number.flags & NUMBER_IS_DEFINED) {
sprintf(buffer, "%ld (0x%lx)", (long) self->u.number.val.intval, (long) self->u.number.val.intval);
DynaBuf_add_string(db, buffer);
} else {
DynaBuf_add_string(db, "<UNDEFINED INT>");
}
}
// float:
// print value for user message
static void float_print(struct object *self, struct dynabuf *db)
{
char buffer[40];
if (self->u.number.flags & NUMBER_IS_DEFINED) {
// write up to 30 significant characters.
// remaining 10 should suffice for sign,
// decimal point, exponent, terminator etc.
sprintf(buffer, "%.30g", self->u.number.val.fpval);
DynaBuf_add_string(db, buffer);
} else {
DynaBuf_add_string(db, "<UNDEFINED FLOAT>");
}
}
struct type type_int = {
//"Integer",
number_is_defined,
int_handle_monadic_operator,
int_handle_dyadic_operator,
int_fix_result,
int_print
};
struct type type_float = {
//"Float",
number_is_defined,
float_handle_monadic_operator,
float_handle_dyadic_operator,
float_fix_result,
float_print
};
/*
struct type type_string = {
//"String",
};
struct type type_list = {
//"List",
};
*/
// handler for special operators like parentheses and start/end of expression:
// returns whether caller should just return without fixing stack (because this fn has fixed it)
@ -1526,24 +1612,14 @@ static void try_to_reduce_stacks(struct expression *expression)
// so perform that operation!
#define ARG_PREV (arg_stack[arg_sp - 2])
#define ARG_NOW (arg_stack[arg_sp - 1])
// TODO - make handler functions for monadic and dyadic operators type-
// specific, so strings and lists can get their own handler functions.
switch (previous_op->group) {
case OPGROUP_MONADIC: // monadic operators
if (ARG_NOW.flags & NUMBER_IS_FLOAT) {
float_handle_monadic_operator(&ARG_NOW, previous_op->handle);
} else {
int_handle_monadic_operator(&ARG_NOW, previous_op->handle);
}
ARG_NOW.type->handle_monadic_operator(&ARG_NOW, previous_op->handle);
// operation was something other than parentheses
expression->is_parenthesized = FALSE;
break;
case OPGROUP_DYADIC: // dyadic operators
if (ARG_PREV.flags & NUMBER_IS_FLOAT) {
float_handle_dyadic_operator(&ARG_PREV, previous_op->handle, &ARG_NOW);
} else {
int_handle_dyadic_operator(&ARG_PREV, previous_op->handle, &ARG_NOW);
}
ARG_PREV.type->handle_dyadic_operator(&ARG_PREV, previous_op->handle, &ARG_NOW);
// decrement argument stack pointer because dyadic operator merged two arguments into one
--arg_sp;
// operation was something other than parentheses
@ -1570,7 +1646,7 @@ static void try_to_reduce_stacks(struct expression *expression)
// this is what the exported functions call
static void parse_expression(struct expression *expression)
{
struct number *result = &expression->number;
struct object *result = &expression->result;
// init
expression->is_empty = TRUE; // becomes FALSE when first valid char gets parsed
@ -1619,27 +1695,27 @@ static void parse_expression(struct expression *expression)
// if there was nothing to parse, mark as undefined FIXME - change this! make "nothing" its own result type; only numbers may be undefined
// (so ALU_defined_int() can react)
if (expression->is_empty) {
result->flags &= ~NUMBER_IS_DEFINED;
result->type = &type_int;
result->u.number.flags = NUMBER_EVER_UNDEFINED; // ...and without NUMBER_IS_DEFINED!
result->u.number.val.intval = 0;
result->u.number.addr_refs = 0;
} else {
// not empty. undefined?
if (!(expression->number.flags & NUMBER_IS_DEFINED)) {
if (!(result->type->is_defined(result))) {
// then count (in all passes)
++pass.undefined_count;
}
}
// do some checks depending on int/float
if (result->flags & NUMBER_IS_FLOAT) {
float_fixresult(result);
} else {
int_fixresult(result);
}
result->type->fix_result(result);
} else {
// State is STATE_ERROR. Errors have already been reported,
// but we must make sure not to pass bogus data to caller.
// FIXME - just use the return value to indicate "there were errors, do not use result!"
result->flags = 0; // maybe set DEFINED flag to suppress follow-up errors?
result->val.intval = 0;
result->addr_refs = 0;
result->type = &type_int;
result->u.number.flags = 0; // maybe set DEFINED flag to suppress follow-up errors?
result->u.number.val.intval = 0;
result->u.number.addr_refs = 0;
// make sure no additional (spurious) errors are reported:
Input_skip_remainder();
// FIXME - remove this when new function interface gets used:
@ -1664,10 +1740,14 @@ intval_t ALU_any_int(void) // ACCEPT_UNDEFINED
Throw_error(exception_paren_open);
if (expression.is_empty)
Throw_error(exception_no_value);
if (expression.number.flags & NUMBER_IS_FLOAT)
return expression.number.val.fpval;
else
return expression.number.val.intval;
if (expression.result.type == &type_int)
return expression.result.u.number.val.intval;
if (expression.result.type == &type_float)
return expression.result.u.number.val.fpval;
Bug_found("Unhandled object type!", 0);
return 0; // inhibit compiler warning
}
@ -1685,15 +1765,20 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
pass.complain_about_undefined = TRUE;
parse_expression(&expression);
pass.complain_about_undefined = buf;
*intresult = expression.number;
if (expression.open_parentheses)
Throw_error(exception_paren_open);
if (expression.is_empty)
Throw_serious_error(exception_no_value);
if (!(intresult->flags & NUMBER_IS_DEFINED))
if (expression.result.type == &type_int) {
// ok
} else if (expression.result.type == &type_float) {
float_to_int(&expression.result);
} else {
Bug_found("Unhandled object type!", 1);
}
if (!(expression.result.u.number.flags & NUMBER_IS_DEFINED))
Throw_serious_error(exception_value_not_defined);
if (intresult->flags & NUMBER_IS_FLOAT)
float_to_int(intresult);
*intresult = expression.result.u.number;
}
@ -1709,8 +1794,10 @@ void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFI
{
parse_expression(expression);
// convert float to int
if (expression->number.flags & NUMBER_IS_FLOAT)
float_to_int(&(expression->number));
if (expression->result.type == &type_float)
float_to_int(&(expression->result));
if (expression->result.type != &type_int)
Bug_found("Unhandled object type!", 2);
if (expression->open_parentheses > paren) {
expression->open_parentheses = 0;
Throw_error(exception_paren_open);
@ -1726,12 +1813,12 @@ void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFI
// EMPTY: complain
// UNDEFINED: allow
// FLOAT: keep
void ALU_any_result(struct number *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT
void ALU_any_result(struct object *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT
{
struct expression expression;
parse_expression(&expression);
*result = expression.number;
*result = expression.result;
if (expression.open_parentheses)
Throw_error(exception_paren_open);
if (expression.is_empty)
@ -1754,7 +1841,7 @@ void ALU_addrmode_int(struct expression *expression, int paren)
when parsing addressing modes needvalue!
// stores value and flags (result may be either int or float)
void ALU_any_result(struct number *result)
void ALU_any_result(struct object *result)
macro.c
macro call, when parsing call-by-value arg don't care
pseudoopcodes.c

View File

@ -10,20 +10,27 @@
#include "config.h"
// types
/*
type_nothing, // needed?
type_int, type_float // what is returned by the current functions
type_string, // TODO
type_register, // reserved cpu constant (register names), TODO
type_list, // TODO
*/
enum op_handle;
struct dynabuf;
struct type {
//const char *name;
boolean (*is_defined)(struct object *self);
void (*handle_monadic_operator)(struct object *self, enum op_handle op);
void (*handle_dyadic_operator)(struct object *self, enum op_handle op, struct object *other);
void (*fix_result)(struct object *self);
void (*print)(struct object *self, struct dynabuf *db);
};
extern struct type type_int;
extern struct type type_float;
//extern struct type type_string;
//extern struct type type_list;
struct expression {
//struct type *type;
struct number number;
struct object result;
boolean is_empty; // nothing parsed (first character was a delimiter)
int open_parentheses; // number of parentheses still open
boolean is_parenthesized; // whole expression was in parentheses (indicating indirect addressing)
// TODO - how to return reserved cpu constant (register names)?
};
@ -41,7 +48,6 @@ struct expression {
// passes; because in the first pass there will almost for sure be
// labels that are undefined, we can't simply get the addressing mode
// from looking at the parameter's value.
#define NUMBER_IS_FLOAT (1u << 6) // floating point value
// create dynamic buffer, operator/function trees and operator/operand stacks
@ -67,7 +73,7 @@ extern void ALU_defined_int(struct number *intresult);
// stores int value and flags, allowing for "paren" '(' too many (x-indirect addr).
extern void ALU_addrmode_int(struct expression *expression, int paren);
// stores value and flags (result may be either int or float)
extern void ALU_any_result(struct number *result);
extern void ALU_any_result(struct object *result);
#endif

View File

@ -19,15 +19,25 @@ typedef enum { FALSE = 0, TRUE } boolean; // yes, I could include <stdbool.h>, b
typedef unsigned int scope_t;
typedef signed long intval_t; // at least 32 bits
typedef unsigned long uintval_t; // just for logical shift right
// result structure type definition with support for floating point
struct number { // either int or float
int flags; // result flags (see alu.h, one if these tells ints and floats apart)
// structure for ints/floats
struct number {
int flags; // DEFINED, FITS_IN_BYTE, etc. (see alu.h)
union {
intval_t intval; // integer value
double fpval; // floating point value
} val; // Expression value
} val;
int addr_refs; // address reference count (only look at this if value is DEFINED)
};
// structure for ints/floats/TODO...
struct type;
struct object {
struct type *type;
union {
struct number number;
// TODO - add string struct
} u;
};
// debugging flag, should be undefined in release version

View File

@ -43,7 +43,7 @@ void flow_forloop(struct for_loop *loop)
{
struct input loop_input,
*outer_input;
struct number loop_counter;
struct object loop_counter;
// switching input makes us lose GotByte. But we know it's '}' anyway!
// set up new input
@ -55,27 +55,28 @@ void flow_forloop(struct for_loop *loop)
// (not yet useable; pointer and line number are still missing)
Input_now = &loop_input;
// init counter
loop_counter.flags = NUMBER_IS_DEFINED;
loop_counter.val.intval = loop->counter.first;
loop_counter.addr_refs = loop->counter.addr_refs;
loop_counter.type = &type_int;
loop_counter.u.number.flags = NUMBER_IS_DEFINED;
loop_counter.u.number.val.intval = loop->counter.first;
loop_counter.u.number.addr_refs = loop->counter.addr_refs;
symbol_set_value(loop->symbol, &loop_counter, TRUE);
if (loop->use_old_algo) {
// old algo for old syntax:
// if count == 0, skip loop
if (loop->counter.last) {
do {
loop_counter.val.intval += loop->counter.increment;
loop_counter.u.number.val.intval += loop->counter.increment;
symbol_set_value(loop->symbol, &loop_counter, TRUE);
parse_ram_block(&loop->block);
} while (loop_counter.val.intval < loop->counter.last);
} while (loop_counter.u.number.val.intval < loop->counter.last);
}
} else {
// new algo for new syntax:
do {
parse_ram_block(&loop->block);
loop_counter.val.intval += loop->counter.increment;
loop_counter.u.number.val.intval += loop->counter.increment;
symbol_set_value(loop->symbol, &loop_counter, TRUE);
} while (loop_counter.val.intval != (loop->counter.last + loop->counter.increment));
} while (loop_counter.u.number.val.intval != (loop->counter.last + loop->counter.increment));
}
// restore previous input:
Input_now = outer_input;

View File

@ -42,7 +42,7 @@ struct macro {
// gives us the possibility to find out which args are call-by-value and
// which ones are call-by-reference.
union macro_arg_t {
struct number result; // value and flags (call by value)
struct object result; // value and flags (call by value)
struct symbol *symbol; // pointer to symbol struct (call by reference)
};

View File

@ -527,7 +527,7 @@ static void get_int_arg(struct number *result, boolean complain_about_indirect)
Throw_first_pass_warning("There are unneeded parentheses, you know indirect addressing is impossible here, right?"); // FIXME - rephrase!
}
}
*result = expression.number;
*result = expression.result.u.number;
}
@ -560,7 +560,7 @@ static int get_addr_mode(struct number *result)
break;
default:
ALU_addrmode_int(&expression, 1); // direct call instead of wrapper, to allow for "(...,"
*result = expression.number;
*result = expression.result.u.number;
typesystem_want_addr(result);
// check for indirect addressing
if (expression.is_parenthesized)

View File

@ -692,7 +692,7 @@ Throw_serious_error("Not yet"); // FIXME
// (re)set symbol
static enum eos po_set(void) // now GotByte = illegal char
{
struct number result;
struct object result;
int force_bit;
struct symbol *symbol;
scope_t scope;
@ -712,11 +712,16 @@ static enum eos po_set(void) // now GotByte = illegal char
GetByte(); // proceed with next char
ALU_any_result(&result);
// clear symbol's force bits and set new ones
symbol->result.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
if (force_bit) {
symbol->result.flags |= force_bit;
result.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
// (but only do this for numbers!)
if (((symbol->result.type == &type_int) || (symbol->result.type == &type_float))
&& ((result.type == &type_int) || (result.type == &type_float))) {
symbol->result.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
if (force_bit) {
symbol->result.u.number.flags |= force_bit;
result.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
}
}
// FIXME - take a good look at the flags handling above and in the fn called below and clean this up!
symbol_set_value(symbol, &result, TRUE);
return ENSURE_EOS;
}
@ -858,7 +863,7 @@ static boolean check_ifdef_condition(void)
// in first pass, count usage
if (FIRST_PASS)
symbol->usage++;
return !!(symbol->result.flags & NUMBER_IS_DEFINED);
return symbol->result.type->is_defined(&symbol->result);
}
// new if/ifdef/ifndef/else function, to be able to do ELSE IF
enum ifmode {
@ -998,7 +1003,7 @@ static enum eos ifdef_ifndef(boolean invert) // now GotByte = illegal char
// in first pass, count usage
if (FIRST_PASS)
symbol->usage++;
if (symbol->result.flags & NUMBER_IS_DEFINED)
if (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
defined = TRUE;
}
SKIPSPACE();
@ -1188,7 +1193,7 @@ static struct dynabuf *user_message; // dynamic buffer (!warn/error/serious)
// helper function to show user-defined messages
static enum eos throw_string(const char prefix[], void (*fn)(const char *))
{
struct number result;
struct object object;
DYNABUF_CLEAR(user_message);
DynaBuf_add_string(user_message, prefix);
@ -1207,31 +1212,8 @@ static enum eos throw_string(const char prefix[], void (*fn)(const char *))
GetByte();
} else {
// parse value
ALU_any_result(&result);
if (result.flags & NUMBER_IS_FLOAT) {
// floating point
if (result.flags & NUMBER_IS_DEFINED) {
char buffer[40];
// write up to 30 significant characters.
// remaining 10 should suffice for sign,
// decimal point, exponent, terminator etc.
sprintf(buffer, "%.30g", result.val.fpval);
DynaBuf_add_string(user_message, buffer);
} else {
DynaBuf_add_string(user_message, "<UNDEFINED FLOAT>");
}
} else {
// integer
if (result.flags & NUMBER_IS_DEFINED) {
char buffer[32]; // 11 for dec, 8 for hex
sprintf(buffer, "%ld (0x%lx)", (long) result.val.intval, (long) result.val.intval);
DynaBuf_add_string(user_message, buffer);
} else {
DynaBuf_add_string(user_message, "<UNDEFINED INT>");
}
}
ALU_any_result(&object);
object.type->print(&object, user_message);
}
} while (Input_accept_comma());
DynaBuf_append(user_message, '\0');

View File

@ -30,12 +30,17 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
{
struct symbol *symbol = node->body;
// if symbol is neither int nor float, skip
if ((symbol->result.type != &type_int)
&& (symbol->result.type != &type_float))
return;
// output name
if (config.warn_on_type_mismatch
&& symbol->result.addr_refs == 1)
&& symbol->result.u.number.addr_refs == 1)
fprintf(fd, "!addr");
fprintf(fd, "\t%s", node->id_string);
switch (symbol->result.flags & NUMBER_FORCEBITS) {
switch (symbol->result.u.number.flags & NUMBER_FORCEBITS) {
case NUMBER_FORCES_16:
fprintf(fd, "+2\t= ");
break;
@ -47,15 +52,17 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
default:
fprintf(fd, "\t= ");
}
if (symbol->result.flags & NUMBER_IS_DEFINED) {
if (symbol->result.flags & NUMBER_IS_FLOAT)
fprintf(fd, "%.30f", symbol->result.val.fpval); //FIXME %g
if (symbol->result.u.number.flags & NUMBER_IS_DEFINED) {
if (symbol->result.type == &type_int)
fprintf(fd, "$%x", (unsigned) symbol->result.u.number.val.intval);
else if (symbol->result.type == &type_float)
fprintf(fd, "%.30f", symbol->result.u.number.val.fpval); //FIXME %g
else
fprintf(fd, "$%x", (unsigned) symbol->result.val.intval);
Bug_found("BogusType", 0); // FIXME - put in docs!
} else {
fprintf(fd, " ?"); // TODO - maybe write "UNDEFINED" instead? then the file could at least be parsed without errors
}
if (symbol->result.flags & NUMBER_EVER_UNDEFINED)
if (symbol->result.u.number.flags & NUMBER_EVER_UNDEFINED)
fprintf(fd, "\t; ?"); // TODO - write "forward" instead?
if (symbol->usage == 0)
fprintf(fd, "\t; unused");
@ -69,10 +76,10 @@ static void dump_vice_address(struct rwnode *node, FILE *fd)
struct symbol *symbol = node->body;
// dump address symbols even if they are not used
if ((symbol->result.flags & NUMBER_IS_DEFINED)
&& !(symbol->result.flags & NUMBER_IS_FLOAT)
&& (symbol->result.addr_refs == 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.val.intval, node->id_string);
if ((symbol->result.type == &type_int)
&& (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
&& (symbol->result.u.number.addr_refs == 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.u.number.val.intval, node->id_string);
}
static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
{
@ -80,10 +87,10 @@ static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
// dump non-addresses that are used
if (symbol->usage
&& (symbol->result.flags & NUMBER_IS_DEFINED)
&& !(symbol->result.flags & NUMBER_IS_FLOAT)
&& (symbol->result.addr_refs != 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.val.intval, node->id_string);
&& (symbol->result.type == &type_int)
&& (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
&& (symbol->result.u.number.addr_refs != 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.u.number.val.intval, node->id_string);
}
static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
{
@ -91,10 +98,10 @@ static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
// dump non-addresses that are unused
if (!symbol->usage
&& (symbol->result.flags & NUMBER_IS_DEFINED)
&& !(symbol->result.flags & NUMBER_IS_FLOAT)
&& (symbol->result.addr_refs != 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.val.intval, node->id_string);
&& (symbol->result.type == &type_int)
&& (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
&& (symbol->result.u.number.addr_refs != 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.u.number.val.intval, node->id_string);
}
@ -105,7 +112,7 @@ struct symbol *symbol_find(scope_t scope, int flags)
struct rwnode *node;
struct symbol *symbol;
boolean node_created;
int force_bits = flags & NUMBER_FORCEBITS;
int new_force_bits;
node_created = Tree_hard_scan(&node, symbols_forest, scope, TRUE);
// if node has just been created, create symbol as well
@ -113,57 +120,75 @@ struct symbol *symbol_find(scope_t scope, int flags)
// create new symbol structure
symbol = safe_malloc(sizeof(*symbol));
// finish empty symbol item
symbol->result.flags = flags;
symbol->result.addr_refs = 0;
if (flags & NUMBER_IS_FLOAT)
symbol->result.val.fpval = 0;
else
symbol->result.val.intval = 0;
symbol->result.type = &type_int;
symbol->result.u.number.flags = flags;
symbol->result.u.number.addr_refs = 0;
symbol->result.u.number.val.intval = 0;
symbol->usage = 0; // usage count
symbol->pass = pass.number;
symbol->has_been_reported = FALSE;
node->body = symbol;
} else {
symbol = node->body;
// make sure the force bits don't clash
if ((symbol->result.type == &type_int)
|| (symbol->result.type == &type_float)) {
new_force_bits = flags & NUMBER_FORCEBITS;
if (new_force_bits)
if ((symbol->result.u.number.flags & NUMBER_FORCEBITS) != new_force_bits)
Throw_error("Too late for postfix.");
}
}
// make sure the force bits don't clash
if ((!node_created) && force_bits)
if ((symbol->result.flags & NUMBER_FORCEBITS) != force_bits)
Throw_error("Too late for postfix.");
return symbol;
}
// assign value to symbol. the function acts upon the symbol's flag bits and
// produces an error if needed.
void symbol_set_value(struct symbol *symbol, struct number *new_value, boolean change_allowed)
void symbol_set_value(struct symbol *symbol, struct object *new_value, boolean change_allowed)
{
int oldflags = symbol->result.flags;
int flags; // for int/float re-definitions
// any new type?
if (((symbol->result.type != &type_int) && (symbol->result.type != &type_float))
|| ((new_value->type != &type_int) && (new_value->type != &type_float))) {
// changing value is ok, changing type needs extra flag:
if (change_allowed || (symbol->result.type == new_value->type))
symbol->result = *new_value;
else
Throw_error("Symbol already defined.");
return;
}
// both old and new are either int or float, so keep old algo:
// value stuff
if ((oldflags & NUMBER_IS_DEFINED) && !change_allowed) {
// symbol is already defined, so compare new and old values
// if different type OR same type but different value, complain
if (((oldflags ^ new_value->flags) & NUMBER_IS_FLOAT)
|| ((oldflags & NUMBER_IS_FLOAT) ? (symbol->result.val.fpval != new_value->val.fpval) : (symbol->result.val.intval != new_value->val.intval)))
Throw_error("Symbol already defined.");
} else {
flags = symbol->result.u.number.flags;
if (change_allowed || !(flags & NUMBER_IS_DEFINED)) {
// symbol is not defined yet OR redefinitions are allowed
symbol->result = *new_value;
} else {
// symbol is already defined, so compare new and old values
// if different type OR same type but different value, complain
if ((symbol->result.type != new_value->type)
|| ((symbol->result.type == &type_float) ? (symbol->result.u.number.val.fpval != new_value->u.number.val.fpval) : (symbol->result.u.number.val.intval != new_value->u.number.val.intval)))
Throw_error("Symbol already defined.");
}
// flags stuff
// Ensure that "unsure" symbols without "isByte" state don't get that
if ((oldflags & (NUMBER_EVER_UNDEFINED | NUMBER_FITS_BYTE)) == NUMBER_EVER_UNDEFINED)
new_value->flags &= ~NUMBER_FITS_BYTE;
if ((flags & (NUMBER_EVER_UNDEFINED | NUMBER_FITS_BYTE)) == NUMBER_EVER_UNDEFINED)
new_value->u.number.flags &= ~NUMBER_FITS_BYTE;
if (change_allowed) {
oldflags = (oldflags & NUMBER_EVER_UNDEFINED) | new_value->flags;
// take flags from new value, then OR EVER_UNDEFINED from old value
flags = (flags & NUMBER_EVER_UNDEFINED) | new_value->u.number.flags;
} else {
if ((oldflags & NUMBER_FORCEBITS) == 0)
if ((oldflags & (NUMBER_EVER_UNDEFINED | NUMBER_IS_DEFINED)) == 0)
oldflags |= new_value->flags & NUMBER_FORCEBITS;
oldflags |= new_value->flags & ~NUMBER_FORCEBITS;
if ((flags & NUMBER_FORCEBITS) == 0)
if ((flags & (NUMBER_EVER_UNDEFINED | NUMBER_IS_DEFINED)) == 0) // FIXME - this can't happen!?
flags |= new_value->u.number.flags & NUMBER_FORCEBITS;
flags |= new_value->u.number.flags & ~NUMBER_FORCEBITS;
}
symbol->result.flags = oldflags;
symbol->result.u.number.flags = flags;
}
@ -171,8 +196,8 @@ void symbol_set_value(struct symbol *symbol, struct number *new_value, boolean c
// name must be held in GlobalDynaBuf.
void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed)
{
struct number pc,
result;
struct number pc;
struct object result;
struct symbol *symbol;
symbol = symbol_find(scope, force_bit);
@ -181,9 +206,10 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean chan
Throw_first_pass_warning("Label name not in leftmost column.");
vcpu_read_pc(&pc);
// FIXME - if undefined, check pass.complain_about_undefined and maybe throw "value not defined"!
result.flags = pc.flags & NUMBER_IS_DEFINED;
result.val.intval = pc.val.intval;
result.addr_refs = pc.addr_refs;
result.type = &type_int;
result.u.number.flags = pc.flags & NUMBER_IS_DEFINED;
result.u.number.val.intval = pc.val.intval;
result.u.number.addr_refs = pc.addr_refs;
symbol_set_value(symbol, &result, change_allowed);
// global labels must open new scope for cheap locals
if (scope == SCOPE_GLOBAL)
@ -195,7 +221,7 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean chan
// name must be held in GlobalDynaBuf.
void symbol_parse_definition(scope_t scope, int stat_flags)
{
struct number result;
struct object result;
struct symbol *symbol;
int force_bit = Input_get_force_bit(); // skips spaces after
// FIXME - force bit is allowed for label definitions?!
@ -207,11 +233,16 @@ void symbol_parse_definition(scope_t scope, int stat_flags)
GetByte(); // skip '='
ALU_any_result(&result);
// if wanted, mark as address reference
if (typesystem_says_address())
result.addr_refs = 1;
if (typesystem_says_address()) {
// FIXME - checking types explicitly is ugly...
if ((result.type == &type_int)
|| (result.type == &type_float))
result.u.number.addr_refs = 1;
}
symbol_set_value(symbol, &result, FALSE);
Input_ensure_EOS();
} else {
// implicit symbol definition (label)
symbol_set_label(scope, stat_flags, force_bit, FALSE);
}
}
@ -221,11 +252,12 @@ void symbol_parse_definition(scope_t scope, int stat_flags)
// Name must be held in GlobalDynaBuf.
void symbol_define(intval_t value)
{
struct number result;
struct object result;
struct symbol *symbol;
result.flags = NUMBER_IS_DEFINED;
result.val.intval = value;
result.type = &type_int;
result.u.number.flags = NUMBER_IS_DEFINED;
result.u.number.val.intval = value;
symbol = symbol_find(SCOPE_GLOBAL, 0);
symbol_set_value(symbol, &result, TRUE);
}
@ -257,7 +289,7 @@ void symbols_vicelabels(FILE *fd)
// references the *next* anonymous forward label definition. The tricky bit is,
// each name length would need its own counter. But hey, ACME's real quick in
// finding symbols, so I'll just abuse the symbol system to store those counters.
void symbol_fix_forward_anon_name(int increment)
void symbol_fix_forward_anon_name(boolean increment)
{
struct symbol *counter_symbol;
unsigned long number;
@ -265,12 +297,15 @@ void symbol_fix_forward_anon_name(int increment)
// terminate name, find "counter" symbol and read value
DynaBuf_append(GlobalDynaBuf, '\0');
counter_symbol = symbol_find(section_now->local_scope, 0);
// sanity check: it must be an int!
if (counter_symbol->result.type != &type_int)
Bug_found("ForwardAnonCounterNotInt", 0);
// make sure it gets reset to zero in each new pass
if (counter_symbol->pass != pass.number) {
counter_symbol->pass = pass.number;
counter_symbol->result.val.intval = 0;
counter_symbol->result.u.number.val.intval = 0;
}
number = (unsigned long) counter_symbol->result.val.intval;
number = (unsigned long) counter_symbol->result.u.number.val.intval;
// now append to the name to make it unique
GlobalDynaBuf->size--; // forget terminator, we want to append
do {
@ -279,5 +314,5 @@ void symbol_fix_forward_anon_name(int increment)
} while (number);
DynaBuf_append(GlobalDynaBuf, '\0');
if (increment)
counter_symbol->result.val.intval++;
counter_symbol->result.u.number.val.intval++;
}

View File

@ -12,7 +12,7 @@
struct symbol {
struct number result; // flags, value, address refs
struct object result; // flags, value, address refs
int usage; // usage count
int pass; // pass of creation (for anon counters)
boolean has_been_reported; // indicates "has been reported as undefined"
@ -29,7 +29,8 @@ extern struct rwnode *symbols_forest[]; // trees (because of 8-bit hash)
// function acts upon the symbol's flag bits and produces an error if needed.
extern void symbol_set_value(struct symbol *symbol, struct number *new_value, boolean change_allowed);
// FIXME - rename to symbol_set_object!
extern void symbol_set_value(struct symbol *symbol, struct object *new_value, boolean change_allowed);
// parse label definition (can be either global or local).
// name must be held in GlobalDynaBuf.
extern void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed);
@ -48,7 +49,7 @@ extern void symbols_list(FILE *fd);
extern void symbols_vicelabels(FILE *fd);
// fix name of anonymous forward label (held in GlobalDynaBuf, NOT TERMINATED!)
// so it references the *next* anonymous forward label definition.
extern void symbol_fix_forward_anon_name(int increment);
extern void symbol_fix_forward_anon_name(boolean increment);
#endif

View File

@ -9,7 +9,7 @@
#define RELEASE "0.96.5" // update before release FIXME
#define CODENAME "Fenchurch" // update before release
#define CHANGE_DATE "12 May" // update before release FIXME
#define CHANGE_DATE "14 May" // update before release FIXME
#define CHANGE_YEAR "2020" // update before release
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME