diff --git a/src/alu.c b/src/alu.c index 266ab06..54a3eea 100644 --- a/src/alu.c +++ b/src/alu.c @@ -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, ""); + } 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, ""); - } -} - -// 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, ""); + 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); diff --git a/src/alu.h b/src/alu.h index 816a892..741caa1 100644 --- a/src/alu.h +++ b/src/alu.h @@ -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 diff --git a/src/config.h b/src/config.h index e18c90e..5f289fd 100644 --- a/src/config.h +++ b/src/config.h @@ -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 diff --git a/src/flow.c b/src/flow.c index 7becfb9..622e6b7 100644 --- a/src/flow.c +++ b/src/flow.c @@ -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 diff --git a/src/global.c b/src/global.c index dbc9793..c859622 100644 --- a/src/global.c +++ b/src/global.c @@ -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); diff --git a/src/mnemo.c b/src/mnemo.c index 5fc995b..4b84509 100644 --- a/src/mnemo.c +++ b/src/mnemo.c @@ -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; diff --git a/src/output.c b/src/output.c index a596f30..03202a0 100644 --- a/src/output.c +++ b/src/output.c @@ -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) { diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index 3110df7..13ea9c1 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -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; } diff --git a/src/symbol.c b/src/symbol.c index 5c18dd8..9d5a263 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -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 diff --git a/src/typesystem.c b/src/typesystem.c index f56c7d3..9077b6c 100644 --- a/src/typesystem.c +++ b/src/typesystem.c @@ -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) { diff --git a/src/version.h b/src/version.h index 3d164ea..3b56f5d 100644 --- a/src/version.h +++ b/src/version.h @@ -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