mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-01-11 13:30:15 +00:00
cleaned up expression handler, it's now able to handle more than just ints/floats
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@158 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
3300c9d468
commit
40afd3311a
515
src/alu.c
515
src/alu.c
@ -167,7 +167,7 @@ static struct op **op_stack = NULL;
|
|||||||
static int opstack_size = HALF_INITIAL_STACK_SIZE;
|
static int opstack_size = HALF_INITIAL_STACK_SIZE;
|
||||||
static int op_sp;
|
static int op_sp;
|
||||||
// argument stack, current size and stack pointer:
|
// argument stack, current size and stack pointer:
|
||||||
static struct number *arg_stack = NULL;
|
static struct object *arg_stack = NULL;
|
||||||
static int argstack_size = HALF_INITIAL_STACK_SIZE;
|
static int argstack_size = HALF_INITIAL_STACK_SIZE;
|
||||||
static int arg_sp;
|
static int arg_sp;
|
||||||
enum alu_state {
|
enum alu_state {
|
||||||
@ -211,17 +211,19 @@ static struct ronode function_list[] = {
|
|||||||
|
|
||||||
#define PUSH_OP(x) op_stack[op_sp++] = (x)
|
#define PUSH_OP(x) op_stack[op_sp++] = (x)
|
||||||
|
|
||||||
#define PUSH_INT_ARG(i, f, r) \
|
#define PUSH_INT_ARG(i, f, r) \
|
||||||
do { \
|
do { \
|
||||||
arg_stack[arg_sp].flags = (f); \
|
arg_stack[arg_sp].type = &type_int; \
|
||||||
arg_stack[arg_sp].val.intval = (i); \
|
arg_stack[arg_sp].u.number.flags = (f); \
|
||||||
arg_stack[arg_sp++].addr_refs = (r); \
|
arg_stack[arg_sp].u.number.val.intval = (i); \
|
||||||
|
arg_stack[arg_sp++].u.number.addr_refs = (r); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define PUSH_FP_ARG(fp, f) \
|
#define PUSH_FP_ARG(fp, f) \
|
||||||
do { \
|
do { \
|
||||||
arg_stack[arg_sp].flags = (f) | NUMBER_IS_FLOAT; \
|
arg_stack[arg_sp].type = &type_float; \
|
||||||
arg_stack[arg_sp].val.fpval = (fp); \
|
arg_stack[arg_sp].u.number.flags = (f); \
|
||||||
arg_stack[arg_sp++].addr_refs = 0; \
|
arg_stack[arg_sp].u.number.val.fpval = (fp); \
|
||||||
|
arg_stack[arg_sp++].u.number.addr_refs = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
@ -296,14 +298,11 @@ static intval_t my_asr(intval_t left, intval_t right)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if needed, throw "Value not defined" error
|
// if wanted, throw "Value not defined" error
|
||||||
// This function is not allowed to change DynaBuf because the symbol's name
|
// This function is not allowed to change DynaBuf because the symbol's name
|
||||||
// might be stored there!
|
// might be stored there!
|
||||||
static void check_for_def(struct symbol *optional_symbol, int flags, char optional_prefix_char, char *name, size_t length)
|
static void is_not_defined(struct symbol *optional_symbol, char optional_prefix_char, char *name, size_t length)
|
||||||
{
|
{
|
||||||
if (flags & NUMBER_IS_DEFINED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!pass.complain_about_undefined)
|
if (!pass.complain_about_undefined)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -349,7 +348,8 @@ static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t na
|
|||||||
// if the symbol gets created now, mark it as unsure
|
// if the symbol gets created now, mark it as unsure
|
||||||
symbol = symbol_find(scope, NUMBER_EVER_UNDEFINED);
|
symbol = symbol_find(scope, NUMBER_EVER_UNDEFINED);
|
||||||
// if needed, output "value not defined" error
|
// if needed, output "value not defined" error
|
||||||
check_for_def(symbol, symbol->result.flags, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
|
if (!(symbol->result.type->is_defined(&symbol->result)))
|
||||||
|
is_not_defined(symbol, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
|
||||||
// in first pass, count usage
|
// in first pass, count usage
|
||||||
if (FIRST_PASS)
|
if (FIRST_PASS)
|
||||||
symbol->usage++;
|
symbol->usage++;
|
||||||
@ -366,7 +366,8 @@ static void parse_program_counter(void) // Now GotByte = "*"
|
|||||||
GetByte();
|
GetByte();
|
||||||
vcpu_read_pc(&pc);
|
vcpu_read_pc(&pc);
|
||||||
// if needed, output "value not defined" error
|
// if needed, output "value not defined" error
|
||||||
check_for_def(NULL, pc.flags, 0, "*", 1);
|
if (!(pc.flags & NUMBER_IS_DEFINED))
|
||||||
|
is_not_defined(NULL, 0, "*", 1);
|
||||||
PUSH_INT_ARG(pc.val.intval, pc.flags, pc.addr_refs);
|
PUSH_INT_ARG(pc.val.intval, pc.flags, pc.addr_refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,59 +957,25 @@ push_dyadic_op:
|
|||||||
|
|
||||||
// int:
|
// int:
|
||||||
// convert to float
|
// convert to float
|
||||||
inline static void int_to_float(struct number *self)
|
inline static void int_to_float(struct object *self)
|
||||||
{
|
{
|
||||||
self->val.fpval = self->val.intval;
|
self->type = &type_float;
|
||||||
self->flags |= NUMBER_IS_FLOAT;
|
self->u.number.val.fpval = self->u.number.val.intval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// float:
|
// float:
|
||||||
// convert to int
|
// convert to int
|
||||||
inline static void float_to_int(struct number *self)
|
inline static void float_to_int(struct object *self)
|
||||||
{
|
{
|
||||||
self->val.intval = self->val.fpval;
|
self->type = &type_int;
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->u.number.val.intval = self->u.number.val.fpval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int/float:
|
// int/float:
|
||||||
// set flags according to result
|
// return DEFINED flag
|
||||||
static void number_fixresult(struct number *self)
|
static boolean number_is_defined(struct object *self)
|
||||||
{
|
{
|
||||||
// only allow a single force bit
|
return !!(self->u.number.flags & NUMBER_IS_DEFINED);
|
||||||
if (self->flags & NUMBER_FORCES_24)
|
|
||||||
self->flags &= ~(NUMBER_FORCES_16 | NUMBER_FORCES_8);
|
|
||||||
else if (self->flags & NUMBER_FORCES_16)
|
|
||||||
self->flags &= ~NUMBER_FORCES_8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int:
|
|
||||||
// set flags according to result
|
|
||||||
static void int_fixresult(struct number *self)
|
|
||||||
{
|
|
||||||
number_fixresult(self);
|
|
||||||
// if undefined, return zero
|
|
||||||
if (!(self->flags & NUMBER_IS_DEFINED))
|
|
||||||
self->val.intval = 0;
|
|
||||||
// if value is sure, check to set FITS BYTE
|
|
||||||
else if ((!(self->flags & NUMBER_EVER_UNDEFINED))
|
|
||||||
&& (self->val.intval <= 255)
|
|
||||||
&& (self->val.intval >= -128))
|
|
||||||
self->flags |= NUMBER_FITS_BYTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// float:
|
|
||||||
// set flags according to result
|
|
||||||
static void float_fixresult(struct number *self)
|
|
||||||
{
|
|
||||||
number_fixresult(self);
|
|
||||||
// if undefined, return zero
|
|
||||||
if (!(self->flags & NUMBER_IS_DEFINED))
|
|
||||||
self->val.fpval = 0;
|
|
||||||
// if value is sure, check to set FITS BYTE
|
|
||||||
else if ((!(self->flags & NUMBER_EVER_UNDEFINED))
|
|
||||||
&& (self->val.fpval <= 255.0)
|
|
||||||
&& (self->val.fpval >= -128.0))
|
|
||||||
self->flags |= NUMBER_FITS_BYTE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this gets called for LSR, AND, OR, XOR with float args
|
// this gets called for LSR, AND, OR, XOR with float args
|
||||||
@ -1018,14 +985,9 @@ static void warn_float_to_int(void)
|
|||||||
Throw_first_pass_warning("Converted to integer for binary logic operator.");
|
Throw_first_pass_warning("Converted to integer for binary logic operator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// prototypes needed because int and float handlers reference each other.
|
|
||||||
// FIXME - remove when handlers are put as pointers into proper "type" structures.
|
|
||||||
static void float_handle_monadic_operator(struct number *self, enum op_handle op);
|
|
||||||
static void float_handle_dyadic_operator(struct number *self, enum op_handle op, struct number *other);
|
|
||||||
|
|
||||||
// int:
|
// int:
|
||||||
// handle monadic operator (includes functions)
|
// handle monadic operator (includes functions)
|
||||||
static void int_handle_monadic_operator(struct number *self, enum op_handle op)
|
static void int_handle_monadic_operator(struct object *self, enum op_handle op)
|
||||||
{
|
{
|
||||||
int refs = 0; // default for "addr_refs", shortens this fn
|
int refs = 0; // default for "addr_refs", shortens this fn
|
||||||
|
|
||||||
@ -1046,33 +1008,33 @@ static void int_handle_monadic_operator(struct number *self, enum op_handle op)
|
|||||||
case OPHANDLE_ARCTAN:
|
case OPHANDLE_ARCTAN:
|
||||||
// convert int to fp and ask fp handler to do the work
|
// convert int to fp and ask fp handler to do the work
|
||||||
int_to_float(self);
|
int_to_float(self);
|
||||||
float_handle_monadic_operator(self, op); // TODO - put recursion check around this?
|
type_float.handle_monadic_operator(self, op); // TODO - put recursion check around this?
|
||||||
return; // float handler has done everything
|
return; // float handler has done everything
|
||||||
|
|
||||||
case OPHANDLE_NOT:
|
case OPHANDLE_NOT:
|
||||||
self->val.intval = ~(self->val.intval);
|
self->u.number.val.intval = ~(self->u.number.val.intval);
|
||||||
self->flags &= ~NUMBER_FITS_BYTE;
|
self->u.number.flags &= ~NUMBER_FITS_BYTE;
|
||||||
refs = -(self->addr_refs); // negate address ref count
|
refs = -(self->u.number.addr_refs); // negate address ref count
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_NEGATE:
|
case OPHANDLE_NEGATE:
|
||||||
self->val.intval = -(self->val.intval);
|
self->u.number.val.intval = -(self->u.number.val.intval);
|
||||||
self->flags &= ~NUMBER_FITS_BYTE;
|
self->u.number.flags &= ~NUMBER_FITS_BYTE;
|
||||||
refs = -(self->addr_refs); // negate address ref count as well
|
refs = -(self->u.number.addr_refs); // negate address ref count as well
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LOWBYTEOF:
|
case OPHANDLE_LOWBYTEOF:
|
||||||
self->val.intval = (self->val.intval) & 255;
|
self->u.number.val.intval = (self->u.number.val.intval) & 255;
|
||||||
self->flags |= NUMBER_FITS_BYTE;
|
self->u.number.flags |= NUMBER_FITS_BYTE;
|
||||||
self->flags &= ~NUMBER_FORCEBITS;
|
self->u.number.flags &= ~NUMBER_FORCEBITS;
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_HIGHBYTEOF:
|
case OPHANDLE_HIGHBYTEOF:
|
||||||
self->val.intval = ((self->val.intval) >> 8) & 255;
|
self->u.number.val.intval = ((self->u.number.val.intval) >> 8) & 255;
|
||||||
self->flags |= NUMBER_FITS_BYTE;
|
self->u.number.flags |= NUMBER_FITS_BYTE;
|
||||||
self->flags &= ~NUMBER_FORCEBITS;
|
self->u.number.flags &= ~NUMBER_FORCEBITS;
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_BANKBYTEOF:
|
case OPHANDLE_BANKBYTEOF:
|
||||||
self->val.intval = ((self->val.intval) >> 16) & 255;
|
self->u.number.val.intval = ((self->u.number.val.intval) >> 16) & 255;
|
||||||
self->flags |= NUMBER_FITS_BYTE;
|
self->u.number.flags |= NUMBER_FITS_BYTE;
|
||||||
self->flags &= ~NUMBER_FORCEBITS;
|
self->u.number.flags &= ~NUMBER_FORCEBITS;
|
||||||
break;
|
break;
|
||||||
// add new monadic operators here
|
// add new monadic operators here
|
||||||
// case OPHANDLE_:
|
// case OPHANDLE_:
|
||||||
@ -1081,26 +1043,26 @@ static void int_handle_monadic_operator(struct number *self, enum op_handle op)
|
|||||||
default:
|
default:
|
||||||
Bug_found("IllegalOperatorHandleIM", op);
|
Bug_found("IllegalOperatorHandleIM", op);
|
||||||
}
|
}
|
||||||
self->addr_refs = refs; // update address refs with local copy
|
self->u.number.addr_refs = refs; // update address refs with local copy
|
||||||
}
|
}
|
||||||
|
|
||||||
// float:
|
// float:
|
||||||
// helper function for asin/acos:
|
// helper function for asin/acos:
|
||||||
// make sure arg is in [-1, 1] range before calling function
|
// make sure arg is in [-1, 1] range before calling function
|
||||||
static void float_ranged_fn(double (*fn)(double), struct number *self)
|
static void float_ranged_fn(double (*fn)(double), struct object *self)
|
||||||
{
|
{
|
||||||
if ((self->val.fpval >= -1) && (self->val.fpval <= 1)) {
|
if ((self->u.number.val.fpval >= -1) && (self->u.number.val.fpval <= 1)) {
|
||||||
self->val.fpval = fn(self->val.fpval);
|
self->u.number.val.fpval = fn(self->u.number.val.fpval);
|
||||||
} else {
|
} else {
|
||||||
if (self->flags & NUMBER_IS_DEFINED)
|
if (self->u.number.flags & NUMBER_IS_DEFINED)
|
||||||
Throw_error("Argument out of range."); // TODO - add number output to error message
|
Throw_error("Argument out of range."); // TODO - add number output to error message
|
||||||
self->val.fpval = 0;
|
self->u.number.val.fpval = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// float:
|
// float:
|
||||||
// handle monadic operator (includes functions)
|
// handle monadic operator (includes functions)
|
||||||
static void float_handle_monadic_operator(struct number *self, enum op_handle op)
|
static void float_handle_monadic_operator(struct object *self, enum op_handle op)
|
||||||
{
|
{
|
||||||
int refs = 0; // default for "addr_refs", shortens this fn
|
int refs = 0; // default for "addr_refs", shortens this fn
|
||||||
|
|
||||||
@ -1114,13 +1076,13 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
|
|||||||
case OPHANDLE_FLOAT:
|
case OPHANDLE_FLOAT:
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_SIN:
|
case OPHANDLE_SIN:
|
||||||
self->val.fpval = sin(self->val.fpval);
|
self->u.number.val.fpval = sin(self->u.number.val.fpval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_COS:
|
case OPHANDLE_COS:
|
||||||
self->val.fpval = cos(self->val.fpval);
|
self->u.number.val.fpval = cos(self->u.number.val.fpval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_TAN:
|
case OPHANDLE_TAN:
|
||||||
self->val.fpval = tan(self->val.fpval);
|
self->u.number.val.fpval = tan(self->u.number.val.fpval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_ARCSIN:
|
case OPHANDLE_ARCSIN:
|
||||||
float_ranged_fn(asin, self);
|
float_ranged_fn(asin, self);
|
||||||
@ -1129,12 +1091,12 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
|
|||||||
float_ranged_fn(acos, self);
|
float_ranged_fn(acos, self);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_ARCTAN:
|
case OPHANDLE_ARCTAN:
|
||||||
self->val.fpval = atan(self->val.fpval);
|
self->u.number.val.fpval = atan(self->u.number.val.fpval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_NEGATE:
|
case OPHANDLE_NEGATE:
|
||||||
self->val.fpval = -(self->val.fpval);
|
self->u.number.val.fpval = -(self->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_FITS_BYTE;
|
self->u.number.flags &= ~NUMBER_FITS_BYTE;
|
||||||
refs = -(self->addr_refs); // negate address ref count as well
|
refs = -(self->u.number.addr_refs); // negate address ref count as well
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_NOT:
|
case OPHANDLE_NOT:
|
||||||
case OPHANDLE_LOWBYTEOF:
|
case OPHANDLE_LOWBYTEOF:
|
||||||
@ -1142,7 +1104,7 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
|
|||||||
case OPHANDLE_BANKBYTEOF:
|
case OPHANDLE_BANKBYTEOF:
|
||||||
// convert fp to int and ask int handler to do the work
|
// convert fp to int and ask int handler to do the work
|
||||||
float_to_int(self);
|
float_to_int(self);
|
||||||
int_handle_monadic_operator(self, op); // TODO - put recursion check around this?
|
type_int.handle_monadic_operator(self, op); // TODO - put recursion check around this?
|
||||||
return; // int handler has done everything
|
return; // int handler has done everything
|
||||||
|
|
||||||
// add new monadic operators here
|
// add new monadic operators here
|
||||||
@ -1152,30 +1114,40 @@ static void float_handle_monadic_operator(struct number *self, enum op_handle op
|
|||||||
default:
|
default:
|
||||||
Bug_found("IllegalOperatorHandleFM", op);
|
Bug_found("IllegalOperatorHandleFM", op);
|
||||||
}
|
}
|
||||||
self->addr_refs = refs; // update address refs with local copy
|
self->u.number.addr_refs = refs; // update address refs with local copy
|
||||||
}
|
}
|
||||||
|
|
||||||
// int/float:
|
// int/float:
|
||||||
// merge result flags
|
// merge result flags
|
||||||
// (used by both int and float handlers for dyadic operators)
|
// (used by both int and float handlers for dyadic operators)
|
||||||
static void number_fix_result_after_dyadic(struct number *self, struct number *other)
|
static void number_fix_result_after_dyadic(struct object *self, struct object *other)
|
||||||
{
|
{
|
||||||
// EVER_UNDEFINED and FORCEBIT flags are ORd together
|
// EVER_UNDEFINED and FORCEBIT flags are ORd together
|
||||||
self->flags |= other->flags & (NUMBER_EVER_UNDEFINED | NUMBER_FORCEBITS);
|
self->u.number.flags |= other->u.number.flags & (NUMBER_EVER_UNDEFINED | NUMBER_FORCEBITS);
|
||||||
// DEFINED flags are ANDed together
|
// DEFINED flags are ANDed together
|
||||||
self->flags &= (other->flags | ~NUMBER_IS_DEFINED);
|
self->u.number.flags &= (other->u.number.flags | ~NUMBER_IS_DEFINED);
|
||||||
// FITS_BYTE is cleared
|
// FITS_BYTE is cleared
|
||||||
self->flags &= ~NUMBER_FITS_BYTE;
|
self->u.number.flags &= ~NUMBER_FITS_BYTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// helper function: don't know how to handle that ARG1 OP ARG2 combination
|
||||||
|
static void unsupported_dyadic(struct object *self, enum op_handle op, struct object *other)
|
||||||
|
{
|
||||||
|
Throw_error("Unsupported combination of argument(s) and operator"); // FIXME - make dynamic, add type names of self/other, add to docs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// int:
|
// int:
|
||||||
// handle dyadic operator
|
// handle dyadic operator
|
||||||
static void int_handle_dyadic_operator(struct number *self, enum op_handle op, struct number *other)
|
static void int_handle_dyadic_operator(struct object *self, enum op_handle op, struct object *other)
|
||||||
{
|
{
|
||||||
int refs = 0; // default for "addr_refs", shortens this fn
|
int refs = 0; // default for "addr_refs", shortens this fn
|
||||||
|
|
||||||
// first check type of second arg:
|
// first check type of second arg:
|
||||||
if (other->flags & NUMBER_IS_FLOAT) {
|
if (other->type == &type_int) {
|
||||||
|
// ok
|
||||||
|
} else if (other->type == &type_float) {
|
||||||
// handle according to operation
|
// handle according to operation
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case OPHANDLE_POWEROF:
|
case OPHANDLE_POWEROF:
|
||||||
@ -1192,7 +1164,7 @@ static void int_handle_dyadic_operator(struct number *self, enum op_handle op, s
|
|||||||
case OPHANDLE_NOTEQUAL:
|
case OPHANDLE_NOTEQUAL:
|
||||||
// become float, delegate to float handler
|
// become float, delegate to float handler
|
||||||
int_to_float(self);
|
int_to_float(self);
|
||||||
float_handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
|
type_float.handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
|
||||||
return; // float handler has done everything
|
return; // float handler has done everything
|
||||||
|
|
||||||
case OPHANDLE_MODULO:
|
case OPHANDLE_MODULO:
|
||||||
@ -1210,97 +1182,105 @@ static void int_handle_dyadic_operator(struct number *self, enum op_handle op, s
|
|||||||
float_to_int(other);
|
float_to_int(other);
|
||||||
warn_float_to_int();
|
warn_float_to_int();
|
||||||
break;
|
break;
|
||||||
// add new dyadic operators here
|
// add new dyadic operators here:
|
||||||
// case OPHANDLE_:
|
// case OPHANDLE_:
|
||||||
// break;
|
// break;
|
||||||
default:
|
default:
|
||||||
break;
|
unsupported_dyadic(self, op, other);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// add new types here:
|
||||||
|
// } else if (other->type == &type_) {
|
||||||
|
// ...
|
||||||
|
} else {
|
||||||
|
unsupported_dyadic(self, op, other);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// sanity check, now "other" can no longer be a float
|
// maybe put this into an extra "int_dyadic_int" function?
|
||||||
if (other->flags & NUMBER_IS_FLOAT)
|
// sanity check, now "other" must be an int
|
||||||
Bug_found("SecondArgIsStillFloatForOp", op); // FIXME - rename? then add to docs!
|
if (other->type != &type_int)
|
||||||
|
Bug_found("SecondArgIsNotAnInt", op); // FIXME - rename? then add to docs!
|
||||||
|
|
||||||
// part 2: now we got rid of floats, perform actual operation:
|
// part 2: now we got rid of floats, perform actual operation:
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case OPHANDLE_POWEROF:
|
case OPHANDLE_POWEROF:
|
||||||
if (other->val.intval >= 0) {
|
if (other->u.number.val.intval >= 0) {
|
||||||
self->val.intval = my_pow(self->val.intval, other->val.intval);
|
self->u.number.val.intval = my_pow(self->u.number.val.intval, other->u.number.val.intval);
|
||||||
} else {
|
} else {
|
||||||
if (other->flags & NUMBER_IS_DEFINED)
|
if (other->u.number.flags & NUMBER_IS_DEFINED)
|
||||||
Throw_error("Exponent is negative.");
|
Throw_error("Exponent is negative.");
|
||||||
self->val.intval = 0;
|
self->u.number.val.intval = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_MULTIPLY:
|
case OPHANDLE_MULTIPLY:
|
||||||
self->val.intval *= other->val.intval;
|
self->u.number.val.intval *= other->u.number.val.intval;
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_DIVIDE:
|
case OPHANDLE_DIVIDE:
|
||||||
case OPHANDLE_INTDIV:
|
case OPHANDLE_INTDIV:
|
||||||
if (other->val.intval) {
|
if (other->u.number.val.intval) {
|
||||||
self->val.intval /= other->val.intval;
|
self->u.number.val.intval /= other->u.number.val.intval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// "division by zero" output is below
|
// "division by zero" output is below
|
||||||
/*FALLTHROUGH*/
|
/*FALLTHROUGH*/
|
||||||
case OPHANDLE_MODULO:
|
case OPHANDLE_MODULO:
|
||||||
if (other->val.intval) {
|
if (other->u.number.val.intval) {
|
||||||
self->val.intval %= other->val.intval;
|
self->u.number.val.intval %= other->u.number.val.intval;
|
||||||
} else {
|
} else {
|
||||||
if (other->flags & NUMBER_IS_DEFINED)
|
if (other->u.number.flags & NUMBER_IS_DEFINED)
|
||||||
Throw_error(exception_div_by_zero);
|
Throw_error(exception_div_by_zero);
|
||||||
self->val.intval = 0;
|
self->u.number.val.intval = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_ADD:
|
case OPHANDLE_ADD:
|
||||||
self->val.intval += other->val.intval;
|
self->u.number.val.intval += other->u.number.val.intval;
|
||||||
refs = self->addr_refs + other->addr_refs; // add address references
|
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_SUBTRACT:
|
case OPHANDLE_SUBTRACT:
|
||||||
self->val.intval -= other->val.intval;
|
self->u.number.val.intval -= other->u.number.val.intval;
|
||||||
refs = self->addr_refs - other->addr_refs; // subtract address references
|
refs = self->u.number.addr_refs - other->u.number.addr_refs; // subtract address references
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_SL:
|
case OPHANDLE_SL:
|
||||||
self->val.intval <<= other->val.intval;
|
self->u.number.val.intval <<= other->u.number.val.intval;
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_ASR:
|
case OPHANDLE_ASR:
|
||||||
self->val.intval = my_asr(self->val.intval, other->val.intval);
|
self->u.number.val.intval = my_asr(self->u.number.val.intval, other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LSR:
|
case OPHANDLE_LSR:
|
||||||
self->val.intval = ((uintval_t) (self->val.intval)) >> other->val.intval;
|
self->u.number.val.intval = ((uintval_t) (self->u.number.val.intval)) >> other->u.number.val.intval;
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LE:
|
case OPHANDLE_LE:
|
||||||
self->val.intval = (self->val.intval <= other->val.intval);
|
self->u.number.val.intval = (self->u.number.val.intval <= other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LESSTHAN:
|
case OPHANDLE_LESSTHAN:
|
||||||
self->val.intval = (self->val.intval < other->val.intval);
|
self->u.number.val.intval = (self->u.number.val.intval < other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_GE:
|
case OPHANDLE_GE:
|
||||||
self->val.intval = (self->val.intval >= other->val.intval);
|
self->u.number.val.intval = (self->u.number.val.intval >= other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_GREATERTHAN:
|
case OPHANDLE_GREATERTHAN:
|
||||||
self->val.intval = (self->val.intval > other->val.intval);
|
self->u.number.val.intval = (self->u.number.val.intval > other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_NOTEQUAL:
|
case OPHANDLE_NOTEQUAL:
|
||||||
self->val.intval = (self->val.intval != other->val.intval);
|
self->u.number.val.intval = (self->u.number.val.intval != other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_EQUALS:
|
case OPHANDLE_EQUALS:
|
||||||
self->val.intval = (self->val.intval == other->val.intval);
|
self->u.number.val.intval = (self->u.number.val.intval == other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_AND:
|
case OPHANDLE_AND:
|
||||||
self->val.intval &= other->val.intval;
|
self->u.number.val.intval &= other->u.number.val.intval;
|
||||||
refs = self->addr_refs + other->addr_refs; // add address references
|
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_OR:
|
case OPHANDLE_OR:
|
||||||
self->val.intval |= other->val.intval;
|
self->u.number.val.intval |= other->u.number.val.intval;
|
||||||
refs = self->addr_refs + other->addr_refs; // add address references
|
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_EOR:
|
case OPHANDLE_EOR:
|
||||||
Throw_first_pass_warning("\"EOR\" is deprecated; use \"XOR\" instead.");
|
Throw_first_pass_warning("\"EOR\" is deprecated; use \"XOR\" instead.");
|
||||||
/*FALLTHROUGH*/
|
/*FALLTHROUGH*/
|
||||||
case OPHANDLE_XOR:
|
case OPHANDLE_XOR:
|
||||||
self->val.intval ^= other->val.intval;
|
self->u.number.val.intval ^= other->u.number.val.intval;
|
||||||
refs = self->addr_refs + other->addr_refs; // add address references
|
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
|
||||||
break;
|
break;
|
||||||
// add new dyadic operators here
|
// add new dyadic operators here
|
||||||
// case OPHANDLE_:
|
// case OPHANDLE_:
|
||||||
@ -1309,18 +1289,20 @@ static void int_handle_dyadic_operator(struct number *self, enum op_handle op, s
|
|||||||
default:
|
default:
|
||||||
Bug_found("IllegalOperatorHandleID", op);
|
Bug_found("IllegalOperatorHandleID", op);
|
||||||
}
|
}
|
||||||
self->addr_refs = refs; // update address refs with local copy
|
self->u.number.addr_refs = refs; // update address refs with local copy
|
||||||
number_fix_result_after_dyadic(self, other); // fix result flags
|
number_fix_result_after_dyadic(self, other); // fix result flags
|
||||||
}
|
}
|
||||||
|
|
||||||
// float:
|
// float:
|
||||||
// handle dyadic operator
|
// handle dyadic operator
|
||||||
static void float_handle_dyadic_operator(struct number *self, enum op_handle op, struct number *other)
|
static void float_handle_dyadic_operator(struct object *self, enum op_handle op, struct object *other)
|
||||||
{
|
{
|
||||||
int refs = 0; // default for "addr_refs", shortens this fn
|
int refs = 0; // default for "addr_refs", shortens this fn
|
||||||
|
|
||||||
// first check type of second arg:
|
// first check type of second arg:
|
||||||
if (!(other->flags & NUMBER_IS_FLOAT)) {
|
if (other->type == &type_float) {
|
||||||
|
// ok
|
||||||
|
} else if (other->type == &type_int) {
|
||||||
// handle according to operation
|
// handle according to operation
|
||||||
switch (op) {
|
switch (op) {
|
||||||
// these want two floats
|
// these want two floats
|
||||||
@ -1354,35 +1336,42 @@ static void float_handle_dyadic_operator(struct number *self, enum op_handle op,
|
|||||||
// case OPHANDLE_:
|
// case OPHANDLE_:
|
||||||
// break;
|
// break;
|
||||||
default:
|
default:
|
||||||
break;
|
unsupported_dyadic(self, op, other);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// add new types here
|
||||||
|
// } else if (other->type == &type_) {
|
||||||
|
// ...
|
||||||
|
} else {
|
||||||
|
unsupported_dyadic(self, op, other);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case OPHANDLE_POWEROF:
|
case OPHANDLE_POWEROF:
|
||||||
self->val.fpval = pow(self->val.fpval, other->val.fpval);
|
self->u.number.val.fpval = pow(self->u.number.val.fpval, other->u.number.val.fpval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_MULTIPLY:
|
case OPHANDLE_MULTIPLY:
|
||||||
self->val.fpval *= other->val.fpval;
|
self->u.number.val.fpval *= other->u.number.val.fpval;
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_DIVIDE:
|
case OPHANDLE_DIVIDE:
|
||||||
if (other->val.fpval) {
|
if (other->u.number.val.fpval) {
|
||||||
self->val.fpval /= other->val.fpval;
|
self->u.number.val.fpval /= other->u.number.val.fpval;
|
||||||
} else {
|
} else {
|
||||||
if (other->flags & NUMBER_IS_DEFINED)
|
if (other->u.number.flags & NUMBER_IS_DEFINED)
|
||||||
Throw_error(exception_div_by_zero);
|
Throw_error(exception_div_by_zero);
|
||||||
self->val.fpval = 0;
|
self->u.number.val.fpval = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_INTDIV:
|
case OPHANDLE_INTDIV:
|
||||||
if (other->val.fpval) {
|
if (other->u.number.val.fpval) {
|
||||||
self->val.intval = self->val.fpval / other->val.fpval;
|
self->u.number.val.intval = self->u.number.val.fpval / other->u.number.val.fpval; // fp becomes int!
|
||||||
} else {
|
} else {
|
||||||
if (other->flags & NUMBER_IS_DEFINED)
|
if (other->u.number.flags & NUMBER_IS_DEFINED)
|
||||||
Throw_error(exception_div_by_zero);
|
Throw_error(exception_div_by_zero);
|
||||||
self->val.intval = 0;
|
self->u.number.val.intval = 0;
|
||||||
}
|
}
|
||||||
self->flags &= ~NUMBER_IS_FLOAT; // result is int
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LSR:
|
case OPHANDLE_LSR:
|
||||||
case OPHANDLE_AND:
|
case OPHANDLE_AND:
|
||||||
@ -1394,50 +1383,50 @@ static void float_handle_dyadic_operator(struct number *self, enum op_handle op,
|
|||||||
case OPHANDLE_MODULO:
|
case OPHANDLE_MODULO:
|
||||||
float_to_int(self);
|
float_to_int(self);
|
||||||
// int handler will check other and, if needed, convert to int
|
// int handler will check other and, if needed, convert to int
|
||||||
int_handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
|
type_int.handle_dyadic_operator(self, op, other); // TODO - put recursion check around this?
|
||||||
return; // int handler has done everything
|
return; // int handler has done everything
|
||||||
|
|
||||||
case OPHANDLE_ADD:
|
case OPHANDLE_ADD:
|
||||||
self->val.fpval += other->val.fpval;
|
self->u.number.val.fpval += other->u.number.val.fpval;
|
||||||
refs = self->addr_refs + other->addr_refs; // add address references
|
refs = self->u.number.addr_refs + other->u.number.addr_refs; // add address references
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_SUBTRACT:
|
case OPHANDLE_SUBTRACT:
|
||||||
self->val.fpval -= other->val.fpval;
|
self->u.number.val.fpval -= other->u.number.val.fpval;
|
||||||
refs = self->addr_refs - other->addr_refs; // subtract address references
|
refs = self->u.number.addr_refs - other->u.number.addr_refs; // subtract address references
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_SL:
|
case OPHANDLE_SL:
|
||||||
if (other->flags & NUMBER_IS_FLOAT)
|
if (other->type == &type_float)
|
||||||
float_to_int(other);
|
float_to_int(other);
|
||||||
self->val.fpval *= pow(2.0, other->val.intval);
|
self->u.number.val.fpval *= pow(2.0, other->u.number.val.intval);
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_ASR:
|
case OPHANDLE_ASR:
|
||||||
if (other->flags & NUMBER_IS_FLOAT)
|
if (other->type == &type_float)
|
||||||
float_to_int(other);
|
float_to_int(other);
|
||||||
self->val.fpval /= (1 << other->val.intval); // FIXME - why not use pow() as in SL above?
|
self->u.number.val.fpval /= (1 << other->u.number.val.intval); // FIXME - why not use pow() as in SL above?
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LE:
|
case OPHANDLE_LE:
|
||||||
self->val.intval = (self->val.fpval <= other->val.fpval);
|
self->u.number.val.intval = (self->u.number.val.fpval <= other->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_LESSTHAN:
|
case OPHANDLE_LESSTHAN:
|
||||||
self->val.intval = (self->val.fpval < other->val.fpval);
|
self->u.number.val.intval = (self->u.number.val.fpval < other->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_GE:
|
case OPHANDLE_GE:
|
||||||
self->val.intval = (self->val.fpval >= other->val.fpval);
|
self->u.number.val.intval = (self->u.number.val.fpval >= other->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_GREATERTHAN:
|
case OPHANDLE_GREATERTHAN:
|
||||||
self->val.intval = (self->val.fpval > other->val.fpval);
|
self->u.number.val.intval = (self->u.number.val.fpval > other->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_NOTEQUAL:
|
case OPHANDLE_NOTEQUAL:
|
||||||
self->val.intval = (self->val.fpval != other->val.fpval);
|
self->u.number.val.intval = (self->u.number.val.fpval != other->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
case OPHANDLE_EQUALS:
|
case OPHANDLE_EQUALS:
|
||||||
self->val.intval = (self->val.fpval == other->val.fpval);
|
self->u.number.val.intval = (self->u.number.val.fpval == other->u.number.val.fpval);
|
||||||
self->flags &= ~NUMBER_IS_FLOAT;
|
self->type = &type_int; // result is int
|
||||||
break;
|
break;
|
||||||
// add new dyadic operators here
|
// add new dyadic operators here
|
||||||
// case OPHANDLE_:
|
// case OPHANDLE_:
|
||||||
@ -1446,10 +1435,107 @@ static void float_handle_dyadic_operator(struct number *self, enum op_handle op,
|
|||||||
default:
|
default:
|
||||||
Bug_found("IllegalOperatorHandleFD", op);
|
Bug_found("IllegalOperatorHandleFD", op);
|
||||||
}
|
}
|
||||||
self->addr_refs = refs; // update address refs with local copy
|
self->u.number.addr_refs = refs; // update address refs with local copy
|
||||||
number_fix_result_after_dyadic(self, other); // fix result flags
|
number_fix_result_after_dyadic(self, other); // fix result flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int/float:
|
||||||
|
// set flags according to result
|
||||||
|
static void number_fix_result(struct object *self)
|
||||||
|
{
|
||||||
|
// only allow a single force bit
|
||||||
|
if (self->u.number.flags & NUMBER_FORCES_24)
|
||||||
|
self->u.number.flags &= ~(NUMBER_FORCES_16 | NUMBER_FORCES_8);
|
||||||
|
else if (self->u.number.flags & NUMBER_FORCES_16)
|
||||||
|
self->u.number.flags &= ~NUMBER_FORCES_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int:
|
||||||
|
// set flags according to result
|
||||||
|
static void int_fix_result(struct object *self)
|
||||||
|
{
|
||||||
|
number_fix_result(self);
|
||||||
|
// if undefined, return zero
|
||||||
|
if (!(self->u.number.flags & NUMBER_IS_DEFINED))
|
||||||
|
self->u.number.val.intval = 0;
|
||||||
|
// if value is sure, check to set FITS BYTE
|
||||||
|
else if ((!(self->u.number.flags & NUMBER_EVER_UNDEFINED))
|
||||||
|
&& (self->u.number.val.intval <= 255)
|
||||||
|
&& (self->u.number.val.intval >= -128))
|
||||||
|
self->u.number.flags |= NUMBER_FITS_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// float:
|
||||||
|
// set flags according to result
|
||||||
|
static void float_fix_result(struct object *self)
|
||||||
|
{
|
||||||
|
number_fix_result(self);
|
||||||
|
// if undefined, return zero
|
||||||
|
if (!(self->u.number.flags & NUMBER_IS_DEFINED))
|
||||||
|
self->u.number.val.fpval = 0;
|
||||||
|
// if value is sure, check to set FITS BYTE
|
||||||
|
else if ((!(self->u.number.flags & NUMBER_EVER_UNDEFINED))
|
||||||
|
&& (self->u.number.val.fpval <= 255.0)
|
||||||
|
&& (self->u.number.val.fpval >= -128.0))
|
||||||
|
self->u.number.flags |= NUMBER_FITS_BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// int:
|
||||||
|
// print value for user message
|
||||||
|
static void int_print(struct object *self, struct dynabuf *db)
|
||||||
|
{
|
||||||
|
char buffer[32]; // 11 for dec, 8 for hex
|
||||||
|
|
||||||
|
if (self->u.number.flags & NUMBER_IS_DEFINED) {
|
||||||
|
sprintf(buffer, "%ld (0x%lx)", (long) self->u.number.val.intval, (long) self->u.number.val.intval);
|
||||||
|
DynaBuf_add_string(db, buffer);
|
||||||
|
} else {
|
||||||
|
DynaBuf_add_string(db, "<UNDEFINED INT>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// float:
|
||||||
|
// print value for user message
|
||||||
|
static void float_print(struct object *self, struct dynabuf *db)
|
||||||
|
{
|
||||||
|
char buffer[40];
|
||||||
|
|
||||||
|
if (self->u.number.flags & NUMBER_IS_DEFINED) {
|
||||||
|
// write up to 30 significant characters.
|
||||||
|
// remaining 10 should suffice for sign,
|
||||||
|
// decimal point, exponent, terminator etc.
|
||||||
|
sprintf(buffer, "%.30g", self->u.number.val.fpval);
|
||||||
|
DynaBuf_add_string(db, buffer);
|
||||||
|
} else {
|
||||||
|
DynaBuf_add_string(db, "<UNDEFINED FLOAT>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct type type_int = {
|
||||||
|
//"Integer",
|
||||||
|
number_is_defined,
|
||||||
|
int_handle_monadic_operator,
|
||||||
|
int_handle_dyadic_operator,
|
||||||
|
int_fix_result,
|
||||||
|
int_print
|
||||||
|
};
|
||||||
|
struct type type_float = {
|
||||||
|
//"Float",
|
||||||
|
number_is_defined,
|
||||||
|
float_handle_monadic_operator,
|
||||||
|
float_handle_dyadic_operator,
|
||||||
|
float_fix_result,
|
||||||
|
float_print
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
struct type type_string = {
|
||||||
|
//"String",
|
||||||
|
};
|
||||||
|
struct type type_list = {
|
||||||
|
//"List",
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// handler for special operators like parentheses and start/end of expression:
|
// handler for special operators like parentheses and start/end of expression:
|
||||||
// returns whether caller should just return without fixing stack (because this fn has fixed it)
|
// returns whether caller should just return without fixing stack (because this fn has fixed it)
|
||||||
@ -1526,24 +1612,14 @@ static void try_to_reduce_stacks(struct expression *expression)
|
|||||||
// so perform that operation!
|
// so perform that operation!
|
||||||
#define ARG_PREV (arg_stack[arg_sp - 2])
|
#define ARG_PREV (arg_stack[arg_sp - 2])
|
||||||
#define ARG_NOW (arg_stack[arg_sp - 1])
|
#define ARG_NOW (arg_stack[arg_sp - 1])
|
||||||
// TODO - make handler functions for monadic and dyadic operators type-
|
|
||||||
// specific, so strings and lists can get their own handler functions.
|
|
||||||
switch (previous_op->group) {
|
switch (previous_op->group) {
|
||||||
case OPGROUP_MONADIC: // monadic operators
|
case OPGROUP_MONADIC: // monadic operators
|
||||||
if (ARG_NOW.flags & NUMBER_IS_FLOAT) {
|
ARG_NOW.type->handle_monadic_operator(&ARG_NOW, previous_op->handle);
|
||||||
float_handle_monadic_operator(&ARG_NOW, previous_op->handle);
|
|
||||||
} else {
|
|
||||||
int_handle_monadic_operator(&ARG_NOW, previous_op->handle);
|
|
||||||
}
|
|
||||||
// operation was something other than parentheses
|
// operation was something other than parentheses
|
||||||
expression->is_parenthesized = FALSE;
|
expression->is_parenthesized = FALSE;
|
||||||
break;
|
break;
|
||||||
case OPGROUP_DYADIC: // dyadic operators
|
case OPGROUP_DYADIC: // dyadic operators
|
||||||
if (ARG_PREV.flags & NUMBER_IS_FLOAT) {
|
ARG_PREV.type->handle_dyadic_operator(&ARG_PREV, previous_op->handle, &ARG_NOW);
|
||||||
float_handle_dyadic_operator(&ARG_PREV, previous_op->handle, &ARG_NOW);
|
|
||||||
} else {
|
|
||||||
int_handle_dyadic_operator(&ARG_PREV, previous_op->handle, &ARG_NOW);
|
|
||||||
}
|
|
||||||
// decrement argument stack pointer because dyadic operator merged two arguments into one
|
// decrement argument stack pointer because dyadic operator merged two arguments into one
|
||||||
--arg_sp;
|
--arg_sp;
|
||||||
// operation was something other than parentheses
|
// operation was something other than parentheses
|
||||||
@ -1570,7 +1646,7 @@ static void try_to_reduce_stacks(struct expression *expression)
|
|||||||
// this is what the exported functions call
|
// this is what the exported functions call
|
||||||
static void parse_expression(struct expression *expression)
|
static void parse_expression(struct expression *expression)
|
||||||
{
|
{
|
||||||
struct number *result = &expression->number;
|
struct object *result = &expression->result;
|
||||||
|
|
||||||
// init
|
// init
|
||||||
expression->is_empty = TRUE; // becomes FALSE when first valid char gets parsed
|
expression->is_empty = TRUE; // becomes FALSE when first valid char gets parsed
|
||||||
@ -1619,27 +1695,27 @@ static void parse_expression(struct expression *expression)
|
|||||||
// if there was nothing to parse, mark as undefined FIXME - change this! make "nothing" its own result type; only numbers may be undefined
|
// 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)
|
// (so ALU_defined_int() can react)
|
||||||
if (expression->is_empty) {
|
if (expression->is_empty) {
|
||||||
result->flags &= ~NUMBER_IS_DEFINED;
|
result->type = &type_int;
|
||||||
|
result->u.number.flags = NUMBER_EVER_UNDEFINED; // ...and without NUMBER_IS_DEFINED!
|
||||||
|
result->u.number.val.intval = 0;
|
||||||
|
result->u.number.addr_refs = 0;
|
||||||
} else {
|
} else {
|
||||||
// not empty. undefined?
|
// not empty. undefined?
|
||||||
if (!(expression->number.flags & NUMBER_IS_DEFINED)) {
|
if (!(result->type->is_defined(result))) {
|
||||||
// then count (in all passes)
|
// then count (in all passes)
|
||||||
++pass.undefined_count;
|
++pass.undefined_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// do some checks depending on int/float
|
// do some checks depending on int/float
|
||||||
if (result->flags & NUMBER_IS_FLOAT) {
|
result->type->fix_result(result);
|
||||||
float_fixresult(result);
|
|
||||||
} else {
|
|
||||||
int_fixresult(result);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// State is STATE_ERROR. Errors have already been reported,
|
// State is STATE_ERROR. Errors have already been reported,
|
||||||
// but we must make sure not to pass bogus data to caller.
|
// 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!"
|
// FIXME - just use the return value to indicate "there were errors, do not use result!"
|
||||||
result->flags = 0; // maybe set DEFINED flag to suppress follow-up errors?
|
result->type = &type_int;
|
||||||
result->val.intval = 0;
|
result->u.number.flags = 0; // maybe set DEFINED flag to suppress follow-up errors?
|
||||||
result->addr_refs = 0;
|
result->u.number.val.intval = 0;
|
||||||
|
result->u.number.addr_refs = 0;
|
||||||
// make sure no additional (spurious) errors are reported:
|
// make sure no additional (spurious) errors are reported:
|
||||||
Input_skip_remainder();
|
Input_skip_remainder();
|
||||||
// FIXME - remove this when new function interface gets used:
|
// FIXME - remove this when new function interface gets used:
|
||||||
@ -1664,10 +1740,14 @@ intval_t ALU_any_int(void) // ACCEPT_UNDEFINED
|
|||||||
Throw_error(exception_paren_open);
|
Throw_error(exception_paren_open);
|
||||||
if (expression.is_empty)
|
if (expression.is_empty)
|
||||||
Throw_error(exception_no_value);
|
Throw_error(exception_no_value);
|
||||||
if (expression.number.flags & NUMBER_IS_FLOAT)
|
if (expression.result.type == &type_int)
|
||||||
return expression.number.val.fpval;
|
return expression.result.u.number.val.intval;
|
||||||
else
|
|
||||||
return expression.number.val.intval;
|
if (expression.result.type == &type_float)
|
||||||
|
return expression.result.u.number.val.fpval;
|
||||||
|
|
||||||
|
Bug_found("Unhandled object type!", 0);
|
||||||
|
return 0; // inhibit compiler warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1685,15 +1765,20 @@ void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
|
|||||||
pass.complain_about_undefined = TRUE;
|
pass.complain_about_undefined = TRUE;
|
||||||
parse_expression(&expression);
|
parse_expression(&expression);
|
||||||
pass.complain_about_undefined = buf;
|
pass.complain_about_undefined = buf;
|
||||||
*intresult = expression.number;
|
|
||||||
if (expression.open_parentheses)
|
if (expression.open_parentheses)
|
||||||
Throw_error(exception_paren_open);
|
Throw_error(exception_paren_open);
|
||||||
if (expression.is_empty)
|
if (expression.is_empty)
|
||||||
Throw_serious_error(exception_no_value);
|
Throw_serious_error(exception_no_value);
|
||||||
if (!(intresult->flags & NUMBER_IS_DEFINED))
|
if (expression.result.type == &type_int) {
|
||||||
|
// ok
|
||||||
|
} else if (expression.result.type == &type_float) {
|
||||||
|
float_to_int(&expression.result);
|
||||||
|
} else {
|
||||||
|
Bug_found("Unhandled object type!", 1);
|
||||||
|
}
|
||||||
|
if (!(expression.result.u.number.flags & NUMBER_IS_DEFINED))
|
||||||
Throw_serious_error(exception_value_not_defined);
|
Throw_serious_error(exception_value_not_defined);
|
||||||
if (intresult->flags & NUMBER_IS_FLOAT)
|
*intresult = expression.result.u.number;
|
||||||
float_to_int(intresult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1709,8 +1794,10 @@ void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFI
|
|||||||
{
|
{
|
||||||
parse_expression(expression);
|
parse_expression(expression);
|
||||||
// convert float to int
|
// convert float to int
|
||||||
if (expression->number.flags & NUMBER_IS_FLOAT)
|
if (expression->result.type == &type_float)
|
||||||
float_to_int(&(expression->number));
|
float_to_int(&(expression->result));
|
||||||
|
if (expression->result.type != &type_int)
|
||||||
|
Bug_found("Unhandled object type!", 2);
|
||||||
if (expression->open_parentheses > paren) {
|
if (expression->open_parentheses > paren) {
|
||||||
expression->open_parentheses = 0;
|
expression->open_parentheses = 0;
|
||||||
Throw_error(exception_paren_open);
|
Throw_error(exception_paren_open);
|
||||||
@ -1726,12 +1813,12 @@ void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFI
|
|||||||
// EMPTY: complain
|
// EMPTY: complain
|
||||||
// UNDEFINED: allow
|
// UNDEFINED: allow
|
||||||
// FLOAT: keep
|
// FLOAT: keep
|
||||||
void ALU_any_result(struct number *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT
|
void ALU_any_result(struct object *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT
|
||||||
{
|
{
|
||||||
struct expression expression;
|
struct expression expression;
|
||||||
|
|
||||||
parse_expression(&expression);
|
parse_expression(&expression);
|
||||||
*result = expression.number;
|
*result = expression.result;
|
||||||
if (expression.open_parentheses)
|
if (expression.open_parentheses)
|
||||||
Throw_error(exception_paren_open);
|
Throw_error(exception_paren_open);
|
||||||
if (expression.is_empty)
|
if (expression.is_empty)
|
||||||
@ -1754,7 +1841,7 @@ void ALU_addrmode_int(struct expression *expression, int paren)
|
|||||||
when parsing addressing modes needvalue!
|
when parsing addressing modes needvalue!
|
||||||
|
|
||||||
// stores value and flags (result may be either int or float)
|
// stores value and flags (result may be either int or float)
|
||||||
void ALU_any_result(struct number *result)
|
void ALU_any_result(struct object *result)
|
||||||
macro.c
|
macro.c
|
||||||
macro call, when parsing call-by-value arg don't care
|
macro call, when parsing call-by-value arg don't care
|
||||||
pseudoopcodes.c
|
pseudoopcodes.c
|
||||||
|
30
src/alu.h
30
src/alu.h
@ -10,20 +10,27 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
// types
|
enum op_handle;
|
||||||
/*
|
struct dynabuf;
|
||||||
type_nothing, // needed?
|
struct type {
|
||||||
type_int, type_float // what is returned by the current functions
|
//const char *name;
|
||||||
type_string, // TODO
|
boolean (*is_defined)(struct object *self);
|
||||||
type_register, // reserved cpu constant (register names), TODO
|
void (*handle_monadic_operator)(struct object *self, enum op_handle op);
|
||||||
type_list, // TODO
|
void (*handle_dyadic_operator)(struct object *self, enum op_handle op, struct object *other);
|
||||||
*/
|
void (*fix_result)(struct object *self);
|
||||||
|
void (*print)(struct object *self, struct dynabuf *db);
|
||||||
|
};
|
||||||
|
extern struct type type_int;
|
||||||
|
extern struct type type_float;
|
||||||
|
//extern struct type type_string;
|
||||||
|
//extern struct type type_list;
|
||||||
|
|
||||||
struct expression {
|
struct expression {
|
||||||
//struct type *type;
|
struct object result;
|
||||||
struct number number;
|
|
||||||
boolean is_empty; // nothing parsed (first character was a delimiter)
|
boolean is_empty; // nothing parsed (first character was a delimiter)
|
||||||
int open_parentheses; // number of parentheses still open
|
int open_parentheses; // number of parentheses still open
|
||||||
boolean is_parenthesized; // whole expression was in parentheses (indicating indirect addressing)
|
boolean is_parenthesized; // whole expression was in parentheses (indicating indirect addressing)
|
||||||
|
// TODO - how to return reserved cpu constant (register names)?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +48,6 @@ struct expression {
|
|||||||
// passes; because in the first pass there will almost for sure be
|
// passes; because in the first pass there will almost for sure be
|
||||||
// labels that are undefined, we can't simply get the addressing mode
|
// labels that are undefined, we can't simply get the addressing mode
|
||||||
// from looking at the parameter's value.
|
// from looking at the parameter's value.
|
||||||
#define NUMBER_IS_FLOAT (1u << 6) // floating point value
|
|
||||||
|
|
||||||
|
|
||||||
// create dynamic buffer, operator/function trees and operator/operand stacks
|
// create dynamic buffer, operator/function trees and operator/operand stacks
|
||||||
@ -67,7 +73,7 @@ extern void ALU_defined_int(struct number *intresult);
|
|||||||
// stores int value and flags, allowing for "paren" '(' too many (x-indirect addr).
|
// stores int value and flags, allowing for "paren" '(' too many (x-indirect addr).
|
||||||
extern void ALU_addrmode_int(struct expression *expression, int paren);
|
extern void ALU_addrmode_int(struct expression *expression, int paren);
|
||||||
// stores value and flags (result may be either int or float)
|
// stores value and flags (result may be either int or float)
|
||||||
extern void ALU_any_result(struct number *result);
|
extern void ALU_any_result(struct object *result);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
18
src/config.h
18
src/config.h
@ -19,15 +19,25 @@ typedef enum { FALSE = 0, TRUE } boolean; // yes, I could include <stdbool.h>, b
|
|||||||
typedef unsigned int scope_t;
|
typedef unsigned int scope_t;
|
||||||
typedef signed long intval_t; // at least 32 bits
|
typedef signed long intval_t; // at least 32 bits
|
||||||
typedef unsigned long uintval_t; // just for logical shift right
|
typedef unsigned long uintval_t; // just for logical shift right
|
||||||
// result structure type definition with support for floating point
|
|
||||||
struct number { // either int or float
|
// structure for ints/floats
|
||||||
int flags; // result flags (see alu.h, one if these tells ints and floats apart)
|
struct number {
|
||||||
|
int flags; // DEFINED, FITS_IN_BYTE, etc. (see alu.h)
|
||||||
union {
|
union {
|
||||||
intval_t intval; // integer value
|
intval_t intval; // integer value
|
||||||
double fpval; // floating point value
|
double fpval; // floating point value
|
||||||
} val; // Expression value
|
} val;
|
||||||
int addr_refs; // address reference count (only look at this if value is DEFINED)
|
int addr_refs; // address reference count (only look at this if value is DEFINED)
|
||||||
};
|
};
|
||||||
|
// structure for ints/floats/TODO...
|
||||||
|
struct type;
|
||||||
|
struct object {
|
||||||
|
struct type *type;
|
||||||
|
union {
|
||||||
|
struct number number;
|
||||||
|
// TODO - add string struct
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// debugging flag, should be undefined in release version
|
// debugging flag, should be undefined in release version
|
||||||
|
17
src/flow.c
17
src/flow.c
@ -43,7 +43,7 @@ void flow_forloop(struct for_loop *loop)
|
|||||||
{
|
{
|
||||||
struct input loop_input,
|
struct input loop_input,
|
||||||
*outer_input;
|
*outer_input;
|
||||||
struct number loop_counter;
|
struct object loop_counter;
|
||||||
|
|
||||||
// switching input makes us lose GotByte. But we know it's '}' anyway!
|
// switching input makes us lose GotByte. But we know it's '}' anyway!
|
||||||
// set up new input
|
// set up new input
|
||||||
@ -55,27 +55,28 @@ void flow_forloop(struct for_loop *loop)
|
|||||||
// (not yet useable; pointer and line number are still missing)
|
// (not yet useable; pointer and line number are still missing)
|
||||||
Input_now = &loop_input;
|
Input_now = &loop_input;
|
||||||
// init counter
|
// init counter
|
||||||
loop_counter.flags = NUMBER_IS_DEFINED;
|
loop_counter.type = &type_int;
|
||||||
loop_counter.val.intval = loop->counter.first;
|
loop_counter.u.number.flags = NUMBER_IS_DEFINED;
|
||||||
loop_counter.addr_refs = loop->counter.addr_refs;
|
loop_counter.u.number.val.intval = loop->counter.first;
|
||||||
|
loop_counter.u.number.addr_refs = loop->counter.addr_refs;
|
||||||
symbol_set_value(loop->symbol, &loop_counter, TRUE);
|
symbol_set_value(loop->symbol, &loop_counter, TRUE);
|
||||||
if (loop->use_old_algo) {
|
if (loop->use_old_algo) {
|
||||||
// old algo for old syntax:
|
// old algo for old syntax:
|
||||||
// if count == 0, skip loop
|
// if count == 0, skip loop
|
||||||
if (loop->counter.last) {
|
if (loop->counter.last) {
|
||||||
do {
|
do {
|
||||||
loop_counter.val.intval += loop->counter.increment;
|
loop_counter.u.number.val.intval += loop->counter.increment;
|
||||||
symbol_set_value(loop->symbol, &loop_counter, TRUE);
|
symbol_set_value(loop->symbol, &loop_counter, TRUE);
|
||||||
parse_ram_block(&loop->block);
|
parse_ram_block(&loop->block);
|
||||||
} while (loop_counter.val.intval < loop->counter.last);
|
} while (loop_counter.u.number.val.intval < loop->counter.last);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// new algo for new syntax:
|
// new algo for new syntax:
|
||||||
do {
|
do {
|
||||||
parse_ram_block(&loop->block);
|
parse_ram_block(&loop->block);
|
||||||
loop_counter.val.intval += loop->counter.increment;
|
loop_counter.u.number.val.intval += loop->counter.increment;
|
||||||
symbol_set_value(loop->symbol, &loop_counter, TRUE);
|
symbol_set_value(loop->symbol, &loop_counter, TRUE);
|
||||||
} while (loop_counter.val.intval != (loop->counter.last + loop->counter.increment));
|
} while (loop_counter.u.number.val.intval != (loop->counter.last + loop->counter.increment));
|
||||||
}
|
}
|
||||||
// restore previous input:
|
// restore previous input:
|
||||||
Input_now = outer_input;
|
Input_now = outer_input;
|
||||||
|
@ -42,7 +42,7 @@ struct macro {
|
|||||||
// gives us the possibility to find out which args are call-by-value and
|
// gives us the possibility to find out which args are call-by-value and
|
||||||
// which ones are call-by-reference.
|
// which ones are call-by-reference.
|
||||||
union macro_arg_t {
|
union macro_arg_t {
|
||||||
struct number result; // value and flags (call by value)
|
struct object result; // value and flags (call by value)
|
||||||
struct symbol *symbol; // pointer to symbol struct (call by reference)
|
struct symbol *symbol; // pointer to symbol struct (call by reference)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -527,7 +527,7 @@ static void get_int_arg(struct number *result, boolean complain_about_indirect)
|
|||||||
Throw_first_pass_warning("There are unneeded parentheses, you know indirect addressing is impossible here, right?"); // FIXME - rephrase!
|
Throw_first_pass_warning("There are unneeded parentheses, you know indirect addressing is impossible here, right?"); // FIXME - rephrase!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*result = expression.number;
|
*result = expression.result.u.number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -560,7 +560,7 @@ static int get_addr_mode(struct number *result)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ALU_addrmode_int(&expression, 1); // direct call instead of wrapper, to allow for "(...,"
|
ALU_addrmode_int(&expression, 1); // direct call instead of wrapper, to allow for "(...,"
|
||||||
*result = expression.number;
|
*result = expression.result.u.number;
|
||||||
typesystem_want_addr(result);
|
typesystem_want_addr(result);
|
||||||
// check for indirect addressing
|
// check for indirect addressing
|
||||||
if (expression.is_parenthesized)
|
if (expression.is_parenthesized)
|
||||||
|
@ -692,7 +692,7 @@ Throw_serious_error("Not yet"); // FIXME
|
|||||||
// (re)set symbol
|
// (re)set symbol
|
||||||
static enum eos po_set(void) // now GotByte = illegal char
|
static enum eos po_set(void) // now GotByte = illegal char
|
||||||
{
|
{
|
||||||
struct number result;
|
struct object result;
|
||||||
int force_bit;
|
int force_bit;
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
scope_t scope;
|
scope_t scope;
|
||||||
@ -712,11 +712,16 @@ static enum eos po_set(void) // now GotByte = illegal char
|
|||||||
GetByte(); // proceed with next char
|
GetByte(); // proceed with next char
|
||||||
ALU_any_result(&result);
|
ALU_any_result(&result);
|
||||||
// clear symbol's force bits and set new ones
|
// clear symbol's force bits and set new ones
|
||||||
symbol->result.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
|
// (but only do this for numbers!)
|
||||||
if (force_bit) {
|
if (((symbol->result.type == &type_int) || (symbol->result.type == &type_float))
|
||||||
symbol->result.flags |= force_bit;
|
&& ((result.type == &type_int) || (result.type == &type_float))) {
|
||||||
result.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
|
symbol->result.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
|
||||||
|
if (force_bit) {
|
||||||
|
symbol->result.u.number.flags |= force_bit;
|
||||||
|
result.u.number.flags &= ~(NUMBER_FORCEBITS | NUMBER_FITS_BYTE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME - take a good look at the flags handling above and in the fn called below and clean this up!
|
||||||
symbol_set_value(symbol, &result, TRUE);
|
symbol_set_value(symbol, &result, TRUE);
|
||||||
return ENSURE_EOS;
|
return ENSURE_EOS;
|
||||||
}
|
}
|
||||||
@ -858,7 +863,7 @@ static boolean check_ifdef_condition(void)
|
|||||||
// in first pass, count usage
|
// in first pass, count usage
|
||||||
if (FIRST_PASS)
|
if (FIRST_PASS)
|
||||||
symbol->usage++;
|
symbol->usage++;
|
||||||
return !!(symbol->result.flags & NUMBER_IS_DEFINED);
|
return symbol->result.type->is_defined(&symbol->result);
|
||||||
}
|
}
|
||||||
// new if/ifdef/ifndef/else function, to be able to do ELSE IF
|
// new if/ifdef/ifndef/else function, to be able to do ELSE IF
|
||||||
enum ifmode {
|
enum ifmode {
|
||||||
@ -998,7 +1003,7 @@ static enum eos ifdef_ifndef(boolean invert) // now GotByte = illegal char
|
|||||||
// in first pass, count usage
|
// in first pass, count usage
|
||||||
if (FIRST_PASS)
|
if (FIRST_PASS)
|
||||||
symbol->usage++;
|
symbol->usage++;
|
||||||
if (symbol->result.flags & NUMBER_IS_DEFINED)
|
if (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
|
||||||
defined = TRUE;
|
defined = TRUE;
|
||||||
}
|
}
|
||||||
SKIPSPACE();
|
SKIPSPACE();
|
||||||
@ -1188,7 +1193,7 @@ static struct dynabuf *user_message; // dynamic buffer (!warn/error/serious)
|
|||||||
// helper function to show user-defined messages
|
// helper function to show user-defined messages
|
||||||
static enum eos throw_string(const char prefix[], void (*fn)(const char *))
|
static enum eos throw_string(const char prefix[], void (*fn)(const char *))
|
||||||
{
|
{
|
||||||
struct number result;
|
struct object object;
|
||||||
|
|
||||||
DYNABUF_CLEAR(user_message);
|
DYNABUF_CLEAR(user_message);
|
||||||
DynaBuf_add_string(user_message, prefix);
|
DynaBuf_add_string(user_message, prefix);
|
||||||
@ -1207,31 +1212,8 @@ static enum eos throw_string(const char prefix[], void (*fn)(const char *))
|
|||||||
GetByte();
|
GetByte();
|
||||||
} else {
|
} else {
|
||||||
// parse value
|
// parse value
|
||||||
ALU_any_result(&result);
|
ALU_any_result(&object);
|
||||||
if (result.flags & NUMBER_IS_FLOAT) {
|
object.type->print(&object, user_message);
|
||||||
// floating point
|
|
||||||
if (result.flags & NUMBER_IS_DEFINED) {
|
|
||||||
char buffer[40];
|
|
||||||
|
|
||||||
// write up to 30 significant characters.
|
|
||||||
// remaining 10 should suffice for sign,
|
|
||||||
// decimal point, exponent, terminator etc.
|
|
||||||
sprintf(buffer, "%.30g", result.val.fpval);
|
|
||||||
DynaBuf_add_string(user_message, buffer);
|
|
||||||
} else {
|
|
||||||
DynaBuf_add_string(user_message, "<UNDEFINED FLOAT>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// integer
|
|
||||||
if (result.flags & NUMBER_IS_DEFINED) {
|
|
||||||
char buffer[32]; // 11 for dec, 8 for hex
|
|
||||||
|
|
||||||
sprintf(buffer, "%ld (0x%lx)", (long) result.val.intval, (long) result.val.intval);
|
|
||||||
DynaBuf_add_string(user_message, buffer);
|
|
||||||
} else {
|
|
||||||
DynaBuf_add_string(user_message, "<UNDEFINED INT>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} while (Input_accept_comma());
|
} while (Input_accept_comma());
|
||||||
DynaBuf_append(user_message, '\0');
|
DynaBuf_append(user_message, '\0');
|
||||||
|
159
src/symbol.c
159
src/symbol.c
@ -30,12 +30,17 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
|
|||||||
{
|
{
|
||||||
struct symbol *symbol = node->body;
|
struct symbol *symbol = node->body;
|
||||||
|
|
||||||
|
// if symbol is neither int nor float, skip
|
||||||
|
if ((symbol->result.type != &type_int)
|
||||||
|
&& (symbol->result.type != &type_float))
|
||||||
|
return;
|
||||||
|
|
||||||
// output name
|
// output name
|
||||||
if (config.warn_on_type_mismatch
|
if (config.warn_on_type_mismatch
|
||||||
&& symbol->result.addr_refs == 1)
|
&& symbol->result.u.number.addr_refs == 1)
|
||||||
fprintf(fd, "!addr");
|
fprintf(fd, "!addr");
|
||||||
fprintf(fd, "\t%s", node->id_string);
|
fprintf(fd, "\t%s", node->id_string);
|
||||||
switch (symbol->result.flags & NUMBER_FORCEBITS) {
|
switch (symbol->result.u.number.flags & NUMBER_FORCEBITS) {
|
||||||
case NUMBER_FORCES_16:
|
case NUMBER_FORCES_16:
|
||||||
fprintf(fd, "+2\t= ");
|
fprintf(fd, "+2\t= ");
|
||||||
break;
|
break;
|
||||||
@ -47,15 +52,17 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
|
|||||||
default:
|
default:
|
||||||
fprintf(fd, "\t= ");
|
fprintf(fd, "\t= ");
|
||||||
}
|
}
|
||||||
if (symbol->result.flags & NUMBER_IS_DEFINED) {
|
if (symbol->result.u.number.flags & NUMBER_IS_DEFINED) {
|
||||||
if (symbol->result.flags & NUMBER_IS_FLOAT)
|
if (symbol->result.type == &type_int)
|
||||||
fprintf(fd, "%.30f", symbol->result.val.fpval); //FIXME %g
|
fprintf(fd, "$%x", (unsigned) symbol->result.u.number.val.intval);
|
||||||
|
else if (symbol->result.type == &type_float)
|
||||||
|
fprintf(fd, "%.30f", symbol->result.u.number.val.fpval); //FIXME %g
|
||||||
else
|
else
|
||||||
fprintf(fd, "$%x", (unsigned) symbol->result.val.intval);
|
Bug_found("BogusType", 0); // FIXME - put in docs!
|
||||||
} else {
|
} else {
|
||||||
fprintf(fd, " ?"); // TODO - maybe write "UNDEFINED" instead? then the file could at least be parsed without errors
|
fprintf(fd, " ?"); // TODO - maybe write "UNDEFINED" instead? then the file could at least be parsed without errors
|
||||||
}
|
}
|
||||||
if (symbol->result.flags & NUMBER_EVER_UNDEFINED)
|
if (symbol->result.u.number.flags & NUMBER_EVER_UNDEFINED)
|
||||||
fprintf(fd, "\t; ?"); // TODO - write "forward" instead?
|
fprintf(fd, "\t; ?"); // TODO - write "forward" instead?
|
||||||
if (symbol->usage == 0)
|
if (symbol->usage == 0)
|
||||||
fprintf(fd, "\t; unused");
|
fprintf(fd, "\t; unused");
|
||||||
@ -69,10 +76,10 @@ static void dump_vice_address(struct rwnode *node, FILE *fd)
|
|||||||
struct symbol *symbol = node->body;
|
struct symbol *symbol = node->body;
|
||||||
|
|
||||||
// dump address symbols even if they are not used
|
// dump address symbols even if they are not used
|
||||||
if ((symbol->result.flags & NUMBER_IS_DEFINED)
|
if ((symbol->result.type == &type_int)
|
||||||
&& !(symbol->result.flags & NUMBER_IS_FLOAT)
|
&& (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
|
||||||
&& (symbol->result.addr_refs == 1))
|
&& (symbol->result.u.number.addr_refs == 1))
|
||||||
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.val.intval, node->id_string);
|
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.u.number.val.intval, node->id_string);
|
||||||
}
|
}
|
||||||
static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
|
static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
|
||||||
{
|
{
|
||||||
@ -80,10 +87,10 @@ static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
|
|||||||
|
|
||||||
// dump non-addresses that are used
|
// dump non-addresses that are used
|
||||||
if (symbol->usage
|
if (symbol->usage
|
||||||
&& (symbol->result.flags & NUMBER_IS_DEFINED)
|
&& (symbol->result.type == &type_int)
|
||||||
&& !(symbol->result.flags & NUMBER_IS_FLOAT)
|
&& (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
|
||||||
&& (symbol->result.addr_refs != 1))
|
&& (symbol->result.u.number.addr_refs != 1))
|
||||||
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.val.intval, node->id_string);
|
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.u.number.val.intval, node->id_string);
|
||||||
}
|
}
|
||||||
static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
|
static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
|
||||||
{
|
{
|
||||||
@ -91,10 +98,10 @@ static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
|
|||||||
|
|
||||||
// dump non-addresses that are unused
|
// dump non-addresses that are unused
|
||||||
if (!symbol->usage
|
if (!symbol->usage
|
||||||
&& (symbol->result.flags & NUMBER_IS_DEFINED)
|
&& (symbol->result.type == &type_int)
|
||||||
&& !(symbol->result.flags & NUMBER_IS_FLOAT)
|
&& (symbol->result.u.number.flags & NUMBER_IS_DEFINED)
|
||||||
&& (symbol->result.addr_refs != 1))
|
&& (symbol->result.u.number.addr_refs != 1))
|
||||||
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.val.intval, node->id_string);
|
fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->result.u.number.val.intval, node->id_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -105,7 +112,7 @@ struct symbol *symbol_find(scope_t scope, int flags)
|
|||||||
struct rwnode *node;
|
struct rwnode *node;
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
boolean node_created;
|
boolean node_created;
|
||||||
int force_bits = flags & NUMBER_FORCEBITS;
|
int new_force_bits;
|
||||||
|
|
||||||
node_created = Tree_hard_scan(&node, symbols_forest, scope, TRUE);
|
node_created = Tree_hard_scan(&node, symbols_forest, scope, TRUE);
|
||||||
// if node has just been created, create symbol as well
|
// if node has just been created, create symbol as well
|
||||||
@ -113,57 +120,75 @@ struct symbol *symbol_find(scope_t scope, int flags)
|
|||||||
// create new symbol structure
|
// create new symbol structure
|
||||||
symbol = safe_malloc(sizeof(*symbol));
|
symbol = safe_malloc(sizeof(*symbol));
|
||||||
// finish empty symbol item
|
// finish empty symbol item
|
||||||
symbol->result.flags = flags;
|
symbol->result.type = &type_int;
|
||||||
symbol->result.addr_refs = 0;
|
symbol->result.u.number.flags = flags;
|
||||||
if (flags & NUMBER_IS_FLOAT)
|
symbol->result.u.number.addr_refs = 0;
|
||||||
symbol->result.val.fpval = 0;
|
symbol->result.u.number.val.intval = 0;
|
||||||
else
|
|
||||||
symbol->result.val.intval = 0;
|
|
||||||
symbol->usage = 0; // usage count
|
symbol->usage = 0; // usage count
|
||||||
symbol->pass = pass.number;
|
symbol->pass = pass.number;
|
||||||
symbol->has_been_reported = FALSE;
|
symbol->has_been_reported = FALSE;
|
||||||
node->body = symbol;
|
node->body = symbol;
|
||||||
} else {
|
} else {
|
||||||
symbol = node->body;
|
symbol = node->body;
|
||||||
|
// make sure the force bits don't clash
|
||||||
|
if ((symbol->result.type == &type_int)
|
||||||
|
|| (symbol->result.type == &type_float)) {
|
||||||
|
new_force_bits = flags & NUMBER_FORCEBITS;
|
||||||
|
if (new_force_bits)
|
||||||
|
if ((symbol->result.u.number.flags & NUMBER_FORCEBITS) != new_force_bits)
|
||||||
|
Throw_error("Too late for postfix.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// make sure the force bits don't clash
|
|
||||||
if ((!node_created) && force_bits)
|
|
||||||
if ((symbol->result.flags & NUMBER_FORCEBITS) != force_bits)
|
|
||||||
Throw_error("Too late for postfix.");
|
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// assign value to symbol. the function acts upon the symbol's flag bits and
|
// assign value to symbol. the function acts upon the symbol's flag bits and
|
||||||
// produces an error if needed.
|
// produces an error if needed.
|
||||||
void symbol_set_value(struct symbol *symbol, struct number *new_value, boolean change_allowed)
|
void symbol_set_value(struct symbol *symbol, struct object *new_value, boolean change_allowed)
|
||||||
{
|
{
|
||||||
int oldflags = symbol->result.flags;
|
int flags; // for int/float re-definitions
|
||||||
|
|
||||||
|
// any new type?
|
||||||
|
if (((symbol->result.type != &type_int) && (symbol->result.type != &type_float))
|
||||||
|
|| ((new_value->type != &type_int) && (new_value->type != &type_float))) {
|
||||||
|
// changing value is ok, changing type needs extra flag:
|
||||||
|
if (change_allowed || (symbol->result.type == new_value->type))
|
||||||
|
symbol->result = *new_value;
|
||||||
|
else
|
||||||
|
Throw_error("Symbol already defined.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// both old and new are either int or float, so keep old algo:
|
||||||
|
|
||||||
// value stuff
|
// value stuff
|
||||||
if ((oldflags & NUMBER_IS_DEFINED) && !change_allowed) {
|
flags = symbol->result.u.number.flags;
|
||||||
// symbol is already defined, so compare new and old values
|
if (change_allowed || !(flags & NUMBER_IS_DEFINED)) {
|
||||||
// if different type OR same type but different value, complain
|
|
||||||
if (((oldflags ^ new_value->flags) & NUMBER_IS_FLOAT)
|
|
||||||
|| ((oldflags & NUMBER_IS_FLOAT) ? (symbol->result.val.fpval != new_value->val.fpval) : (symbol->result.val.intval != new_value->val.intval)))
|
|
||||||
Throw_error("Symbol already defined.");
|
|
||||||
} else {
|
|
||||||
// symbol is not defined yet OR redefinitions are allowed
|
// symbol is not defined yet OR redefinitions are allowed
|
||||||
symbol->result = *new_value;
|
symbol->result = *new_value;
|
||||||
|
} else {
|
||||||
|
// symbol is already defined, so compare new and old values
|
||||||
|
// if different type OR same type but different value, complain
|
||||||
|
if ((symbol->result.type != new_value->type)
|
||||||
|
|| ((symbol->result.type == &type_float) ? (symbol->result.u.number.val.fpval != new_value->u.number.val.fpval) : (symbol->result.u.number.val.intval != new_value->u.number.val.intval)))
|
||||||
|
Throw_error("Symbol already defined.");
|
||||||
}
|
}
|
||||||
// flags stuff
|
// flags stuff
|
||||||
// Ensure that "unsure" symbols without "isByte" state don't get that
|
// Ensure that "unsure" symbols without "isByte" state don't get that
|
||||||
if ((oldflags & (NUMBER_EVER_UNDEFINED | NUMBER_FITS_BYTE)) == NUMBER_EVER_UNDEFINED)
|
if ((flags & (NUMBER_EVER_UNDEFINED | NUMBER_FITS_BYTE)) == NUMBER_EVER_UNDEFINED)
|
||||||
new_value->flags &= ~NUMBER_FITS_BYTE;
|
new_value->u.number.flags &= ~NUMBER_FITS_BYTE;
|
||||||
|
|
||||||
if (change_allowed) {
|
if (change_allowed) {
|
||||||
oldflags = (oldflags & NUMBER_EVER_UNDEFINED) | new_value->flags;
|
// take flags from new value, then OR EVER_UNDEFINED from old value
|
||||||
|
flags = (flags & NUMBER_EVER_UNDEFINED) | new_value->u.number.flags;
|
||||||
} else {
|
} else {
|
||||||
if ((oldflags & NUMBER_FORCEBITS) == 0)
|
if ((flags & NUMBER_FORCEBITS) == 0)
|
||||||
if ((oldflags & (NUMBER_EVER_UNDEFINED | NUMBER_IS_DEFINED)) == 0)
|
if ((flags & (NUMBER_EVER_UNDEFINED | NUMBER_IS_DEFINED)) == 0) // FIXME - this can't happen!?
|
||||||
oldflags |= new_value->flags & NUMBER_FORCEBITS;
|
flags |= new_value->u.number.flags & NUMBER_FORCEBITS;
|
||||||
oldflags |= new_value->flags & ~NUMBER_FORCEBITS;
|
flags |= new_value->u.number.flags & ~NUMBER_FORCEBITS;
|
||||||
}
|
}
|
||||||
symbol->result.flags = oldflags;
|
symbol->result.u.number.flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -171,8 +196,8 @@ void symbol_set_value(struct symbol *symbol, struct number *new_value, boolean c
|
|||||||
// name must be held in GlobalDynaBuf.
|
// name must be held in GlobalDynaBuf.
|
||||||
void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed)
|
void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed)
|
||||||
{
|
{
|
||||||
struct number pc,
|
struct number pc;
|
||||||
result;
|
struct object result;
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
|
|
||||||
symbol = symbol_find(scope, force_bit);
|
symbol = symbol_find(scope, force_bit);
|
||||||
@ -181,9 +206,10 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean chan
|
|||||||
Throw_first_pass_warning("Label name not in leftmost column.");
|
Throw_first_pass_warning("Label name not in leftmost column.");
|
||||||
vcpu_read_pc(&pc);
|
vcpu_read_pc(&pc);
|
||||||
// FIXME - if undefined, check pass.complain_about_undefined and maybe throw "value not defined"!
|
// FIXME - if undefined, check pass.complain_about_undefined and maybe throw "value not defined"!
|
||||||
result.flags = pc.flags & NUMBER_IS_DEFINED;
|
result.type = &type_int;
|
||||||
result.val.intval = pc.val.intval;
|
result.u.number.flags = pc.flags & NUMBER_IS_DEFINED;
|
||||||
result.addr_refs = pc.addr_refs;
|
result.u.number.val.intval = pc.val.intval;
|
||||||
|
result.u.number.addr_refs = pc.addr_refs;
|
||||||
symbol_set_value(symbol, &result, change_allowed);
|
symbol_set_value(symbol, &result, change_allowed);
|
||||||
// global labels must open new scope for cheap locals
|
// global labels must open new scope for cheap locals
|
||||||
if (scope == SCOPE_GLOBAL)
|
if (scope == SCOPE_GLOBAL)
|
||||||
@ -195,7 +221,7 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean chan
|
|||||||
// name must be held in GlobalDynaBuf.
|
// name must be held in GlobalDynaBuf.
|
||||||
void symbol_parse_definition(scope_t scope, int stat_flags)
|
void symbol_parse_definition(scope_t scope, int stat_flags)
|
||||||
{
|
{
|
||||||
struct number result;
|
struct object result;
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
int force_bit = Input_get_force_bit(); // skips spaces after
|
int force_bit = Input_get_force_bit(); // skips spaces after
|
||||||
// FIXME - force bit is allowed for label definitions?!
|
// FIXME - force bit is allowed for label definitions?!
|
||||||
@ -207,11 +233,16 @@ void symbol_parse_definition(scope_t scope, int stat_flags)
|
|||||||
GetByte(); // skip '='
|
GetByte(); // skip '='
|
||||||
ALU_any_result(&result);
|
ALU_any_result(&result);
|
||||||
// if wanted, mark as address reference
|
// if wanted, mark as address reference
|
||||||
if (typesystem_says_address())
|
if (typesystem_says_address()) {
|
||||||
result.addr_refs = 1;
|
// FIXME - checking types explicitly is ugly...
|
||||||
|
if ((result.type == &type_int)
|
||||||
|
|| (result.type == &type_float))
|
||||||
|
result.u.number.addr_refs = 1;
|
||||||
|
}
|
||||||
symbol_set_value(symbol, &result, FALSE);
|
symbol_set_value(symbol, &result, FALSE);
|
||||||
Input_ensure_EOS();
|
Input_ensure_EOS();
|
||||||
} else {
|
} else {
|
||||||
|
// implicit symbol definition (label)
|
||||||
symbol_set_label(scope, stat_flags, force_bit, FALSE);
|
symbol_set_label(scope, stat_flags, force_bit, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,11 +252,12 @@ void symbol_parse_definition(scope_t scope, int stat_flags)
|
|||||||
// Name must be held in GlobalDynaBuf.
|
// Name must be held in GlobalDynaBuf.
|
||||||
void symbol_define(intval_t value)
|
void symbol_define(intval_t value)
|
||||||
{
|
{
|
||||||
struct number result;
|
struct object result;
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
|
|
||||||
result.flags = NUMBER_IS_DEFINED;
|
result.type = &type_int;
|
||||||
result.val.intval = value;
|
result.u.number.flags = NUMBER_IS_DEFINED;
|
||||||
|
result.u.number.val.intval = value;
|
||||||
symbol = symbol_find(SCOPE_GLOBAL, 0);
|
symbol = symbol_find(SCOPE_GLOBAL, 0);
|
||||||
symbol_set_value(symbol, &result, TRUE);
|
symbol_set_value(symbol, &result, TRUE);
|
||||||
}
|
}
|
||||||
@ -257,7 +289,7 @@ void symbols_vicelabels(FILE *fd)
|
|||||||
// references the *next* anonymous forward label definition. The tricky bit is,
|
// references the *next* anonymous forward label definition. The tricky bit is,
|
||||||
// each name length would need its own counter. But hey, ACME's real quick in
|
// each name length would need its own counter. But hey, ACME's real quick in
|
||||||
// finding symbols, so I'll just abuse the symbol system to store those counters.
|
// finding symbols, so I'll just abuse the symbol system to store those counters.
|
||||||
void symbol_fix_forward_anon_name(int increment)
|
void symbol_fix_forward_anon_name(boolean increment)
|
||||||
{
|
{
|
||||||
struct symbol *counter_symbol;
|
struct symbol *counter_symbol;
|
||||||
unsigned long number;
|
unsigned long number;
|
||||||
@ -265,12 +297,15 @@ void symbol_fix_forward_anon_name(int increment)
|
|||||||
// terminate name, find "counter" symbol and read value
|
// terminate name, find "counter" symbol and read value
|
||||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||||
counter_symbol = symbol_find(section_now->local_scope, 0);
|
counter_symbol = symbol_find(section_now->local_scope, 0);
|
||||||
|
// sanity check: it must be an int!
|
||||||
|
if (counter_symbol->result.type != &type_int)
|
||||||
|
Bug_found("ForwardAnonCounterNotInt", 0);
|
||||||
// make sure it gets reset to zero in each new pass
|
// make sure it gets reset to zero in each new pass
|
||||||
if (counter_symbol->pass != pass.number) {
|
if (counter_symbol->pass != pass.number) {
|
||||||
counter_symbol->pass = pass.number;
|
counter_symbol->pass = pass.number;
|
||||||
counter_symbol->result.val.intval = 0;
|
counter_symbol->result.u.number.val.intval = 0;
|
||||||
}
|
}
|
||||||
number = (unsigned long) counter_symbol->result.val.intval;
|
number = (unsigned long) counter_symbol->result.u.number.val.intval;
|
||||||
// now append to the name to make it unique
|
// now append to the name to make it unique
|
||||||
GlobalDynaBuf->size--; // forget terminator, we want to append
|
GlobalDynaBuf->size--; // forget terminator, we want to append
|
||||||
do {
|
do {
|
||||||
@ -279,5 +314,5 @@ void symbol_fix_forward_anon_name(int increment)
|
|||||||
} while (number);
|
} while (number);
|
||||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||||
if (increment)
|
if (increment)
|
||||||
counter_symbol->result.val.intval++;
|
counter_symbol->result.u.number.val.intval++;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
|
|
||||||
struct symbol {
|
struct symbol {
|
||||||
struct number result; // flags, value, address refs
|
struct object result; // flags, value, address refs
|
||||||
int usage; // usage count
|
int usage; // usage count
|
||||||
int pass; // pass of creation (for anon counters)
|
int pass; // pass of creation (for anon counters)
|
||||||
boolean has_been_reported; // indicates "has been reported as undefined"
|
boolean has_been_reported; // indicates "has been reported as undefined"
|
||||||
@ -29,7 +29,8 @@ extern struct rwnode *symbols_forest[]; // trees (because of 8-bit hash)
|
|||||||
|
|
||||||
|
|
||||||
// function acts upon the symbol's flag bits and produces an error if needed.
|
// function acts upon the symbol's flag bits and produces an error if needed.
|
||||||
extern void symbol_set_value(struct symbol *symbol, struct number *new_value, boolean change_allowed);
|
// FIXME - rename to symbol_set_object!
|
||||||
|
extern void symbol_set_value(struct symbol *symbol, struct object *new_value, boolean change_allowed);
|
||||||
// parse label definition (can be either global or local).
|
// parse label definition (can be either global or local).
|
||||||
// name must be held in GlobalDynaBuf.
|
// name must be held in GlobalDynaBuf.
|
||||||
extern void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed);
|
extern void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed);
|
||||||
@ -48,7 +49,7 @@ extern void symbols_list(FILE *fd);
|
|||||||
extern void symbols_vicelabels(FILE *fd);
|
extern void symbols_vicelabels(FILE *fd);
|
||||||
// fix name of anonymous forward label (held in GlobalDynaBuf, NOT TERMINATED!)
|
// fix name of anonymous forward label (held in GlobalDynaBuf, NOT TERMINATED!)
|
||||||
// so it references the *next* anonymous forward label definition.
|
// so it references the *next* anonymous forward label definition.
|
||||||
extern void symbol_fix_forward_anon_name(int increment);
|
extern void symbol_fix_forward_anon_name(boolean increment);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#define RELEASE "0.96.5" // update before release FIXME
|
#define RELEASE "0.96.5" // update before release FIXME
|
||||||
#define CODENAME "Fenchurch" // update before release
|
#define CODENAME "Fenchurch" // update before release
|
||||||
#define CHANGE_DATE "12 May" // update before release FIXME
|
#define CHANGE_DATE "14 May" // update before release FIXME
|
||||||
#define CHANGE_YEAR "2020" // update before release
|
#define CHANGE_YEAR "2020" // update before release
|
||||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||||
|
Loading…
x
Reference in New Issue
Block a user