diff options
Diffstat (limited to 'bas2aplus.c')
-rw-r--r-- | bas2aplus.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/bas2aplus.c b/bas2aplus.c new file mode 100644 index 0000000..de259aa --- /dev/null +++ b/bas2aplus.c @@ -0,0 +1,272 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#include "bas.h" + +#undef DUMP_TABLES + +#include "tokens.c" +#include "aplus_tokens.c" +#include "bxl_tokens.c" +#include "bxe_tokens.c" + +int errs = 0; + +/* there are a few more BXL commands past 0x55, but they have no + A+ equivalents. */ +#define LAST_BXL_CMD 0x55 +#define LAST_BXL_OP 0x65 + +/* cmd_table[basic_token] or op_table[basic_token] gives the equivalent + A+ token. note that there's no "GO TO" or "COM" in A+, we translate + those as GOTO and DIM. */ +unsigned char cmd_table[] = { + /* Atari BASIC: */ + /* REM DATA INPUT COLOR LIST ENTER LET IF:*/ + 0x00, 0x01, 0x02, 0x3f, 0x03, 0x04, 0x05, 0x06, /* 0x00 - 0x07 */ + + /* FOR NEXT GOTO GO<sp>TO GOSUB TRAP BYE CONT: */ + 0x07, 0x08, 0x09, 0x09, 0x0b, 0x0c, 0x0d, 0x0e, /* 0x08 - 0x0f */ + + /* COM CLOSE CLR DEG DIM END NEW OPEN: */ + 0x12, 0x0f, 0x10, 0x11, 0x12, 0x19, 0x1a, 0x1b, /* 0x10 - 0x17 */ + + /* LOAD SAVE STATUS NOTE POINT XIO ON POKE: */ + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, /* 0x18 - 0x1f */ + + /* PRINT RAD READ RESTORE RETURN RUN STOP POP: */ + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, /* 0x20 - 0x27 */ + + /* ? GET PUT GRAPHICS PLOT POSITION DOS DRAWTO: */ + 0x2d, 0x2e, 0x2f, 0x40, 0x41, 0x42, 0x38, 0x43, /* 0x28 - 0x2f */ + + /* SETCOLOR LOCATE SOUND LPRINT CSAVE CLOAD <silent-let> ERROR-: */ + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x52, 0x53, /* 0x30 - 0x37 */ + + /* BASIC XL: */ + /* WHILE ENDWHILE TRACEOFF TRACE ELSE ENDIF DPOKE LOMEM: */ + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x24, 0x30, /* 0x38-0x3f */ + + /* DEL RPUT RGET BPUT BGET TAB CP ERASE: */ + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x39, /* 0x40-0x47 */ + + /* PROTECT UNPROTECT DIR RENAME MOVE MISSILE PMCLR PMCOLOR: */ + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x4a, 0x4b, 0x4c, /* 0x48-0x4f */ + + /* PMGRAPHICS PMMOVE PMWIDTH SET LVAR RENUM: */ + 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x0a, /* 0x50-0x55 */ + +}; + +/* 0xff means "untranslatable". these are: + BUMP( FIND( HEX$ RANDOM( + ...though BUMP( and FIND( do have A+ equivalents (they just need + a left paren inserted after) */ +unsigned char op_table[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* not used: 0x00-0x07 */ + 0xff, 0xff, 0xff, 0xff, 0xff, /* not used: 0x08-0x0c */ + 0x0e, /* convert BXL hex const to decimal */ + 0x0e, 0x0f, /* numeric and string consts are the same */ + 0xff, 0xff, /* these 2 not used: 0x10-0x11 */ + + /* these are the same, 0x12-0x1b */ + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + + /* 0x1c-0x2a off by one due to USING inserted at 0x1c */ + 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + + /* 0x2b-0x43 off by 3 due to ! and & */ + 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, + + /* 0x44-0x50 */ + 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, + + /* 0x51-0x54 (last BASIC) */ + 0x58, 0x59, 0x5a, 0x5b, + + /* BXL stuff, 0x55-0x5f */ + 0x1c, 0xff /* % */, 0x2c, 0x2d, + 0xff, /* string array semicolon */ + 0xff, /* BUMP( (TODO: A+ token 0x47 plus a paren) */ + 0xff, /* FIND( (TODO: A+ token 0x48 plus a paren) */ + 0xff, /* HEX$ */ + 0xff, /* RANDOM( */ + 0x49, /* DPEEK */ + 0x57, /* SYS */ + 0x5c, /* VSTICK */ + 0x5d, /* HSTICK */ + 0x5e, /* PMADR */ + 0x5f, /* ERR */ + 0x60, /* TAB */ + 0x61, /* PEN */ + +}; + +#ifdef DUMP_TABLES +void dump_tables(void) { + int i; + + for(i = 0; i <= LAST_BXL_CMD; i++) { + const char *b, *ap = aplus_cmds[cmd_table[i]]; + if(i <= last_command) + b = commands[i]; + else + b = bxl_cmds[i - 0x38]; + printf("%02x: %s %s%s\n", i, b, ap, (strcmp(b, ap) == 0) ? " SAME" : ""); + } + + printf("\n\n"); + + for(i = 0x12; i <= LAST_BXL_OP; i++) { + int j = op_table[i];; + const char *b, *ap; + if(j == 0xff) + ap = "(not in A+)"; + else + ap = aplus_ops[j]; + if(i <= last_operator) + b = operators[i]; + else + b = bxl_ops[i - 0x55]; + printf("%02x: %s %s%s\n", i, b, ap, (strcmp(b, ap) == 0) ? " SAME" : ""); + } +} +#endif + +void print_help(void) { + printf("%s [input-file] [output-file]\n", self); +} + +void parse_args(int argc, char **argv) { + int opt; + + while( (opt = getopt(argc, argv, "v")) != -1) { + switch(opt) { + case 'v': verbose = 1; break; + case 'h': print_help(); exit(0); + default: + print_help(); + exit(1); + } + } + + if(optind == argc) + die("No input file given."); + else + open_input(argv[optind]); + + if(++optind == argc) + die("No output file given."); + else + output_filename = argv[optind]; + + if(argv[++optind]) + die("Only one input and one output file allowed."); +} + +const char *get_tok_name(unsigned char tok, int is_cmd) { + if(is_cmd) { + if(tok <= last_command) { + return commands[tok]; + } else if(tok == 0x5a) { + return "BASIC XL LOCAL/EXIT/PROCEDURE/CALL/SORTUP/SORTDOWN"; + } else if(tok == 0x59 || (tok > 0x5a && tok < 0x65)) { + return bxe_cmds[tok - 0x57]; + } else if(tok > last_command && tok <= 0x58) { + return bxl_cmds[tok - 0x38]; + } else { + return "(maybe Turbo BASIC?)"; + } + } else { + if(tok < 0x12) return ""; + if(tok <= last_operator) { + return operators[tok]; + } else if(tok <= 0x68) { + return bxl_ops[tok - 0x55]; + } else { + return "(maybe Turbo BASIC?)"; + } + } +} + +void unsupported_msg(unsigned char tok, int lineno, int is_cmd) { + fprintf(stderr, "%s: Invalid %s \"%s\" ($%02x) at line %d, not converted.\n", + self, is_cmd ? "command" : "operator", get_tok_name(tok, is_cmd), tok, lineno); + errs++; +} + +int is_supported_cmd(unsigned char tok, int lineno) { + if(tok > LAST_BXL_CMD) { + unsupported_msg(tok, lineno, 1); + return 0; + } + return 1; +} + +int is_supported_op(unsigned char tok, int lineno) { + if(tok > LAST_BXL_OP || op_table[tok] == 0xff) { + unsupported_msg(tok, lineno, 0); + return 0; + } + return 1; +} + +CALLBACK(conv_cmd) { + if(!is_supported_cmd(tok, lineno)) + return; + + program[pos] = cmd_table[tok]; + + if(verbose && tok != program[pos]) + fprintf(stderr, "command \"%s\" ($%02x) converted to $%02x at line %d, pos $%04x\n", + get_tok_name(tok, 1), tok, program[pos], lineno, pos); +} + +CALLBACK(conv_op) { + if(!is_supported_op(tok, lineno)) + return; + + program[pos] = op_table[tok]; + + if(verbose && tok != program[pos]) + fprintf(stderr, "operator \"%s\" ($%02x) converted to $%02x at line %d, pos $%04x\n", + get_tok_name(tok, 0), tok, program[pos], lineno, pos); +} + +int main(int argc, char **argv) { +#ifdef DUMP_TABLES + dump_tables(); exit(0); +#endif + set_self(*argv); + parse_general_args(argc, argv, print_help); + parse_args(argc, argv); + + readfile(); + parse_header(); + + on_cmd_token = conv_cmd; + on_exp_token = conv_op; + + allow_hex_const = 1; + walk_all_code(); + + open_output(output_filename); + writefile(); + + if(errs) { + fprintf(stderr, "%s: program has %d invalid tokens; BASIC/A+ won't RUN it.\n", + self, errs); + return 1; + } + + return 0; +} |