added "--from-to" (and did some internal cleanup)

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@334 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2024-02-11 23:08:58 +00:00
parent 10af90860d
commit f52430f620
11 changed files with 290 additions and 168 deletions

View File

@ -45,7 +45,7 @@ do { \
// output of platform-specific command line switches
#define PLATFORM_OPTION_HELP \
" -t, --throwback use the DDEUtils module's \"throwback\" protocol\n"
" -t, --throwback use the DDEUtils module's \"throwback\" protocol\n"
// processing of platform-specific command line switches
#define PLATFORM_SHORTOPTION_CODE \

View File

@ -54,6 +54,7 @@ static const char arg_vicelabels[] = "VICE labels filename";
#define OPTION_VICELABELS "vicelabels"
#define OPTION_REPORT "report"
#define OPTION_SETPC "setpc"
#define OPTION_FROM_TO "from-to"
#define OPTION_CPU "cpu"
#define OPTION_INITMEM "initmem"
#define OPTION_MAXERRORS "maxerrors"
@ -79,9 +80,6 @@ static const char arg_vicelabels[] = "VICE labels filename";
// variables
static const char **toplevel_sources;
static int toplevel_src_count = 0;
#define ILLEGAL_START_ADDRESS (-1)
static signed long start_address = ILLEGAL_START_ADDRESS;
static signed long fill_value = MEMINIT_USE_DEFAULT;
static const struct cpu_type *default_cpu = NULL;
const char *symbollist_filename = NULL;
const char *vicelabels_filename = NULL;
@ -124,40 +122,41 @@ static void show_help_and_exit(void)
"acme [OPTION...] [FILE]...\n"
"\n"
"Options:\n"
" -h, --" OPTION_HELP " show this help and exit\n"
" -f, --" OPTION_FORMAT " FORMAT set output file format\n"
" -o, --" OPTION_OUTFILE " FILE set output file name\n"
" -r, --" OPTION_REPORT " FILE set report file name\n"
" -l, --" OPTION_SYMBOLLIST " FILE set symbol list file name\n"
" --" OPTION_LABELDUMP " (old name for --" OPTION_SYMBOLLIST ")\n"
" --" OPTION_VICELABELS " FILE set file name for label dump in VICE format\n"
" --" OPTION_SETPC " VALUE set program counter\n"
" --" OPTION_CPU " CPU set target processor\n"
" --" OPTION_INITMEM " VALUE define 'empty' memory\n"
" --" OPTION_MAXERRORS " NUMBER set number of errors before exiting\n"
" --" OPTION_MAXDEPTH " NUMBER set recursion depth for macro calls and !src\n"
" --" OPTION_IGNORE_ZEROES " do not determine number size by leading zeroes\n"
" --" OPTION_STRICT_SEGMENTS " turn segment overlap warnings into errors\n"
" --" OPTION_STRICT " treat all warnings like errors\n"
" -vDIGIT set verbosity level\n"
" -DSYMBOL=VALUE define global symbol\n"
" -I PATH/TO/DIR add search path for input files\n"
" -h, --" OPTION_HELP " show this help and exit\n"
" -f, --" OPTION_FORMAT " FORMAT set output file format\n"
" -o, --" OPTION_OUTFILE " FILE set output file name\n"
" -r, --" OPTION_REPORT " FILE set report file name\n"
" -l, --" OPTION_SYMBOLLIST " FILE set symbol list file name\n"
" --" OPTION_LABELDUMP " (old name for --" OPTION_SYMBOLLIST ")\n"
" --" OPTION_VICELABELS " FILE set file name for label dump in VICE format\n"
" --" OPTION_SETPC " VALUE set program counter\n"
" --" OPTION_FROM_TO " VALUE VALUE set start and end of output file\n"
" --" OPTION_CPU " CPU set target processor\n"
" --" OPTION_INITMEM " VALUE define 'empty' memory\n"
" --" OPTION_MAXERRORS " NUMBER set number of errors before exiting\n"
" --" OPTION_MAXDEPTH " NUMBER set recursion depth for macro calls and !src\n"
" --" OPTION_IGNORE_ZEROES " do not determine number size by leading zeroes\n"
" --" OPTION_STRICT_SEGMENTS " turn segment overlap warnings into errors\n"
" --" OPTION_STRICT " treat all warnings like errors\n"
" -vDIGIT set verbosity level\n"
" -DSYMBOL=VALUE define global symbol\n"
" -I PATH/TO/DIR add search path for input files\n"
// TODO: replace these:
" -W" OPTIONWNO_LABEL_INDENT " suppress warnings about indented labels\n"
" -W" OPTIONWNO_OLD_FOR " (old, use \"--dialect 0.94.8\" instead)\n"
" -W" OPTIONWNO_BIN_LEN " suppress warnings about lengths of binary literals\n"
" -W" OPTIONWTYPE_MISMATCH " enable type checking (warn about type mismatch)\n"
" -W" OPTIONWNO_LABEL_INDENT " suppress warnings about indented labels\n"
" -W" OPTIONWNO_OLD_FOR " (old, use \"--dialect 0.94.8\" instead)\n"
" -W" OPTIONWNO_BIN_LEN " suppress warnings about lengths of binary literals\n"
" -W" OPTIONWTYPE_MISMATCH " enable type checking (warn about type mismatch)\n"
// with this line and add a separate function:
//" -W show warning level options\n"
" --" OPTION_USE_STDOUT " fix for 'Relaunch64' IDE (see docs)\n"
" --" OPTION_MSVC " output errors in MS VS format\n"
" --" OPTION_COLOR " use ANSI color codes for error output\n"
" --" OPTION_FULLSTOP " use '.' as pseudo opcode prefix\n"
" --" OPTION_DIALECT " VERSION behave like different version\n"
" --" OPTION_DEBUGLEVEL " VALUE drop all higher-level debug messages\n"
" --" OPTION_TEST " enable experimental features\n"
" --" OPTION_USE_STDOUT " fix for 'Relaunch64' IDE (see docs)\n"
" --" OPTION_MSVC " output errors in MS VS format\n"
" --" OPTION_COLOR " use ANSI color codes for error output\n"
" --" OPTION_FULLSTOP " use '.' as pseudo opcode prefix\n"
" --" OPTION_DIALECT " VERSION behave like different version\n"
" --" OPTION_DEBUGLEVEL " VALUE drop all higher-level debug messages\n"
" --" OPTION_TEST " enable experimental features\n"
PLATFORM_OPTION_HELP
" -V, --" OPTION_VERSION " show version and exit\n");
" -V, --" OPTION_VERSION " show version and exit\n");
exit(EXIT_SUCCESS);
}
@ -256,8 +255,8 @@ static void perform_pass(void)
output_passinit(); // disable output, PC undefined
cputype_passinit(default_cpu); // set default cpu type
// if start address was given on command line, use it:
if (start_address != ILLEGAL_START_ADDRESS)
vcpu_set_pc(start_address, 0);
if (config.initial_pc != NO_VALUE_GIVEN)
vcpu_set_pc(config.initial_pc, 0); // 0 -> no segment flags
encoding_passinit(); // set default encoding
section_passinit(); // set initial zone (untitled)
// init variables
@ -419,29 +418,27 @@ static signed long string_to_number(const char *string)
could_not_parse(end);
return result;
}
// set program counter
static void set_starting_pc(const char expression[])
// wrapper for fn above: complain about negative numbers
static signed long string_to_nonneg_number(const char *string)
{
start_address = string_to_number(expression);
if ((start_address > -1) && (start_address < 65536))
return;
signed long result = string_to_number(string);
fprintf(stderr, "%sProgram counter out of range (0-0xffff).\n", cliargs_error);
exit(EXIT_FAILURE);
if (result < 0) {
fprintf(stderr, "%sInvalid value, number is negative: '%s'.\n", cliargs_error, string);
exit(EXIT_FAILURE);
}
return result;
}
// set initial memory contents
static void set_mem_contents(const char expression[])
{
fill_value = string_to_number(expression);
if ((fill_value >= -128) && (fill_value <= 255))
return;
fprintf(stderr, "%sInitmem value out of range (0-0xff).\n", cliargs_error);
exit(EXIT_FAILURE);
config.mem_init_value = string_to_number(expression);
if ((config.mem_init_value < -128) || (config.mem_init_value > 255)) {
fprintf(stderr, "%sInitmem value out of range (0-0xff).\n", cliargs_error);
exit(EXIT_FAILURE);
}
}
@ -533,8 +530,11 @@ static const char *long_option(const char *string)
else if (strcmp(string, OPTION_REPORT) == 0)
report_filename = cliargs_safe_get_next(arg_reportfile);
else if (strcmp(string, OPTION_SETPC) == 0)
set_starting_pc(cliargs_safe_get_next("program counter"));
else if (strcmp(string, OPTION_CPU) == 0)
config.initial_pc = string_to_nonneg_number(cliargs_safe_get_next("program counter"));
else if (strcmp(string, OPTION_FROM_TO) == 0) {
config.outfile_start = string_to_nonneg_number(cliargs_safe_get_next("start address of output file"));
config.outfile_end = string_to_nonneg_number(cliargs_safe_get_next("end address of output file"));
} else if (strcmp(string, OPTION_CPU) == 0)
set_starting_cpu(cliargs_get_next()); // NULL is ok (handled like unknown)
else if (strcmp(string, OPTION_INITMEM) == 0)
set_mem_contents(cliargs_safe_get_next("initmem value"));
@ -563,6 +563,7 @@ static const char *long_option(const char *string)
else if (strcmp(string, OPTION_TEST) == 0) {
config.wanted_version = VER_FUTURE;
config.test_new_features = TRUE;
config.outbuf_size = 0x1000000; // 16 MiB (FIXME - give it its own cli switch!)
} PLATFORM_LONGOPTION_CODE
else if (strcmp(string, OPTION_COLOR) == 0)
config.format_color = TRUE;
@ -656,8 +657,28 @@ int main(int argc, const char *argv[])
cliargs_handle_options(short_option, long_option);
// generate list of files to process
cliargs_get_rest(&toplevel_src_count, &toplevel_sources, "No top level sources given");
// now that we have processed all cli switches, check a few values for
// valid range:
if ((config.initial_pc != NO_VALUE_GIVEN) && (config.initial_pc >= config.outbuf_size)) {
fprintf(stderr, "%sProgram counter exceeds outbuffer size.\n", cliargs_error);
exit(EXIT_FAILURE);
}
if ((config.outfile_start != NO_VALUE_GIVEN) && (config.outfile_start >= config.outbuf_size)) {
fprintf(stderr, "%sStart address of output file exceeds outbuffer size.\n", cliargs_error);
exit(EXIT_FAILURE);
}
if ((config.outfile_end != NO_VALUE_GIVEN) && (config.outfile_end >= config.outbuf_size)) {
fprintf(stderr, "%sEnd address of output file exceeds outbuffer size.\n", cliargs_error);
exit(EXIT_FAILURE);
}
if (config.outfile_start > config.outfile_end) {
fprintf(stderr, "%sStart address of output file exceeds end address.\n", cliargs_error);
exit(EXIT_FAILURE);
}
// init output buffer
output_createbuffer(fill_value, /* use_large_buf= */ config.test_new_features);
output_createbuffer();
if (do_actual_work())
save_output_file();
return ACME_finalize(EXIT_SUCCESS); // dump labels, if wanted

