From 0a892d1ef0aca718c82603f2df1406cf76c017f6 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sun, 21 Jul 2024 05:19:13 -0400 Subject: bas2aplus: added. --- Makefile | 6 +- bas2aplus.1 | 166 ++++++++++++++++++++++++++++++++++++++++++ bas2aplus.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bas2aplus.rst | 99 +++++++++++++++++++++++++ 4 files changed, 499 insertions(+), 2 deletions(-) create mode 100644 bas2aplus.1 create mode 100644 bas2aplus.c create mode 100644 bas2aplus.rst diff --git a/Makefile b/Makefile index 5a785a5..036929f 100644 --- a/Makefile +++ b/Makefile @@ -16,9 +16,9 @@ CC=gcc CFLAGS=-Wall $(COPT) -ansi -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" # BINS and SCRIPTS go in $BINDIR, DOCS go in $DOCDIR -BINS=a8eol atr2xfd atrsize axe blob2c blob2xex cart2xex cxrefbas dumpbas fenders protbas renumbas rom2cart unmac65 unprotbas vxrefbas xex1to2 xexamine xexcat xexsplit xfd2atr listbas a8cat a8xd whichbas +BINS=a8eol atr2xfd atrsize axe blob2c blob2xex cart2xex cxrefbas dumpbas fenders protbas renumbas rom2cart unmac65 unprotbas vxrefbas xex1to2 xexamine xexcat xexsplit xfd2atr listbas a8cat a8xd whichbas bas2aplus SCRIPTS=dasm2atasm diffbas a8diff -MANS=a8eol.1 xfd2atr.1 atr2xfd.1 blob2c.1 cart2xex.1 fenders.1 xexsplit.1 xexcat.1 atrsize.1 rom2cart.1 unmac65.1 axe.1 dasm2atasm.1 blob2xex.1 xexamine.1 xex1to2.1 unprotbas.1 protbas.1 renumbas.1 dumpbas.1 vxrefbas.1 cxrefbas.1 listbas.1 a8cat.1 a8xd.1 whichbas.1 diffbas.1 a8diff.1 +MANS=a8eol.1 xfd2atr.1 atr2xfd.1 blob2c.1 cart2xex.1 fenders.1 xexsplit.1 xexcat.1 atrsize.1 rom2cart.1 unmac65.1 axe.1 dasm2atasm.1 blob2xex.1 xexamine.1 xex1to2.1 unprotbas.1 protbas.1 renumbas.1 dumpbas.1 vxrefbas.1 cxrefbas.1 listbas.1 a8cat.1 a8xd.1 whichbas.1 diffbas.1 a8diff.1 bas2aplus.1 MAN5S=xex.5 MAN7S=atascii.7 DOCS=README.txt equates.inc *.dasm LICENSE ksiders/atr.txt @@ -63,6 +63,8 @@ vxrefbas: bas.o cxrefbas: bas.o bcdfp.o linetab.o +bas2aplus: bas.o + listbas: listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.o aplus_tokens.o bxl_tokens.o bxe_tokens.o $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.o aplus_tokens.o bxl_tokens.o bxe_tokens.o -lm diff --git a/bas2aplus.1 b/bas2aplus.1 new file mode 100644 index 0000000..d263293 --- /dev/null +++ b/bas2aplus.1 @@ -0,0 +1,166 @@ +.\" Man page generated from reStructuredText. +. +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.TH "BAS2APLUS" 1 "2024-07-21" "0.2.1" "Urchlay's Atari 8-bit Tools" +.SH NAME +bas2aplus \- Convert Atari BASIC (and some BASIC XL) programs to BASIC/A+ +.SH SYNOPSIS +.sp +bas2aplus \fIinput\-file\fP \fIoutput\-file\fP +.SH DESCRIPTION +.sp +\fBbas2aplus\fP reads an Atari BASIC or BASIC XL tokenized (SAVEd) program +and converts it to BASIC/A+. +.sp +All Atari BASIC programs can be successfully converted. Some BASIC +XL operators have no equivalent in BASIC/A+, so programs using these +can\(aqt be converted (you will see messages on standard error, in that +case). +.SH OPTIONS +.SS General Options +.INDENT 0.0 +.TP +.B \fB\-\-help\fP +Print usage message and exit. +.TP +.B \fB\-\-version\fP +Print version number and exit. +.TP +.B \fB\-v\fP +Verbose operation. When displaying a number in verbose mode, it will +be prefixed with \fI$\fP if it\(aqs in hex, or no prefix for decimal. +.UNINDENT +.SH BASIC +.sp +BASIC/A+ is basically a later version of Atari BASIC, by the same team +that developed Atari BASIC. As such, it\(aqs source\-compatible with Atari +BASIC, but \fInot\fP token\-compatible. +.sp +BASIC/A+ uses a different set of token numbers, but has all but two +of the same tokens used by Atari BASIC. Conversion should always +succeed, for an Atari BASIC program. +.sp +The two missing tokens are the \fBCOM\fP and \fBGO TO\fP commands, which +are converted to \fBDIM\fP and \fBGOTO\fP, respectively. +.sp +The resulting program should \fBLOAD\fP and \fBRUN\fP in BASIC/A+ and +function identically to the BASIC version, unless it uses memory +that\(aqs reserved in A+. \fBUSR()\fP routines that are stored in the lower +half of Page 6 will have to be relocated, since A+ uses this area +itself. See the BASIC/A+ manual for full details. +.SH BASIC XL +.sp +BASIC XL is basically the next version of BASIC/A+, by the +same developers. The token lists were rearranged so that it\(aqs +token\-compatible with Atari BASIC, and includes all the extra +commands/functions/etc from BASIC/A+... with different token numbers. +.sp +BASIC XL has keywords and operators that don\(aqt exist in BASIC/A+. These +are: +.INDENT 0.0 +.TP +.B \fBNUM\fP +Rarely found in a program (usually only used in direct mode). +.TP +.B \fBFAST\fP +Just doesn\(aqt exist in BASIC/A+. +.TP +.B \fBLOCAL\fP, \fBEXIT\fP, \fBPROCEDURE\fP, \fBCALL\fP, \fBSORTUP\fP, \fBSORTDOWN\fP +These BASIC XL commands are provided by the disk\-based Toolkit +extension, which doesn\(aqt exist for BASIC/A+. +.TP +.B \fBString Arrays\fP +BASIC/A+ doesn\(aqt support these; if your BASIC XL program uses them, +it won\(aqt convert correctly. +.TP +.B \fBBUMP\fP and \fBFIND\fP +While BASIC/A+ does support these functions, the token\-level syntax +is different; it would be possible to translate them, but it would +require recalculating the line offset and statement offsets for +every line that uses them. For now, they\(aqre not supported. +.TP +.B \fB%\fP +The exclusive OR operator in BASIC XL. No such animal, in A+. +.TP +.B \fBHEX$\fP, \fBRANDOM\fP, \fBLEFT$\fP, \fBRIGHT$\fP, \fBMID$\fP +These functions don\(aqt exist in BASIC/A+. +.UNINDENT +.sp +Also, BASIC XL supports hex constants, with a leading \fB$\fP\&. A+ +doesn\(aqt support these, so they get converted to the equivalent decimal +constant. This is basically a cosmetic change; \fBA=$0600\fP assigns the +same value as \fBA=1536\fP\&. +.SH EXIT STATUS +.sp +0 for success, non\-zero for failuse. +.SH COPYRIGHT +.sp +WTFPL. See \fI\%http://www.wtfpl.net/txt/copying/\fP for details. +.SH AUTHOR +.INDENT 0.0 +.IP B. 3 +Watson <\fI\%urchlay@slackware.uk\fP>; Urchlay on irc.libera.chat \fI##atari\fP\&. +.UNINDENT +.SH SEE ALSO +.sp +\fBa8cat\fP(1), +\fBa8eol\fP(1), +\fBa8xd\fP(1), +\fBatr2xfd\fP(1), +\fBatrsize\fP(1), +\fBaxe\fP(1), +\fBblob2c\fP(1), +\fBblob2xex\fP(1), +\fBcart2xex\fP(1), +\fBcxrefbas\fP(1), +\fBdasm2atasm\fP(1), +\fBdiffbas\fP(1), +\fBdumpbas\fP(1), +\fBf2toxex\fP(1), +\fBfenders\fP(1), +\fBlistbas\fP(1), +\fBprotbas\fP(1), +\fBrenumbas\fP(1), +\fBrom2cart\fP(1), +\fBunmac65\fP(1), +\fBunprotbas\fP(1), +\fBvxrefbas\fP(1), +\fBwhichbas\fP(1), +\fBxex1to2\fP(1), +\fBxexamine\fP(1), +\fBxexcat\fP(1), +\fBxexsplit\fP(1), +\fBxfd2atr\fP(1), +\fBxex\fP(5), +\fBatascii\fP(7). +.sp +Any good Atari 8\-bit book: \fIDe Re Atari\fP, \fIThe Atari BASIC Reference +Manual\fP, the \fIOS Users\(aq Guide\fP, \fIMapping the Atari\fP, etc. +.\" Generated by docutils manpage writer. +. diff --git a/bas2aplus.c b/bas2aplus.c new file mode 100644 index 0000000..d7768cd --- /dev/null +++ b/bas2aplus.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include +#include +#include + +#include "bas.h" + +#undef DUMP_TABLES + +#ifdef DUMP_TABLES +#include "tokens.c" +#include "aplus_tokens.c" +#include "bxl_tokens.c" +#endif + +/* 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 GOTO 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 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[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0x0e, /* convert BXL hex const to decimal */ + 0, 0, 0, 0, + + /* 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."); +} + +CALLBACK(conv_cmd) { + if(tok > LAST_BXL_CMD) { + fprintf(stderr, "%s: Invalid cmd token %02x at line %d, pos %04x, skipping.\n", + self, tok, lineno, pos); + return; + } + + program[pos] = cmd_table[tok]; + if(verbose) + fprintf(stderr, "cmd tok %02x converted to %02x at line %d, pos %04x\n", tok, program[pos], lineno, pos); +} + +CALLBACK(conv_op) { + unsigned char newtok; + + if(tok < 0x12 && tok != OP_HEXCONST) return; + + if(tok > LAST_BXL_OP) { + fprintf(stderr, "%s: Invalid op token %02x at line %d, pos %04x, skipping.\n", + self, tok, lineno, pos); + return; + } + + newtok = op_table[tok]; + if(newtok == 0xff) { + fprintf(stderr, "%s: BXL op token %02x at line %d, pos %04x, has no A+ equivalent, skipping.\n", + self, tok, lineno, pos); + return; + } + + program[pos] = newtok; + if(verbose) + fprintf(stderr, "op tok %02x converted to %02x at line %d, pos %04x\n", 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(); + + return 0; +} diff --git a/bas2aplus.rst b/bas2aplus.rst new file mode 100644 index 0000000..0eb44d6 --- /dev/null +++ b/bas2aplus.rst @@ -0,0 +1,99 @@ +========= +bas2aplus +========= + +------------------------------------------------------------ +Convert Atari BASIC (and some BASIC XL) programs to BASIC/A+ +------------------------------------------------------------ + +.. include:: manhdr.rst + +SYNOPSIS +======== + +bas2aplus *input-file* *output-file* + +DESCRIPTION +=========== + +**bas2aplus** reads an Atari BASIC or BASIC XL tokenized (SAVEd) program +and converts it to BASIC/A+. + +All Atari BASIC programs can be successfully converted. Some BASIC +XL operators have no equivalent in BASIC/A+, so programs using these +can't be converted (you will see messages on standard error, in that +case). + +OPTIONS +======= + +.. include:: genopts.rst + +BASIC +===== + +BASIC/A+ is basically a later version of Atari BASIC, by the same team +that developed Atari BASIC. As such, it's source-compatible with Atari +BASIC, but *not* token-compatible. + +BASIC/A+ uses a different set of token numbers, but has all but two +of the same tokens used by Atari BASIC. Conversion should always +succeed, for an Atari BASIC program. + +The two missing tokens are the **COM** and **GO TO** commands, which +are converted to **DIM** and **GOTO**, respectively. + +The resulting program should **LOAD** and **RUN** in BASIC/A+ and +function identically to the BASIC version, unless it uses memory +that's reserved in A+. **USR()** routines that are stored in the lower +half of Page 6 will have to be relocated, since A+ uses this area +itself. See the BASIC/A+ manual for full details. + +BASIC XL +======== + +BASIC XL is basically the next version of BASIC/A+, by the +same developers. The token lists were rearranged so that it's +token-compatible with Atari BASIC, and includes all the extra +commands/functions/etc from BASIC/A+... with different token numbers. + +BASIC XL has keywords and operators that don't exist in BASIC/A+. These +are: + +**NUM** + Rarely found in a program (usually only used in direct mode). + +**FAST** + Just doesn't exist in BASIC/A+. + +**LOCAL**, **EXIT**, **PROCEDURE**, **CALL**, **SORTUP**, **SORTDOWN** + These BASIC XL commands are provided by the disk-based Toolkit + extension, which doesn't exist for BASIC/A+. + +**String Arrays** + BASIC/A+ doesn't support these; if your BASIC XL program uses them, + it won't convert correctly. + +**BUMP** and **FIND** + While BASIC/A+ does support these functions, the token-level syntax + is different; it would be possible to translate them, but it would + require recalculating the line offset and statement offsets for + every line that uses them. For now, they're not supported. + +**%** + The exclusive OR operator in BASIC XL. No such animal, in A+. + +**HEX$**, **RANDOM**, **LEFT$**, **RIGHT$**, **MID$** + These functions don't exist in BASIC/A+. + +Also, BASIC XL supports hex constants, with a leading **$**. A+ +doesn't support these, so they get converted to the equivalent decimal +constant. This is basically a cosmetic change; **A=$0600** assigns the +same value as **A=1536**. + +EXIT STATUS +=========== + +0 for success, non-zero for failuse. + +.. include:: manftr.rst -- cgit v1.2.3