2012-02-27 21:14:46 +00:00
|
|
|
// ACME - a crossassembler for producing 6502/65c02/65816 code.
|
2014-03-10 00:17:10 +00:00
|
|
|
// Copyright (C) 1998-2014 Marco Baye
|
2012-02-27 21:14:46 +00:00
|
|
|
// Have a look at "acme.c" for further info
|
|
|
|
//
|
|
|
|
// Character encoding stuff
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "alu.h"
|
|
|
|
#include "acme.h"
|
|
|
|
#include "dynabuf.h"
|
|
|
|
#include "encoding.h"
|
|
|
|
#include "global.h"
|
|
|
|
#include "output.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "tree.h"
|
|
|
|
|
|
|
|
|
|
|
|
// Encoder function type definition
|
|
|
|
typedef char (*encoder_t)(char) ;
|
|
|
|
|
|
|
|
|
|
|
|
// Constants
|
|
|
|
static const char s_pet[] = "pet";
|
|
|
|
static const char s_raw[] = "raw";
|
|
|
|
static const char s_scr[] = "scr";
|
|
|
|
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
static char outermost_table[256]; // space for encoding table...
|
|
|
|
static char *loaded_table = outermost_table; // ...loaded from file
|
|
|
|
// predefined stuff
|
|
|
|
static struct node_t *encoder_tree = NULL; // tree to hold encoders
|
|
|
|
|
|
|
|
|
|
|
|
// Functions
|
|
|
|
|
|
|
|
// convert character using current encoding
|
|
|
|
// Conversion function pointer. No init needed: gets set before each pass.
|
|
|
|
char (*Encoding_encode_char)(char);
|
|
|
|
|
|
|
|
// Insert string(s)
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos encode_string(encoder_t inner_encoder, char xor)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
encoder_t outer_encoder = Encoding_encode_char; // buffer encoder
|
|
|
|
|
|
|
|
// make given encoder the current one (for ALU-parsed values)
|
|
|
|
Encoding_encode_char = inner_encoder;
|
|
|
|
do {
|
|
|
|
if (GotByte == '"') {
|
|
|
|
// read initial character
|
|
|
|
GetQuotedByte();
|
|
|
|
// send characters until closing quote is reached
|
|
|
|
while (GotByte && (GotByte != '"')) {
|
|
|
|
Output_8b(xor ^ Encoding_encode_char(GotByte));
|
|
|
|
GetQuotedByte();
|
|
|
|
}
|
|
|
|
if (GotByte == CHAR_EOS)
|
|
|
|
return AT_EOS_ANYWAY;
|
|
|
|
|
|
|
|
// after closing quote, proceed with next char
|
|
|
|
GetByte();
|
|
|
|
} else {
|
|
|
|
// Parse value. No problems with single characters
|
|
|
|
// because the current encoding is
|
|
|
|
// temporarily set to the given one.
|
|
|
|
Output_8b(ALU_any_int());
|
|
|
|
}
|
|
|
|
} while (Input_accept_comma());
|
|
|
|
Encoding_encode_char = outer_encoder; // reactivate buffered encoder
|
|
|
|
return ENSURE_EOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert text string (default format)
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_text(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
return encode_string(Encoding_encode_char, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert raw to raw (do not convert at all)
|
|
|
|
static char encoder_raw(char byte)
|
|
|
|
{
|
|
|
|
return byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert raw string
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_raw(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
return encode_string(encoder_raw, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert raw to petscii
|
|
|
|
static char encoder_pet(char byte)
|
|
|
|
{
|
|
|
|
if ((byte >= 'A') && (byte <= 'Z'))
|
|
|
|
return (char) (byte | 0x80); // FIXME - check why SAS-C
|
|
|
|
if ((byte >= 'a') && (byte <= 'z')) // wants these casts.
|
|
|
|
return (char) (byte - 32); // There are more below.
|
|
|
|
return byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert PetSCII string
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_pet(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
return encode_string(encoder_pet, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert raw to C64 screencode
|
|
|
|
static char encoder_scr(char byte)
|
|
|
|
{
|
|
|
|
if ((byte >= 'a') && (byte <= 'z'))
|
|
|
|
return (char) (byte - 96); // shift uppercase down
|
|
|
|
if ((byte >= '[') && (byte <= '_'))
|
|
|
|
return (char) (byte - 64); // shift [\]^_ down
|
|
|
|
if (byte == '`')
|
|
|
|
return 64; // shift ` down
|
|
|
|
if (byte == '@')
|
|
|
|
return 0; // shift @ down
|
|
|
|
return byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert screencode string
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_scr(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
return encode_string(encoder_scr, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert screencode string, XOR'd
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_scrxor(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
intval_t num = ALU_any_int();
|
|
|
|
|
|
|
|
if (Input_accept_comma())
|
|
|
|
return encode_string(encoder_scr, num);
|
|
|
|
Throw_error(exception_syntax);
|
|
|
|
return SKIP_REMAINDER;
|
|
|
|
}
|
|
|
|
|
2014-03-10 00:17:10 +00:00
|
|
|
// "!cbm" pseudo opcode (now obsolete)
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_cbm(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2014-03-10 00:17:10 +00:00
|
|
|
Throw_error("\"!cbm\" is obsolete; use \"!ct pet\" instead.");
|
2012-02-27 21:14:46 +00:00
|
|
|
return ENSURE_EOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
static char encoder_file(char byte)
|
|
|
|
{
|
|
|
|
return loaded_table[(unsigned char) byte];
|
|
|
|
}
|
|
|
|
|
|
|
|
// read encoding table from file
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos user_defined_encoding(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
FILE *fd;
|
|
|
|
char local_table[256],
|
|
|
|
*buffered_table = loaded_table;
|
|
|
|
encoder_t buffered_encoder = Encoding_encode_char;
|
|
|
|
|
|
|
|
// if file name is missing, don't bother continuing
|
|
|
|
if (Input_read_filename(TRUE))
|
|
|
|
return SKIP_REMAINDER;
|
|
|
|
fd = fopen(GLOBALDYNABUF_CURRENT, FILE_READBINARY);
|
|
|
|
if (fd) {
|
|
|
|
if (fread(local_table, sizeof(char), 256, fd) != 256)
|
|
|
|
Throw_error("Conversion table incomplete.");
|
|
|
|
fclose(fd);
|
|
|
|
} else {
|
|
|
|
Throw_error(exception_cannot_open_input_file);
|
|
|
|
}
|
|
|
|
Encoding_encode_char = encoder_file; // activate new encoding
|
|
|
|
loaded_table = local_table; // activate local table
|
|
|
|
// If there's a block, parse that and then restore old values
|
|
|
|
if (Parse_optional_block())
|
|
|
|
Encoding_encode_char = buffered_encoder;
|
|
|
|
else
|
|
|
|
// if there's *no* block, the table must be used from now on.
|
|
|
|
// copy the local table to the "outer" table
|
|
|
|
memcpy(buffered_table, local_table, 256);
|
|
|
|
// re-activate "outer" table (it might have been changed by memcpy())
|
|
|
|
loaded_table = buffered_table;
|
|
|
|
return ENSURE_EOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// use one of the pre-defined encodings (raw, pet, scr)
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos predefined_encoding(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
void *node_body;
|
|
|
|
char local_table[256],
|
|
|
|
*buffered_table = loaded_table;
|
|
|
|
encoder_t buffered_encoder = Encoding_encode_char;
|
|
|
|
|
|
|
|
// use one of the pre-defined encodings
|
|
|
|
if (Input_read_and_lower_keyword()) {
|
|
|
|
// search for tree item
|
|
|
|
if (Tree_easy_scan(encoder_tree, &node_body, GlobalDynaBuf))
|
|
|
|
Encoding_encode_char = (encoder_t) node_body; // activate new encoder
|
|
|
|
else
|
|
|
|
Throw_error("Unknown encoding.");
|
|
|
|
}
|
|
|
|
loaded_table = local_table; // activate local table
|
|
|
|
// If there's a block, parse that and then restore old values
|
|
|
|
if (Parse_optional_block())
|
|
|
|
Encoding_encode_char = buffered_encoder;
|
|
|
|
// re-activate "outer" table
|
|
|
|
loaded_table = buffered_table;
|
|
|
|
return ENSURE_EOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set current encoding ("!convtab" pseudo opcode)
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_convtab(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
if ((GotByte == '<') || (GotByte == '"'))
|
|
|
|
return user_defined_encoding();
|
|
|
|
else
|
|
|
|
return predefined_encoding();
|
|
|
|
}
|
|
|
|
|
|
|
|
// pseudo opcode table
|
|
|
|
static struct node_t pseudo_opcodes[] = {
|
|
|
|
PREDEFNODE(s_cbm, PO_cbm),
|
|
|
|
PREDEFNODE("ct", PO_convtab),
|
|
|
|
PREDEFNODE("convtab", PO_convtab),
|
|
|
|
PREDEFNODE(s_pet, PO_pet),
|
|
|
|
PREDEFNODE(s_raw, PO_raw),
|
|
|
|
PREDEFNODE(s_scr, PO_scr),
|
|
|
|
PREDEFNODE(s_scrxor, PO_scrxor),
|
|
|
|
PREDEFNODE("text", PO_text),
|
|
|
|
PREDEFLAST("tx", PO_text),
|
|
|
|
// ^^^^ this marks the last element
|
|
|
|
};
|
|
|
|
|
|
|
|
// keywords for "!convtab" pseudo opcode
|
|
|
|
static struct node_t encoders[] = {
|
|
|
|
PREDEFNODE(s_pet, encoder_pet),
|
|
|
|
PREDEFNODE(s_raw, encoder_raw),
|
|
|
|
PREDEFLAST(s_scr, encoder_scr),
|
|
|
|
// ^^^^ this marks the last element
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Exported functions
|
|
|
|
|
|
|
|
// register pseudo opcodes and build keyword tree for encoders
|
|
|
|
void Encoding_init(void)
|
|
|
|
{
|
|
|
|
Tree_add_table(&encoder_tree, encoders);
|
|
|
|
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set "raw" as default encoding
|
|
|
|
void Encoding_passinit(void)
|
|
|
|
{
|
|
|
|
Encoding_encode_char = encoder_raw;
|
|
|
|
}
|