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:
marcobaye 2014-12-04 15:31:54 +00:00
parent de896f41f2
commit e042ec8602
14 changed files with 422 additions and 446 deletions

View File

@ -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 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 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 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 section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c

View File

@ -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 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 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 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 section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c

View File

@ -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 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 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 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 section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c

View File

@ -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 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 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 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 section.o: config.h dynabuf.h global.h section.h tree.h section.h section.c

View File

@ -345,8 +345,13 @@ static void set_output_format(void)
// check CPU type (the cpu type tree must be set up at this point!) // check CPU type (the cpu type tree must be set up at this point!)
static void set_starting_cpu(void) static void set_starting_cpu(void)
{ {
const struct cpu_type *new_cpu_type;
keyword_to_dynabuf(cliargs_safe_get_next("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 - list actual types instead of outputting a fixed list!
// FIXME - or AT LEAST define error message near the actual type list, so they match! // 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); 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(); CPU_init();
Encoding_init(); Encoding_init();
Flow_init(); Flow_init();
Input_init();
symbols_register_init();
Macro_init(); Macro_init();
Mnemo_init(); Mnemo_init();
Output_init(fill_value); Output_init(fill_value);

286
src/cpu.c
View File

@ -61,8 +61,8 @@ static struct cpu_type cpu_type_65816 = {
// variables // variables
// predefined stuff // predefined stuff
static struct ronode *CPU_tree = NULL; // tree to hold CPU types static struct ronode *cputype_tree = NULL;
static struct ronode CPUs[] = { static struct ronode cputype_list[] = {
// PREDEFNODE("z80", &cpu_type_Z80), // PREDEFNODE("z80", &cpu_type_Z80),
PREDEFNODE("6502", &cpu_type_6502), PREDEFNODE("6502", &cpu_type_6502),
PREDEFNODE("6510", &cpu_type_6510), PREDEFNODE("6510", &cpu_type_6510),
@ -75,108 +75,19 @@ static struct ronode CPUs[] = {
}; };
// insert byte until PC fits condition // lookup cpu type held in DynaBuf and return its struct pointer (or NULL on failure)
// FIXME - move to basics.c const struct cpu_type *cputype_find(void)
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)
{ {
void *node_body; void *node_body;
// make sure tree is initialised // make sure tree is initialised
if (CPU_tree == NULL) if (cputype_tree == NULL)
Tree_add_table(&CPU_tree, CPUs); Tree_add_table(&cputype_tree, cputype_list);
// perform lookup // perform lookup
if (!Tree_easy_scan(CPU_tree, &node_body, GlobalDynaBuf)) if (!Tree_easy_scan(cputype_tree, &node_body, GlobalDynaBuf))
return 0; return NULL;
*target = node_body;
return 1;
}
return node_body;
// 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;
} }
@ -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 // set default values for pass
void CPU_passinit(const struct cpu_type *cpu_type) 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) // register pseudo opcodes (done later)
// FIXME - move to basics.c
void CPU_init(void) void CPU_init(void)
{ {
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes); Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);

View File

@ -27,9 +27,8 @@ struct cpu_type {
extern void CPU_init(void); extern void CPU_init(void);
// set default value for pass // set default value for pass
extern void CPU_passinit(const struct cpu_type *cpu_type); extern void CPU_passinit(const struct cpu_type *cpu_type);
// try to find CPU type held in DynaBuf. Returns whether succeeded. // lookup cpu type held in DynaBuf and return its struct pointer (or NULL on failure)
// FIXME - why not simply return struct ptr, or NULL in case of failure? extern const struct cpu_type *cputype_find(void);
extern int CPU_find_cpu_struct(const struct cpu_type **target);
#endif #endif

View File

@ -18,7 +18,6 @@
#include "dynabuf.h" #include "dynabuf.h"
#include "global.h" // FIXME - remove when no longer needed #include "global.h" // FIXME - remove when no longer needed
#include "input.h" #include "input.h"
#include "macro.h"
#include "mnemo.h" #include "mnemo.h"
#include "pseudoopcodes.h" // FIXME - remove when no longer needed #include "pseudoopcodes.h" // FIXME - remove when no longer needed
#include "symbol.h" #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->line_number = line_number; // set line number to loop start
Input_now->src.ram_ptr = body; // set RAM read pointer to loop Input_now->src.ram_ptr = body; // set RAM read pointer to loop
// Parse loop body // parse loop body
Parse_until_eob_or_eof(); Parse_until_eob_or_eof();
if (GotByte != CHAR_EOB) if (GotByte != CHAR_EOB)
Bug_found("IllegalBlockTerminator", GotByte); Bug_found("IllegalBlockTerminator", GotByte);
@ -73,7 +72,7 @@ static void store_condition(struct loop_condition *condition, char terminator)
Throw_error(exception_syntax); Throw_error(exception_syntax);
return; return;
} }
// Write given condition into buffer // write given condition into buffer
SKIPSPACE(); SKIPSPACE();
DYNABUF_CLEAR(GlobalDynaBuf); DYNABUF_CLEAR(GlobalDynaBuf);
Input_until_terminator(terminator); Input_until_terminator(terminator);
@ -88,7 +87,7 @@ static int check_condition(struct loop_condition *condition)
{ {
intval_t expression; intval_t expression;
// First, check whether there actually *is* a condition // first, check whether there actually *is* a condition
if (condition->body == NULL) if (condition->body == NULL)
return TRUE; // non-existing conditions are always true 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. // looping assembly ("!do"). has to be re-entrant.
static enum eos PO_do(void) // Now GotByte = illegal char static enum eos po_do(void) // now GotByte = illegal char
{ {
struct loop_condition condition1, struct loop_condition condition1,
condition2; condition2;
@ -113,24 +112,24 @@ static enum eos PO_do(void) // Now GotByte = illegal char
char *loop_body; char *loop_body;
int go_on, int go_on,
loop_start; // line number of loop pseudo opcode loop_start; // line number of loop pseudo opcode
// Init // init
condition1.is_until = FALSE; condition1.is_until = FALSE;
condition1.body = NULL; condition1.body = NULL;
condition2.is_until = FALSE; condition2.is_until = FALSE;
condition2.body = NULL; condition2.body = NULL;
// Read head condition to buffer // read head condition to buffer
SKIPSPACE(); SKIPSPACE();
store_condition(&condition1, CHAR_SOB); store_condition(&condition1, CHAR_SOB);
if (GotByte != CHAR_SOB) if (GotByte != CHAR_SOB)
Throw_serious_error(exception_no_left_brace); 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 // then read block and get copy
loop_start = Input_now->line_number; loop_start = Input_now->line_number;
loop_body = Input_skip_or_store_block(TRUE); // changes line number! loop_body = Input_skip_or_store_block(TRUE); // changes line number!
// now GotByte = '}' // now GotByte = '}'
NEXTANDSKIPSPACE(); // Now GotByte = first non-blank char after block NEXTANDSKIPSPACE(); // now GotByte = first non-blank char after block
// Read tail condition to buffer // read tail condition to buffer
store_condition(&condition2, CHAR_EOS); store_condition(&condition2, CHAR_EOS);
// now GotByte = CHAR_EOS // now GotByte = CHAR_EOS
// set up new input // 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) // line number are not yet set up)
Input_now = &loop_input; Input_now = &loop_input;
do { do {
// Check head condition // check head condition
go_on = check_condition(&condition1); go_on = check_condition(&condition1);
if (go_on) { if (go_on) {
parse_ram_block(loop_start, loop_body); parse_ram_block(loop_start, loop_body);
// Check tail condition // check tail condition
go_on = check_condition(&condition2); go_on = check_condition(&condition2);
} }
} while (go_on); } while (go_on);
// Free memory // free memory
free(condition1.body); free(condition1.body);
free(loop_body); free(loop_body);
free(condition2.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 // 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 // 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, struct input loop_input,
*outer_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 if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
return SKIP_REMAINDER; return SKIP_REMAINDER;
// Now GotByte = illegal char // now GotByte = illegal char
force_bit = Input_get_force_bit(); // skips spaces after force_bit = Input_get_force_bit(); // skips spaces after
symbol = symbol_find(zone, force_bit); symbol = symbol_find(zone, force_bit);
if (!Input_accept_comma()) { 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); symbol_set_value(symbol, &loop_counter, TRUE);
} while (loop_counter.val.intval != (counter_last + counter_increment)); } while (loop_counter.val.intval != (counter_last + counter_increment));
} }
// Free memory // free memory
free(loop_body); free(loop_body);
// restore previous input: // restore previous input:
Input_now = outer_input; Input_now = outer_input;
@ -278,7 +277,7 @@ static int skip_or_parse_block(int parse)
// parse {block} [else {block}] // 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. // Parse first block.
// If it's not correctly terminated, return immediately (because // 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 // parse a whole source code file
void Parse_and_close_file(FILE *fd, const char *filename) 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 // pseudo opcode table
static struct ronode pseudo_opcodes[] = { static struct ronode pseudo_opcodes[] = {
PREDEFNODE("do", PO_do), PREDEFNODE("do", po_do),
PREDEFNODE("for", PO_for), PREDEFLAST("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),
// ^^^^ this marks the last element // ^^^^ this marks the last element
}; };
// register pseudo opcodes and build keyword tree for until/while // register pseudo opcodes
void Flow_init(void) void Flow_init(void)
{ {
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes); Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);

View File

@ -13,10 +13,12 @@
// Prototypes // Prototypes
// register pseudo opcodes and build keyword tree for until/while // register pseudo opcodes
extern void Flow_init(void); 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); 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 #endif

View File

@ -38,36 +38,13 @@ static struct input outermost = {
}; };
// Variables // variables
struct input *Input_now = &outermost; // current input structure struct input *Input_now = &outermost; // current input structure
// End of source file ("!endoffile" or "!eof") // functions
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;
}
// predefined stuff // let current input point to start of file
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
void Input_new_file(const char *filename, FILE *fd) void Input_new_file(const char *filename, FILE *fd)
{ {
Input_now->original_filename = filename; Input_now->original_filename = filename;

View File

@ -54,9 +54,7 @@ extern struct input *Input_now; // current input structure
// Prototypes // Prototypes
// register pseudo opcodes // let current input point to start of file
extern void Input_init(void);
// Let current input point to start of file
extern void Input_new_file(const char *filename, FILE *fd); extern void Input_new_file(const char *filename, FILE *fd);
// get next byte from currently active byte source in shortened high-level // get next byte from currently active byte source in shortened high-level
// format. When inside quotes, use GetQuotedByte() instead! // format. When inside quotes, use GetQuotedByte() instead!

View File

@ -5,15 +5,18 @@
// pseudo opcode stuff // pseudo opcode stuff
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
//#include "acme.h" #include "acme.h"
#include "config.h" #include "config.h"
#include "cpu.h" #include "cpu.h"
#include "alu.h" #include "alu.h"
#include "dynabuf.h" #include "dynabuf.h"
#include "flow.h"
#include "input.h" #include "input.h"
#include "macro.h"
#include "global.h" #include "global.h"
#include "output.h" #include "output.h"
#include "section.h" #include "section.h"
#include "symbol.h"
#include "tree.h" #include "tree.h"
#include "typesystem.h" #include "typesystem.h"
#include "pseudoopcodes.h" #include "pseudoopcodes.h"
@ -23,6 +26,7 @@
static const char s_08[] = "08"; static const char s_08[] = "08";
#define s_8 (s_08 + 1) // Yes, I know I'm sick #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_16 (s_65816 + 3) // Yes, I know I'm sick
#define s_sl (s_asl + 1) // Yes, I know I'm sick
// variables // variables
@ -244,6 +248,69 @@ static enum eos po_addr(void) // now GotByte = illegal char
return PARSE_REMAINDER; 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) // 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 // 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 // constants
#define USERMSG_DYNABUF_INITIALSIZE 80 #define USERMSG_DYNABUF_INITIALSIZE 80
@ -390,35 +572,55 @@ 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 // pseudo opcode table
static struct ronode pseudo_opcodes[] = { static struct ronode pseudo_opcode_list[] = {
PREDEFNODE("initmem", po_initmem), PREDEFNODE("initmem", po_initmem),
PREDEFNODE("to", po_to), PREDEFNODE("to", po_to),
PREDEFNODE(s_08, po_8), PREDEFNODE(s_8, po_8),
PREDEFNODE(s_8, po_8), PREDEFNODE(s_08, po_8),
PREDEFNODE("by", po_8), PREDEFNODE("by", po_8),
PREDEFNODE("byte", po_8), PREDEFNODE("byte", po_8),
PREDEFNODE(s_16, po_16), PREDEFNODE(s_16, po_16),
PREDEFNODE("wo", po_16), PREDEFNODE("wo", po_16),
PREDEFNODE("word", po_16), PREDEFNODE("word", po_16),
PREDEFNODE("24", po_24), PREDEFNODE("24", po_24),
PREDEFNODE("32", po_32), PREDEFNODE("32", po_32),
PREDEFNODE("bin", po_binary), PREDEFNODE("bin", po_binary),
PREDEFNODE("binary", po_binary), PREDEFNODE("binary", po_binary),
PREDEFNODE("fi", po_fill), PREDEFNODE("fi", po_fill),
PREDEFNODE("fill", po_fill), PREDEFNODE("fill", po_fill),
PREDEFNODE("addr", po_addr), PREDEFNODE("addr", po_addr),
PREDEFNODE("address", po_addr), PREDEFNODE("address", po_addr),
// PREDEFNODE("skip", po_skip), PREDEFNODE("set", po_set),
PREDEFNODE(s_zone, po_zone), PREDEFNODE(s_sl, po_sl),
PREDEFNODE("zn", po_zone), PREDEFNODE("symbollist", po_sl),
PREDEFNODE(s_subzone, po_subzone), // PREDEFNODE("skip", po_skip),
PREDEFNODE("sz", po_subzone), PREDEFNODE("zn", po_zone),
// PREDEFNODE("debug", po_debug), PREDEFNODE(s_zone, po_zone),
// PREDEFNODE("info", po_info), PREDEFNODE("sz", po_subzone),
PREDEFNODE("warn", po_warn), PREDEFNODE(s_subzone, po_subzone),
PREDEFNODE(s_error, po_error), PREDEFNODE("src", po_source),
PREDEFLAST("serious", po_serious), 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),
PREDEFNODE("serious", po_serious),
PREDEFNODE("eof", po_eof),
PREDEFLAST("endoffile", po_eof),
// ^^^^ this marks the last element // ^^^^ this marks the last element
}; };
@ -427,12 +629,12 @@ static struct ronode pseudo_opcodes[] = {
void pseudoopcodes_init(void) void pseudoopcodes_init(void)
{ {
user_message = DynaBuf_create(USERMSG_DYNABUF_INITIALSIZE); 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. // parse a pseudo opcode. has to be re-entrant.
void pseudoopcode_parse(void) // Now GotByte = "!" void pseudoopcode_parse(void) // now GotByte = "!"
{ {
void *node_body; void *node_body;
enum eos (*fn)(void), enum eos (*fn)(void),

View File

@ -22,10 +22,6 @@
#include "typesystem.h" #include "typesystem.h"
// constants
#define s_sl (s_asl + 1) // Yes, I know I'm sick
// variables // variables
struct rwnode *symbols_forest[256] = { NULL }; // because of 8-bit hash - must be (at least partially) pre-defined so array will be zeroed! 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). // parse label definition (can be either global or local).
// name must be held in GlobalDynaBuf. // name must be held in GlobalDynaBuf.
void symbol_set_label(zone_t zone, int stat_flags, int force_bit, int change_allowed) 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 // fix name of anonymous forward label (held in DynaBuf, NOT TERMINATED!) so it
// 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

View File

@ -22,8 +22,6 @@ struct symbol {
extern struct rwnode *symbols_forest[]; // trees (because of 8-bit hash) 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. // 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); extern void symbol_set_value(struct symbol *symbol, struct result *new_value, int change_allowed);
// parse label definition (can be either global or local). // parse label definition (can be either global or local).