mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-11-29 04:49:20 +00:00
still more refactoring (almost there, almost there) - no change in functionality
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@49 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
de896f41f2
commit
e042ec8602
@ -29,7 +29,7 @@ dynabuf.o: config.h acme.h global.h input.h dynabuf.h dynabuf.c
|
||||
|
||||
encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h encoding.h encoding.c
|
||||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h macro.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
@ -43,7 +43,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
||||
|
||||
platform.o: config.h platform.h platform.c
|
||||
|
||||
pseudoopcodes.o: acme.h alu.h input.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
|
||||
section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c
|
||||
|
||||
|
@ -30,7 +30,7 @@ dynabuf.o: config.h acme.h global.h input.h dynabuf.h dynabuf.c
|
||||
|
||||
encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h encoding.h encoding.c
|
||||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h macro.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
@ -44,7 +44,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
||||
|
||||
platform.o: config.h platform.h platform.c
|
||||
|
||||
pseudoopcodes.o: acme.h alu.h input.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
|
||||
section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c
|
||||
|
||||
|
@ -33,7 +33,7 @@ dynabuf.o: config.h acme.h global.h input.h dynabuf.h dynabuf.c
|
||||
|
||||
encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h encoding.h encoding.c
|
||||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h macro.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
@ -47,7 +47,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
||||
|
||||
platform.o: config.h platform.h platform.c
|
||||
|
||||
pseudoopcodes.o: acme.h alu.h input.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
|
||||
section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c
|
||||
|
||||
|
@ -28,7 +28,7 @@ dynabuf.o: config.h acme.h global.h input.h dynabuf.h dynabuf.c
|
||||
|
||||
encoding.o: config.h alu.h acme.h dynabuf.h global.h output.h input.h tree.h encoding.h encoding.c
|
||||
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h macro.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
flow.o: config.h acme.h alu.h dynabuf.h global.h input.h mnemo.h symbol.h tree.h flow.h flow.c
|
||||
|
||||
global.o: config.h platform.h acme.h cpu.h input.h macro.h pseudoopcodes.h section.h symbol.h global.h global.c
|
||||
|
||||
@ -42,7 +42,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
||||
|
||||
platform.o: config.h platform.h platform.c
|
||||
|
||||
pseudoopcodes.o: acme.h alu.h input.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||
|
||||
section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c
|
||||
|
||||
|
@ -345,8 +345,13 @@ static void set_output_format(void)
|
||||
// check CPU type (the cpu type tree must be set up at this point!)
|
||||
static void set_starting_cpu(void)
|
||||
{
|
||||
const struct cpu_type *new_cpu_type;
|
||||
|
||||
keyword_to_dynabuf(cliargs_safe_get_next("CPU type"));
|
||||
if (!CPU_find_cpu_struct(&default_cpu)) {
|
||||
new_cpu_type = cputype_find();
|
||||
if (new_cpu_type) {
|
||||
default_cpu = new_cpu_type;
|
||||
} else {
|
||||
// FIXME - list actual types instead of outputting a fixed list!
|
||||
// FIXME - or AT LEAST define error message near the actual type list, so they match!
|
||||
fprintf(stderr, "%sUnknown CPU type (use 6502, 6510, c64dtv2, 65c02 or 65816).\n", cliargs_error);
|
||||
@ -556,8 +561,6 @@ int main(int argc, const char *argv[])
|
||||
CPU_init();
|
||||
Encoding_init();
|
||||
Flow_init();
|
||||
Input_init();
|
||||
symbols_register_init();
|
||||
Macro_init();
|
||||
Mnemo_init();
|
||||
Output_init(fill_value);
|
||||
|
286
src/cpu.c
286
src/cpu.c
@ -61,8 +61,8 @@ static struct cpu_type cpu_type_65816 = {
|
||||
// variables
|
||||
|
||||
// predefined stuff
|
||||
static struct ronode *CPU_tree = NULL; // tree to hold CPU types
|
||||
static struct ronode CPUs[] = {
|
||||
static struct ronode *cputype_tree = NULL;
|
||||
static struct ronode cputype_list[] = {
|
||||
// PREDEFNODE("z80", &cpu_type_Z80),
|
||||
PREDEFNODE("6502", &cpu_type_6502),
|
||||
PREDEFNODE("6510", &cpu_type_6510),
|
||||
@ -75,108 +75,19 @@ static struct ronode CPUs[] = {
|
||||
};
|
||||
|
||||
|
||||
// insert byte until PC fits condition
|
||||
// FIXME - move to basics.c
|
||||
static enum eos PO_align(void)
|
||||
{
|
||||
// FIXME - read cpu state via function call!
|
||||
intval_t and,
|
||||
equal,
|
||||
fill,
|
||||
test = CPU_state.pc.val.intval;
|
||||
|
||||
// make sure PC is defined.
|
||||
if ((CPU_state.pc.flags & MVALUE_DEFINED) == 0) {
|
||||
Throw_error(exception_pc_undefined);
|
||||
CPU_state.pc.flags |= MVALUE_DEFINED; // do not complain again
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
and = ALU_defined_int();
|
||||
if (!Input_accept_comma())
|
||||
Throw_error(exception_syntax);
|
||||
equal = ALU_defined_int();
|
||||
if (Input_accept_comma())
|
||||
fill = ALU_any_int();
|
||||
else
|
||||
fill = CPU_state.type->default_align_value;
|
||||
while ((test++ & and) != equal)
|
||||
output_8(fill);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// try to find CPU type held in DynaBuf. Returns whether succeeded.
|
||||
// FIXME - why not return ptr (or NULL to indicate failure)?
|
||||
int CPU_find_cpu_struct(const struct cpu_type **target)
|
||||
// lookup cpu type held in DynaBuf and return its struct pointer (or NULL on failure)
|
||||
const struct cpu_type *cputype_find(void)
|
||||
{
|
||||
void *node_body;
|
||||
|
||||
// make sure tree is initialised
|
||||
if (CPU_tree == NULL)
|
||||
Tree_add_table(&CPU_tree, CPUs);
|
||||
if (cputype_tree == NULL)
|
||||
Tree_add_table(&cputype_tree, cputype_list);
|
||||
// perform lookup
|
||||
if (!Tree_easy_scan(CPU_tree, &node_body, GlobalDynaBuf))
|
||||
return 0;
|
||||
*target = node_body;
|
||||
return 1;
|
||||
}
|
||||
if (!Tree_easy_scan(cputype_tree, &node_body, GlobalDynaBuf))
|
||||
return NULL;
|
||||
|
||||
|
||||
// select CPU ("!cpu" pseudo opcode)
|
||||
// FIXME - move to pseudoopcodes.c
|
||||
static enum eos PO_cpu(void)
|
||||
{
|
||||
const struct cpu_type *cpu_buffer = CPU_state.type; // remember current cpu
|
||||
|
||||
if (Input_read_and_lower_keyword())
|
||||
if (!CPU_find_cpu_struct(&CPU_state.type))
|
||||
Throw_error("Unknown processor.");
|
||||
// if there's a block, parse that and then restore old value!
|
||||
if (Parse_optional_block())
|
||||
CPU_state.type = cpu_buffer;
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
static const char Error_old_offset_assembly[] =
|
||||
"\"!pseudopc/!realpc\" is obsolete; use \"!pseudopc {}\" instead.";
|
||||
|
||||
|
||||
// "!realpc" pseudo opcode (now obsolete)
|
||||
// FIXME - move to basics.c
|
||||
static enum eos PO_realpc(void)
|
||||
{
|
||||
Throw_error(Error_old_offset_assembly);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// start offset assembly
|
||||
// FIXME - split into PO (move to basics.c) and backend (move to output.c)
|
||||
// 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)
|
||||
{
|
||||
// FIXME - read pc using a function call!
|
||||
intval_t new_pc,
|
||||
new_offset;
|
||||
int outer_flags = CPU_state.pc.flags;
|
||||
|
||||
// set new
|
||||
new_pc = ALU_defined_int(); // FIXME - allow for undefined!
|
||||
new_offset = (new_pc - CPU_state.pc.val.intval) & 0xffff;
|
||||
CPU_state.pc.val.intval = new_pc;
|
||||
CPU_state.pc.flags |= MVALUE_DEFINED; // FIXME - remove when allowing undefined!
|
||||
// if there's a block, parse that and then restore old value!
|
||||
if (Parse_optional_block()) {
|
||||
// restore old
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - new_offset) & 0xffff;
|
||||
CPU_state.pc.flags = outer_flags;
|
||||
} else {
|
||||
// not using a block is no longer allowed
|
||||
Throw_error(Error_old_offset_assembly);
|
||||
}
|
||||
return ENSURE_EOS;
|
||||
return node_body;
|
||||
}
|
||||
|
||||
|
||||
@ -205,49 +116,6 @@ static enum eos set_register_length(int *var, int make_long)
|
||||
}
|
||||
|
||||
|
||||
// switch to long accumulator ("!al" pseudo opcode)
|
||||
static enum eos PO_al(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.a_is_long, TRUE);
|
||||
}
|
||||
|
||||
|
||||
// switch to short accumulator ("!as" pseudo opcode)
|
||||
static enum eos PO_as(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.a_is_long, FALSE);
|
||||
}
|
||||
|
||||
|
||||
// switch to long index registers ("!rl" pseudo opcode)
|
||||
static enum eos PO_rl(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.xy_are_long, TRUE);
|
||||
}
|
||||
|
||||
|
||||
// switch to short index registers ("!rs" pseudo opcode)
|
||||
static enum eos PO_rs(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.xy_are_long, FALSE);
|
||||
}
|
||||
|
||||
|
||||
// pseudo opcode table
|
||||
// FIXME - move to basics.c
|
||||
static struct ronode pseudo_opcodes[] = {
|
||||
PREDEFNODE("align", PO_align),
|
||||
PREDEFNODE("cpu", PO_cpu),
|
||||
PREDEFNODE("pseudopc", PO_pseudopc),
|
||||
PREDEFNODE("realpc", PO_realpc),
|
||||
PREDEFNODE("al", PO_al),
|
||||
PREDEFNODE("as", PO_as),
|
||||
PREDEFNODE(s_rl, PO_rl),
|
||||
PREDEFLAST("rs", PO_rs),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// set default values for pass
|
||||
void CPU_passinit(const struct cpu_type *cpu_type)
|
||||
{
|
||||
@ -256,8 +124,142 @@ void CPU_passinit(const struct cpu_type *cpu_type)
|
||||
}
|
||||
|
||||
|
||||
// FIXME - move to pseudoopcodes.c:
|
||||
|
||||
|
||||
// insert byte until PC fits condition
|
||||
static enum eos po_align(void)
|
||||
{
|
||||
// FIXME - read cpu state via function call!
|
||||
intval_t and,
|
||||
equal,
|
||||
fill,
|
||||
test = CPU_state.pc.val.intval;
|
||||
|
||||
// make sure PC is defined.
|
||||
if ((CPU_state.pc.flags & MVALUE_DEFINED) == 0) {
|
||||
Throw_error(exception_pc_undefined);
|
||||
CPU_state.pc.flags |= MVALUE_DEFINED; // do not complain again
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
and = ALU_defined_int();
|
||||
if (!Input_accept_comma())
|
||||
Throw_error(exception_syntax);
|
||||
equal = ALU_defined_int();
|
||||
if (Input_accept_comma())
|
||||
fill = ALU_any_int();
|
||||
else
|
||||
fill = CPU_state.type->default_align_value;
|
||||
while ((test++ & and) != equal)
|
||||
output_8(fill);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// select CPU ("!cpu" pseudo opcode)
|
||||
static enum eos po_cpu(void)
|
||||
{
|
||||
const struct cpu_type *cpu_buffer = CPU_state.type; // remember current cpu
|
||||
const struct cpu_type *new_cpu_type;
|
||||
|
||||
if (Input_read_and_lower_keyword()) {
|
||||
new_cpu_type = cputype_find();
|
||||
if (new_cpu_type)
|
||||
CPU_state.type = new_cpu_type;
|
||||
else
|
||||
Throw_error("Unknown processor.");
|
||||
}
|
||||
// if there's a block, parse that and then restore old value!
|
||||
if (Parse_optional_block())
|
||||
CPU_state.type = cpu_buffer;
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
static const char Error_old_offset_assembly[] =
|
||||
"\"!pseudopc/!realpc\" is obsolete; use \"!pseudopc {}\" instead.";
|
||||
|
||||
|
||||
// "!realpc" pseudo opcode (now obsolete)
|
||||
static enum eos po_realpc(void)
|
||||
{
|
||||
Throw_error(Error_old_offset_assembly);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// start offset assembly
|
||||
// FIXME - split into PO (move to pseudoopcodes.c) and backend (move to output.c?)
|
||||
// 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)
|
||||
{
|
||||
// FIXME - read pc using a function call!
|
||||
intval_t new_pc,
|
||||
new_offset;
|
||||
int outer_flags = CPU_state.pc.flags;
|
||||
|
||||
// set new
|
||||
new_pc = ALU_defined_int(); // FIXME - allow for undefined!
|
||||
new_offset = (new_pc - CPU_state.pc.val.intval) & 0xffff;
|
||||
CPU_state.pc.val.intval = new_pc;
|
||||
CPU_state.pc.flags |= MVALUE_DEFINED; // FIXME - remove when allowing undefined!
|
||||
// if there's a block, parse that and then restore old value!
|
||||
if (Parse_optional_block()) {
|
||||
// restore old
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - new_offset) & 0xffff;
|
||||
CPU_state.pc.flags = outer_flags;
|
||||
} else {
|
||||
// not using a block is no longer allowed
|
||||
Throw_error(Error_old_offset_assembly);
|
||||
}
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// switch to long accumulator ("!al" pseudo opcode)
|
||||
static enum eos po_al(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.a_is_long, TRUE);
|
||||
}
|
||||
|
||||
|
||||
// switch to short accumulator ("!as" pseudo opcode)
|
||||
static enum eos po_as(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.a_is_long, FALSE);
|
||||
}
|
||||
|
||||
|
||||
// switch to long index registers ("!rl" pseudo opcode)
|
||||
static enum eos po_rl(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.xy_are_long, TRUE);
|
||||
}
|
||||
|
||||
|
||||
// switch to short index registers ("!rs" pseudo opcode)
|
||||
static enum eos po_rs(void)
|
||||
{
|
||||
return set_register_length(&CPU_state.xy_are_long, FALSE);
|
||||
}
|
||||
|
||||
|
||||
// pseudo opcode table
|
||||
static struct ronode pseudo_opcodes[] = {
|
||||
PREDEFNODE("align", po_align),
|
||||
PREDEFNODE("cpu", po_cpu),
|
||||
PREDEFNODE("pseudopc", po_pseudopc),
|
||||
PREDEFNODE("realpc", po_realpc), // obsolete
|
||||
PREDEFNODE("al", po_al),
|
||||
PREDEFNODE("as", po_as),
|
||||
PREDEFNODE(s_rl, po_rl),
|
||||
PREDEFLAST("rs", po_rs),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// register pseudo opcodes (done later)
|
||||
// FIXME - move to basics.c
|
||||
void CPU_init(void)
|
||||
{
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
||||
|
@ -27,9 +27,8 @@ struct cpu_type {
|
||||
extern void CPU_init(void);
|
||||
// set default value for pass
|
||||
extern void CPU_passinit(const struct cpu_type *cpu_type);
|
||||
// try to find CPU type held in DynaBuf. Returns whether succeeded.
|
||||
// FIXME - why not simply return struct ptr, or NULL in case of failure?
|
||||
extern int CPU_find_cpu_struct(const struct cpu_type **target);
|
||||
// lookup cpu type held in DynaBuf and return its struct pointer (or NULL on failure)
|
||||
extern const struct cpu_type *cputype_find(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
164
src/flow.c
164
src/flow.c
@ -18,7 +18,6 @@
|
||||
#include "dynabuf.h"
|
||||
#include "global.h" // FIXME - remove when no longer needed
|
||||
#include "input.h"
|
||||
#include "macro.h"
|
||||
#include "mnemo.h"
|
||||
#include "pseudoopcodes.h" // FIXME - remove when no longer needed
|
||||
#include "symbol.h"
|
||||
@ -41,7 +40,7 @@ static void parse_ram_block(int line_number, char *body)
|
||||
{
|
||||
Input_now->line_number = line_number; // set line number to loop start
|
||||
Input_now->src.ram_ptr = body; // set RAM read pointer to loop
|
||||
// Parse loop body
|
||||
// parse loop body
|
||||
Parse_until_eob_or_eof();
|
||||
if (GotByte != CHAR_EOB)
|
||||
Bug_found("IllegalBlockTerminator", GotByte);
|
||||
@ -73,7 +72,7 @@ static void store_condition(struct loop_condition *condition, char terminator)
|
||||
Throw_error(exception_syntax);
|
||||
return;
|
||||
}
|
||||
// Write given condition into buffer
|
||||
// write given condition into buffer
|
||||
SKIPSPACE();
|
||||
DYNABUF_CLEAR(GlobalDynaBuf);
|
||||
Input_until_terminator(terminator);
|
||||
@ -88,7 +87,7 @@ static int check_condition(struct loop_condition *condition)
|
||||
{
|
||||
intval_t expression;
|
||||
|
||||
// First, check whether there actually *is* a condition
|
||||
// first, check whether there actually *is* a condition
|
||||
if (condition->body == NULL)
|
||||
return TRUE; // non-existing conditions are always true
|
||||
|
||||
@ -103,8 +102,8 @@ static int check_condition(struct loop_condition *condition)
|
||||
}
|
||||
|
||||
|
||||
// looping assembly ("!do"). Has to be re-entrant.
|
||||
static enum eos PO_do(void) // Now GotByte = illegal char
|
||||
// looping assembly ("!do"). has to be re-entrant.
|
||||
static enum eos po_do(void) // now GotByte = illegal char
|
||||
{
|
||||
struct loop_condition condition1,
|
||||
condition2;
|
||||
@ -113,24 +112,24 @@ static enum eos PO_do(void) // Now GotByte = illegal char
|
||||
char *loop_body;
|
||||
int go_on,
|
||||
loop_start; // line number of loop pseudo opcode
|
||||
// Init
|
||||
// init
|
||||
condition1.is_until = FALSE;
|
||||
condition1.body = NULL;
|
||||
condition2.is_until = FALSE;
|
||||
condition2.body = NULL;
|
||||
|
||||
// Read head condition to buffer
|
||||
// read head condition to buffer
|
||||
SKIPSPACE();
|
||||
store_condition(&condition1, CHAR_SOB);
|
||||
if (GotByte != CHAR_SOB)
|
||||
Throw_serious_error(exception_no_left_brace);
|
||||
// Remember line number of loop body,
|
||||
// remember line number of loop body,
|
||||
// then read block and get copy
|
||||
loop_start = Input_now->line_number;
|
||||
loop_body = Input_skip_or_store_block(TRUE); // changes line number!
|
||||
// now GotByte = '}'
|
||||
NEXTANDSKIPSPACE(); // Now GotByte = first non-blank char after block
|
||||
// Read tail condition to buffer
|
||||
NEXTANDSKIPSPACE(); // now GotByte = first non-blank char after block
|
||||
// read tail condition to buffer
|
||||
store_condition(&condition2, CHAR_EOS);
|
||||
// now GotByte = CHAR_EOS
|
||||
// set up new input
|
||||
@ -142,15 +141,15 @@ static enum eos PO_do(void) // Now GotByte = illegal char
|
||||
// line number are not yet set up)
|
||||
Input_now = &loop_input;
|
||||
do {
|
||||
// Check head condition
|
||||
// check head condition
|
||||
go_on = check_condition(&condition1);
|
||||
if (go_on) {
|
||||
parse_ram_block(loop_start, loop_body);
|
||||
// Check tail condition
|
||||
// check tail condition
|
||||
go_on = check_condition(&condition2);
|
||||
}
|
||||
} while (go_on);
|
||||
// Free memory
|
||||
// free memory
|
||||
free(condition1.body);
|
||||
free(loop_body);
|
||||
free(condition2.body);
|
||||
@ -165,10 +164,10 @@ static enum eos PO_do(void) // Now GotByte = illegal char
|
||||
}
|
||||
|
||||
|
||||
// looping assembly ("!for"). Has to be re-entrant.
|
||||
// looping assembly ("!for"). has to be re-entrant.
|
||||
// old syntax: !for VAR, END { BLOCK } VAR counts from 1 to END
|
||||
// new syntax: !for VAR, START, END { BLOCK } VAR counts from START to END
|
||||
static enum eos PO_for(void) // Now GotByte = illegal char
|
||||
static enum eos po_for(void) // now GotByte = illegal char
|
||||
{
|
||||
struct input loop_input,
|
||||
*outer_input;
|
||||
@ -186,7 +185,7 @@ static enum eos PO_for(void) // Now GotByte = illegal char
|
||||
|
||||
if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
|
||||
return SKIP_REMAINDER;
|
||||
// Now GotByte = illegal char
|
||||
// now GotByte = illegal char
|
||||
force_bit = Input_get_force_bit(); // skips spaces after
|
||||
symbol = symbol_find(zone, force_bit);
|
||||
if (!Input_accept_comma()) {
|
||||
@ -248,7 +247,7 @@ static enum eos PO_for(void) // Now GotByte = illegal char
|
||||
symbol_set_value(symbol, &loop_counter, TRUE);
|
||||
} while (loop_counter.val.intval != (counter_last + counter_increment));
|
||||
}
|
||||
// Free memory
|
||||
// free memory
|
||||
free(loop_body);
|
||||
// restore previous input:
|
||||
Input_now = outer_input;
|
||||
@ -278,7 +277,7 @@ static int skip_or_parse_block(int parse)
|
||||
|
||||
|
||||
// parse {block} [else {block}]
|
||||
static void parse_block_else_block(int parse_first)
|
||||
void flow_parse_block_else_block(int parse_first)
|
||||
{
|
||||
// Parse first block.
|
||||
// If it's not correctly terminated, return immediately (because
|
||||
@ -309,85 +308,6 @@ static void parse_block_else_block(int parse_first)
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!if"). Has to be re-entrant.
|
||||
static enum eos PO_if(void) // Now GotByte = illegal char
|
||||
{
|
||||
intval_t cond;
|
||||
|
||||
cond = ALU_defined_int();
|
||||
if (GotByte != CHAR_SOB)
|
||||
Throw_serious_error(exception_no_left_brace);
|
||||
parse_block_else_block(!!cond);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!ifdef" and "!ifndef"). Has to be re-entrant.
|
||||
static enum eos ifdef_ifndef(int is_ifndef) // Now GotByte = illegal char
|
||||
{
|
||||
struct rwnode *node;
|
||||
struct symbol *symbol;
|
||||
zone_t zone;
|
||||
int defined = FALSE;
|
||||
|
||||
if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
Tree_hard_scan(&node, symbols_forest, zone, FALSE);
|
||||
if (node) {
|
||||
symbol = (struct symbol *) node->body;
|
||||
// in first pass, count usage
|
||||
if (pass_count == 0)
|
||||
symbol->usage++;
|
||||
if (symbol->result.flags & MVALUE_DEFINED)
|
||||
defined = TRUE;
|
||||
}
|
||||
SKIPSPACE();
|
||||
// if "ifndef", invert condition
|
||||
if (is_ifndef)
|
||||
defined = !defined;
|
||||
if (GotByte != CHAR_SOB)
|
||||
return defined ? PARSE_REMAINDER : SKIP_REMAINDER;
|
||||
|
||||
parse_block_else_block(defined);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!ifdef"). Has to be re-entrant.
|
||||
static enum eos PO_ifdef(void) // Now GotByte = illegal char
|
||||
{
|
||||
return ifdef_ifndef(FALSE);
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!ifndef"). Has to be re-entrant.
|
||||
static enum eos PO_ifndef(void) // Now GotByte = illegal char
|
||||
{
|
||||
return ifdef_ifndef(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// macro definition ("!macro").
|
||||
static enum eos PO_macro(void) // Now GotByte = illegal char
|
||||
{
|
||||
// In first pass, parse. In all other passes, skip.
|
||||
if (pass_count == 0) {
|
||||
Macro_parse_definition(); // now GotByte = '}'
|
||||
} else {
|
||||
// skip until CHAR_SOB ('{') is found.
|
||||
// no need to check for end-of-statement, because such an
|
||||
// error would already have been detected in first pass.
|
||||
// for the same reason, there is no need to check for quotes.
|
||||
while (GotByte != CHAR_SOB)
|
||||
GetByte();
|
||||
Input_skip_or_store_block(FALSE); // now GotByte = '}'
|
||||
}
|
||||
GetByte(); // Proceed with next character
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// parse a whole source code file
|
||||
void Parse_and_close_file(FILE *fd, const char *filename)
|
||||
{
|
||||
@ -405,57 +325,15 @@ void Parse_and_close_file(FILE *fd, const char *filename)
|
||||
}
|
||||
|
||||
|
||||
// include source file ("!source" or "!src"). Has to be re-entrant.
|
||||
static enum eos PO_source(void) // Now GotByte = illegal char
|
||||
{
|
||||
FILE *fd;
|
||||
char local_gotbyte;
|
||||
struct input new_input,
|
||||
*outer_input;
|
||||
|
||||
// Enter new nesting level.
|
||||
// Quit program if recursion too deep.
|
||||
if (--source_recursions_left < 0)
|
||||
Throw_serious_error("Too deeply nested. Recursive \"!source\"?");
|
||||
// Read file name. Quit function on error.
|
||||
if (Input_read_filename(TRUE))
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// If file could be opened, parse it. Otherwise, complain.
|
||||
if ((fd = fopen(GLOBALDYNABUF_CURRENT, FILE_READBINARY))) {
|
||||
char filename[GlobalDynaBuf->size];
|
||||
|
||||
strcpy(filename, GLOBALDYNABUF_CURRENT);
|
||||
outer_input = Input_now; // remember old input
|
||||
local_gotbyte = GotByte; // CAUTION - ugly kluge
|
||||
Input_now = &new_input; // activate new input
|
||||
Parse_and_close_file(fd, filename);
|
||||
Input_now = outer_input; // restore previous input
|
||||
GotByte = local_gotbyte; // CAUTION - ugly kluge
|
||||
} else {
|
||||
Throw_error(exception_cannot_open_input_file);
|
||||
}
|
||||
// Leave nesting level
|
||||
++source_recursions_left;
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// pseudo opcode table
|
||||
static struct ronode pseudo_opcodes[] = {
|
||||
PREDEFNODE("do", PO_do),
|
||||
PREDEFNODE("for", PO_for),
|
||||
PREDEFNODE("if", PO_if),
|
||||
PREDEFNODE("ifdef", PO_ifdef),
|
||||
PREDEFNODE("ifndef", PO_ifndef),
|
||||
PREDEFNODE("macro", PO_macro),
|
||||
PREDEFNODE("source", PO_source),
|
||||
PREDEFLAST("src", PO_source),
|
||||
PREDEFNODE("do", po_do),
|
||||
PREDEFLAST("for", po_for),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// register pseudo opcodes and build keyword tree for until/while
|
||||
// register pseudo opcodes
|
||||
void Flow_init(void)
|
||||
{
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
||||
|
@ -13,10 +13,12 @@
|
||||
|
||||
// Prototypes
|
||||
|
||||
// register pseudo opcodes and build keyword tree for until/while
|
||||
// register pseudo opcodes
|
||||
extern void Flow_init(void);
|
||||
// Parse a whole source code file
|
||||
// parse a whole source code file
|
||||
extern void Parse_and_close_file(FILE *fd, const char *filename);
|
||||
// parse {block} [else {block}]
|
||||
extern void flow_parse_block_else_block(int parse_first);
|
||||
|
||||
|
||||
#endif
|
||||
|
29
src/input.c
29
src/input.c
@ -38,36 +38,13 @@ static struct input outermost = {
|
||||
};
|
||||
|
||||
|
||||
// Variables
|
||||
// variables
|
||||
struct input *Input_now = &outermost; // current input structure
|
||||
|
||||
|
||||
// End of source file ("!endoffile" or "!eof")
|
||||
static enum eos PO_eof(void)
|
||||
{
|
||||
// Well, it doesn't end right here and now, but at end-of-line! :-)
|
||||
Input_ensure_EOS();
|
||||
Input_now->state = INPUTSTATE_EOF;
|
||||
return AT_EOS_ANYWAY;
|
||||
}
|
||||
// functions
|
||||
|
||||
// predefined stuff
|
||||
static struct ronode pseudo_opcodes[] = {
|
||||
PREDEFNODE("eof", PO_eof),
|
||||
PREDEFLAST("endoffile", PO_eof),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// Functions
|
||||
|
||||
// register pseudo opcodes
|
||||
void Input_init(void)
|
||||
{
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
||||
}
|
||||
|
||||
// Let current input point to start of file
|
||||
// let current input point to start of file
|
||||
void Input_new_file(const char *filename, FILE *fd)
|
||||
{
|
||||
Input_now->original_filename = filename;
|
||||
|
@ -54,9 +54,7 @@ extern struct input *Input_now; // current input structure
|
||||
|
||||
// Prototypes
|
||||
|
||||
// register pseudo opcodes
|
||||
extern void Input_init(void);
|
||||
// Let current input point to start of file
|
||||
// let current input point to start of file
|
||||
extern void Input_new_file(const char *filename, FILE *fd);
|
||||
// get next byte from currently active byte source in shortened high-level
|
||||
// format. When inside quotes, use GetQuotedByte() instead!
|
||||
|
@ -5,15 +5,18 @@
|
||||
// pseudo opcode stuff
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
//#include "acme.h"
|
||||
#include "acme.h"
|
||||
#include "config.h"
|
||||
#include "cpu.h"
|
||||
#include "alu.h"
|
||||
#include "dynabuf.h"
|
||||
#include "flow.h"
|
||||
#include "input.h"
|
||||
#include "macro.h"
|
||||
#include "global.h"
|
||||
#include "output.h"
|
||||
#include "section.h"
|
||||
#include "symbol.h"
|
||||
#include "tree.h"
|
||||
#include "typesystem.h"
|
||||
#include "pseudoopcodes.h"
|
||||
@ -23,6 +26,7 @@
|
||||
static const char s_08[] = "08";
|
||||
#define s_8 (s_08 + 1) // Yes, I know I'm sick
|
||||
#define s_16 (s_65816 + 3) // Yes, I know I'm sick
|
||||
#define s_sl (s_asl + 1) // Yes, I know I'm sick
|
||||
|
||||
|
||||
// variables
|
||||
@ -244,6 +248,69 @@ static enum eos po_addr(void) // now GotByte = illegal char
|
||||
return PARSE_REMAINDER;
|
||||
}
|
||||
|
||||
|
||||
// (re)set symbol
|
||||
static enum eos po_set(void) // now GotByte = illegal char
|
||||
{
|
||||
struct result result;
|
||||
int force_bit;
|
||||
struct symbol *symbol;
|
||||
zone_t zone;
|
||||
|
||||
if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
|
||||
// now GotByte = illegal char
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
force_bit = Input_get_force_bit(); // skips spaces after
|
||||
symbol = symbol_find(zone, force_bit);
|
||||
if (GotByte != '=') {
|
||||
Throw_error(exception_syntax);
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// symbol = parsed value
|
||||
GetByte(); // proceed with next char
|
||||
ALU_any_result(&result);
|
||||
// clear symbol's force bits and set new ones
|
||||
symbol->result.flags &= ~(MVALUE_FORCEBITS | MVALUE_ISBYTE);
|
||||
if (force_bit) {
|
||||
symbol->result.flags |= force_bit;
|
||||
result.flags &= ~(MVALUE_FORCEBITS | MVALUE_ISBYTE);
|
||||
}
|
||||
symbol_set_value(symbol, &result, TRUE);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// set file name for symbol list
|
||||
static enum eos po_sl(void)
|
||||
{
|
||||
// bugfix: first read filename, *then* check for first pass.
|
||||
// if skipping right away, quoted colons might be misinterpreted as EOS
|
||||
// FIXME - why not just fix the skipping code to handle quotes? :)
|
||||
// "!to" has been fixed as well
|
||||
|
||||
// read filename to global dynamic buffer
|
||||
// if no file name given, exit (complaining will have been done)
|
||||
if (Input_read_filename(FALSE))
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// only process this pseudo opcode in first pass
|
||||
if (pass_count)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// if symbol list file name already set, complain and exit
|
||||
if (symbollist_filename) {
|
||||
Throw_warning("Symbol list file name already chosen.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// get malloc'd copy of filename
|
||||
symbollist_filename = DynaBuf_get_copy(GlobalDynaBuf);
|
||||
// ensure there's no garbage at end of line
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO - add "!skip AMOUNT" pseudo opcode as alternative to "* = * + AMOUNT" (needed for assemble-to-end-address)
|
||||
// the new pseudo opcode would skip the given amount of bytes without starting a new segment
|
||||
@ -297,6 +364,121 @@ static enum eos po_subzone(void)
|
||||
}
|
||||
|
||||
|
||||
// include source file ("!source" or "!src"). has to be re-entrant.
|
||||
static enum eos po_source(void) // now GotByte = illegal char
|
||||
{
|
||||
FILE *fd;
|
||||
char local_gotbyte;
|
||||
struct input new_input,
|
||||
*outer_input;
|
||||
|
||||
// enter new nesting level
|
||||
// quit program if recursion too deep
|
||||
if (--source_recursions_left < 0)
|
||||
Throw_serious_error("Too deeply nested. Recursive \"!source\"?");
|
||||
// read file name. quit function on error
|
||||
if (Input_read_filename(TRUE))
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// if file could be opened, parse it. otherwise, complain
|
||||
if ((fd = fopen(GLOBALDYNABUF_CURRENT, FILE_READBINARY))) {
|
||||
char filename[GlobalDynaBuf->size];
|
||||
|
||||
strcpy(filename, GLOBALDYNABUF_CURRENT);
|
||||
outer_input = Input_now; // remember old input
|
||||
local_gotbyte = GotByte; // CAUTION - ugly kluge
|
||||
Input_now = &new_input; // activate new input
|
||||
Parse_and_close_file(fd, filename);
|
||||
Input_now = outer_input; // restore previous input
|
||||
GotByte = local_gotbyte; // CAUTION - ugly kluge
|
||||
} else {
|
||||
Throw_error(exception_cannot_open_input_file);
|
||||
}
|
||||
// leave nesting level
|
||||
++source_recursions_left;
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!if"). has to be re-entrant.
|
||||
static enum eos po_if(void) // now GotByte = illegal char
|
||||
{
|
||||
intval_t cond;
|
||||
|
||||
cond = ALU_defined_int();
|
||||
if (GotByte != CHAR_SOB)
|
||||
Throw_serious_error(exception_no_left_brace);
|
||||
flow_parse_block_else_block(!!cond);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!ifdef" and "!ifndef"). has to be re-entrant.
|
||||
static enum eos ifdef_ifndef(int is_ifndef) // now GotByte = illegal char
|
||||
{
|
||||
struct rwnode *node;
|
||||
struct symbol *symbol;
|
||||
zone_t zone;
|
||||
int defined = FALSE;
|
||||
|
||||
if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
Tree_hard_scan(&node, symbols_forest, zone, FALSE);
|
||||
if (node) {
|
||||
symbol = (struct symbol *) node->body;
|
||||
// in first pass, count usage
|
||||
if (pass_count == 0)
|
||||
symbol->usage++;
|
||||
if (symbol->result.flags & MVALUE_DEFINED)
|
||||
defined = TRUE;
|
||||
}
|
||||
SKIPSPACE();
|
||||
// if "ifndef", invert condition
|
||||
if (is_ifndef)
|
||||
defined = !defined;
|
||||
if (GotByte != CHAR_SOB)
|
||||
return defined ? PARSE_REMAINDER : SKIP_REMAINDER;
|
||||
|
||||
flow_parse_block_else_block(defined);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!ifdef"). has to be re-entrant.
|
||||
static enum eos po_ifdef(void) // now GotByte = illegal char
|
||||
{
|
||||
return ifdef_ifndef(FALSE);
|
||||
}
|
||||
|
||||
|
||||
// conditional assembly ("!ifndef"). has to be re-entrant.
|
||||
static enum eos po_ifndef(void) // now GotByte = illegal char
|
||||
{
|
||||
return ifdef_ifndef(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// macro definition ("!macro").
|
||||
static enum eos po_macro(void) // now GotByte = illegal char
|
||||
{
|
||||
// in first pass, parse. In all other passes, skip.
|
||||
if (pass_count == 0) {
|
||||
Macro_parse_definition(); // now GotByte = '}'
|
||||
} else {
|
||||
// skip until CHAR_SOB ('{') is found.
|
||||
// no need to check for end-of-statement, because such an
|
||||
// error would already have been detected in first pass.
|
||||
// for the same reason, there is no need to check for quotes.
|
||||
while (GotByte != CHAR_SOB)
|
||||
GetByte();
|
||||
Input_skip_or_store_block(FALSE); // now GotByte = '}'
|
||||
}
|
||||
GetByte(); // Proceed with next character
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// constants
|
||||
#define USERMSG_DYNABUF_INITIALSIZE 80
|
||||
|
||||
@ -390,12 +572,21 @@ static enum eos po_serious(void)
|
||||
}
|
||||
|
||||
|
||||
// end of source file ("!endoffile" or "!eof")
|
||||
static enum eos po_eof(void)
|
||||
{
|
||||
// well, it doesn't end right here and now, but at end-of-line! :-)
|
||||
Input_ensure_EOS();
|
||||
Input_now->state = INPUTSTATE_EOF;
|
||||
return AT_EOS_ANYWAY;
|
||||
}
|
||||
|
||||
// pseudo opcode table
|
||||
static struct ronode pseudo_opcodes[] = {
|
||||
static struct ronode pseudo_opcode_list[] = {
|
||||
PREDEFNODE("initmem", po_initmem),
|
||||
PREDEFNODE("to", po_to),
|
||||
PREDEFNODE(s_08, po_8),
|
||||
PREDEFNODE(s_8, po_8),
|
||||
PREDEFNODE(s_08, po_8),
|
||||
PREDEFNODE("by", po_8),
|
||||
PREDEFNODE("byte", po_8),
|
||||
PREDEFNODE(s_16, po_16),
|
||||
@ -409,16 +600,27 @@ static struct ronode pseudo_opcodes[] = {
|
||||
PREDEFNODE("fill", po_fill),
|
||||
PREDEFNODE("addr", po_addr),
|
||||
PREDEFNODE("address", po_addr),
|
||||
PREDEFNODE("set", po_set),
|
||||
PREDEFNODE(s_sl, po_sl),
|
||||
PREDEFNODE("symbollist", po_sl),
|
||||
// PREDEFNODE("skip", po_skip),
|
||||
PREDEFNODE(s_zone, po_zone),
|
||||
PREDEFNODE("zn", po_zone),
|
||||
PREDEFNODE(s_subzone, po_subzone),
|
||||
PREDEFNODE(s_zone, po_zone),
|
||||
PREDEFNODE("sz", po_subzone),
|
||||
PREDEFNODE(s_subzone, po_subzone),
|
||||
PREDEFNODE("src", po_source),
|
||||
PREDEFNODE("source", po_source),
|
||||
PREDEFNODE("if", po_if),
|
||||
PREDEFNODE("ifdef", po_ifdef),
|
||||
PREDEFNODE("ifndef", po_ifndef),
|
||||
PREDEFNODE("macro", po_macro),
|
||||
// PREDEFNODE("debug", po_debug),
|
||||
// PREDEFNODE("info", po_info),
|
||||
PREDEFNODE("warn", po_warn),
|
||||
PREDEFNODE(s_error, po_error),
|
||||
PREDEFLAST("serious", po_serious),
|
||||
PREDEFNODE("serious", po_serious),
|
||||
PREDEFNODE("eof", po_eof),
|
||||
PREDEFLAST("endoffile", po_eof),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
@ -427,12 +629,12 @@ static struct ronode pseudo_opcodes[] = {
|
||||
void pseudoopcodes_init(void)
|
||||
{
|
||||
user_message = DynaBuf_create(USERMSG_DYNABUF_INITIALSIZE);
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcode_list);
|
||||
}
|
||||
|
||||
|
||||
// parse a pseudo opcode. has to be re-entrant.
|
||||
void pseudoopcode_parse(void) // Now GotByte = "!"
|
||||
void pseudoopcode_parse(void) // now GotByte = "!"
|
||||
{
|
||||
void *node_body;
|
||||
enum eos (*fn)(void),
|
||||
|
83
src/symbol.c
83
src/symbol.c
@ -22,10 +22,6 @@
|
||||
#include "typesystem.h"
|
||||
|
||||
|
||||
// constants
|
||||
#define s_sl (s_asl + 1) // Yes, I know I'm sick
|
||||
|
||||
|
||||
// variables
|
||||
struct rwnode *symbols_forest[256] = { NULL }; // because of 8-bit hash - must be (at least partially) pre-defined so array will be zeroed!
|
||||
|
||||
@ -171,78 +167,6 @@ void symbol_set_value(struct symbol *symbol, struct result *new_value, int chang
|
||||
}
|
||||
|
||||
|
||||
// (Re)set symbol
|
||||
static enum eos PO_set(void) // Now GotByte = illegal char
|
||||
{
|
||||
struct result result;
|
||||
int force_bit;
|
||||
struct symbol *symbol;
|
||||
zone_t zone;
|
||||
|
||||
if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
|
||||
// Now GotByte = illegal char
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
force_bit = Input_get_force_bit(); // skips spaces after
|
||||
symbol = symbol_find(zone, force_bit);
|
||||
if (GotByte != '=') {
|
||||
Throw_error(exception_syntax);
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// symbol = parsed value
|
||||
GetByte(); // proceed with next char
|
||||
ALU_any_result(&result);
|
||||
// clear symbol's force bits and set new ones
|
||||
symbol->result.flags &= ~(MVALUE_FORCEBITS | MVALUE_ISBYTE);
|
||||
if (force_bit) {
|
||||
symbol->result.flags |= force_bit;
|
||||
result.flags &= ~(MVALUE_FORCEBITS | MVALUE_ISBYTE);
|
||||
}
|
||||
symbol_set_value(symbol, &result, TRUE);
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// set file name for symbol list
|
||||
static enum eos PO_sl(void)
|
||||
{
|
||||
// bugfix: first read filename, *then* check for first pass.
|
||||
// if skipping right away, quoted colons might be misinterpreted as EOS
|
||||
// FIXME - why not just fix the skipping code to handle quotes? :)
|
||||
// "!to" has been fixed as well
|
||||
|
||||
// read filename to global dynamic buffer
|
||||
// if no file name given, exit (complaining will have been done)
|
||||
if (Input_read_filename(FALSE))
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// only process this pseudo opcode in first pass
|
||||
if (pass_count)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// if symbol list file name already set, complain and exit
|
||||
if (symbollist_filename) {
|
||||
Throw_warning("Symbol list file name already chosen.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// get malloc'd copy of filename
|
||||
symbollist_filename = DynaBuf_get_copy(GlobalDynaBuf);
|
||||
// ensure there's no garbage at end of line
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
|
||||
// predefined stuff
|
||||
static struct ronode pseudo_opcodes[] = {
|
||||
PREDEFNODE("set", PO_set),
|
||||
PREDEFNODE("symbollist", PO_sl),
|
||||
PREDEFLAST(s_sl, PO_sl),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// parse label definition (can be either global or local).
|
||||
// name must be held in GlobalDynaBuf.
|
||||
void symbol_set_label(zone_t zone, int stat_flags, int force_bit, int change_allowed)
|
||||
@ -324,13 +248,6 @@ void symbols_vicelabels(FILE *fd)
|
||||
}
|
||||
|
||||
|
||||
// register pseudo opcodes (done later)
|
||||
void symbols_register_init(void)
|
||||
{
|
||||
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
||||
}
|
||||
|
||||
|
||||
// fix name of anonymous forward label (held in DynaBuf, NOT TERMINATED!) so it
|
||||
// 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
|
||||
|
@ -22,8 +22,6 @@ struct symbol {
|
||||
extern struct rwnode *symbols_forest[]; // trees (because of 8-bit hash)
|
||||
|
||||
|
||||
// register pseudo opcodes (done later)
|
||||
extern void symbols_register_init(void);
|
||||
// function acts upon the symbol's flag bits and produces an error if needed.
|
||||
extern void symbol_set_value(struct symbol *symbol, struct result *new_value, int change_allowed);
|
||||
// parse label definition (can be either global or local).
|
||||
|
Loading…
Reference in New Issue
Block a user