diff --git a/src/Makefile b/src/Makefile index 6864200..4218057 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 diff --git a/src/Makefile.dos b/src/Makefile.dos index c2c9ddb..b63b2aa 100644 --- a/src/Makefile.dos +++ b/src/Makefile.dos @@ -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 diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 31f2378..61a54cb 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -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 diff --git a/src/Makefile.riscos b/src/Makefile.riscos index 1a1c4e8..ae17f47 100644 --- a/src/Makefile.riscos +++ b/src/Makefile.riscos @@ -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 diff --git a/src/acme.c b/src/acme.c index 6018095..3b2ec92 100644 --- a/src/acme.c +++ b/src/acme.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); diff --git a/src/cpu.c b/src/cpu.c index 4bc9994..984dfd4 100644 --- a/src/cpu.c +++ b/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); diff --git a/src/cpu.h b/src/cpu.h index a381218..3e466dc 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -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 diff --git a/src/flow.c b/src/flow.c index 403e5bc..62f690d 100644 --- a/src/flow.c +++ b/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); diff --git a/src/flow.h b/src/flow.h index 94f638e..c3e6f5a 100644 --- a/src/flow.h +++ b/src/flow.h @@ -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 diff --git a/src/input.c b/src/input.c index f3fbcbd..daef26f 100644 --- a/src/input.c +++ b/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; diff --git a/src/input.h b/src/input.h index fa71cfb..0c67669 100644 --- a/src/input.h +++ b/src/input.h @@ -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! diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index dd3fb05..c7592c3 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -5,15 +5,18 @@ // pseudo opcode stuff #include #include -//#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,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 -static struct ronode pseudo_opcodes[] = { - PREDEFNODE("initmem", po_initmem), - PREDEFNODE("to", po_to), - PREDEFNODE(s_08, po_8), - PREDEFNODE(s_8, po_8), - PREDEFNODE("by", po_8), - PREDEFNODE("byte", po_8), - PREDEFNODE(s_16, po_16), - PREDEFNODE("wo", po_16), - PREDEFNODE("word", po_16), - PREDEFNODE("24", po_24), - PREDEFNODE("32", po_32), - PREDEFNODE("bin", po_binary), - PREDEFNODE("binary", po_binary), - PREDEFNODE("fi", po_fill), - PREDEFNODE("fill", po_fill), - PREDEFNODE("addr", po_addr), - PREDEFNODE("address", po_addr), -// PREDEFNODE("skip", po_skip), - PREDEFNODE(s_zone, po_zone), - PREDEFNODE("zn", po_zone), - PREDEFNODE(s_subzone, po_subzone), - PREDEFNODE("sz", po_subzone), -// PREDEFNODE("debug", po_debug), -// PREDEFNODE("info", po_info), - PREDEFNODE("warn", po_warn), - PREDEFNODE(s_error, po_error), - PREDEFLAST("serious", po_serious), +static struct ronode pseudo_opcode_list[] = { + PREDEFNODE("initmem", po_initmem), + PREDEFNODE("to", po_to), + PREDEFNODE(s_8, po_8), + PREDEFNODE(s_08, po_8), + PREDEFNODE("by", po_8), + PREDEFNODE("byte", po_8), + PREDEFNODE(s_16, po_16), + PREDEFNODE("wo", po_16), + PREDEFNODE("word", po_16), + PREDEFNODE("24", po_24), + PREDEFNODE("32", po_32), + PREDEFNODE("bin", po_binary), + PREDEFNODE("binary", po_binary), + PREDEFNODE("fi", po_fill), + 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("zn", po_zone), + 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), + 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), diff --git a/src/symbol.c b/src/symbol.c index 9e63cbf..d3a0cc4 100644 --- a/src/symbol.c +++ b/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 diff --git a/src/symbol.h b/src/symbol.h index 7424858..77de086 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -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).