got rid of DEFINED flag by making UNDEFINED its own number type

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@235 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2020-06-16 22:44:54 +00:00
parent 929fefe0e6
commit f9a2f5f698
11 changed files with 372 additions and 243 deletions

487
src/alu.c
View File

@ -219,14 +219,16 @@ do { \
#define PUSH_INT_ARG(i, f, r) \
do { \
arg_stack[arg_sp].type = &type_int; \
arg_stack[arg_sp].type = &type_number; \
arg_stack[arg_sp].u.number.ntype = NUMTYPE_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].type = &type_float; \
arg_stack[arg_sp].type = &type_number; \
arg_stack[arg_sp].u.number.ntype = NUMTYPE_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; \
@ -354,20 +356,21 @@ static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t na
symbol = symbol_find(scope);
symbol->has_been_read = TRUE;
if (symbol->object.type == NULL) {
// finish symbol item by making it an undefined int
symbol->object.type = &type_int;
// finish symbol item by making it an undefined number
symbol->object.type = &type_number;
symbol->object.u.number.ntype = NUMTYPE_UNDEFINED;
symbol->object.u.number.flags = NUMBER_EVER_UNDEFINED; // reading undefined taints it
symbol->object.u.number.addr_refs = 0;
symbol->object.u.number.val.intval = 0;
} else {
// FIXME - add sanity check for int/float where DEFINED is false and EVER_UNDEFINED is false -> Bug_found()!
// (because the only way to have DEFINED clear is the block above, and EVER_UNDEFINED taints everything it touches)
// FIXME - add sanity check for UNDEFINED where EVER_UNDEFINED is false -> Bug_found()!
// (because the only way to have UNDEFINED is the block above, and EVER_UNDEFINED taints everything it touches)
}
// first push on arg stack, so we have a local copy we can "unpseudopc"
arg = &arg_stack[arg_sp++];
*arg = symbol->object;
if (unpseudo_count) {
if (arg->type == &type_int) {
if (arg->type == &type_number) {
pseudopc_unpseudo(&arg->u.number, symbol->pseudopc, unpseudo_count);
// TODO - check return value and enter error state if nonzero?
} else {
@ -391,9 +394,9 @@ static void parse_program_counter(void) // Now GotByte = "*"
GetByte();
vcpu_read_pc(&pc);
// if needed, output "value not defined" error
if (!(pc.flags & NUMBER_IS_DEFINED))
if (pc.ntype == NUMTYPE_UNDEFINED)
is_not_defined(NULL, 0, "*", 1);
PUSH_INT_ARG(pc.val.intval, pc.flags, pc.addr_refs);
PUSH_INT_ARG(pc.val.intval, pc.flags, pc.addr_refs); // FIXME - when undefined pc is allowed, this must be changed for numtype!
}
@ -443,13 +446,13 @@ static void parse_quoted(char closing_quote)
Throw_error("There's more than one character.");
// parse character
value = (intval_t) (unsigned char) encoding_encode_char(GLOBALDYNABUF_CURRENT[0]);
PUSH_INT_ARG(value, NUMBER_IS_DEFINED | NUMBER_FITS_BYTE, 0); // FIXME - why set FITS_BYTE? it's only really useful for undefined values!
PUSH_INT_ARG(value, NUMBER_FITS_BYTE, 0); // FIXME - why set FITS_BYTE? it's only really useful for undefined values!
}
// Now GotByte = char following closing quote (or CHAR_EOS on error)
return;
fail:
PUSH_INT_ARG(0, NUMBER_IS_DEFINED | NUMBER_FITS_BYTE, 0); // dummy
PUSH_INT_ARG(0, NUMBER_FITS_BYTE, 0); // dummy
alu_state = STATE_ERROR;
}
@ -460,7 +463,7 @@ fail:
static void parse_binary_literal(void) // Now GotByte = "%" or "b"
{
intval_t value = 0;
bits flags = NUMBER_IS_DEFINED;
bits flags = 0;
int digits = -1; // digit counter
for (;;) {
@ -503,7 +506,7 @@ static void parse_hex_literal(void) // Now GotByte = "$" or "x"
{
char byte;
int digits = -1; // digit counter
bits flags = NUMBER_IS_DEFINED;
bits flags = 0;
intval_t value = 0;
for (;;) {
@ -556,7 +559,7 @@ static void parse_frac_part(int integer_part) // Now GotByte = first digit after
GetByte();
}
// FIXME - add possibility to read 'e' and exponent!
PUSH_FP_ARG(fpval / denominator, NUMBER_IS_DEFINED);
PUSH_FP_ARG(fpval / denominator, 0);
}
@ -601,7 +604,7 @@ static void parse_number_literal(void) // Now GotByte = first digit
GetByte();
parse_frac_part(intval);
} else {
PUSH_INT_ARG(intval, NUMBER_IS_DEFINED, 0);
PUSH_INT_ARG(intval, 0, 0);
}
// Now GotByte = non-decimal char
}
@ -612,7 +615,7 @@ static void parse_number_literal(void) // Now GotByte = first digit
static void parse_octal_literal(void) // Now GotByte = first octal digit
{
intval_t value = 0;
bits flags = NUMBER_IS_DEFINED;
bits flags = 0;
int digits = 0; // digit counter
while ((GotByte >= '0') && (GotByte <= '7')) {
@ -908,7 +911,7 @@ static boolean expect_argument_or_monadic_operator(void)
// illegal character read - so don't go on
// we found end-of-expression instead of an argument,
// that's either an empty expression or an erroneous one!
PUSH_INT_ARG(0, 0, 0); // push dummy argument so stack checking code won't bark
PUSH_INT_ARG(0, 0, 0); // push dummy argument so stack checking code won't bark FIXME - use undefined?
if (op_stack[op_sp - 1] == &ops_start_expression) {
PUSH_OP(&ops_end_expression);
alu_state = STATE_TRY_TO_REDUCE_STACKS;
@ -1126,8 +1129,9 @@ static void unsupported_operation(const struct object *optional, const struct op
// create byte-sized int object (for comparison results, converted characters, ...)
static void int_create_byte(struct object *self, intval_t byte)
{
self->type = &type_int;
self->u.number.flags = NUMBER_IS_DEFINED | NUMBER_FITS_BYTE; // FIXME - if DEFINED anyway, what use is there for FITS_BYTE?
self->type = &type_number;
self->u.number.ntype = NUMTYPE_INT;
self->u.number.flags = NUMBER_FITS_BYTE; // FIXME - if DEFINED anyway, what use is there for FITS_BYTE?
self->u.number.val.intval = byte;
self->u.number.addr_refs = 0;
}
@ -1136,7 +1140,7 @@ static void int_create_byte(struct object *self, intval_t byte)
// convert to float
inline static void int_to_float(struct object *self)
{
self->type = &type_float;
self->u.number.ntype = NUMTYPE_FLOAT;
self->u.number.val.fpval = self->u.number.val.intval;
}
@ -1144,7 +1148,7 @@ inline static void int_to_float(struct object *self)
// convert to int
inline static void float_to_int(struct object *self)
{
self->type = &type_int;
self->u.number.ntype = NUMTYPE_INT;
self->u.number.val.intval = self->u.number.val.fpval;
}
@ -1152,7 +1156,7 @@ inline static void float_to_int(struct object *self)
// return DEFINED flag
static boolean number_is_defined(const struct object *self)
{
return !!(self->u.number.flags & NUMBER_IS_DEFINED);
return self->u.number.ntype != NUMTYPE_UNDEFINED;
}
// list/string:
@ -1165,24 +1169,24 @@ static boolean object_return_true(const struct object *self)
// int/float:
// helper function to check two values for equality
// in case of undefined value(s), "fallback" is returned
static inline boolean num_different(const struct object *self, const struct object *other, boolean fallback)
static inline boolean num_different(const struct number *self, const struct number *other, boolean fallback)
{
if ((self->u.number.flags & NUMBER_IS_DEFINED) == 0)
if (self->ntype == NUMTYPE_UNDEFINED)
return fallback;
if ((other->u.number.flags & NUMBER_IS_DEFINED) == 0)
if (other->ntype == NUMTYPE_UNDEFINED)
return fallback;
if (self->type == &type_int) {
if (other->type == &type_int)
return self->u.number.val.intval != other->u.number.val.intval;
if (self->ntype == NUMTYPE_INT) {
if (other->ntype == NUMTYPE_INT)
return self->val.intval != other->val.intval;
else
return self->u.number.val.intval != other->u.number.val.fpval;
return self->val.intval != other->val.fpval;
} else {
if (other->type == &type_int)
return self->u.number.val.fpval != other->u.number.val.intval;
if (other->ntype == NUMTYPE_INT)
return self->val.fpval != other->val.intval;
else
return self->u.number.val.fpval != other->u.number.val.fpval;
return self->val.fpval != other->val.fpval;
}
}
@ -1198,18 +1202,19 @@ static void number_assign(struct object *self, const struct object *new_value, b
// accepting a different value is easily done by just forgetting the old one:
if (accept_change) {
own_flags &= ~(NUMBER_IS_DEFINED | NUMBER_FITS_BYTE);
self->u.number.ntype = NUMTYPE_UNDEFINED;
own_flags &= ~(NUMBER_FITS_BYTE);
}
// copy struct over?
if (!(own_flags & NUMBER_IS_DEFINED)) {
if (self->u.number.ntype == NUMTYPE_UNDEFINED) {
// symbol is undefined OR redefinitions are allowed, so use new value:
*self = *new_value; // copy type and flags/value/addr_refs
// flags will be fixed, see below
} else {
// symbol is already defined, so compare new and old values
// if values differ, complain and return
if (num_different(self, new_value, FALSE)) {
if (num_different(&self->u.number, &new_value->u.number, FALSE)) {
Throw_error(exception_symbol_defined);
return;
}
@ -1227,7 +1232,7 @@ static void number_assign(struct object *self, const struct object *new_value, b
// (any hypothetical problems about "new value is later found out to
// _not_ fit byte" would be detected when assigning a different value
// raises an error in a later pass)
own_flags |= other_flags & (NUMBER_FITS_BYTE | NUMBER_IS_DEFINED | NUMBER_EVER_UNDEFINED);
own_flags |= other_flags & (NUMBER_FITS_BYTE | NUMBER_EVER_UNDEFINED);
self->u.number.flags = own_flags;
}
@ -1275,6 +1280,50 @@ static void warn_float_to_int(void)
Throw_first_pass_warning("Converted to integer for binary logic operator.");
}
// undefined:
// handle monadic operator (includes functions)
static void undef_handle_monadic_operator(struct object *self, const struct op *op)
{
switch (op->id) {
case OPID_ADDRESS:
self->u.number.addr_refs = 1; // result now is an address
break;
case OPID_INT:
case OPID_FLOAT:
self->u.number.addr_refs = 0;
break;
case OPID_SIN:
case OPID_COS:
case OPID_TAN:
case OPID_ARCSIN:
case OPID_ARCCOS:
case OPID_ARCTAN:
self->u.number.flags &= ~NUMBER_FITS_BYTE;
self->u.number.addr_refs = 0;
break;
case OPID_NOT:
case OPID_NEGATE:
self->u.number.flags &= ~NUMBER_FITS_BYTE;
self->u.number.addr_refs = -(self->u.number.addr_refs); // negate address ref count
break;
case OPID_LOWBYTEOF:
case OPID_HIGHBYTEOF:
case OPID_BANKBYTEOF:
self->u.number.flags |= NUMBER_FITS_BYTE;
self->u.number.flags &= ~NUMBER_FORCEBITS;
self->u.number.addr_refs = 0;
break;
// add new monadic operators here
// case OPID_:
// break;
default:
unsupported_operation(NULL, op, self);
}
self->u.number.val.intval = 0; // FIXME - should not be needed...
}
// prototype for int/float passing
static void float_handle_monadic_operator(struct object *self, const struct op *op);
// int:
// handle monadic operator (includes functions)
static void int_handle_monadic_operator(struct object *self, const struct op *op)
@ -1298,7 +1347,7 @@ static void int_handle_monadic_operator(struct object *self, const struct op *op
case OPID_ARCTAN:
// convert int to fp and ask fp handler to do the work
int_to_float(self);
type_float.monadic_op(self, op); // TODO - put recursion check around this?
float_handle_monadic_operator(self, op); // TODO - put recursion check around this?
return; // float handler has done everything
case OPID_NOT:
@ -1343,8 +1392,7 @@ static void float_ranged_fn(double (*fn)(double), struct object *self)
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->u.number.flags & NUMBER_IS_DEFINED)
Throw_error("Argument out of range."); // TODO - add number output to error message
Throw_error("Argument out of range."); // TODO - add number output to error message
self->u.number.val.fpval = 0;
}
}
@ -1399,7 +1447,7 @@ static void float_handle_monadic_operator(struct object *self, const struct op *
case OPID_BANKBYTEOF:
// convert fp to int and ask int handler to do the work
float_to_int(self);
type_int.monadic_op(self, op); // TODO - put recursion check around this?
int_handle_monadic_operator(self, op); // TODO - put recursion check around this?
return; // int handler has done everything
// add new monadic operators here
@ -1411,6 +1459,25 @@ static void float_handle_monadic_operator(struct object *self, const struct op *
self->u.number.addr_refs = refs; // update address refs with local copy
}
// num:
// handle monadic operator (includes functions)
static void number_handle_monadic_operator(struct object *self, const struct op *op)
{
switch (self->u.number.ntype) {
case NUMTYPE_UNDEFINED:
undef_handle_monadic_operator(self, op);
break;
case NUMTYPE_INT:
int_handle_monadic_operator(self, op);
break;
case NUMTYPE_FLOAT:
float_handle_monadic_operator(self, op);
break;
default:
Bug_found("IllegalNumberType1", self->u.number.ntype); // FIXME - add to docs!
}
}
// list:
// handle monadic operator (includes functions)
static void list_handle_monadic_operator(struct object *self, const struct op *op)
@ -1420,8 +1487,9 @@ static void list_handle_monadic_operator(struct object *self, const struct op *o
if (op->id == OPID_LEN) {
length = self->u.listhead->length;
self->u.listhead->refs--; // FIXME - call some list_decrement_refs() instead...
self->type = &type_int;
self->u.number.flags = NUMBER_IS_DEFINED;
self->type = &type_number;
self->u.number.ntype = NUMTYPE_INT;
self->u.number.flags = 0;
self->u.number.val.intval = length;
self->u.number.addr_refs = 0;
} else {
@ -1438,8 +1506,9 @@ static void string_handle_monadic_operator(struct object *self, const struct op
if (op->id == OPID_LEN) {
length = self->u.string->length;
self->u.string->refs--; // FIXME - call some string_decrement_refs() instead...
self->type = &type_int;
self->u.number.flags = NUMBER_IS_DEFINED;
self->type = &type_number;
self->u.number.ntype = NUMTYPE_INT;
self->u.number.flags = 0;
self->u.number.val.intval = length;
self->u.number.addr_refs = 0;
} else {
@ -1450,28 +1519,87 @@ static void string_handle_monadic_operator(struct object *self, const struct op
// int/float:
// merge result flags
// (used by both int and float handlers for comparison operators)
static void number_fix_result_after_comparison(struct object *self, const struct object *other, intval_t result)
static void intfloat_fix_result_after_comparison(struct object *self, const struct object *other, intval_t result)
{
bits flags;
self->type = &type_int;
self->type = &type_number;
self->u.number.ntype = NUMTYPE_INT;
self->u.number.val.intval = result;
self->u.number.addr_refs = 0;
flags = (self->u.number.flags & other->u.number.flags) & NUMBER_IS_DEFINED; // DEFINED flags are ANDed together
flags |= (self->u.number.flags | other->u.number.flags) & NUMBER_EVER_UNDEFINED; // EVER_UNDEFINED flags are ORd together
flags = (self->u.number.flags | other->u.number.flags) & NUMBER_EVER_UNDEFINED; // EVER_UNDEFINED flags are ORd together
flags |= NUMBER_FITS_BYTE; // FITS_BYTE gets set
// (FORCEBITS are cleared)
self->u.number.flags = flags;
}
// (used by both int and float handlers for all other dyadic operators)
static void number_fix_result_after_dyadic(struct object *self, const struct object *other)
static void intfloat_fix_result_after_dyadic(struct object *self, const struct object *other)
{
self->u.number.flags |= other->u.number.flags & (NUMBER_EVER_UNDEFINED | NUMBER_FORCEBITS); // EVER_UNDEFINED and FORCEBITs are ORd together
self->u.number.flags &= (other->u.number.flags | ~NUMBER_IS_DEFINED); // DEFINED flags are ANDed together
self->u.number.flags &= ~NUMBER_FITS_BYTE; // FITS_BYTE is cleared
}
// undefined/int/float:
// handle dyadic operator
// (both args are numbers, but at least one of them is undefined!)
static void undef_handle_dyadic_operator(struct object *self, const struct op *op, struct object *other)
{
int refs = 0; // default for "addr_refs", shortens this fn
switch (op->id) {
case OPID_POWEROF:
case OPID_MULTIPLY:
case OPID_DIVIDE:
case OPID_INTDIV:
case OPID_MODULO:
case OPID_SHIFTLEFT:
case OPID_ASR:
case OPID_LSR:
break;
case OPID_SUBTRACT:
refs = self->u.number.addr_refs - other->u.number.addr_refs; // subtract address references
break;
case OPID_LESSOREQUAL:
case OPID_LESSTHAN:
case OPID_GREATEROREQUAL:
case OPID_GREATERTHAN:
case OPID_NOTEQUAL:
case OPID_EQUALS:
// only for comparisons:
self->u.number.flags |= NUMBER_FITS_BYTE; // FITS_BYTE gets set
self->u.number.flags &= ~NUMBER_FORCEBITS; // FORCEBITS are cleared
goto shared;
case OPID_EOR:
Throw_first_pass_warning("\"EOR\" is deprecated; use \"XOR\" instead.");
/*FALLTHROUGH*/
case OPID_XOR:
case OPID_AND:
case OPID_OR:
case OPID_ADD:
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
break;
// add new dyadic operators here
// case OPID_:
// break;
default:
unsupported_operation(self, op, other);
return;
}
// CAUTION: comparisons goto label below instead of jumping here
self->u.number.flags |= (other->u.number.flags & NUMBER_FORCEBITS); // FORCEBITs are ORd together
self->u.number.flags &= ~NUMBER_FITS_BYTE; // FITS_BYTE is cleared
shared:
self->u.number.flags |= (other->u.number.flags & NUMBER_EVER_UNDEFINED); // EVER_UNDEFINED flags are ORd together
self->u.number.ntype = NUMTYPE_UNDEFINED;
self->u.number.val.intval = 0; // FIXME - should not be needed...
self->u.number.addr_refs = refs; // update address refs with local copy
}
// prototype for int/float passing
static void float_handle_dyadic_operator(struct object *self, const struct op *op, struct object *other);
// int:
// handle dyadic operator
static void int_handle_dyadic_operator(struct object *self, const struct op *op, struct object *other)
@ -1479,9 +1607,9 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
int refs = 0; // default for "addr_refs", shortens this fn
// first check type of second arg:
if (other->type == &type_int) {
if (other->u.number.ntype == NUMTYPE_INT) {
// ok
} else if (other->type == &type_float) {
} else if (other->u.number.ntype == NUMTYPE_FLOAT) {
// handle according to operation
switch (op->id) {
case OPID_POWEROF:
@ -1498,23 +1626,22 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
case OPID_NOTEQUAL:
// become float, delegate to float handler
int_to_float(self);
type_float.dyadic_op(self, op, other); // TODO - put recursion check around this?
float_handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
return; // float handler has done everything
case OPID_MODULO:
case OPID_SHIFTLEFT:
case OPID_ASR:
// convert other to int
float_to_int(other);
break;
case OPID_LSR:
case OPID_AND:
case OPID_OR:
case OPID_EOR:
case OPID_XOR:
// convert other to int, warning user
float_to_int(other);
warn_float_to_int();
/*FALLTHROUGH*/
case OPID_MODULO:
case OPID_SHIFTLEFT:
case OPID_ASR:
// convert other to int
float_to_int(other);
break;
// add new dyadic operators here:
// case OPID_:
@ -1524,7 +1651,7 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
return;
}
// add new types here:
// } else if (other->type == &type_) {
// } else if (other->u.number.ntype == NUMTYPE_) {
// ...
} else {
unsupported_operation(self, op, other);
@ -1532,7 +1659,7 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
}
// maybe put this into an extra "int_dyadic_int" function?
// sanity check, now "other" must be an int
if (other->type != &type_int)
if (other->u.number.ntype != NUMTYPE_INT)
Bug_found("SecondArgIsNotAnInt", op->id);
// part 2: now we got rid of non-ints, perform actual operation:
@ -1541,8 +1668,7 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
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->u.number.flags & NUMBER_IS_DEFINED)
Throw_error("Exponent is negative.");
Throw_error("Exponent is negative.");
self->u.number.val.intval = 0;
}
break;
@ -1561,8 +1687,7 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
if (other->u.number.val.intval) {
self->u.number.val.intval %= other->u.number.val.intval;
} else {
if (other->u.number.flags & NUMBER_IS_DEFINED)
Throw_error(exception_div_by_zero);
Throw_error(exception_div_by_zero);
self->u.number.val.intval = 0;
}
break;
@ -1584,17 +1709,17 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
self->u.number.val.intval = ((uintval_t) (self->u.number.val.intval)) >> other->u.number.val.intval;
break;
case OPID_LESSOREQUAL:
return number_fix_result_after_comparison(self, other, self->u.number.val.intval <= other->u.number.val.intval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.intval <= other->u.number.val.intval);
case OPID_LESSTHAN:
return number_fix_result_after_comparison(self, other, self->u.number.val.intval < other->u.number.val.intval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.intval < other->u.number.val.intval);
case OPID_GREATEROREQUAL:
return number_fix_result_after_comparison(self, other, self->u.number.val.intval >= other->u.number.val.intval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.intval >= other->u.number.val.intval);
case OPID_GREATERTHAN:
return number_fix_result_after_comparison(self, other, self->u.number.val.intval > other->u.number.val.intval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.intval > other->u.number.val.intval);
case OPID_NOTEQUAL:
return number_fix_result_after_comparison(self, other, self->u.number.val.intval != other->u.number.val.intval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.intval != other->u.number.val.intval);
case OPID_EQUALS:
return number_fix_result_after_comparison(self, other, self->u.number.val.intval == other->u.number.val.intval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.intval == other->u.number.val.intval);
case OPID_AND:
self->u.number.val.intval &= other->u.number.val.intval;
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
@ -1617,9 +1742,9 @@ static void int_handle_dyadic_operator(struct object *self, const struct op *op,
unsupported_operation(self, op, other);
return;
}
// CAUTION: comparisons call number_fix_result_after_comparison instead of jumping here
// CAUTION: comparisons call intfloat_fix_result_after_comparison instead of jumping here
self->u.number.addr_refs = refs; // update address refs with local copy
number_fix_result_after_dyadic(self, other); // fix result flags
intfloat_fix_result_after_dyadic(self, other); // fix result flags
}
// float:
@ -1629,9 +1754,9 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
int refs = 0; // default for "addr_refs", shortens this fn
// first check type of second arg:
if (other->type == &type_float) {
if (other->u.number.ntype == NUMTYPE_FLOAT) {
// ok
} else if (other->type == &type_int) {
} else if (other->u.number.ntype == NUMTYPE_INT) {
// handle according to operation
switch (op->id) {
// these want two floats
@ -1669,7 +1794,7 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
return;
}
// add new types here
// } else if (other->type == &type_) {
// } else if (other->u.number.ntype == NUMTYPE_) {
// ...
} else {
unsupported_operation(self, op, other);
@ -1687,8 +1812,7 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
if (other->u.number.val.fpval) {
self->u.number.val.fpval /= other->u.number.val.fpval;
} else {
if (other->u.number.flags & NUMBER_IS_DEFINED)
Throw_error(exception_div_by_zero);
Throw_error(exception_div_by_zero);
self->u.number.val.fpval = 0;
}
break;
@ -1696,11 +1820,10 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
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->u.number.flags & NUMBER_IS_DEFINED)
Throw_error(exception_div_by_zero);
Throw_error(exception_div_by_zero);
self->u.number.val.intval = 0;
}
self->type = &type_int; // result is int
self->u.number.ntype = NUMTYPE_INT; // result is int
break;
case OPID_LSR:
case OPID_AND:
@ -1712,7 +1835,7 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
case OPID_MODULO:
float_to_int(self);
// int handler will check other and, if needed, convert to int
type_int.dyadic_op(self, op, other); // TODO - put recursion check around this?
int_handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
return; // int handler has done everything
case OPID_ADD:
@ -1724,27 +1847,27 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
refs = self->u.number.addr_refs - other->u.number.addr_refs; // subtract address references
break;
case OPID_SHIFTLEFT:
if (other->type == &type_float)
if (other->u.number.ntype == NUMTYPE_FLOAT)
float_to_int(other);
self->u.number.val.fpval *= pow(2.0, other->u.number.val.intval);
break;
case OPID_ASR:
if (other->type == &type_float)
if (other->u.number.ntype == NUMTYPE_FLOAT)
float_to_int(other);
self->u.number.val.fpval /= (1 << other->u.number.val.intval); // FIXME - why not use pow() as in SL above?
break;
case OPID_LESSOREQUAL:
return number_fix_result_after_comparison(self, other, self->u.number.val.fpval <= other->u.number.val.fpval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.fpval <= other->u.number.val.fpval);
case OPID_LESSTHAN:
return number_fix_result_after_comparison(self, other, self->u.number.val.fpval < other->u.number.val.fpval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.fpval < other->u.number.val.fpval);
case OPID_GREATEROREQUAL:
return number_fix_result_after_comparison(self, other, self->u.number.val.fpval >= other->u.number.val.fpval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.fpval >= other->u.number.val.fpval);
case OPID_GREATERTHAN:
return number_fix_result_after_comparison(self, other, self->u.number.val.fpval > other->u.number.val.fpval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.fpval > other->u.number.val.fpval);
case OPID_NOTEQUAL:
return number_fix_result_after_comparison(self, other, self->u.number.val.fpval != other->u.number.val.fpval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.fpval != other->u.number.val.fpval);
case OPID_EQUALS:
return number_fix_result_after_comparison(self, other, self->u.number.val.fpval == other->u.number.val.fpval);
return intfloat_fix_result_after_comparison(self, other, self->u.number.val.fpval == other->u.number.val.fpval);
// add new dyadic operators here
// case OPID_:
// break;
@ -1752,9 +1875,30 @@ static void float_handle_dyadic_operator(struct object *self, const struct op *o
unsupported_operation(self, op, other);
return;
}
// CAUTION: comparisons call number_fix_result_after_comparison instead of jumping here
// CAUTION: comparisons call intfloat_fix_result_after_comparison instead of jumping here
self->u.number.addr_refs = refs; // update address refs with local copy
number_fix_result_after_dyadic(self, other); // fix result flags
intfloat_fix_result_after_dyadic(self, other); // fix result flags
}
// num:
// handle dyadic operator
static void number_handle_dyadic_operator(struct object *self, const struct op *op, struct object *other)
{
// first check type of second arg:
if (other->type != &type_number) {
unsupported_operation(self, op, other);
return;
}
if ((self->u.number.ntype == NUMTYPE_UNDEFINED)
|| (other->u.number.ntype == NUMTYPE_UNDEFINED))
undef_handle_dyadic_operator(self, op, other);
else if (self->u.number.ntype == NUMTYPE_INT)
int_handle_dyadic_operator(self, op, other);
else if (self->u.number.ntype == NUMTYPE_FLOAT)
float_handle_dyadic_operator(self, op, other);
else
Bug_found("IllegalNumberType2", self->u.number.ntype); // FIXME - add to docs!
}
@ -1764,16 +1908,19 @@ static int get_valid_index(int *target, int length, const struct object *self, c
{
int index;
if (other->type == &type_float)
float_to_int(other);
if (other->type != &type_int) {
if (other->type != &type_number) {
unsupported_operation(self, op, other);
return 1;
}
if (!(other->u.number.flags & NUMBER_IS_DEFINED)) {
if (other->u.number.ntype == NUMTYPE_UNDEFINED) {
Throw_error("Index is undefined.");
return 1;
}
if (other->u.number.ntype == NUMTYPE_FLOAT)
float_to_int(other);
if (other->u.number.ntype != NUMTYPE_INT)
Bug_found("IllegalNumberType3", other->u.number.ntype); // FIXME - add to docs!
index = other->u.number.val.intval;
// negative indices access from the end
if (index < 0)
@ -1900,36 +2047,24 @@ static void number_fix_result(struct object *self)
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;
if (self->u.number.ntype == NUMTYPE_UNDEFINED) {
self->u.number.val.intval = 0; // FIXME - should not be needed!
} else if (self->u.number.ntype == NUMTYPE_INT) {
// if value is sure, check to set FITS BYTE
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; // FIXME - what for? isn't this flag only of use when undefined?
} else if (self->u.number.ntype == NUMTYPE_FLOAT) {
// if value is sure, check to set FITS BYTE
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; // FIXME - what for? isn't this flag only of use when undefined?
} else {
Bug_found("IllegalNumberType4", self->u.number.ntype); // FIXME - add to docs!
}
}
// list/string:
@ -1938,34 +2073,25 @@ static void object_no_op(struct object *self)
{
}
// int:
// int/float:
// print value for user message
static void int_print(const struct object *self, struct dynabuf *db)
static void number_print(const struct object *self, struct dynabuf *db)
{
char buffer[32]; // 11 for dec, 8 for hex
char buffer[40]; // large enough(tm)
if (self->u.number.flags & NUMBER_IS_DEFINED) {
if (self->u.number.ntype == NUMTYPE_UNDEFINED) {
DynaBuf_add_string(db, "<UNDEFINED NUMBER>");
} else if (self->u.number.ntype == NUMTYPE_INT) {
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(const struct object *self, struct dynabuf *db)
{
char buffer[40];
if (self->u.number.flags & NUMBER_IS_DEFINED) {
} else if (self->u.number.ntype == NUMTYPE_FLOAT) {
// 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>");
Bug_found("IllegalNumberType5", self->u.number.ntype); // FIXME - add to docs!
}
}
@ -1998,23 +2124,14 @@ static void string_print(const struct object *self, struct dynabuf *db)
DynaBuf_add_string(db, self->u.string->payload); // there is a terminator after the actual payload, so this works
}
struct type type_int = {
"integer",
struct type type_number = {
"number",
number_is_defined,
number_assign,
int_handle_monadic_operator,
int_handle_dyadic_operator,
int_fix_result,
int_print
};
struct type type_float = {
"float",
number_is_defined,
number_assign,
float_handle_monadic_operator,
float_handle_dyadic_operator,
float_fix_result,
float_print
number_handle_monadic_operator,
number_handle_dyadic_operator,
number_fix_result,
number_print
};
struct type type_list = {
"list",
@ -2228,9 +2345,10 @@ static int 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->type = &type_int;
result->u.number.flags = NUMBER_EVER_UNDEFINED; // ...and without NUMBER_IS_DEFINED!
result->u.number.val.intval = 0;
result->type = &type_number;
result->u.number.ntype = NUMTYPE_UNDEFINED;
result->u.number.flags = NUMBER_EVER_UNDEFINED;
result->u.number.val.intval = 0; // FIXME - should not be needed!
result->u.number.addr_refs = 0;
} else {
// not empty. undefined?
@ -2246,8 +2364,9 @@ static int parse_expression(struct expression *expression)
// 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->type = &type_int;
result->u.number.flags = 0; // maybe set DEFINED flag to suppress follow-up errors?
result->type = &type_number;
result->u.number.ntype = NUMTYPE_UNDEFINED; // maybe use NUMTYPE_INT to suppress follow-up errors?
result->u.number.flags = 0;
result->u.number.val.intval = 0;
result->u.number.addr_refs = 0;
// make sure no additional (spurious) errors are reported:
@ -2275,11 +2394,16 @@ void ALU_any_int(intval_t *target) // ACCEPT_UNDEFINED
Throw_error(exception_paren_open);
if (expression.is_empty)
Throw_error(exception_no_value);
if (expression.result.type == &type_int)
*target = expression.result.u.number.val.intval;
else if (expression.result.type == &type_float)
*target = expression.result.u.number.val.fpval;
else {
if (expression.result.type == &type_number) {
if (expression.result.u.number.ntype == NUMTYPE_UNDEFINED)
*target = 0;
else if (expression.result.u.number.ntype == NUMTYPE_INT)
*target = expression.result.u.number.val.intval;
else if (expression.result.u.number.ntype == NUMTYPE_FLOAT)
*target = expression.result.u.number.val.fpval;
else
Bug_found("IllegalNumberType6", expression.result.u.number.ntype); // FIXME - add to docs!
} else {
*target = 0;
Throw_error(exception_not_number);
}
@ -2306,15 +2430,19 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
Throw_error(exception_paren_open);
if (expression.is_empty)
Throw_serious_error(exception_no_value);
if (expression.result.type == &type_int) {
// ok
} else if (expression.result.type == &type_float) {
float_to_int(&expression.result);
if (expression.result.type == &type_number) {
if (expression.result.u.number.ntype == NUMTYPE_UNDEFINED) {
Throw_serious_error(exception_value_not_defined);
} else if (expression.result.u.number.ntype == NUMTYPE_INT) {
// ok
} else if (expression.result.u.number.ntype == NUMTYPE_FLOAT) {
float_to_int(&expression.result);
} else {
Bug_found("IllegalNumberType7", expression.result.u.number.ntype); // FIXME - add to docs!
}
} else {
Throw_serious_error(exception_not_number);
}
if (!(expression.result.u.number.flags & NUMBER_IS_DEFINED))
Throw_serious_error(exception_value_not_defined);
*intresult = expression.result.u.number;
}
@ -2330,11 +2458,14 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFINED | ACCEPT_OPENPARENTHESIS
{
parse_expression(expression); // FIXME - check return value and pass to caller!
// convert float to int
if (expression->result.type == &type_float)
float_to_int(&(expression->result));
if (expression->result.type != &type_int)
if (expression->result.type == &type_number) {
// convert float to int
if (expression->result.u.number.ntype == NUMTYPE_FLOAT)
float_to_int(&(expression->result));
// FIXME - check for undefined?
} else {
Throw_error(exception_not_number);
}
if (expression->open_parentheses > paren) {
expression->open_parentheses = 0;
Throw_error(exception_paren_open);

View File

@ -21,8 +21,7 @@ struct type {
void (*fix_result)(struct object *self);
void (*print)(const struct object *self, struct dynabuf *db);
};
extern struct type type_int;
extern struct type type_float;
extern struct type type_number;
extern struct type type_list;
extern struct type type_string;
@ -44,8 +43,7 @@ struct expression {
#define NUMBER_FORCES_24 (1u << 2) // value usage forces 24-bit usage
#define NUMBER_FORCEBITS (NUMBER_FORCES_8 | NUMBER_FORCES_16 | NUMBER_FORCES_24)
#define NUMBER_FITS_BYTE (1u << 3) // value is guaranteed to fit in one byte
#define NUMBER_IS_DEFINED (1u << 4) // 0: undefined expression (value will be zero). 1: known result
#define NUMBER_EVER_UNDEFINED (1u << 5) // value once was related to
#define NUMBER_EVER_UNDEFINED (1u << 4) // value once was related to
// undefined expression. Needed for producing the same addresses in all
// passes; because in the first pass there will almost for sure be
// labels that are undefined, we can't simply get the addressing mode

View File

@ -20,10 +20,16 @@ typedef unsigned int bits;
typedef unsigned int scope_t;
typedef signed long intval_t; // at least 32 bits
typedef unsigned long uintval_t; // just for logical shift right
enum numtype {
NUMTYPE_UNDEFINED,
NUMTYPE_INT,
NUMTYPE_FLOAT,
};
// structure for ints/floats
struct number {
bits flags; // DEFINED, FITS_IN_BYTE, etc. (see alu.h)
enum numtype ntype;
bits flags; // FITS_IN_BYTE etc. (see alu.h)
union {
intval_t intval; // integer value
double fpval; // floating point value

View File

@ -57,8 +57,9 @@ void flow_forloop(struct for_loop *loop)
// fix line number (not for block, but in case symbol handling throws errors)
Input_now->line_number = loop->block.start;
// init counter
loop_counter.type = &type_int;
loop_counter.u.number.flags = NUMBER_IS_DEFINED;
loop_counter.type = &type_number;
loop_counter.u.number.ntype = NUMTYPE_INT;
loop_counter.u.number.flags = 0;
loop_counter.u.number.val.intval = loop->counter.first;
loop_counter.u.number.addr_refs = loop->counter.addr_refs;
// CAUTION: next line does not have power to change symbol type, but if

View File

@ -174,8 +174,9 @@ static void set_label(scope_t scope, bits stat_flags, bits force_bit, bits power
Throw_first_pass_warning("Label name not in leftmost column.");
symbol = symbol_find(scope);
vcpu_read_pc(&pc); // FIXME - if undefined, check pass.complain_about_undefined and maybe throw "value not defined"!
result.type = &type_int;
result.u.number.flags = pc.flags & NUMBER_IS_DEFINED;
result.type = &type_number;
result.u.number.ntype = NUMTYPE_INT; // FIXME - if undefined, use NUMTYPE_UNDEFINED!
result.u.number.flags = 0;
result.u.number.val.intval = pc.val.intval;
result.u.number.addr_refs = pc.addr_refs;
symbol_set_object(symbol, &result, powers);
@ -201,8 +202,7 @@ void parse_assignment(scope_t scope, bits force_bit, bits powers)
// if wanted, mark as address reference
if (typesystem_says_address()) {
// FIXME - checking types explicitly is ugly...
if ((result.type == &type_int)
|| (result.type == &type_float))
if (result.type == &type_number)
result.u.number.addr_refs = 1;
}
symbol_set_object(symbol, &result, powers);

View File

@ -648,7 +648,7 @@ static bits get_addr_mode(struct number *result)
static bits check_oversize(bits size_bit, struct number *argument)
{
// only check if value is *defined*
if ((argument->flags & NUMBER_IS_DEFINED) == 0)
if (argument->ntype == NUMTYPE_UNDEFINED)
return size_bit; // pass on result
// value is defined, so check
@ -792,7 +792,7 @@ static void near_branch(int preoffset)
vcpu_read_pc(&pc);
get_int_arg(&target, TRUE);
typesystem_want_addr(&target);
if (pc.flags & target.flags & NUMBER_IS_DEFINED) {
if ((pc.ntype == NUMTYPE_INT) && (target.ntype == NUMTYPE_INT)) {
if ((target.val.intval | 0xffff) != 0xffff) {
not_in_bank(target.val.intval);
} else {
@ -827,7 +827,7 @@ static void far_branch(int preoffset)
vcpu_read_pc(&pc);
get_int_arg(&target, TRUE);
typesystem_want_addr(&target);
if (pc.flags & target.flags & NUMBER_IS_DEFINED) {
if ((pc.ntype == NUMTYPE_INT) && (target.ntype == NUMTYPE_INT)) {
if ((target.val.intval | 0xffff) != 0xffff) {
not_in_bank(target.val.intval);
} else {
@ -903,7 +903,7 @@ static unsigned int imm_ops(bits *force_bit, unsigned char opcode, bits immediat
// helper function to warn if zp pointer wraps around
static void check_zp_wraparound(struct number *result)
{
if ((result->flags & NUMBER_IS_DEFINED)
if ((result->ntype == NUMTYPE_INT)
&& (result->val.intval == 0xff)
&& (CPU_state.type->flags & CPUFLAG_WARN_ABOUT_FF_PTR))
Throw_warning("Zeropage pointer wraps around from $ff to $00");
@ -995,8 +995,8 @@ static void group_misc(int index, bits immediate_mode)
make_command(force_bit, &result, immediate_opcodes);
// warn about unstable ANE/LXA (undocumented opcode of NMOS 6502)?
if ((CPU_state.type->flags & CPUFLAG_8B_AND_AB_NEED_0_ARG)
&& ((result.val.intval & 0xff) != 0x00)
&& (result.flags & NUMBER_IS_DEFINED)) {
&& (result.ntype == NUMTYPE_INT)
&& (result.val.intval != 0x00)) {
if (immediate_opcodes == 0x8b)
Throw_warning("Assembling unstable ANE #NONZERO instruction");
else if (immediate_opcodes == 0xab)
@ -1104,8 +1104,8 @@ static void group_jump(int index)
case INDIRECT_ADDRESSING: // ($ffff)
make_command(force_bit, &result, jump_ind[index]);
// check whether to warn about 6502's JMP() bug
if (((result.val.intval & 0xff) == 0xff)
&& (result.flags & NUMBER_IS_DEFINED)
if ((result.ntype == NUMTYPE_INT)
&& ((result.val.intval & 0xff) == 0xff)
&& (CPU_state.type->flags & CPUFLAG_INDIRECTJMPBUGGY))
Throw_warning("Assembling buggy JMP($xxff) instruction");
break;

View File

@ -496,7 +496,10 @@ void Output_passinit(void)
out->xor = 0;
//vcpu stuff:
CPU_state.pc.flags = 0; // not defined yet
CPU_state.pc.ntype = NUMTYPE_UNDEFINED; // not defined yet
CPU_state.pc.flags = 0;
// FIXME - number type is "undefined", but still the intval 0 below will
// be used to calculate diff when pc is first set.
CPU_state.pc.val.intval = 0; // same as output's write_idx on pass init
CPU_state.add_to_pc = 0; // increase PC by this at end of statement
@ -593,7 +596,7 @@ void vcpu_set_pc(intval_t new_pc, bits segment_flags)
}
new_offset = (new_pc - CPU_state.pc.val.intval) & 0xffff;
CPU_state.pc.val.intval = new_pc;
CPU_state.pc.flags |= NUMBER_IS_DEFINED; // FIXME - remove when allowing undefined!
CPU_state.pc.ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
CPU_state.pc.addr_refs = 1; // yes, PC counts as address
// now tell output buffer to start a new segment
Output_start_segment(new_offset, segment_flags);
@ -654,7 +657,7 @@ void vcpu_end_statement(void)
struct pseudopc {
struct pseudopc *outer; // next layer (to be able to "unpseudopc" labels by more than one level)
intval_t offset; // inner minus outer pc
bits flags; // flags of outer pc
enum numtype ntype; // type of outer pc (INT/UNDEFINED)
};
// start offset assembly
void pseudopc_start(struct number *new_pc)
@ -665,10 +668,10 @@ void pseudopc_start(struct number *new_pc)
new_context->outer = pseudopc_current_context; // let it point to previous one
pseudopc_current_context = new_context; // make it the current one
new_context->flags = CPU_state.pc.flags;
new_context->ntype = CPU_state.pc.ntype;
new_context->offset = new_pc->val.intval - CPU_state.pc.val.intval;
CPU_state.pc.val.intval = new_pc->val.intval;
CPU_state.pc.flags |= NUMBER_IS_DEFINED; // FIXME - remove when allowing undefined!
CPU_state.pc.ntype = NUMTYPE_INT; // FIXME - remove when allowing undefined!
//new: CPU_state.pc.flags = new_pc->flags & (NUMBER_IS_DEFINED | NUMBER_EVER_UNDEFINED);
}
// end offset assembly
@ -685,7 +688,7 @@ void pseudopc_end(void)
Bug_found("ClosingUnopenedPseudopcBlock", 0);
} else {
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & 0xffff; // pc might have wrapped around
CPU_state.pc.flags = pseudopc_current_context->flags;
CPU_state.pc.ntype = pseudopc_current_context->ntype;
pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block
}
}
@ -700,7 +703,7 @@ void pseudopc_end_all(void)
int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels)
{
while (levels--) {
if ((target->flags & NUMBER_IS_DEFINED) == 0)
if (target->ntype == NUMTYPE_UNDEFINED)
return 0; // ok (no sense in trying to unpseudo this, and it might be an unresolved forward ref anway)
if (context == NULL) {

View File

@ -580,7 +580,7 @@ static enum eos po_align(void)
// make sure PC is defined
vcpu_read_pc(&pc);
if (!(pc.flags & NUMBER_IS_DEFINED)) {
if (pc.ntype == NUMTYPE_UNDEFINED) {
Throw_error(exception_pc_undefined);
return SKIP_REMAINDER;
}

View File

@ -31,8 +31,7 @@ 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->object.type != &type_int)
&& (symbol->object.type != &type_float))
if (symbol->object.type != &type_number)
return;
// CAUTION: if more types are added, check for NULL before using type pointer!
@ -54,16 +53,14 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
default:
fprintf(fd, "\t= ");
}
if (symbol->object.u.number.flags & NUMBER_IS_DEFINED) {
if (symbol->object.type == &type_int)
fprintf(fd, "$%x", (unsigned) symbol->object.u.number.val.intval);
else if (symbol->object.type == &type_float)
fprintf(fd, "%.30f", symbol->object.u.number.val.fpval); //FIXME %g
else
Bug_found("BogusType", 0); // FIXME - put in docs!
} else {
if (symbol->object.u.number.ntype == NUMTYPE_UNDEFINED)
fprintf(fd, " ?"); // TODO - maybe write "UNDEFINED" instead? then the file could at least be parsed without errors
}
else if (symbol->object.u.number.ntype == NUMTYPE_INT)
fprintf(fd, "$%x", (unsigned) symbol->object.u.number.val.intval);
else if (symbol->object.u.number.ntype == NUMTYPE_FLOAT)
fprintf(fd, "%.30f", symbol->object.u.number.val.fpval); //FIXME %g
else
Bug_found("BogusType", 0); // FIXME - put in docs!
if (symbol->object.u.number.flags & NUMBER_EVER_UNDEFINED)
fprintf(fd, "\t; ?"); // TODO - write "forward" instead?
if (!symbol->has_been_read)
@ -78,8 +75,8 @@ 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->object.type == &type_int)
&& (symbol->object.u.number.flags & NUMBER_IS_DEFINED)
if ((symbol->object.type == &type_number)
&& (symbol->object.u.number.ntype == NUMTYPE_INT)
&& (symbol->object.u.number.addr_refs == 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->object.u.number.val.intval, node->id_string);
}
@ -89,8 +86,8 @@ static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
// dump non-addresses that are used
if (symbol->has_been_read
&& (symbol->object.type == &type_int)
&& (symbol->object.u.number.flags & NUMBER_IS_DEFINED)
&& (symbol->object.type == &type_number)
&& (symbol->object.u.number.ntype == NUMTYPE_INT)
&& (symbol->object.u.number.addr_refs != 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->object.u.number.val.intval, node->id_string);
}
@ -100,8 +97,8 @@ static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
// dump non-addresses that are unused
if (!symbol->has_been_read
&& (symbol->object.type == &type_int)
&& (symbol->object.u.number.flags & NUMBER_IS_DEFINED)
&& (symbol->object.type == &type_number)
&& (symbol->object.u.number.ntype == NUMTYPE_INT)
&& (symbol->object.u.number.addr_refs != 1))
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->object.u.number.val.intval, node->id_string);
}
@ -146,9 +143,6 @@ struct symbol *symbol_find(scope_t scope)
// CAUTION: actual incrementing of counter is then done directly without calls here!
void symbol_set_object(struct symbol *symbol, struct object *new_value, bits powers)
{
struct type *symbol_class, // helper vars to group
*newval_class; // ints and floats
// if symbol has no object assigned to it yet, fine:
if (symbol->object.type == NULL) {
symbol->object = *new_value; // copy whole struct including type
@ -159,15 +153,9 @@ void symbol_set_object(struct symbol *symbol, struct object *new_value, bits pow
// now we know symbol already has a type
// compare types (CAUTION, ints and floats are grouped!)
symbol_class = symbol->object.type;
if (symbol_class == &type_float)
symbol_class = &type_int;
newval_class = new_value->type;
if (newval_class == &type_float)
newval_class = &type_int;
// compare types
// if too different, needs power (or complains)
if (symbol_class != newval_class) {
if (symbol->object.type != new_value->type) {
if (!(powers & POWER_CHANGE_OBJTYPE))
Throw_error(exception_symbol_defined);
// CAUTION: if above line throws error, we still go ahead and change type!
@ -191,7 +179,7 @@ void symbol_set_force_bit(struct symbol *symbol, bits force_bit)
if (symbol->object.type == NULL)
Bug_found("NullObject", 0); // FIXME - add to docs!
if ((symbol->object.type != &type_int) && (symbol->object.type != &type_float)) {
if (symbol->object.type != &type_number) {
Throw_error("Force bits can only be given to numbers."); // FIXME - add to docs!
return;
}
@ -216,8 +204,9 @@ void symbol_define(intval_t value)
struct object result;
struct symbol *symbol;
result.type = &type_int;
result.u.number.flags = NUMBER_IS_DEFINED;
result.type = &type_number;
result.u.number.ntype = NUMTYPE_INT;
result.u.number.flags = 0;
result.u.number.val.intval = value;
symbol = symbol_find(SCOPE_GLOBAL);
symbol->object = result;
@ -266,12 +255,13 @@ void symbol_fix_forward_anon_name(boolean increment)
counter_symbol = symbol_find(section_now->local_scope);
if (counter_symbol->object.type == NULL) {
// finish freshly created symbol item
counter_symbol->object.type = &type_int;
counter_symbol->object.u.number.flags = NUMBER_IS_DEFINED;
counter_symbol->object.type = &type_number;
counter_symbol->object.u.number.ntype = NUMTYPE_INT;
counter_symbol->object.u.number.flags = 0;
counter_symbol->object.u.number.addr_refs = 0;
counter_symbol->object.u.number.val.intval = 0;
} else if (counter_symbol->object.type != &type_int) {
// sanity check: it must be an int!
} else if (counter_symbol->object.type != &type_number) {
// sanity check: it must be a number!
Bug_found("ForwardAnonCounterNotInt", 0);
}
// make sure it gets reset to zero in each new pass

View File

@ -42,7 +42,7 @@ void typesystem_want_nonaddr(struct number *result)
if (!config.warn_on_type_mismatch)
return;
if (!(result->flags & NUMBER_IS_DEFINED))
if (result->ntype == NUMTYPE_UNDEFINED)
return;
if (result->addr_refs != 0) {
@ -56,7 +56,7 @@ void typesystem_want_addr(struct number *result)
if (!config.warn_on_type_mismatch)
return;
if (!(result->flags & NUMBER_IS_DEFINED))
if (result->ntype == NUMTYPE_UNDEFINED)
return;
if (result->addr_refs != 1) {

View File

@ -9,7 +9,7 @@
#define RELEASE "0.96.5" // update before release FIXME
#define CODENAME "Fenchurch" // update before release
#define CHANGE_DATE "14 June" // update before release FIXME
#define CHANGE_DATE "17 June" // 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