mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-02-07 06:31:03 +00:00
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:
parent
929fefe0e6
commit
f9a2f5f698
487
src/alu.c
487
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, "<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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
16
src/mnemo.c
16
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;
|
||||
|
17
src/output.c
17
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
60
src/symbol.c
60
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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user