From 7b2728284fda571410b15ab175e48d5ef4d40115 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Tue, 16 Jul 2024 01:29:29 -0400 Subject: listbas: add support for Turbo BASIC XL. --- Makefile | 4 +- listbas.1 | 30 +++++++++- listbas.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++------ listbas.rst | 26 ++++++++- turbo_tokens.c | 82 +++++++++++++++++++++++++++ turbo_tokens.h | 5 ++ 6 files changed, 296 insertions(+), 23 deletions(-) create mode 100644 turbo_tokens.c create mode 100644 turbo_tokens.h diff --git a/Makefile b/Makefile index b8e29c7..7d33a91 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,8 @@ vxrefbas: bas.o cxrefbas: bas.o bcdfp.o linetab.o -listbas: listbas.c bas.o bcdfp.o tokens.o atables.o - $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o atables.o -lm +listbas: listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.c + $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.c -lm bas.o: bas.c bas.h diff --git a/listbas.1 b/listbas.1 index ba293f2..f8e4219 100644 --- a/listbas.1 +++ b/listbas.1 @@ -27,12 +27,12 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "LISTBAS" 1 "2024-07-14" "0.2.1" "Urchlay's Atari 8-bit Tools" +.TH "LISTBAS" 1 "2024-07-16" "0.2.1" "Urchlay's Atari 8-bit Tools" .SH NAME listbas \- List the source of a tokenized Atari 8-bit BASIC program .SH SYNOPSIS .sp -listbas [\fB\-a\fP | \fB\-d\fP | \fB\-m\fP | \fB\-x\fP | \fB\-U\fP] [\fB\-b\fP] [\fB\-u\fP] [\fB\-i\fP] [\fB\-l\fP] [\fB\-n\fP | \fB\-C\fP] [\fB\-v\fP] [\fB\-c\fP \fIcolors\fP] \fBinput\-file\fP +listbas [\fB\-a\fP | \fB\-d\fP | \fB\-m\fP | \fB\-x\fP | \fB\-U\fP] [\fB\-B\fP] [\fB\-u\fP] [\fB\-i\fP] [\fB\-l\fP] [\fB\-n\fP | \fB\-C\fP] [\fB\-v\fP] [\fB\-c\fP \fIcolors\fP] \fBinput\-file\fP .SH DESCRIPTION .sp \fBlistbas\fP acts like the \fILIST\fP command in BASIC. It reads a @@ -77,6 +77,30 @@ because you can\(aqt tell what the dots are supposed to represent. .SS Other options .INDENT 0.0 .TP +.B \fB\-b\fP +Set the BASIC the program was written in. Choices are: +.INDENT 7.0 +.TP +.B \fB\-ba\fP +Program is Atari BASIC; this is the default. +.TP +.B \fB\-ba+\fP +Program is OSS BASIC/A+. +.TP +.B \fB\-bt\fP +Program is Turbo BASIC XL. +.TP +.B \fB\-bxl\fP +Program is OSS BASIC XL. +.TP +.B \fB\-bxe\fP +Program is OSS BASIC XE. +.UNINDENT +.sp +If you see lots of "bad token XX" messages, or if the code just doesn\(aqt +make any sense, you\(aqre using the wrong BASIC option. \fBwhichbas\fP(1) +can (usually) detect the BASIC a program was written in. +.TP .B \fB\-i\fP Include the immediate mode command (line 32768) in the output. .TP @@ -94,7 +118,7 @@ No color. Has no effect if \fB\-a\fP is in effect, since this mode doesn\(aqt support color anyway. Disabling color does not disable reverse video. .TP -.B \fB\-b\fP +.B \fB\-B\fP Use bold for color output. This may make it easier to read on some terminals. Or, it may hurt your eyes... .TP diff --git a/listbas.c b/listbas.c index dcd303b..bfe7615 100644 --- a/listbas.c +++ b/listbas.c @@ -11,7 +11,20 @@ #include "bas.h" #include "bcdfp.h" #include "tokens.h" +#include "turbo_tokens.h" +/* +#include "aplus_tokens.h" +#include "bxl_tokens.h" +#include "bxe_tokens.h" +*/ #include "atables.h" +#include "whichbas.h" + +#define B_ATARI SRET_ATARI +#define B_TURBO SRET_TURBO +#define B_APLUS SRET_APLUS +#define B_BXL SRET_BXL +#define B_BXE SRET_BXE #define COLOR_FMT "\x1b[%d;3%dm" /* 1st %d is 1 for bold, 2nd is color */ @@ -50,6 +63,11 @@ #define M_MAG 3 /* -m */ #define M_DOTS 4 /* -d */ +const char *cmd_tokens[256]; +const char *op_tokens[256]; + +int bas_type = B_ATARI; + int output_mode = M_UTF8; int bold = 0; /* 1 with -b */ @@ -99,14 +117,37 @@ void parse_color_scheme(const char *arg) { color_varnames = parse_color(arg[7]); } +int get_bas_type(char *arg) { + if(arg[0] == 't') + return B_TURBO; + + if(arg[0] == 'a') { + if(arg[1] == '+') + return B_APLUS; + else + return B_ATARI; + } + + if(arg[0] == 'x') { + if(arg[1] == 'l') + return B_BXL; + else if(arg[1] == 'e') + return B_BXE; + } + + fprintf(stderr, "%s: Invalid BASIC type for -b option: %s\n", self, arg); + exit(1); +} + void print_help(void) { - printf("Usage: %s [-a|-d|-m|-x|-U] [-b] [-i] [-l] [-u] [-n|-C] [-v] [-c *colors*] \n", self); + printf("Usage: %s [-a|-d|-m|-x|-U] [-B] [-i] [-l] [-u] [-n|-C] [-v] [-c *colors*] \n", self); + printf(" -b : set BASIC type. XX is: a = atari, t = turbo, xl, xe, a+.\n"); printf(" -U: output ATASCII as Unicode/UTF-8 (this is the default).\n"); printf(" -a: output raw ATASCII.\n"); printf(" -d: use dots instead of Unicode/UTF-8.\n"); printf(" -m: magazine style listing (see a8cat(1)).\n"); printf(" -x: XL international character set (UTF-8).\n"); - printf(" -b: use bold for color output.\n"); + printf(" -B: use bold for color output.\n"); printf(" -i: show immediate mode command (line 32768).\n"); printf(" -l: don't print line numbers.\n"); printf(" -C: enable color syntax highlighting (this is the default).\n"); @@ -121,7 +162,7 @@ void parse_args(int argc, char **argv, int from_env) { optind = 1; - while( (opt = getopt(argc, argv, "UCviamnbdhxulc:")) != -1) { + while( (opt = getopt(argc, argv, "b:UCviamnBdhxulc:")) != -1) { switch(opt) { case 'U': output_mode = M_UTF8; break; case 'a': output_mode = M_ATASCII; break; @@ -130,11 +171,12 @@ void parse_args(int argc, char **argv, int from_env) { case 'x': output_mode = M_UTF8_I; break; case 'v': verbose = 1; break; case 'i': immediate = 1; break; - case 'b': bold = 1; break; + case 'B': bold = 1; break; case 'u': underline = 1; break; case 'C': color = 1; break; case 'n': color = 0; break; case 'l': skip_lineno = 1; break; + case 'b': bas_type = get_bas_type(optarg); break; case 'c': parse_color_scheme(optarg); break; case 'h': print_help(); exit(0); default: @@ -389,7 +431,7 @@ CALLBACK(print_cmd) { if(tok == CMD_ILET) return; if(color) color_on(color_cmd); - if(tok > last_command || (!(name = commands[tok]))) { + if((!(name = cmd_tokens[tok]))) { fprintf(outfh, "(bad cmd token $%02x) ", tok); badtok = 1; } else { @@ -398,10 +440,70 @@ CALLBACK(print_cmd) { if(color) color_off(); } +void aplus_op_color_on(unsigned char tok) { +} + +void op_color_on(unsigned char tok) { + if(!color) return; + + if(bas_type == B_APLUS) { + aplus_op_color_on(tok); + return; + } + + /* common ops for Atari, Turbo, BXL, BXE */ + if(tok <= last_operator) { + if(tok > 0x3c) + color_on(color_func); + else if(tok == OP_UMINUS || tok == OP_UPLUS) + color_on(color_const); /* show leading sign in same color as the number */ + else if((tok >= 0x17 && tok <= 0x1b) || (tok >= 0x28 && tok <= 0x2a)) + color_on(color_cmd); + else + color_on(color_op); + return; + } + + if(bas_type == B_TURBO) { + switch(tok) { + case 0x55: + case 0x58: + case 0x59: /* pseudo-func */ + case 0x5b: + case 0x5c: + case 0x5e: + case 0x5f: /* pseudo-func */ + case 0x60: /* pseudo-func */ + case 0x63: /* pseudo-func */ + case 0x64: + case 0x65: + case 0x6b: + case 0x6c: /* pseudo-func */ + case 0x6d: /* pseudo-func */ + color_on(color_func); + return; + case 0x5a: + case 0x5d: + case 0x61: + case 0x62: + case 0x6a: + color_on(color_cmd); + return; + default: + color_on(color_op); + } + } +} + CALLBACK(print_op) { const char *name; switch(tok) { + case OP_HEXCONST: + if(color) color_on(color_op); + outchr('$'); + if(color) color_off(); + /* fall thru */ case OP_NUMCONST: print_number(pos + 1); return; @@ -413,17 +515,9 @@ CALLBACK(print_op) { default: break; } - if(color) { - if(tok > 0x3c) - color_on(color_func); - else if(tok == OP_UMINUS || tok == OP_UPLUS) - color_on(color_const); /* show leading sign in same color as the number */ - else if((tok >= 0x17 && tok <= 0x1b) || (tok >= 0x28 && tok <= 0x2a)) - color_on(color_cmd); - else - color_on(color_op); - } - if(tok > last_operator || (!(name = operators[tok]))) { + if(color) op_color_on(tok); + + if((!(name = op_tokens[tok]))) { fprintf(outfh, "(bad op token $%02x)", tok); badtok = 1; } else { @@ -496,12 +590,58 @@ void list(void) { walk_code(0, 32767 + immediate); } +void init_bas_tables() { + memmove(cmd_tokens, commands, (last_command + 1) * sizeof(char *)); + memmove(op_tokens, operators, (last_operator + 1) * sizeof(char *)); +} + +void init_aplus_tables() { + die("BASIC A+ not supported yet!"); + /* + memmove(cmd_tokens, aplus_commands, (last_aplus_command + 1) * sizeof(char *)); + memmove(op_tokens, aplus_operators, (last_aplus_operator + 1) * sizeof(char *)); + */ +} + +void init_turbo_tables() { + memmove(cmd_tokens + last_command + 1, turbo_cmds, turbo_cmd_size); + memmove(op_tokens + last_operator + 1, turbo_ops, turbo_ops_size); +} + +void init_bxl_tables() { + die("BASIC XL not supported yet!"); +} + +void init_bxe_tables() { + die("BASIC XE not supported yet!"); +} + +void init_token_tables() { + if(bas_type == B_APLUS) { + init_aplus_tables(); + return; + } + + init_bas_tables(); + + if(bas_type == B_TURBO) + init_turbo_tables(); + else if(bas_type == B_BXL) + init_bxl_tables(); + else if(bas_type == B_BXE) + init_bxe_tables(); +} + int main(int argc, char **argv) { set_self(*argv); parse_general_args(argc, argv, print_help); parse_env_args(); parse_args(argc, argv, 0); + if(bas_type != B_ATARI) allow_hex_const = 1; + + init_token_tables(); + readfile(); parse_header(); diff --git a/listbas.rst b/listbas.rst index 63eb575..518dd5f 100644 --- a/listbas.rst +++ b/listbas.rst @@ -11,7 +11,7 @@ List the source of a tokenized Atari 8-bit BASIC program SYNOPSIS ======== -listbas [**-a** | **-d** | **-m** | **-x** | **-U**] [**-b**] [**-u**] [**-i**] [**-l**] [**-n** | **-C**] [**-v**] [**-c** *colors*] **input-file** +listbas [**-a** | **-d** | **-m** | **-x** | **-U**] [**-B**] [**-u**] [**-i**] [**-l**] [**-n** | **-C**] [**-v**] [**-c** *colors*] **input-file** DESCRIPTION =========== @@ -61,6 +61,28 @@ characters. Other options ------------- +**-b** + Set the BASIC the program was written in. Choices are: + + **-ba** + Program is Atari BASIC; this is the default. + + **-ba+** + Program is OSS BASIC/A+. + + **-bt** + Program is Turbo BASIC XL. + + **-bxl** + Program is OSS BASIC XL. + + **-bxe** + Program is OSS BASIC XE. + + If you see lots of "bad token XX" messages, or if the code just doesn't + make any sense, you're using the wrong BASIC option. **whichbas**\(1) + can (usually) detect the BASIC a program was written in. + **-i** Include the immediate mode command (line 32768) in the output. @@ -78,7 +100,7 @@ Other options mode doesn't support color anyway. Disabling color does not disable reverse video. -**-b** +**-B** Use bold for color output. This may make it easier to read on some terminals. Or, it may hurt your eyes... diff --git a/turbo_tokens.c b/turbo_tokens.c new file mode 100644 index 0000000..2278e21 --- /dev/null +++ b/turbo_tokens.c @@ -0,0 +1,82 @@ +/* these start at token 0x38 */ +const char *turbo_cmds[] = { + "DPOKE", /* $38 */ + "MOVE", + "-MOVE", + "*F", + "REPEAT", + "UNTIL", + "WHILE", + "WEND", + "ELSE", /* $40 */ + "ENDIF", + "BPUT", + "BGET", + "FILLTO", + "DO", + "LOOP", + "EXIT", + "DIR", /* $48 */ + "LOCK", + "UNLOCK", + "RENAME", + "DELETE", + "PAUSE", + "TIME$=", + "PROC", + "EXEC", /* $50 */ + "ENDPROC", + "FCOLOR", + "*L", + "------------------------------", + "RENUM", + "DEL", + "DUMP", + "TRACE", /* $58 */ + "TEXT", + "BLOAD", + "BRUN", + "GO#", + "#", + "*B", + "PAINT", + "CLS", /* $58 */ + "DSOUND", + "CIRCLE", + "%PUT", + "%GET" /* $64 */ +}; + +const int turbo_cmd_size = sizeof(turbo_cmds); + +/* these start at token 0x55 */ +const char *turbo_ops[] = { + "DPEEK", /* $55 */ + "&", + "!", + "INSTR", /* $58 */ + "INKEY$", + " EXOR ", + "HEX$", + "DEC", + " DIV ", + "FRAC", + "TIME$", + "TIME", /* $60 */ + " MOD ", + " EXEC ", + "RND", + "RAND", + "TRUNC", + "%0", + "%1", + "%2", /* $68 */ + "%3", + " GO# ", + "UINSTR", + "ERR", + "ERL", /* $6D */ +}; + +const int turbo_ops_size = sizeof(turbo_ops); + diff --git a/turbo_tokens.h b/turbo_tokens.h new file mode 100644 index 0000000..7696d52 --- /dev/null +++ b/turbo_tokens.h @@ -0,0 +1,5 @@ +extern const char *turbo_cmds[] ; +extern const int turbo_cmd_size ; + +extern const char *turbo_ops[] ; +extern const int turbo_ops_size ; -- cgit v1.2.3