View File

@ -72,8 +72,6 @@ struct listitem {
// maximum nesting depth of "!src" and macro calls
// is not actually a limitation, but a means of finding recursions
#define MAX_NESTING 64
// default value for output buffer
#define FILLVALUE_INITIAL 0
// default value for "!fill"
#define FILLVALUE_FILL 0

View File

@ -122,6 +122,11 @@ void config_default(struct config *conf)
conf->test_new_features = FALSE; // enabled by --test
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->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
conf->outfile_end = NO_VALUE_GIVEN; // set by --from-to
}
// memory allocation stuff
@ -164,8 +169,8 @@ boolean parser_change_nowarn_block_flag(boolean new_value)
return old_value;
}
#define SF_FOUND_BLANK (1u << 0) // statement had space or tab
#define SF_IMPLIED_LABEL (1u << 1) // statement had implied label def
#define SF_FOUND_BLANK (1u << 0) // statement started with space or tab
#define SF_FOUND_SYMBOL (1u << 1) // statement had label or symbol definition
#define SF_ADDR_PREFIX (1u << 2) // explicit symbol definition is an address
#define SF_NOWARN_PREFIX (1u << 3) // suppress warnings for this statement
static bits statement_flags;
@ -181,15 +186,15 @@ extern void parser_set_nowarn_prefix(void)
statement_flags |= SF_NOWARN_PREFIX;
}
// Check and return whether first label of statement. Complain if not.
static int first_label_of_statement(void)
// Check and return whether first symbol of statement. Complain if not.
static int first_symbol_of_statement(void)
{
if (statement_flags & SF_IMPLIED_LABEL) {
if (statement_flags & SF_FOUND_SYMBOL) {
Throw_error(exception_syntax);
input_skip_remainder();
return FALSE;
}
statement_flags |= SF_IMPLIED_LABEL; // now there has been one
statement_flags |= SF_FOUND_SYMBOL; // now there has been one
return TRUE;
}
@ -270,20 +275,21 @@ static void parse_symbol_definition(scope_t scope)
// Parse global symbol definition or assembler mnemonic
static void parse_mnemo_or_global_symbol_def(void)
{
boolean is_mnemonic;
// read keyword and ask current cpu type if it's a mnemonic
if (CPU_state.type->keyword_is_mnemonic(input_read_keyword()))
return; // statement has been handled
is_mnemonic = CPU_state.type->keyword_is_mnemonic(input_read_keyword());
// It is only a label if it isn't a mnemonic
if ((!is_mnemonic)
&& first_label_of_statement()) {
// Now GotByte = illegal char
// 04 Jun 2005: this fix should help to explain "strange" error messages.
// 17 May 2014: now it works for UTF-8 as well.
if ((*GLOBALDYNABUF_CURRENT == (char) 0xa0)
|| ((GlobalDynaBuf->size >= 2) && (GLOBALDYNABUF_CURRENT[0] == (char) 0xc2) && (GLOBALDYNABUF_CURRENT[1] == (char) 0xa0)))
Throw_first_pass_warning("Label name starts with a shift-space character.");
parse_symbol_definition(SCOPE_GLOBAL);
}
// if we're here, it wasn't a mnemonic, so it can only be a symbol name
if (!first_symbol_of_statement())
return; // more than one symbol, error has been reported
// Now GotByte = illegal char
// 04 Jun 2005: this fix should help to explain "strange" error messages.
// 17 May 2014: now it works for UTF-8 as well.
if ((*GLOBALDYNABUF_CURRENT == (char) 0xa0)
|| ((GlobalDynaBuf->size >= 2) && (GLOBALDYNABUF_CURRENT[0] == (char) 0xc2) && (GLOBALDYNABUF_CURRENT[1] == (char) 0xa0)))
Throw_first_pass_warning("Symbol name starts with a shift-space character.");
parse_symbol_definition(SCOPE_GLOBAL);
}
@ -292,7 +298,7 @@ static void parse_local_symbol_def(void)
{
scope_t scope;
if (!first_label_of_statement())
if (!first_symbol_of_statement())
return;
if (input_read_scope_and_symbol_name(&scope) == 0)
@ -303,7 +309,7 @@ static void parse_local_symbol_def(void)
// parse anonymous backward label definition. Called with GotByte == '-'
static void parse_backward_anon_def(void)
{
if (!first_label_of_statement())
if (!first_symbol_of_statement())
return;
dynabuf_clear(GlobalDynaBuf);
@ -319,7 +325,7 @@ static void parse_backward_anon_def(void)
// parse anonymous forward label definition. called with GotByte == ?
static void parse_forward_anon_def(void)
{
if (!first_label_of_statement())
if (!first_symbol_of_statement())
return;
dynabuf_clear(GlobalDynaBuf);

View File

@ -14,8 +14,8 @@
#include <string.h>
#include "config.h"
#define LOCAL_PREFIX '.' // FIXME - this is not yet used consistently!
#define CHEAP_PREFIX '@' // prefix character for cheap locals
#define LOCAL_PREFIX '.' // FIXME - this is not yet used consistently!
#define CHEAP_PREFIX '@' // prefix character for cheap locals
// Constants
@ -77,6 +77,13 @@ struct config {
boolean test_new_features; // FALSE, enabled by --test
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
#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:
signed long initial_pc; // set by --setpc
signed long outfile_start; // set by --from-to
signed long outfile_end; // set by --from-to
};
extern struct config config;

View File

@ -339,11 +339,25 @@ static char GetQuotedByte(void)
}
// Skip remainder of statement, for example on error
// FIXME - check for quotes, otherwise this might treat a quoted colon like EOS!
void input_skip_remainder(void)
{
while (GotByte)
while (GotByte) {
GetByte(); // Read characters until end-of-statement
}
/* FIXME - check for quotes, otherwise this might treat a quoted colon like EOS!
this has already been a bug with "!to" and "!sl" where a workaround was implemented.
fix it here, once and for all, maybe like this:
dynabuf_clear(GlobalDynaBuf);
while (GotByte != CHAR_EOS) {
// check for quotes
if ((GotByte == '"') || (GotByte == '\'')) {
if (input_quoted_to_dynabuf(GotByte))
break; // error (CHAR_EOS before closing quote)
}
GetByte();
}
dynabuf_clear(GlobalDynaBuf);
*/
}
// Ensure that the remainder of the current statement is empty, for example
@ -599,33 +613,51 @@ int input_read_and_lower_keyword(void)
return length;
}
// Try to read a file name.
// If "allow_library" is TRUE, library access by using <...> quoting
// is possible as well. If "uses_lib" is non-NULL, info about library
// usage is stored there.
// shared ending when trying to read a file name.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns nonzero on error. Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// input_skip_remainder() then.
int input_read_filename(boolean allow_library, boolean *uses_lib)
static int read_filename_shared_end(int prefix_size)
{
int start_of_string;
char *lib_prefix,
terminator;
// check length
if (GlobalDynaBuf->size == prefix_size) {
Throw_error("No file name given.");
return 1; // error
}
// resolve backslash escapes
if (input_unescape_dynabuf(prefix_size))
return 1; // escaping error
// terminate string
dynabuf_append(GlobalDynaBuf, '\0');
#ifdef PLATFORM_CONVERTPATH
// platform-specific path name conversion
PLATFORM_CONVERTPATH(GLOBALDYNABUF_CURRENT + prefix_size);
#endif
return 0; // ok
}
// try to read a file name for an input file.
// library access by using <...> quoting is allowed. function will store info
// about library usage at "uses_lib" ptr.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns nonzero on error. Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// input_skip_remainder() then.
int input_read_input_filename(boolean *uses_lib)
{
char *lib_prefix; // depends on platform
int prefix_size; // this much does not get platform-converted because it is already correct
dynabuf_clear(GlobalDynaBuf);
SKIPSPACE();
switch (GotByte) {
case '<': // library access
if (uses_lib)
*uses_lib = TRUE;
// if library access forbidden, complain
if (!allow_library) {
Throw_error("Writing to library not supported.");
return 1; // error
}
if (GotByte == '<') {
// library access:
*uses_lib = TRUE;
// read platform's lib prefix
lib_prefix = PLATFORM_LIBPREFIX;
#ifndef NO_NEED_FOR_ENV_VAR
@ -635,45 +667,71 @@ int input_read_filename(boolean allow_library, boolean *uses_lib)
return 1; // error
}
#endif
// copy lib path and set quoting char
// copy lib path
dynabuf_add_string(GlobalDynaBuf, lib_prefix);
terminator = '>';
break;
case '"': // normal access
if (uses_lib)
*uses_lib = FALSE;
terminator = '"';
break;
default: // none of the above
Throw_error("File name quotes not found (\"\" or <>).");
// remember border between optional library prefix and string from assembler source file
prefix_size = GlobalDynaBuf->size;
// read file name string (must be a single string <literal>)
if (input_quoted_to_dynabuf('>'))
return 1; // unterminated or escaping error
GetByte(); // eat '>' terminator
} else {
// "normal", non-library access:
*uses_lib = FALSE;
prefix_size = 0; // no prefix in DynaBuf
// old algo (do not merge with similar parts from "if" block!):
if (GotByte != '"') {
Throw_error("File name quotes not found (\"\" or <>).");
return 1; // error
}
// read file name string
if (input_quoted_to_dynabuf('"'))
return 1; // unterminated or escaping error
GetByte(); // eat terminator
// new algo:
// it should be possible to construct the name of input file from symbols, so
// build environments can define a name at one place and use it at another.
// FIXME - use expression parser to read filename string!
// see lines 416 and 1317 in pseudoopcodes.c for two more possible callers!
}
// check length, unescape, terminate, do platform conversion
return read_filename_shared_end(prefix_size);
}
// try to read a file name for an output file.
// library access by using <...> quoting is forbidden.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns nonzero on error. Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// input_skip_remainder() then.
//
// this is only used for "!to" and "!sl", i.e. output file names. these
// must be given as a literal string, and it should be kept this way.
int input_read_output_filename(void)
{
SKIPSPACE();
if (GotByte == '<') {
Throw_error("Writing to library not supported.");
return 1; // error
}
// remember border between optional library prefix and string from assembler source file
start_of_string = GlobalDynaBuf->size;
// read file name string
if (input_quoted_to_dynabuf(terminator))
if (GotByte != '"') {
Throw_error("File name quotes not found (\"\").");
return 1; // error
}
dynabuf_clear(GlobalDynaBuf);
// read file name string (must be a single string literal! do not change this!)
if (input_quoted_to_dynabuf('"'))
return 1; // unterminated or escaping error
GetByte(); // eat terminator
// check length
if (GlobalDynaBuf->size == start_of_string) {
Throw_error("No file name given.");
return 1; // error
}
// resolve backslash escapes
if (input_unescape_dynabuf(start_of_string))
return 1; // escaping error
// terminate string
dynabuf_append(GlobalDynaBuf, '\0');
#ifdef PLATFORM_CONVERTPATH
// platform-specific path name conversion
PLATFORM_CONVERTPATH(GLOBALDYNABUF_CURRENT + start_of_string);
#endif
return 0; // ok
// check length, unescape, terminate, do platform conversion:
return read_filename_shared_end(0); // 0 -> there is no library prefix
}
// Try to read a comma, skipping spaces before and after. Return TRUE if comma
// found, otherwise FALSE.
int input_accept_comma(void)

View File

@ -116,16 +116,24 @@ extern int input_read_keyword(void);
// Zero lengths will produce a "missing string" error.
extern int input_read_and_lower_keyword(void);
// Try to read a file name.
// If "allow_library" is TRUE, library access by using <...> quoting
// is possible as well. If "uses_lib" is non-NULL, info about library
// usage is stored there.
// try to read a file name for an input file.
// library access by using <...> quoting is allowed. function will store info
// about library usage at "uses_lib" ptr.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns nonzero on error. Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// input_skip_remainder() then.
extern int input_read_filename(boolean library_allowed, boolean *uses_lib);
extern int input_read_input_filename(boolean *uses_lib);
// try to read a file name for an output file ("!to" and "!sl" only).
// library access by using <...> quoting is forbidden.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns nonzero on error. Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// input_skip_remainder() then.
extern int input_read_output_filename(void);
// Try to read a comma, skipping spaces before and after. Return TRUE if comma
// found, otherwise FALSE.

View File

@ -38,8 +38,7 @@ struct segment {
// structure for all output stuff:
struct output {
// output buffer stuff
intval_t bufsize; // either 64 KiB or 16 MiB
char *buffer; // holds assembled code
char *buffer; // holds assembled code (size is config.outbuf_size)
intval_t write_idx; // index of next write
intval_t lowest_written; // smallest address used
intval_t highest_written; // largest address used
@ -111,7 +110,7 @@ static void find_segment_max(intval_t new_pc)
while (test_segment->start <= new_pc)
test_segment = test_segment->next;
if (test_segment == &out->segment.list_head)
out->segment.max = out->bufsize - 1;
out->segment.max = config.outbuf_size - 1;
else
out->segment.max = test_segment->start - 1; // last free address available
}
@ -120,7 +119,7 @@ static void find_segment_max(intval_t new_pc)
//
static void border_crossed(int current_offset)
{
if (current_offset >= out->bufsize)
if (current_offset >= config.outbuf_size)
Throw_serious_error("Produced too much code.");
// TODO - get rid of FIRST_PASS condition, because user can suppress these warnings if they want
if (FIRST_PASS) {
@ -206,7 +205,7 @@ void output_skip(int size)
// fill output buffer with given byte value
static void fill_completely(char value)
{
memset(out->buffer, value, out->bufsize);
memset(out->buffer, value, config.outbuf_size);
}
@ -276,42 +275,54 @@ int outputfile_set_filename(void)
// init output struct (done later)
void output_createbuffer(signed long fill_value, boolean use_large_buf)
void output_createbuffer(void)
{
out->bufsize = use_large_buf ? 0x1000000 : 0x10000;
out->buffer = safe_malloc(out->bufsize);
if (fill_value == MEMINIT_USE_DEFAULT) {
fill_value = FILLVALUE_INITIAL;
out->initvalue_set = FALSE;
char fill_value = 0; // default value for output buffer
out->buffer = safe_malloc(config.outbuf_size);
if (config.mem_init_value == MEMINIT_USE_DEFAULT) {
out->initvalue_set = FALSE; // "!initmem" can be used
} else {
out->initvalue_set = TRUE;
out->initvalue_set = TRUE; // "!initmem" generates a warning
fill_value = 0xff & config.mem_init_value;
}
// init output buffer (fill memory with initial value)
fill_completely(fill_value & 0xff);
fill_completely(fill_value);
// init ring list of segments
out->segment.list_head.next = &out->segment.list_head;
out->segment.list_head.prev = &out->segment.list_head;
}
// dump used portion of output buffer into output file
// write used portion of output buffer to output file
void output_save_file(FILE *fd)
{
intval_t start,
end,
amount;
if (out->highest_written < out->lowest_written) {
start = out->lowest_written;
end = out->highest_written;
// if cli args were given, they override the actual values:
if (config.outfile_start != NO_VALUE_GIVEN)
start = config.outfile_start;
if (config.outfile_end != NO_VALUE_GIVEN)
end = config.outfile_end;
if (end < start) {
// nothing written
start = 0; // I could try to use some segment start, but what for?
amount = 0;
// FIXME - how about not writing anything in this case?
// a CBM file would consist of a bogus load address and nothing else!
} else {
start = out->lowest_written;
amount = out->highest_written - start + 1;
amount = end - start + 1;
}
if (config.process_verbosity)
printf("Saving %ld (0x%lx) bytes (0x%lx - 0x%lx exclusive).\n",
amount, amount, start, start + amount);
// output file header according to file format
// FIXME - add checks and error messages for "start is above $ffff"!)
switch (output_format) {
case OUTPUT_FORMAT_APPLE:
PLATFORM_SETFILETYPE_APPLE(output_filename);
@ -402,13 +413,13 @@ void output_passinit(void)
// }
// invalidate start and end (first byte actually written will fix them)
out->lowest_written = out->bufsize - 1;
out->lowest_written = config.outbuf_size - 1;
out->highest_written = 0;
// deactivate output - any byte written will trigger error:
output_byte = no_output;
out->write_idx = 0; // same as pc on pass init!
out->segment.start = NO_SEGMENT_START; // TODO - "no active segment" could be made a segment flag!
out->segment.max = out->bufsize - 1; // TODO - use end of bank?
out->segment.max = config.outbuf_size - 1; // TODO - use end of bank?
out->segment.flags = 0;
out->xor = 0;
@ -467,7 +478,7 @@ void output_start_segment(intval_t address_change, bits segment_flags)
output_end_segment();
// calculate start of new segment
out->write_idx = (out->write_idx + address_change) & (out->bufsize - 1);
out->write_idx = (out->write_idx + address_change) & (config.outbuf_size - 1);
out->segment.start = out->write_idx;
out->segment.flags = segment_flags;
// allow writing to output buffer
@ -568,7 +579,7 @@ int vcpu_get_statement_size(void)
// 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) & (out->bufsize - 1);
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;
}
@ -607,7 +618,7 @@ void pseudopc_end(void)
if (config.wanted_version >= VER_DISABLED_OBSOLETE_STUFF)
BUG("ClosingUnopenedPseudopcBlock", 0);
} else {
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & (out->bufsize - 1); // pc might have wrapped around
CPU_state.pc.val.intval = (CPU_state.pc.val.intval - pseudopc_current_context->offset) & (config.outbuf_size - 1); // pc might have wrapped around
CPU_state.pc.ntype = pseudopc_current_context->ntype;
pseudopc_current_context = pseudopc_current_context->outer; // go back to outer block
}
@ -631,7 +642,7 @@ int pseudopc_unpseudo(struct number *target, struct pseudopc *context, unsigned
return 1; // error
}
// FIXME - in future, check both target and context for NUMTYPE_UNDEFINED!
target->val.intval = (target->val.intval - context->offset) & (out->bufsize - 1); // FIXME - is masking really needed? TODO
target->val.intval = (target->val.intval - context->offset) & (config.outbuf_size - 1); // FIXME - is masking really needed? TODO
context = context->outer;
}
return 0; // ok

View File

@ -12,7 +12,7 @@
// constants
#define MEMINIT_USE_DEFAULT 256
// segment flags
#define SEGMENT_FLAG_OVERLAY (1u << 0) // do not warn about this segment overwriting another one
#define SEGMENT_FLAG_INVISIBLE (1u << 1) // do not warn about other segments overwriting this one
@ -43,7 +43,7 @@ extern void output_passinit(void);
// outbuf stuff:
// alloc and init mem buffer (done later)
extern void output_createbuffer(signed long fill_value, boolean use_large_buf);
extern void output_createbuffer(void);
// skip over some bytes in output buffer without starting a new segment
// (used by "!skip", and also called by "!binary" if really calling
@ -72,7 +72,7 @@ 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 smallest-possible part of memory buffer to file
// write used portion of output buffer to output file
extern void output_save_file(FILE *fd);
// change output pointer and enable output

View File

@ -136,7 +136,7 @@ static enum eos po_to(void)
// read filename to global dynamic buffer
// if no file name given, exit (complaining will have been done)
if (input_read_filename(FALSE, NULL))
if (input_read_output_filename())
return SKIP_REMAINDER;
// only act upon this pseudo opcode in first pass
@ -360,6 +360,15 @@ static enum eos predefined_encoding(void)
}
// 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;
@ -367,7 +376,7 @@ static enum eos po_convtab(void)
if ((GotByte == '<') || (GotByte == '"')) {
// encoding table from file
if (input_read_filename(TRUE, &uses_lib))
if (input_read_input_filename(&uses_lib))
return SKIP_REMAINDER; // missing or unterminated file name
stream = includepaths_open_ro(uses_lib);
@ -403,6 +412,8 @@ static enum eos encode_string(const struct encoder *inner_encoder, unsigned char
// eat closing quote
GetByte();
// now convert to unescaped version
// FIXME - next call does nothing because wanted<escaping!
// FIXME - there is another block like this in line 1317!
if (input_unescape_dynabuf(0))
return SKIP_REMAINDER; // escaping error
@ -467,7 +478,7 @@ static enum eos po_binary(void)
skip.val.intval = 0;
// if file name is missing, don't bother continuing
if (input_read_filename(TRUE, &uses_lib))
if (input_read_input_filename(&uses_lib))
return SKIP_REMAINDER;
// try to open file
@ -767,7 +778,7 @@ static enum eos po_symbollist(void)
// read filename to global dynamic buffer
// if no file name given, exit (complaining will have been done)
if (input_read_filename(FALSE, NULL))
if (input_read_output_filename())
return SKIP_REMAINDER;
// only process this pseudo opcode in first pass
@ -849,7 +860,7 @@ static enum eos po_source(void) // now GotByte = illegal char
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, &uses_lib))
if (input_read_input_filename(&uses_lib))
return SKIP_REMAINDER;
// if file could be opened, parse it. otherwise, complain
@ -1302,6 +1313,8 @@ static enum eos throw_src_string(enum debuglevel level, const char prefix[])
// eat closing quote
GetByte();
// now convert to unescaped version
// FIXME - next call does nothing because wanted<escaping!
// FIXME - there is another block like this in line 416!
if (input_unescape_dynabuf(0))
return SKIP_REMAINDER; // escaping error

View File

@ -9,7 +9,7 @@
#define RELEASE "0.97" // update before release FIXME
#define CODENAME "Zem" // update before release
#define CHANGE_DATE "10 Feb" // update before release FIXME
#define CHANGE_DATE "11 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