mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-04-06 22:37:05 +00:00
'&' operator (for un-pseudopc-ing) seems to be finished
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@196 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
636080ce25
commit
dddf3f3d10
92
src/alu.c
92
src/alu.c
@ -345,23 +345,33 @@ static void is_not_defined(struct symbol *optional_symbol, char optional_prefix_
|
||||
// their internal name is different (longer) than their displayed name.
|
||||
// This function is not allowed to change DynaBuf because that's where the
|
||||
// symbol name is stored!
|
||||
static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t name_length, int derefs)
|
||||
static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t name_length, unsigned int unpseudo_count)
|
||||
{
|
||||
struct symbol *symbol;
|
||||
struct object *arg;
|
||||
|
||||
if (derefs)
|
||||
Bug_found("DerefsNotDoneYet", derefs); // TODO - support!
|
||||
// if the symbol gets created now, mark it as unsure
|
||||
symbol = symbol_find(scope, NUMBER_EVER_UNDEFINED);
|
||||
// first push on arg stack, so we have a local copy we can "unpseudopc"
|
||||
arg = &arg_stack[arg_sp++];
|
||||
*arg = symbol->result;
|
||||
if (unpseudo_count) {
|
||||
if (arg->type == &type_int) {
|
||||
pseudopc_unpseudo(&arg->u.number, symbol->pseudopc, unpseudo_count);
|
||||
// TODO - check return value and enter error state if nonzero?
|
||||
} else {
|
||||
Throw_error("Monadic '&' operator can only be applied to labels."); // TODO - add to docs
|
||||
// TODO - enter error state?
|
||||
}
|
||||
}
|
||||
// if needed, output "value not defined" error
|
||||
if (!(symbol->result.type->is_defined(&symbol->result)))
|
||||
// FIXME - in case of unpseudopc, error message should include the correct amount of '&' characters
|
||||
if (!(arg->type->is_defined(arg)))
|
||||
is_not_defined(symbol, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
|
||||
// in first pass, count usage
|
||||
if (FIRST_PASS)
|
||||
symbol->usage++;
|
||||
// push argument, regardless of whether int or float
|
||||
// FIXME - if arg is list, increment ref count!
|
||||
arg_stack[arg_sp++] = symbol->result;
|
||||
}
|
||||
|
||||
|
||||
@ -651,6 +661,42 @@ static void list_init_list(struct object *self)
|
||||
// expression parser
|
||||
|
||||
|
||||
// helper function for "monadic &" (either octal value or "unpseudo" operator)
|
||||
// returns nonzero on error
|
||||
static int parse_octal_or_unpseudo(void) // now GotByte = '&'
|
||||
{
|
||||
unsigned int unpseudo_count = 1;
|
||||
|
||||
while (GetByte() == '&')
|
||||
++unpseudo_count;
|
||||
if ((unpseudo_count == 1) && (GotByte >= '0') & (GotByte <= '7')) {
|
||||
parse_octal_literal(); // now GotByte = non-octal char
|
||||
return 0; // ok
|
||||
}
|
||||
|
||||
// TODO - support anonymous labels as well?
|
||||
if (GotByte == '.') {
|
||||
GetByte();
|
||||
if (Input_read_keyword() == 0) // now GotByte = illegal char
|
||||
return 1; // error (no string given)
|
||||
|
||||
get_symbol_value(section_now->local_scope, LOCAL_PREFIX, GlobalDynaBuf->size - 1, unpseudo_count); // -1 to not count terminator
|
||||
} else if (GotByte == CHEAP_PREFIX) {
|
||||
GetByte();
|
||||
if (Input_read_keyword() == 0) // now GotByte = illegal char
|
||||
return 1; // error (no string given)
|
||||
|
||||
get_symbol_value(section_now->cheap_scope, CHEAP_PREFIX, GlobalDynaBuf->size - 1, unpseudo_count); // -1 to not count terminator
|
||||
} else if (BYTE_STARTS_KEYWORD(GotByte)) {
|
||||
Input_read_keyword(); // now GotByte = illegal char
|
||||
get_symbol_value(SCOPE_GLOBAL, '\0', GlobalDynaBuf->size - 1, unpseudo_count); // no prefix, -1 to not count terminator
|
||||
} else {
|
||||
Throw_error(exception_missing_string);
|
||||
return 1; // error
|
||||
}
|
||||
return 0; // ok
|
||||
}
|
||||
|
||||
// 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)
|
||||
@ -670,7 +716,7 @@ static boolean expect_argument_or_monadic_operator(void)
|
||||
while (GetByte() == '+');
|
||||
ugly_length_kluge = GlobalDynaBuf->size; // FIXME - get rid of this!
|
||||
symbol_fix_forward_anon_name(FALSE); // FALSE: do not increment counter
|
||||
get_symbol_value(section_now->local_scope, '\0', ugly_length_kluge, 0); // no prefix, no derefs
|
||||
get_symbol_value(section_now->local_scope, '\0', ugly_length_kluge, 0); // no prefix, no unpseudo
|
||||
goto now_expect_dyadic_op;
|
||||
|
||||
case '-': // NEGATION operator or anonymous backward label
|
||||
@ -684,7 +730,7 @@ static boolean expect_argument_or_monadic_operator(void)
|
||||
SKIPSPACE();
|
||||
if (BYTE_FOLLOWS_ANON(GotByte)) {
|
||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||
get_symbol_value(section_now->local_scope, '\0', GlobalDynaBuf->size - 1, 0); // no prefix, -1 to not count terminator, no derefs
|
||||
get_symbol_value(section_now->local_scope, '\0', GlobalDynaBuf->size - 1, 0); // no prefix, -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op;
|
||||
}
|
||||
|
||||
@ -742,12 +788,13 @@ static boolean expect_argument_or_monadic_operator(void)
|
||||
parse_binary_literal(); // Now GotByte = non-binary char
|
||||
goto now_expect_dyadic_op;
|
||||
|
||||
case '&': // Octal value
|
||||
// TODO - count consecutive '&' and allow symbol afterward, for pseudopc-de-ref!
|
||||
GetByte(); // this was moved here from parse_octal_literal to prepare for the TODO above
|
||||
parse_octal_literal(); // Now GotByte = non-octal char
|
||||
goto now_expect_dyadic_op;
|
||||
case '&': // octal value or "unpseudo" operator applied to label
|
||||
if (parse_octal_or_unpseudo() == 0)
|
||||
goto now_expect_dyadic_op;
|
||||
|
||||
// if we're here, there was an error (like "no string given"):
|
||||
alu_state = STATE_ERROR;
|
||||
break;//goto done;
|
||||
case '$': // Hexadecimal value
|
||||
parse_hex_literal();
|
||||
// Now GotByte = non-hexadecimal char
|
||||
@ -763,15 +810,13 @@ static boolean expect_argument_or_monadic_operator(void)
|
||||
GetByte(); // start after '.'
|
||||
// check for fractional part of float value
|
||||
if ((GotByte >= '0') && (GotByte <= '9')) {
|
||||
parse_frac_part(0);
|
||||
// Now GotByte = non-decimal char
|
||||
parse_frac_part(0); // now GotByte = non-decimal char
|
||||
goto now_expect_dyadic_op;
|
||||
}
|
||||
|
||||
if (Input_read_keyword()) {
|
||||
// Now GotByte = illegal char
|
||||
get_symbol_value(section_now->local_scope, LOCAL_PREFIX, GlobalDynaBuf->size - 1, 0); // -1 to not count terminator, no derefs
|
||||
goto now_expect_dyadic_op;
|
||||
if (Input_read_keyword()) { // now GotByte = illegal char
|
||||
get_symbol_value(section_now->local_scope, LOCAL_PREFIX, GlobalDynaBuf->size - 1, 0); // -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op; // ok
|
||||
}
|
||||
|
||||
// if we're here, Input_read_keyword() will have thrown an error (like "no string given"):
|
||||
@ -780,10 +825,9 @@ static boolean expect_argument_or_monadic_operator(void)
|
||||
case CHEAP_PREFIX: // cheap local symbol
|
||||
//printf("looking in cheap scope %d\n", section_now->cheap_scope);
|
||||
GetByte(); // start after '@'
|
||||
if (Input_read_keyword()) {
|
||||
// Now GotByte = illegal char
|
||||
get_symbol_value(section_now->cheap_scope, CHEAP_PREFIX, GlobalDynaBuf->size - 1, 0); // -1 to not count terminator, no derefs
|
||||
goto now_expect_dyadic_op;
|
||||
if (Input_read_keyword()) { // now GotByte = illegal char
|
||||
get_symbol_value(section_now->cheap_scope, CHEAP_PREFIX, GlobalDynaBuf->size - 1, 0); // -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op; // ok
|
||||
}
|
||||
|
||||
// if we're here, Input_read_keyword() will have thrown an error (like "no string given"):
|
||||
@ -822,7 +866,7 @@ static boolean expect_argument_or_monadic_operator(void)
|
||||
// however, apart from that check above, function calls have nothing to do with
|
||||
// parentheses: "sin(x+y)" gets parsed just like "not(x+y)".
|
||||
} else {
|
||||
get_symbol_value(SCOPE_GLOBAL, '\0', GlobalDynaBuf->size - 1, 0); // no prefix, -1 to not count terminator, no derefs
|
||||
get_symbol_value(SCOPE_GLOBAL, '\0', GlobalDynaBuf->size - 1, 0); // no prefix, -1 to not count terminator, no unpseudo
|
||||
goto now_expect_dyadic_op;
|
||||
}
|
||||
}
|
||||
|
60
src/output.c
60
src/output.c
@ -53,6 +53,9 @@ struct output {
|
||||
char xor; // output modifier
|
||||
};
|
||||
|
||||
// for offset assembly:
|
||||
static struct pseudopc *pseudopc_current_context; // current struct (NULL when not in pseudopc block)
|
||||
|
||||
|
||||
// variables
|
||||
static struct output default_output;
|
||||
@ -496,6 +499,9 @@ void Output_passinit(void)
|
||||
CPU_state.pc.flags = 0; // not defined yet
|
||||
CPU_state.pc.val.intval = 0; // same as output's write_idx on pass init
|
||||
CPU_state.add_to_pc = 0; // increase PC by this at end of statement
|
||||
|
||||
// pseudopc stuff:
|
||||
pseudopc_current_context = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -629,18 +635,60 @@ void vcpu_end_statement(void)
|
||||
CPU_state.add_to_pc = 0;
|
||||
}
|
||||
|
||||
|
||||
// struct to describe a pseudopc context
|
||||
struct pseudopc {
|
||||
struct pseudopc *outer; // next layer (to be able to "unpseudopc" labels by more than one level)
|
||||
intval_t offset; // inner minus outer pc
|
||||
int flags; // flags of outer pc
|
||||
};
|
||||
// start offset assembly
|
||||
void pseudopc_start(struct pseudopc *buffer, struct number *new_pc)
|
||||
void pseudopc_start(struct number *new_pc)
|
||||
{
|
||||
buffer->flags = CPU_state.pc.flags;
|
||||
buffer->offset = (new_pc->val.intval - CPU_state.pc.val.intval) & 0xffff;
|
||||
struct pseudopc *new_context;
|
||||
|
||||
new_context = safe_malloc(sizeof(*new_context)); // create new struct (this must never be freed, as it gets linked to labels!)
|
||||
new_context->outer = pseudopc_current_context; // let it point to previous one
|
||||
pseudopc_current_context = new_context; // make it the current one
|
||||
|
||||
new_context->flags = CPU_state.pc.flags;
|
||||
new_context->offset = new_pc->val.intval - CPU_state.pc.val.intval;
|
||||
CPU_state.pc.val.intval = new_pc->val.intval;
|
||||
CPU_state.pc.flags |= NUMBER_IS_DEFINED; // FIXME - remove when allowing undefined!
|
||||
//new: CPU_state.pc.flags = new_pc->flags & (NUMBER_IS_DEFINED | NUMBER_EVER_UNDEFINED);
|
||||
}
|
||||
// end offset assembly
|
||||
void pseudopc_end(struct pseudopc *buffer)
|
||||
void pseudopc_end(void)
|
||||
{
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - buffer->offset) & 0xffff;
|
||||
CPU_state.pc.flags = buffer->flags;
|
||||
if (pseudopc_current_context == NULL) {
|
||||
Bug_found("ClosingUnopenedPseudopcBlock", 0);
|
||||
} else {
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & 0xffff; // pc might have wrapped around
|
||||
CPU_state.pc.flags = pseudopc_current_context->flags;
|
||||
pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block
|
||||
}
|
||||
}
|
||||
// un-pseudopc a label value by given number of levels
|
||||
// returns nonzero on error (if level too high)
|
||||
int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels)
|
||||
{
|
||||
while (levels--) {
|
||||
if ((target->flags & NUMBER_IS_DEFINED) == 0)
|
||||
return 0; // ok (no sense in trying to unpseudo this, and it might be an unresolved forward ref anway)
|
||||
|
||||
if (context == NULL) {
|
||||
Throw_error("Too many monadic '&' operators for this label."); // TODO - add to docs
|
||||
return 1; // error
|
||||
}
|
||||
// FIXME - in future, check DEFINED flag of context!
|
||||
target->val.intval = (target->val.intval - context->offset) & 0xffff; // FIXME - is masking really needed?
|
||||
context = context->outer;
|
||||
}
|
||||
return 0; // ok
|
||||
}
|
||||
// return pointer to current "pseudopc" struct (may be NULL!)
|
||||
// this gets called when parsing label definitions
|
||||
struct pseudopc *pseudopc_get_context(void)
|
||||
{
|
||||
return pseudopc_current_context;
|
||||
}
|
||||
|
17
src/output.h
17
src/output.h
@ -27,11 +27,6 @@ struct vcpu {
|
||||
boolean a_is_long;
|
||||
boolean xy_are_long;
|
||||
};
|
||||
// buffer to hold outer state while parsing "pseudopc" block
|
||||
struct pseudopc {
|
||||
intval_t offset;
|
||||
int flags;
|
||||
};
|
||||
|
||||
|
||||
// variables
|
||||
@ -103,10 +98,18 @@ extern void vcpu_read_pc(struct number *target);
|
||||
extern int vcpu_get_statement_size(void);
|
||||
// adjust program counter (called at end of each statement)
|
||||
extern void vcpu_end_statement(void);
|
||||
|
||||
struct pseudopc;
|
||||
// start offset assembly
|
||||
extern void pseudopc_start(struct pseudopc *buffer, struct number *new_pc);
|
||||
extern void pseudopc_start(struct number *new_pc);
|
||||
// end offset assembly
|
||||
extern void pseudopc_end(struct pseudopc *buffer);
|
||||
extern void pseudopc_end(void);
|
||||
// un-pseudopc a label value by given number of levels
|
||||
// returns nonzero on error (if level too high)
|
||||
extern int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned int levels);
|
||||
// return pointer to current "pseudopc" struct (may be NULL!)
|
||||
// this gets called when parsing label definitions
|
||||
extern struct pseudopc *pseudopc_get_context(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -586,7 +586,6 @@ static const char Error_old_offset_assembly[] =
|
||||
// TODO - maybe add a label argument to assign the block size afterwards (for assemble-to-end-address) (or add another pseudo opcode)
|
||||
static enum eos po_pseudopc(void)
|
||||
{
|
||||
struct pseudopc buffer;
|
||||
struct number new_pc;
|
||||
|
||||
// get new value
|
||||
@ -610,12 +609,11 @@ static enum eos po_pseudopc(void)
|
||||
}
|
||||
}
|
||||
*/
|
||||
// remember old state in buffer, set new state
|
||||
pseudopc_start(&buffer, &new_pc);
|
||||
pseudopc_start(&new_pc);
|
||||
// if there's a block, parse that and then restore old value!
|
||||
if (Parse_optional_block()) {
|
||||
// restore old state
|
||||
pseudopc_end(&buffer);
|
||||
pseudopc_end();
|
||||
} else {
|
||||
// not using a block is no longer allowed
|
||||
Throw_error(Error_old_offset_assembly);
|
||||
|
@ -127,6 +127,7 @@ struct symbol *symbol_find(scope_t scope, int flags)
|
||||
symbol->usage = 0; // usage count
|
||||
symbol->pass = pass.number;
|
||||
symbol->has_been_reported = FALSE;
|
||||
symbol->pseudopc = NULL;
|
||||
node->body = symbol;
|
||||
} else {
|
||||
symbol = node->body;
|
||||
@ -194,6 +195,7 @@ void symbol_set_object(struct symbol *symbol, struct object *new_value, boolean
|
||||
|
||||
// parse label definition (can be either global or local).
|
||||
// name must be held in GlobalDynaBuf.
|
||||
// TODO - this is parsing, so move elsewhere
|
||||
void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean change_allowed)
|
||||
{
|
||||
struct number pc;
|
||||
@ -211,6 +213,7 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean chan
|
||||
result.u.number.val.intval = pc.val.intval;
|
||||
result.u.number.addr_refs = pc.addr_refs;
|
||||
symbol_set_object(symbol, &result, change_allowed);
|
||||
symbol->pseudopc = pseudopc_get_context();
|
||||
// global labels must open new scope for cheap locals
|
||||
if (scope == SCOPE_GLOBAL)
|
||||
section_new_cheap_scope(section_now);
|
||||
@ -219,6 +222,7 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, boolean chan
|
||||
|
||||
// parse symbol definition (can be either global or local, may turn out to be a label).
|
||||
// name must be held in GlobalDynaBuf.
|
||||
// TODO - this is parsing, so move elsewhere
|
||||
void symbol_parse_definition(scope_t scope, int stat_flags)
|
||||
{
|
||||
struct object result;
|
||||
|
@ -16,6 +16,7 @@ struct symbol {
|
||||
int usage; // usage count
|
||||
int pass; // pass of creation (for anon counters)
|
||||
boolean has_been_reported; // indicates "has been reported as undefined"
|
||||
struct pseudopc *pseudopc;
|
||||
// add file ref + line num of last definition
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define RELEASE "0.96.5" // update before release FIXME
|
||||
#define CODENAME "Fenchurch" // update before release
|
||||
#define CHANGE_DATE "27 May" // update before release FIXME
|
||||
#define CHANGE_DATE "28 May" // update before release FIXME
|
||||
#define CHANGE_YEAR "2020" // update before release
|
||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||
|
Loading…
x
Reference in New Issue
Block a user