mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-10-06 13:59:41 +00:00
more cleanup
added "outfilestart" keyword to "*=" added "file" keyword to "!convtab" git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@339 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
6c3ec454d3
commit
496fde6f1a
@ -28,7 +28,7 @@ cpu.o: config.h alu.h dynabuf.h global.h input.h mnemo.h output.h tree.h cpu.h c
|
||||
|
||||
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: encoding.h encoding.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
|
||||
|
||||
|
@ -28,7 +28,7 @@ cpu.o: config.h alu.h dynabuf.h global.h input.h mnemo.h output.h tree.h cpu.h c
|
||||
|
||||
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: encoding.h encoding.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
|
||||
|
||||
|
@ -31,7 +31,7 @@ cpu.o: config.h alu.h dynabuf.h global.h input.h mnemo.h output.h tree.h cpu.h c
|
||||
|
||||
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: encoding.h encoding.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
|
||||
|
||||
|
@ -27,7 +27,7 @@ cpu.o: config.h alu.h dynabuf.h global.h input.h mnemo.h output.h tree.h cpu.h c
|
||||
|
||||
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: encoding.h encoding.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
|
||||
|
||||
|
52
src/acme.c
52
src/acme.c
@ -80,11 +80,6 @@ static const char arg_vicelabels[] = "VICE labels filename";
|
||||
// variables
|
||||
static const char **toplevel_sources;
|
||||
static int toplevel_src_count = 0;
|
||||
static const struct cpu_type *default_cpu = NULL;
|
||||
const char *symbollist_filename = NULL;
|
||||
const char *vicelabels_filename = NULL;
|
||||
const char *output_filename = NULL;
|
||||
const char *report_filename = NULL;
|
||||
// maximum recursion depth for macro calls and "!source"
|
||||
signed long macro_recursions_left = MAX_NESTING;
|
||||
signed long source_recursions_left = MAX_NESTING;
|
||||
@ -197,25 +192,25 @@ int ACME_finalize(int exit_code)
|
||||
FILE *fd;
|
||||
|
||||
report_close(report);
|
||||
if (symbollist_filename) {
|
||||
fd = fopen(symbollist_filename, FILE_WRITETEXT); // FIXME - what if filename is given via !sl in sub-dir? fix path!
|
||||
if (config.symbollist_filename) {
|
||||
fd = fopen(config.symbollist_filename, FILE_WRITETEXT); // FIXME - what if filename is given via !sl in sub-dir? fix path!
|
||||
if (fd) {
|
||||
symbols_list(fd);
|
||||
fclose(fd);
|
||||
PLATFORM_SETFILETYPE_TEXT(symbollist_filename);
|
||||
PLATFORM_SETFILETYPE_TEXT(config.symbollist_filename);
|
||||
} else {
|
||||
fprintf(stderr, "Error: Cannot open symbol list file \"%s\".\n", symbollist_filename);
|
||||
fprintf(stderr, "Error: Cannot open symbol list file \"%s\".\n", config.symbollist_filename);
|
||||
exit_code = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (vicelabels_filename) {
|
||||
fd = fopen(vicelabels_filename, FILE_WRITETEXT);
|
||||
if (config.vicelabels_filename) {
|
||||
fd = fopen(config.vicelabels_filename, FILE_WRITETEXT);
|
||||
if (fd) {
|
||||
symbols_vicelabels(fd);
|
||||
fclose(fd);
|
||||
PLATFORM_SETFILETYPE_TEXT(vicelabels_filename);
|
||||
PLATFORM_SETFILETYPE_TEXT(config.vicelabels_filename);
|
||||
} else {
|
||||
fprintf(stderr, "Error: Cannot open VICE label dump file \"%s\".\n", vicelabels_filename);
|
||||
fprintf(stderr, "Error: Cannot open VICE label dump file \"%s\".\n", config.vicelabels_filename);
|
||||
exit_code = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -229,14 +224,13 @@ static void save_output_file(void)
|
||||
FILE *fd;
|
||||
|
||||
// if no output file chosen, tell user and do nothing
|
||||
if (output_filename == NULL) {
|
||||
if (config.output_filename == NULL) {
|
||||
fputs("No output file specified (use the \"-o\" option or the \"!to\" pseudo opcode).\n", stderr);
|
||||
return;
|
||||
}
|
||||
fd = fopen(output_filename, FILE_WRITEBINARY); // FIXME - what if filename is given via !to in sub-dir? fix path!
|
||||
fd = fopen(config.output_filename, FILE_WRITEBINARY); // FIXME - what if filename is given via !to in sub-dir? fix path!
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr, "Error: Cannot open output file \"%s\".\n",
|
||||
output_filename);
|
||||
fprintf(stderr, "Error: Cannot open output file \"%s\".\n", config.output_filename);
|
||||
return;
|
||||
}
|
||||
output_save_file(fd);
|
||||
@ -253,7 +247,7 @@ static void perform_pass(void)
|
||||
++pass.number;
|
||||
// call modules' "pass init" functions
|
||||
output_passinit(); // disable output, PC undefined
|
||||
cputype_passinit(default_cpu); // set default cpu type
|
||||
cputype_passinit(config.default_cpu); // set default cpu type
|
||||
// if start address was given on command line, use it:
|
||||
if (config.initial_pc != NO_VALUE_GIVEN)
|
||||
vcpu_set_pc(config.initial_pc, 0); // 0 -> no segment flags
|
||||
@ -312,10 +306,10 @@ static boolean do_actual_work(void)
|
||||
if (pass.undefined_count == 0) { // FIXME - use pass.needvalue_count instead!
|
||||
// if listing report is wanted and there were no errors,
|
||||
// do another pass to generate listing report
|
||||
if (report_filename) {
|
||||
if (config.report_filename) {
|
||||
if (config.process_verbosity > 1)
|
||||
puts("Extra pass to generate listing report.");
|
||||
if (report_open(report, report_filename) == 0) {
|
||||
if (report_open(report, config.report_filename) == 0) {
|
||||
perform_pass();
|
||||
report_close(report);
|
||||
}
|
||||
@ -370,7 +364,7 @@ static void set_starting_cpu(const char cpu_name[])
|
||||
keyword_to_dynabuf(cpu_name);
|
||||
new_cpu_type = cputype_find();
|
||||
if (new_cpu_type) {
|
||||
default_cpu = new_cpu_type;
|
||||
config.default_cpu = new_cpu_type;
|
||||
return; // ok
|
||||
}
|
||||
fputs("Error: Unknown CPU type.\n", stderr);
|
||||
@ -520,15 +514,15 @@ static const char *long_option(const char *string)
|
||||
else if (strcmp(string, OPTION_FORMAT) == 0)
|
||||
set_output_format(cliargs_get_next()); // NULL is ok (handled like unknown)
|
||||
else if (strcmp(string, OPTION_OUTFILE) == 0)
|
||||
output_filename = cliargs_safe_get_next(name_outfile);
|
||||
config.output_filename = cliargs_safe_get_next(name_outfile);
|
||||
else if (strcmp(string, OPTION_LABELDUMP) == 0) // old
|
||||
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
config.symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
else if (strcmp(string, OPTION_SYMBOLLIST) == 0) // new
|
||||
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
config.symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
else if (strcmp(string, OPTION_VICELABELS) == 0)
|
||||
vicelabels_filename = cliargs_safe_get_next(arg_vicelabels);
|
||||
config.vicelabels_filename = cliargs_safe_get_next(arg_vicelabels);
|
||||
else if (strcmp(string, OPTION_REPORT) == 0)
|
||||
report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||
config.report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||
else if (strcmp(string, OPTION_SETPC) == 0)
|
||||
config.initial_pc = string_to_nonneg_number(cliargs_safe_get_next("program counter"));
|
||||
else if (strcmp(string, OPTION_FROM_TO) == 0) {
|
||||
@ -596,13 +590,13 @@ static char short_option(const char *argument)
|
||||
includepaths_add(cliargs_safe_get_next("include path"));
|
||||
goto done;
|
||||
case 'l': // "-l" selects symbol list filename
|
||||
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
config.symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
break;
|
||||
case 'o': // "-o" selects output filename
|
||||
output_filename = cliargs_safe_get_next(name_outfile);
|
||||
config.output_filename = cliargs_safe_get_next(name_outfile);
|
||||
break;
|
||||
case 'r': // "-r" selects report filename
|
||||
report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||
config.report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||
break;
|
||||
case 'v': // "-v" changes verbosity
|
||||
++config.process_verbosity;
|
||||
|
@ -10,10 +10,6 @@
|
||||
#include "config.h"
|
||||
|
||||
|
||||
// Variables
|
||||
extern const char *symbollist_filename;
|
||||
extern const char *output_filename; // TODO - put in "part" struct
|
||||
extern const char *report_filename; // TODO - put in "part" struct
|
||||
// maximum recursion depth for macro calls and "!source"
|
||||
extern signed long macro_recursions_left;
|
||||
extern signed long source_recursions_left;
|
||||
|
@ -70,6 +70,8 @@ static struct cpu_type cpu_type_m65 = {
|
||||
|
||||
// variables
|
||||
|
||||
boolean cpu_a_is_long = FALSE;
|
||||
boolean cpu_xy_are_long = FALSE;
|
||||
// predefined stuff
|
||||
static struct ronode cputype_tree[] = {
|
||||
PREDEF_START,
|
||||
@ -121,6 +123,6 @@ void cputype_passinit(const struct cpu_type *cpu_type)
|
||||
{
|
||||
// handle cpu type (default is 6502)
|
||||
CPU_state.type = cpu_type ? cpu_type : &cpu_type_6502;
|
||||
CPU_state.a_is_long = FALSE; // short accu
|
||||
CPU_state.xy_are_long = FALSE; // short index regs
|
||||
cpu_a_is_long = FALSE; // short accu
|
||||
cpu_xy_are_long = FALSE; // short index regs
|
||||
}
|
||||
|
@ -25,6 +25,10 @@ struct cpu_type {
|
||||
#define CPUFLAG_DECIMALSUBTRACTBUGGY (1u << 4) // warn if "sed" is assembled
|
||||
#define CPUFLAG_WARN_ABOUT_FF_PTR (1u << 5) // warn if MNEMO($ff) is assembled
|
||||
|
||||
// variables
|
||||
extern boolean cpu_a_is_long;
|
||||
extern boolean cpu_xy_are_long;
|
||||
|
||||
// if cpu type and value match, set register length variable to value.
|
||||
// if cpu type and value don't match, complain instead.
|
||||
extern void vcpu_check_and_set_reg_length(boolean *var, boolean make_long);
|
||||
|
@ -4,15 +4,6 @@
|
||||
//
|
||||
// Character encoding stuff
|
||||
#include "encoding.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "alu.h"
|
||||
#include "acme.h"
|
||||
#include "dynabuf.h"
|
||||
#include "global.h"
|
||||
#include "output.h"
|
||||
#include "input.h"
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
// struct definition
|
||||
@ -82,17 +73,6 @@ const struct encoder encoder_file = {
|
||||
};
|
||||
|
||||
|
||||
// keywords for "!convtab" pseudo opcode
|
||||
static struct ronode encoder_tree[] = {
|
||||
PREDEF_START,
|
||||
//no! PREDEFNODE("file", &encoder_file), "!ct file" is not needed; just use {} after initial loading of table!
|
||||
PREDEFNODE("pet", &encoder_pet),
|
||||
PREDEFNODE("raw", &encoder_raw),
|
||||
PREDEF_END("scr", &encoder_scr),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
|
||||
// exported functions
|
||||
|
||||
|
||||
@ -107,24 +87,3 @@ void encoding_passinit(void)
|
||||
{
|
||||
encoder_current = &encoder_raw;
|
||||
}
|
||||
|
||||
// try to load encoding table from given file
|
||||
void encoding_load_from_file(unsigned char target[256], FILE *stream)
|
||||
{
|
||||
if (fread(target, sizeof(char), 256, stream) != 256)
|
||||
Throw_error("Conversion table incomplete.");
|
||||
}
|
||||
|
||||
// lookup encoder held in DynaBuf and return its struct pointer (or NULL on failure)
|
||||
const struct encoder *encoding_find(void)
|
||||
{
|
||||
void *node_body;
|
||||
|
||||
// perform lookup
|
||||
if (!tree_easy_scan(encoder_tree, &node_body, GlobalDynaBuf)) {
|
||||
Throw_error("Unknown encoding.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return node_body;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||
// Copyright (C) 1998-2020 Marco Baye
|
||||
// Copyright (C) 1998-2024 Marco Baye
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// Character encoding stuff
|
||||
@ -7,10 +7,6 @@
|
||||
#define encoding_H
|
||||
|
||||
|
||||
#include <stdio.h> // for FILE*
|
||||
|
||||
|
||||
//struct encoder;
|
||||
extern const struct encoder *encoder_current; // gets set before each pass TODO - set for each part
|
||||
extern const struct encoder encoder_raw;
|
||||
extern const struct encoder encoder_pet;
|
||||
@ -23,12 +19,9 @@ extern unsigned char *encoding_loaded_table; // ...loaded from file
|
||||
|
||||
// convert character using current encoding
|
||||
extern unsigned char encoding_encode_char(unsigned char byte);
|
||||
|
||||
// set "raw" as default encoding
|
||||
extern void encoding_passinit(void);
|
||||
// try to load encoding table from given file
|
||||
extern void encoding_load_from_file(unsigned char target[256], FILE *stream);
|
||||
// lookup encoder held in DynaBuf and return its struct pointer (or NULL on failure)
|
||||
extern const struct encoder *encoding_find(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -35,7 +35,7 @@ char s_untitled[] = "<untitled>"; // FIXME - this is actually const
|
||||
// Exception messages during assembly
|
||||
const char exception_missing_string[] = "No string given.";
|
||||
const char exception_negative_size[] = "Negative size argument.";
|
||||
const char exception_no_left_brace[] = "Missing '{'.";
|
||||
const char exception_no_left_brace[] = "Missing '{' character.";
|
||||
const char exception_no_memory_left[] = "Out of memory.";
|
||||
const char exception_no_right_brace[] = "Found end-of-file instead of '}'.";
|
||||
//const char exception_not_yet[] = "Sorry, feature not yet implemented.";
|
||||
@ -123,6 +123,11 @@ void config_default(struct config *conf)
|
||||
conf->wanted_version = VER_CURRENT; // changed by --dialect
|
||||
conf->debuglevel = DEBUGLEVEL_DEBUG; // changed by --debuglevel, used by "!debug"
|
||||
conf->outbuf_size = 0x10000; // 64K, "--test" changes to 16M
|
||||
conf->default_cpu = NULL;
|
||||
conf->symbollist_filename = NULL;
|
||||
conf->vicelabels_filename = NULL;
|
||||
conf->output_filename = NULL;
|
||||
conf->report_filename = NULL;
|
||||
conf->mem_init_value = MEMINIT_USE_DEFAULT; // set by --initmem
|
||||
conf->initial_pc = NO_VALUE_GIVEN; // set by --setpc
|
||||
conf->outfile_start = NO_VALUE_GIVEN; // set by --from-to
|
||||
|
@ -87,6 +87,11 @@ struct config {
|
||||
enum version wanted_version; // set by --dialect (and --test --test)
|
||||
signed long debuglevel; // set by --debuglevel, used by "!debug"
|
||||
signed long outbuf_size; // 64K, "--test" changes to 16M
|
||||
const struct cpu_type *default_cpu;
|
||||
const char *symbollist_filename;
|
||||
const char *vicelabels_filename;
|
||||
const char *output_filename; // TODO - put in "part" struct
|
||||
const char *report_filename; // TODO - put in "part" struct
|
||||
#define MEMINIT_USE_DEFAULT 256 // default value for next field if cli switch not used:
|
||||
signed long mem_init_value; // set by --initmem
|
||||
#define NO_VALUE_GIVEN (-1) // default value for these fields if cli switch not used:
|
||||
|
@ -889,10 +889,10 @@ static unsigned int imm_ops(bits *force_bit, unsigned char opcode, bits immediat
|
||||
return ((unsigned int) opcode) << 8; // opcode in bits8.15 forces two-byte argument
|
||||
|
||||
case IM_ACCUMULATOR: // for 65816
|
||||
long_register = CPU_state.a_is_long;
|
||||
long_register = cpu_a_is_long;
|
||||
break;
|
||||
case IM_INDEXREGS: // for 65816
|
||||
long_register = CPU_state.xy_are_long;
|
||||
long_register = cpu_xy_are_long;
|
||||
break;
|
||||
default:
|
||||
BUG("IllegalImmediateMode", immediate_mode);
|
||||
|
34
src/output.c
34
src/output.c
@ -59,6 +59,7 @@ static struct pseudopc *pseudopc_current_context; // current struct (NULL when n
|
||||
// variables
|
||||
static struct output default_output;
|
||||
static struct output *out = &default_output;
|
||||
static int statement_size; // add to PC after statement
|
||||
// FIXME - make static
|
||||
struct vcpu CPU_state; // current CPU state
|
||||
|
||||
@ -151,7 +152,7 @@ static void real_output(intval_t byte)
|
||||
if (report->fd)
|
||||
report_binary(byte & 0xff); // file for reporting, taking also CPU_2add
|
||||
out->buffer[out->write_idx++] = (byte & 0xff) ^ out->xor;
|
||||
++CPU_state.add_to_pc;
|
||||
++statement_size; // count this byte
|
||||
}
|
||||
|
||||
|
||||
@ -194,7 +195,7 @@ void output_skip(int size)
|
||||
out->highest_written = out->write_idx + size - 1;
|
||||
// advance ptrs
|
||||
out->write_idx += size;
|
||||
CPU_state.add_to_pc += size;
|
||||
statement_size += size; // count bytes so PC will be adjusted correctly after this
|
||||
}
|
||||
|
||||
|
||||
@ -280,21 +281,6 @@ int outputfile_prefer_cbm_format(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// select output file ("!to" pseudo opcode)
|
||||
// returns zero on success, nonzero if already set
|
||||
int outputfile_set_filename(void)
|
||||
{
|
||||
// if output file already chosen, complain and exit
|
||||
if (output_filename) {
|
||||
Throw_warning("Output file already chosen.");
|
||||
return 1; // failed
|
||||
}
|
||||
|
||||
// get malloc'd copy of filename
|
||||
output_filename = dynabuf_get_copy(GlobalDynaBuf);
|
||||
return 0; // ok
|
||||
}
|
||||
|
||||
|
||||
// init output struct (done later)
|
||||
void output_createbuffer(void)
|
||||
@ -353,7 +339,7 @@ void output_save_file(FILE *fd)
|
||||
// FIXME - add checks and error messages for "start is above $ffff"!)
|
||||
switch (output_format) {
|
||||
case OUTPUT_FORMAT_APPLE:
|
||||
PLATFORM_SETFILETYPE_APPLE(output_filename);
|
||||
PLATFORM_SETFILETYPE_APPLE(config.output_filename);
|
||||
// output 16-bit load address in little-endian byte order
|
||||
putc(start & 255, fd);
|
||||
putc(start >> 8, fd);
|
||||
@ -363,10 +349,10 @@ void output_save_file(FILE *fd)
|
||||
break;
|
||||
case OUTPUT_FORMAT_UNSPECIFIED:
|
||||
case OUTPUT_FORMAT_PLAIN:
|
||||
PLATFORM_SETFILETYPE_PLAIN(output_filename);
|
||||
PLATFORM_SETFILETYPE_PLAIN(config.output_filename);
|
||||
break;
|
||||
case OUTPUT_FORMAT_CBM:
|
||||
PLATFORM_SETFILETYPE_CBM(output_filename);
|
||||
PLATFORM_SETFILETYPE_CBM(config.output_filename);
|
||||
// output 16-bit load address in little-endian byte order
|
||||
putc(start & 255, fd);
|
||||
putc(start >> 8, fd);
|
||||
@ -454,7 +440,7 @@ void output_passinit(void)
|
||||
// FIXME - number type is "undefined", but still the intval 0 below will
|
||||
// be used to calculate diff when pc is first set.
|
||||
CPU_state.pc.val.intval = 0; // same as output's write_idx on pass init
|
||||
CPU_state.add_to_pc = 0; // increase PC by this at end of statement
|
||||
statement_size = 0; // increase PC by this at end of statement
|
||||
|
||||
// pseudopc stuff:
|
||||
pseudopc_current_context = NULL;
|
||||
@ -597,15 +583,15 @@ void vcpu_read_pc(struct number *target)
|
||||
// get size of current statement (until now) - needed for "!bin" verbose output
|
||||
int vcpu_get_statement_size(void)
|
||||
{
|
||||
return CPU_state.add_to_pc;
|
||||
return statement_size;
|
||||
}
|
||||
|
||||
|
||||
// adjust program counter (called at end of each statement)
|
||||
void vcpu_end_statement(void)
|
||||
{
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval + CPU_state.add_to_pc) & (config.outbuf_size - 1);
|
||||
CPU_state.add_to_pc = 0;
|
||||
CPU_state.pc.val.intval = (CPU_state.pc.val.intval + statement_size) & (config.outbuf_size - 1);
|
||||
statement_size = 0; // reset
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,9 +23,6 @@
|
||||
struct vcpu {
|
||||
const struct cpu_type *type; // current CPU type (default 6502) (FIXME - move out of struct again?)
|
||||
struct number pc; // current program counter (pseudo value)
|
||||
int add_to_pc; // add to PC after statement
|
||||
boolean a_is_long;
|
||||
boolean xy_are_long;
|
||||
};
|
||||
|
||||
|
||||
@ -71,9 +68,6 @@ extern const char outputfile_formats[]; // string to show if outputfile_set_form
|
||||
// if file format isn't set, chooses CBM and returns 1.
|
||||
extern int outputfile_prefer_cbm_format(void);
|
||||
|
||||
// try to set output file name held in DynaBuf. Returns zero on success.
|
||||
extern int outputfile_set_filename(void);
|
||||
|
||||
// write used portion of output buffer to output file
|
||||
extern void output_save_file(FILE *fd);
|
||||
|
||||
|
@ -33,19 +33,24 @@ enum eos {
|
||||
|
||||
// constants
|
||||
static const char exception_unknown_pseudo_opcode[] = "Unknown pseudo opcode.";
|
||||
static const char exception_missing_equals[] = "Missing '=' character.";
|
||||
|
||||
|
||||
// local prototype because "*=" might fake a "!outfilestart":
|
||||
static enum eos po_outfilestart(void);
|
||||
|
||||
// this is not really a pseudo opcode, but similar enough to be put here:
|
||||
// called when "*= EXPRESSION" is parsed, to set the program counter
|
||||
void notreallypo_setpc(void) // GotByte is '*'
|
||||
{
|
||||
bits segment_flags = 0;
|
||||
boolean do_outfilestart = FALSE;
|
||||
struct number intresult;
|
||||
|
||||
// next non-space must be '='
|
||||
NEXTANDSKIPSPACE();
|
||||
if (GotByte != '=') {
|
||||
Throw_error(exception_syntax);
|
||||
Throw_error(exception_missing_equals);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -61,6 +66,8 @@ void notreallypo_setpc(void) // GotByte is '*'
|
||||
segment_flags |= SEGMENT_FLAG_OVERLAY;
|
||||
} else if (strcmp(GlobalDynaBuf->buffer, "invisible") == 0) {
|
||||
segment_flags |= SEGMENT_FLAG_INVISIBLE;
|
||||
} else if (strcmp(GlobalDynaBuf->buffer, "outfilestart") == 0) {
|
||||
do_outfilestart = TRUE;
|
||||
/*TODO } else if (strcmp(GlobalDynaBuf->buffer, "limit") == 0) {
|
||||
skip '='
|
||||
read memory limit
|
||||
@ -68,8 +75,6 @@ void notreallypo_setpc(void) // GotByte is '*'
|
||||
mutually exclusive with all other arguments!
|
||||
this would mean to keep all previous segment data,
|
||||
so it could be used with "*=*-5" or "*=*+3"
|
||||
} else if (strcmp(GlobalDynaBuf->buffer, "outfilestart") == 0) {
|
||||
FIXME set flag to automatically do "!outfilestart" afterward.
|
||||
} else if (strcmp(GlobalDynaBuf->buffer, "name") == 0) {
|
||||
skip '='
|
||||
read segment name (quoted string!) */
|
||||
@ -79,7 +84,11 @@ FIXME set flag to automatically do "!outfilestart" afterward.
|
||||
}
|
||||
}
|
||||
vcpu_set_pc(intresult.val.intval, segment_flags);
|
||||
// TODO - allow block syntax, so it is possible to put data "somewhere else" and then return to old position?
|
||||
|
||||
// if wanted, perform "!outfilestart":
|
||||
if (do_outfilestart)
|
||||
po_outfilestart();
|
||||
|
||||
input_ensure_EOS();
|
||||
return;
|
||||
|
||||
@ -128,20 +137,26 @@ static enum eos po_xor(void)
|
||||
}
|
||||
|
||||
|
||||
// select output file and format ("!to" pseudo opcode)
|
||||
// select output file name and format ("!to" pseudo opcode)
|
||||
static enum eos po_to(void)
|
||||
{
|
||||
// only act upon this pseudo opcode in first pass
|
||||
// only process this pseudo opcode in first pass
|
||||
if (!FIRST_PASS)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// cli arg and earlier calls supersede this call
|
||||
if (config.output_filename) {
|
||||
Throw_warning("Output file already chosen.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// read filename to global dynamic buffer
|
||||
// if no file name given, exit (complaining will have been done)
|
||||
if (input_read_output_filename())
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
if (outputfile_set_filename())
|
||||
return SKIP_REMAINDER;
|
||||
// get malloc'd copy of filename
|
||||
config.output_filename = dynabuf_get_copy(GlobalDynaBuf);
|
||||
|
||||
// select output format
|
||||
// if no comma found, use default file format
|
||||
@ -308,18 +323,32 @@ static enum eos po_cbm(void)
|
||||
|
||||
// read encoding table from file
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos user_defined_encoding(FILE *stream)
|
||||
static enum eos use_encoding_from_file(void)
|
||||
{
|
||||
boolean uses_lib;
|
||||
FILE *stream;
|
||||
unsigned char local_table[256],
|
||||
*buffered_table = encoding_loaded_table;
|
||||
const struct encoder *buffered_encoder = encoder_current;
|
||||
*buffered_table;
|
||||
const struct encoder *buffered_encoder;
|
||||
|
||||
// read file name
|
||||
if (input_read_input_filename(&uses_lib))
|
||||
return SKIP_REMAINDER; // missing or unterminated file name
|
||||
|
||||
// read from file
|
||||
stream = includepaths_open_ro(uses_lib);
|
||||
if (stream) {
|
||||
encoding_load_from_file(local_table, stream);
|
||||
// try to load encoding table from given file
|
||||
if (fread(local_table, sizeof(char), 256, stream) != 256)
|
||||
Throw_error("Conversion table incomplete.");
|
||||
fclose(stream);
|
||||
}
|
||||
encoder_current = &encoder_file; // activate new encoding
|
||||
encoding_loaded_table = local_table; // activate local table
|
||||
|
||||
// now switch encoding
|
||||
buffered_encoder = encoder_current;
|
||||
encoder_current = &encoder_file;
|
||||
buffered_table = encoding_loaded_table;
|
||||
encoding_loaded_table = local_table;
|
||||
// if there's a block, parse that and then restore old values
|
||||
if (parse_optional_block()) {
|
||||
encoder_current = buffered_encoder;
|
||||
@ -335,19 +364,17 @@ static enum eos user_defined_encoding(FILE *stream)
|
||||
|
||||
// use one of the pre-defined encodings (raw, pet, scr)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos predefined_encoding(void)
|
||||
static enum eos use_predefined_encoding(const struct encoder *new_encoder)
|
||||
{
|
||||
unsigned char local_table[256],
|
||||
*buffered_table = encoding_loaded_table;
|
||||
const struct encoder *buffered_encoder = encoder_current;
|
||||
*buffered_table;
|
||||
const struct encoder *buffered_encoder;
|
||||
|
||||
if (input_read_and_lower_keyword()) {
|
||||
const struct encoder *new_encoder = encoding_find();
|
||||
|
||||
if (new_encoder)
|
||||
encoder_current = new_encoder; // activate new encoder
|
||||
}
|
||||
encoding_loaded_table = local_table; // activate local table
|
||||
// switch encoding
|
||||
buffered_encoder = encoder_current;
|
||||
encoder_current = new_encoder;
|
||||
buffered_table = encoding_loaded_table;
|
||||
encoding_loaded_table = local_table;
|
||||
// if there's a block, parse that and then restore old values
|
||||
if (parse_optional_block())
|
||||
encoder_current = buffered_encoder;
|
||||
@ -355,33 +382,42 @@ static enum eos predefined_encoding(void)
|
||||
encoding_loaded_table = buffered_table;
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
|
||||
// set current encoding ("!convtab" pseudo opcode)
|
||||
// (allows for block, so must be reentrant)
|
||||
// FIXME: current code does not allow for stuff like
|
||||
// !convtab some_string_symbol + ".bin"
|
||||
// because anything not starting with '<' or '"' is supposed to be a keyword.
|
||||
// maybe fix this by using
|
||||
// !convtab file = base + ".txt"
|
||||
// in the future?
|
||||
// another workaround would be:
|
||||
// !convtab "" + some_string_symbol + ".bin"
|
||||
// but even then input_read_input_filename needs to be fixed!
|
||||
static enum eos po_convtab(void)
|
||||
{
|
||||
boolean uses_lib;
|
||||
FILE *stream;
|
||||
// is file name given old-style, without "file" keyword?
|
||||
if ((GotByte == '<') || (GotByte == '"'))
|
||||
return use_encoding_from_file();
|
||||
|
||||
if ((GotByte == '<') || (GotByte == '"')) {
|
||||
// encoding table from file
|
||||
if (input_read_input_filename(&uses_lib))
|
||||
return SKIP_REMAINDER; // missing or unterminated file name
|
||||
// expect keyword: either one of the pre-defined encodings or
|
||||
// "file" with a filename argument:
|
||||
if (input_read_and_lower_keyword() == 0)
|
||||
return SKIP_REMAINDER; // "No string given" error has already been thrown
|
||||
|
||||
stream = includepaths_open_ro(uses_lib);
|
||||
return user_defined_encoding(stream);
|
||||
} else {
|
||||
// one of the pre-defined encodings
|
||||
return predefined_encoding();
|
||||
// now check for known keywords:
|
||||
if (strcmp(GlobalDynaBuf->buffer, "pet") == 0)
|
||||
return use_predefined_encoding(&encoder_pet);
|
||||
|
||||
if (strcmp(GlobalDynaBuf->buffer, "raw") == 0)
|
||||
return use_predefined_encoding(&encoder_raw);
|
||||
|
||||
if (strcmp(GlobalDynaBuf->buffer, "scr") == 0)
|
||||
return use_predefined_encoding(&encoder_scr);
|
||||
|
||||
if (strcmp(GlobalDynaBuf->buffer, "file") == 0) {
|
||||
SKIPSPACE();
|
||||
if (GotByte != '=') {
|
||||
Throw_error(exception_missing_equals);
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
GetByte(); // eat '='
|
||||
return use_encoding_from_file();
|
||||
}
|
||||
|
||||
Throw_error("Unknown encoding.");
|
||||
return use_predefined_encoding(encoder_current); // keep going
|
||||
}
|
||||
// insert string(s)
|
||||
static enum eos encode_string(const struct encoder *inner_encoder, unsigned char xor)
|
||||
@ -410,7 +446,7 @@ static enum eos encode_string(const struct encoder *inner_encoder, unsigned char
|
||||
GetByte();
|
||||
// now convert to unescaped version
|
||||
// FIXME - next call does nothing because wanted<escaping!
|
||||
// FIXME - there is another block like this in line 1317!
|
||||
// FIXME - there is another block like this, scan for ROOSTA!
|
||||
if (input_unescape_dynabuf(0))
|
||||
return SKIP_REMAINDER; // escaping error
|
||||
|
||||
@ -694,34 +730,34 @@ static enum eos po_cpu(void)
|
||||
// (allows for block, so must be reentrant)
|
||||
static enum eos set_register_length(boolean *var, boolean make_long)
|
||||
{
|
||||
int old_size = *var;
|
||||
boolean long_before = *var;
|
||||
|
||||
// set new register length (or complain - whichever is more fitting)
|
||||
vcpu_check_and_set_reg_length(var, make_long);
|
||||
// if there's a block, parse that and then restore old value!
|
||||
if (parse_optional_block())
|
||||
vcpu_check_and_set_reg_length(var, old_size); // restore old length
|
||||
vcpu_check_and_set_reg_length(var, long_before); // restore old length
|
||||
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);
|
||||
return set_register_length(&cpu_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);
|
||||
return set_register_length(&cpu_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);
|
||||
return set_register_length(&cpu_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);
|
||||
return set_register_length(&cpu_xy_are_long, FALSE);
|
||||
}
|
||||
|
||||
|
||||
@ -750,7 +786,7 @@ static enum eos po_set(void) // now GotByte = illegal char
|
||||
|
||||
force_bit = input_get_force_bit(); // skips spaces after
|
||||
if (GotByte != '=') {
|
||||
Throw_error(exception_syntax);
|
||||
Throw_error(exception_missing_equals);
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
@ -772,19 +808,20 @@ static enum eos po_symbollist(void)
|
||||
if (!FIRST_PASS)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// cli arg and earlier calls supersede this call
|
||||
if (config.symbollist_filename) {
|
||||
Throw_warning("Symbol list file name already chosen.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// read filename to global dynamic buffer
|
||||
// if no file name given, exit (complaining will have been done)
|
||||
if (input_read_output_filename())
|
||||
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);
|
||||
config.symbollist_filename = dynabuf_get_copy(GlobalDynaBuf);
|
||||
|
||||
// ensure there's no garbage at end of line
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
@ -1306,7 +1343,7 @@ static enum eos throw_src_string(enum debuglevel level, const char prefix[])
|
||||
GetByte();
|
||||
// now convert to unescaped version
|
||||
// FIXME - next call does nothing because wanted<escaping!
|
||||
// FIXME - there is another block like this in line 416!
|
||||
// FIXME - there is another block like this, scan for ROOSTA!
|
||||
if (input_unescape_dynabuf(0))
|
||||
return SKIP_REMAINDER; // escaping error
|
||||
|
||||
@ -1485,7 +1522,7 @@ static struct ronode pseudo_opcode_tree[] = {
|
||||
|
||||
|
||||
// parse a pseudo opcode. has to be re-entrant.
|
||||
void pseudoopcode_parse(void) // now GotByte = "!"
|
||||
void pseudoopcode_parse(void) // now GotByte = '!' (or '.' in case of --fullstop)
|
||||
{
|
||||
void *node_body;
|
||||
enum eos (*fn)(void),
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define RELEASE "0.97" // update before release FIXME
|
||||
#define CODENAME "Zem" // update before release
|
||||
#define CHANGE_DATE "13 Feb" // update before release FIXME
|
||||
#define CHANGE_DATE "14 Feb" // update before release FIXME
|
||||
#define CHANGE_YEAR "2024" // update before release
|
||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||
|
Loading…
Reference in New Issue
Block a user