cleanup (moved functions between files; no change in functionality!)

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@245 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2020-06-20 16:45:37 +00:00
parent beb875ff2b
commit 5b37c4d24e
8 changed files with 278 additions and 275 deletions

290
src/alu.c
View File

@ -693,11 +693,6 @@ static void list_append_list(struct listitem *selfhead, struct listitem *otherhe
}
// expression parser
// prototype (FIXME, re-arrange code so this is no longer needed!)
static void push_dyadic_and_check(struct expression *expression, struct op *op);
// helper function for "monadic &" (either octal value or "unpseudo" operator)
// returns nonzero on error
static int parse_octal_or_unpseudo(void) // now GotByte = '&'
@ -736,6 +731,150 @@ static int parse_octal_or_unpseudo(void) // now GotByte = '&'
return 0; // ok
}
// expression parser
// handler for special operators like parentheses and start/end of expression:
// returns whether caller can remove "previous" operator from stack
static boolean handle_special_operator(struct expression *expression, enum op_id previous)
{
// when this gets called, "current" operator is OPID_TERMINATOR
switch (previous) {
case OPID_START_EXPRESSION:
// therefore we know we are done.
// don't touch "is_parenthesized", because start/end are obviously not "real" operators
alu_state = STATE_END; // done
return TRUE; // caller can remove this operator (we are done, so not really needed, but there are sanity checks for stack pointers)
case OPID_SUBEXPR_PAREN:
expression->is_parenthesized = TRUE; // found parentheses. if this is not the outermost level, the outermost level will fix this flag later on.
if (GotByte == ')') {
// matching parenthesis
GetByte(); // eat char
op_sp -= 2; // remove both SUBEXPR_PAREN and TERMINATOR
alu_state = STATE_EXPECT_DYADIC_OP;
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
}
// unmatched parenthesis, as in "lda ($80,x)"
++(expression->open_parentheses); // count
return TRUE; // caller can remove "SUBEXPR_PAREN" operator from stack
case OPID_START_LIST:
if (GotByte == ',') {
GetByte(); // eat ','
op_stack[op_sp - 1] = &ops_list_append; // change "end of expression" to "append"
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return FALSE; // stack remains, so caller shouldn't touch it
}
if (GotByte == ']') {
GetByte(); // eat ']'
op_sp -= 2; // remove both START_LIST and TERMINATOR
alu_state = STATE_EXPECT_DYADIC_OP;
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
}
Throw_error("Unterminated list.");
alu_state = STATE_ERROR;
return TRUE; // caller can remove START_LIST operator from stack
case OPID_SUBEXPR_BRACKET:
if (GotByte == ']') {
GetByte(); // eat ']'
op_sp -= 2; // remove both SUBEXPR_BRACKET and TERMINATOR
alu_state = STATE_EXPECT_DYADIC_OP;
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
}
Throw_error("Unterminated index spec.");
alu_state = STATE_ERROR;
return TRUE; // caller can remove SUBEXPR_BRACKET operator from stack
default:
Bug_found("IllegalOperatorId", previous);
}
// this is unreachable
return FALSE; // stack is done, so caller shouldn't touch it
}
// Try to reduce stacks by performing high-priority operations
// (if the previous operator has a higher priority than the current one, do it)
static void push_dyadic_and_check(struct expression *expression, struct op *op)
{
struct op *previous_op;
struct op *current_op;
PUSH_OP(op);
if (alu_state < STATE_MAX_GO_ON)
alu_state = STATE_TRY_TO_REDUCE_STACKS;
while (alu_state == STATE_TRY_TO_REDUCE_STACKS) {
if (op_sp < 2) {
// we only have one operator, which must be "start of expression",
// so there isn't anything left to do, so go on trying to parse the expression
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return;
}
previous_op = op_stack[op_sp - 2];
current_op = op_stack[op_sp - 1];
// previous operator has lower piority than current one? then do nothing.
if (previous_op->priority < current_op->priority) {
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return;
}
// previous operator has same priority as current one? then check associativity
if ((previous_op->priority == current_op->priority)
&& (current_op->priority == PRIO_POWEROF)
&& (config.wanted_version >= VER_RIGHTASSOCIATIVEPOWEROF)) {
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return;
}
// we now know that either
// - the previous operator has higher priority, or
// - it has the same priority and is left-associative,
// so perform that operation!
#define ARG_PREV (arg_stack[arg_sp - 2])
#define ARG_NOW (arg_stack[arg_sp - 1])
switch (previous_op->group) {
case OPGROUP_MONADIC: // monadic operators
if (arg_sp < 1)
Bug_found("ArgStackEmpty", arg_sp);
ARG_NOW.type->monadic_op(&ARG_NOW, previous_op);
// operation was something other than parentheses
expression->is_parenthesized = FALSE;
break;
case OPGROUP_DYADIC: // dyadic operators
if (arg_sp < 2)
Bug_found("NotEnoughArgs", arg_sp);
ARG_PREV.type->dyadic_op(&ARG_PREV, previous_op, &ARG_NOW);
// decrement argument stack pointer because dyadic operator merged two arguments into one
--arg_sp;
// operation was something other than parentheses
expression->is_parenthesized = FALSE;
break;
case OPGROUP_SPECIAL: // special (pseudo) operators
if (current_op->id != OPID_TERMINATOR)
Bug_found("StrangeOperator", current_op->id);
if (!handle_special_operator(expression, previous_op->id))
continue; // called fn has fixed the stack, so we don't touch it
// both monadics and dyadics clear "is_parenthesized", but here we don't touch it!
break;
default:
Bug_found("IllegalOperatorGroup", previous_op->group);
}
// shared endings for "we did the operation indicated by previous operator":
// fix stack:
// remove previous operator and shift down current one
// CAUTION - fiddling with our local copies like "previous_op = current_op" is not enough... ;)
op_stack[op_sp - 2] = op_stack[op_sp - 1];
--op_sp; // decrement operator stack pointer
}
}
// Expect argument or monadic operator (hopefully inlined)
// returns TRUE if it ate any non-space (-> so expression isn't empty)
// returns FALSE if first non-space is delimiter (-> end of expression)
@ -2144,6 +2283,7 @@ 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
}
// "class" definitions
struct type type_number = {
"number",
number_is_defined,
@ -2176,146 +2316,6 @@ struct type type_string = {
};
// handler for special operators like parentheses and start/end of expression:
// returns whether caller can remove "previous" operator from stack
static boolean handle_special_operator(struct expression *expression, enum op_id previous)
{
// when this gets called, "current" operator is OPID_TERMINATOR
switch (previous) {
case OPID_START_EXPRESSION:
// therefore we know we are done.
// don't touch "is_parenthesized", because start/end are obviously not "real" operators
alu_state = STATE_END; // done
return TRUE; // caller can remove this operator (we are done, so not really needed, but there are sanity checks for stack pointers)
case OPID_SUBEXPR_PAREN:
expression->is_parenthesized = TRUE; // found parentheses. if this is not the outermost level, the outermost level will fix this flag later on.
if (GotByte == ')') {
// matching parenthesis
GetByte(); // eat char
op_sp -= 2; // remove both SUBEXPR_PAREN and TERMINATOR
alu_state = STATE_EXPECT_DYADIC_OP;
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
}
// unmatched parenthesis, as in "lda ($80,x)"
++(expression->open_parentheses); // count
return TRUE; // caller can remove "SUBEXPR_PAREN" operator from stack
case OPID_START_LIST:
if (GotByte == ',') {
GetByte(); // eat ','
op_stack[op_sp - 1] = &ops_list_append; // change "end of expression" to "append"
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return FALSE; // stack remains, so caller shouldn't touch it
}
if (GotByte == ']') {
GetByte(); // eat ']'
op_sp -= 2; // remove both START_LIST and TERMINATOR
alu_state = STATE_EXPECT_DYADIC_OP;
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
}
Throw_error("Unterminated list.");
alu_state = STATE_ERROR;
return TRUE; // caller can remove START_LIST operator from stack
case OPID_SUBEXPR_BRACKET:
if (GotByte == ']') {
GetByte(); // eat ']'
op_sp -= 2; // remove both SUBEXPR_BRACKET and TERMINATOR
alu_state = STATE_EXPECT_DYADIC_OP;
return FALSE; // we fixed the stack ourselves, so caller shouldn't touch it
}
Throw_error("Unterminated index spec.");
alu_state = STATE_ERROR;
return TRUE; // caller can remove SUBEXPR_BRACKET operator from stack
default:
Bug_found("IllegalOperatorId", previous);
}
// this is unreachable
return FALSE; // stack is done, so caller shouldn't touch it
}
// Try to reduce stacks by performing high-priority operations
// (if the previous operator has a higher priority than the current one, do it)
static void push_dyadic_and_check(struct expression *expression, struct op *op)
{
struct op *previous_op;
struct op *current_op;
PUSH_OP(op);
if (alu_state < STATE_MAX_GO_ON)
alu_state = STATE_TRY_TO_REDUCE_STACKS;
while (alu_state == STATE_TRY_TO_REDUCE_STACKS) {
if (op_sp < 2) {
// we only have one operator, which must be "start of expression",
// so there isn't anything left to do, so go on trying to parse the expression
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return;
}
previous_op = op_stack[op_sp - 2];
current_op = op_stack[op_sp - 1];
// previous operator has lower piority than current one? then do nothing.
if (previous_op->priority < current_op->priority) {
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return;
}
// previous operator has same priority as current one? then check associativity
if ((previous_op->priority == current_op->priority)
&& (current_op->priority == PRIO_POWEROF)
&& (config.wanted_version >= VER_RIGHTASSOCIATIVEPOWEROF)) {
alu_state = STATE_EXPECT_ARG_OR_MONADIC_OP;
return;
}
// we now know that either
// - the previous operator has higher priority, or
// - it has the same priority and is left-associative,
// so perform that operation!
#define ARG_PREV (arg_stack[arg_sp - 2])
#define ARG_NOW (arg_stack[arg_sp - 1])
switch (previous_op->group) {
case OPGROUP_MONADIC: // monadic operators
if (arg_sp < 1)
Bug_found("ArgStackEmpty", arg_sp);
ARG_NOW.type->monadic_op(&ARG_NOW, previous_op);
// operation was something other than parentheses
expression->is_parenthesized = FALSE;
break;
case OPGROUP_DYADIC: // dyadic operators
if (arg_sp < 2)
Bug_found("NotEnoughArgs", arg_sp);
ARG_PREV.type->dyadic_op(&ARG_PREV, previous_op, &ARG_NOW);
// decrement argument stack pointer because dyadic operator merged two arguments into one
--arg_sp;
// operation was something other than parentheses
expression->is_parenthesized = FALSE;
break;
case OPGROUP_SPECIAL: // special (pseudo) operators
if (current_op->id != OPID_TERMINATOR)
Bug_found("StrangeOperator", current_op->id);
if (!handle_special_operator(expression, previous_op->id))
continue; // called fn has fixed the stack, so we don't touch it
// both monadics and dyadics clear "is_parenthesized", but here we don't touch it!
break;
default:
Bug_found("IllegalOperatorGroup", previous_op->group);
}
// shared endings for "we did the operation indicated by previous operator":
// fix stack:
// remove previous operator and shift down current one
// CAUTION - fiddling with our local copies like "previous_op = current_op" is not enough... ;)
op_stack[op_sp - 2] = op_stack[op_sp - 1];
--op_sp; // decrement operator stack pointer
}
}
// this is what the exported functions call
// returns nonzero on parse error
static int parse_expression(struct expression *expression)

View File

@ -24,7 +24,32 @@
#include "tree.h"
// helper functions for "!for" and "!do"
// helper functions for if/ifdef/ifndef/else/for/do/while
// parse symbol name and return if symbol has defined value (called by ifdef/ifndef)
boolean check_ifdef_condition(void)
{
scope_t scope;
struct rwnode *node;
struct symbol *symbol;
// read symbol name
if (Input_read_scope_and_keyword(&scope) == 0) // skips spaces before
return FALSE; // there was an error, it has been reported, so return value is more or less meaningless anway
// look for it
Tree_hard_scan(&node, symbols_forest, scope, FALSE);
if (!node)
return FALSE; // not found -> no, not defined
symbol = (struct symbol *) node->body;
symbol->has_been_read = TRUE; // we did not really read the symbol's value, but checking for its existence still counts as "used it"
if (symbol->object.type == NULL)
Bug_found("ObjectHasNullType", 0); // FIXME - add to docs!
return symbol->object.type->is_defined(&symbol->object);
}
// parse a loop body (TODO - also use for macro body?)
static void parse_ram_block(struct block *block)

View File

@ -43,6 +43,8 @@ struct do_while {
};
// parse symbol name and return if symbol has defined value (called by ifdef/ifndef)
extern boolean check_ifdef_condition(void);
// back end function for "!for" pseudo opcode
extern void flow_forloop(struct for_loop *loop);
// try to read a condition into DynaBuf and store pointer to copy in

View File

@ -513,3 +513,91 @@ void output_object(struct object *object, struct iter_context *iter)
Bug_found("IllegalObjectType9", 0); // FIXME - add to docs!
}
}
// output 8-bit value with range check
void output_8(intval_t value)
{
if ((value <= 0xff) && (value >= -0x80))
Output_byte(value);
else
Throw_error(exception_number_out_of_range);
}
// output 16-bit value with range check big-endian
void output_be16(intval_t value)
{
if ((value <= 0xffff) && (value >= -0x8000)) {
Output_byte(value >> 8);
Output_byte(value);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 16-bit value with range check little-endian
void output_le16(intval_t value)
{
if ((value <= 0xffff) && (value >= -0x8000)) {
Output_byte(value);
Output_byte(value >> 8);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 24-bit value with range check big-endian
void output_be24(intval_t value)
{
if ((value <= 0xffffff) && (value >= -0x800000)) {
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 24-bit value with range check little-endian
void output_le24(intval_t value)
{
if ((value <= 0xffffff) && (value >= -0x800000)) {
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 32-bit value (without range check) big-endian
void output_be32(intval_t value)
{
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
Output_byte(value >> 24);
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
// } else {
// Throw_error(exception_number_out_of_range);
// }
}
// output 32-bit value (without range check) little-endian
void output_le32(intval_t value)
{
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
Output_byte(value >> 24);
// } else {
// Throw_error(exception_number_out_of_range);
// }
}

View File

@ -175,6 +175,21 @@ struct iter_context {
char stringxor; // for !scrxor, 0 otherwise
};
extern void output_object(struct object *object, struct iter_context *iter);
// output 8-bit value with range check
extern void output_8(intval_t value);
// output 16-bit value with range check big-endian
extern void output_be16(intval_t value);
// output 16-bit value with range check little-endian
extern void output_le16(intval_t value);
// output 24-bit value with range check big-endian
extern void output_be24(intval_t value);
// output 24-bit value with range check little-endian
extern void output_le24(intval_t value);
// output 32-bit value (without range check) big-endian
extern void output_be32(intval_t value);
// output 32-bit value (without range check) little-endian
extern void output_le32(intval_t value);
#endif

View File

@ -197,94 +197,6 @@ void output_skip(int size)
}
// output 8-bit value with range check
void output_8(intval_t value)
{
if ((value <= 0xff) && (value >= -0x80))
Output_byte(value);
else
Throw_error(exception_number_out_of_range);
}
// output 16-bit value with range check big-endian
void output_be16(intval_t value)
{
if ((value <= 0xffff) && (value >= -0x8000)) {
Output_byte(value >> 8);
Output_byte(value);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 16-bit value with range check little-endian
void output_le16(intval_t value)
{
if ((value <= 0xffff) && (value >= -0x8000)) {
Output_byte(value);
Output_byte(value >> 8);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 24-bit value with range check big-endian
void output_be24(intval_t value)
{
if ((value <= 0xffffff) && (value >= -0x800000)) {
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 24-bit value with range check little-endian
void output_le24(intval_t value)
{
if ((value <= 0xffffff) && (value >= -0x800000)) {
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
} else {
Throw_error(exception_number_out_of_range);
}
}
// output 32-bit value (without range check) big-endian
void output_be32(intval_t value)
{
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
Output_byte(value >> 24);
Output_byte(value >> 16);
Output_byte(value >> 8);
Output_byte(value);
// } else {
// Throw_error(exception_number_out_of_range);
// }
}
// output 32-bit value (without range check) little-endian
void output_le32(intval_t value)
{
// if ((Value <= 0x7fffffff) && (Value >= -0x80000000)) {
Output_byte(value);
Output_byte(value >> 8);
Output_byte(value >> 16);
Output_byte(value >> 24);
// } else {
// Throw_error(exception_number_out_of_range);
// }
}
// fill output buffer with given byte value
static void fill_completely(char value)
{

View File

@ -54,23 +54,6 @@ extern void (*Output_byte)(intval_t);
// returns zero if ok, nonzero if already set
extern int output_initmem(char content);
// move elsewhere:
// Output 8-bit value with range check
extern void output_8(intval_t value);
// Output 16-bit value with range check big-endian
extern void output_be16(intval_t value);
// Output 16-bit value with range check little-endian
extern void output_le16(intval_t value);
// Output 24-bit value with range check big-endian
extern void output_be24(intval_t value);
// Output 24-bit value with range check little-endian
extern void output_le24(intval_t value);
// Output 32-bit value (without range check) big-endian
extern void output_be32(intval_t value);
// Output 32-bit value (without range check) little-endian
extern void output_le32(intval_t value);
// outfile stuff:
// try to set output format held in DynaBuf. Returns zero on success.

View File

@ -892,36 +892,14 @@ static enum eos po_source(void) // now GotByte = illegal char
return ENSURE_EOS;
}
// FIXME - move this to flow.c!
static boolean check_ifdef_condition(void)
{
scope_t scope;
struct rwnode *node;
struct symbol *symbol;
// read symbol name
if (Input_read_scope_and_keyword(&scope) == 0) // skips spaces before
return FALSE; // there was an error, it has been reported, so return value is more or less meaningless anway
// look for it
Tree_hard_scan(&node, symbols_forest, scope, FALSE);
if (!node)
return FALSE; // not found -> no, not defined
symbol = (struct symbol *) node->body;
symbol->has_been_read = TRUE; // we did not really read the symbol's value, but checking for its existence still counts as "used it"
if (symbol->object.type == NULL)
Bug_found("ObjectHasNullType", 0); // FIXME - add to docs!
return symbol->object.type->is_defined(&symbol->object);
}
// if/ifdef/ifndef/else function, to be able to do ELSE IF
// if/ifdef/ifndef/else
enum ifmode {
IFMODE_IF, // parse expression, then block
IFMODE_IFDEF, // check symbol, then parse block or line
IFMODE_IFNDEF, // check symbol, then parse block or line
IFMODE_ELSE // unconditional last block
};
// function for if/ifdef/ifndef/else. has to be re-entrant.
// has to be re-entrant
static enum eos ifelse(enum ifmode mode)
{
boolean nothing_done = TRUE; // once a block gets executed, this becomes FALSE, so all others will be skipped even if condition met