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
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

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
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

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
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

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
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

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!)
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
View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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!

View File

@ -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),

View File

@ -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

View File

@ -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).