From 577f49a6cb613a63b422fcdeeec85d326009637f Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sun, 7 Jul 2024 16:36:00 -0400 Subject: whichbas: rewrite handle_op as a switch, keep track of last op token, improve EXOR/BUMP( and DIV/RANDOM( logic. --- whichbas.c | 167 +++++++++++++++++++++++++++---------------------------------- 1 file changed, 74 insertions(+), 93 deletions(-) diff --git a/whichbas.c b/whichbas.c index 20b2fdf..f4bd151 100644 --- a/whichbas.c +++ b/whichbas.c @@ -19,6 +19,7 @@ int bas_type = 0x0f; /* start out with all enabled */ int comma_count; /* count of regular commas (not string/array) in statement */ unsigned char last_cmd; +unsigned char last_op_tok; unsigned short last_cmd_pos; int keep_going = 0; /* -k flag */ @@ -260,102 +261,82 @@ CALLBACK(handle_op) { print_result(); } - /* FIXME: I should have written this as a switch, not a bunch of if's */ - - if(tok == 0x55) { - /* DPEEK (function) TB, USING (infix, not a function) in BXL/BXE */ - if(nexttok == OP_FUNC_LPAR) { - remove_type(BT_BXL_BXE); - } else { - remove_type(BT_TURBO); - } - } - - /* 56! & (logical AND) or % (XOR), both infix numeric ops; can't tell apart */ - /* 57! ! (logical OR) in both Turbo and BXL/BXE, can't tell apart */ - - /* 58: INSTR (function) or & (infix numeric) */ - if(tok == 0x58) { - if(nexttok == OP_FUNC_LPAR) { - remove_type(BT_BXL_BXE); - } else { - remove_type(BT_TURBO); - } - } - - /* 59: INKEY$ (pseudo-function) in TB, string array separator semicolon in BXL/BXE */ - if(tok == 0x59) { - if(nexttok == OP_NUMCONST || nexttok >= 0x80) { - /* INKEY$ may not be followed by a numeric constant or a variable of any kind */ - remove_type(BT_TURBO); - } - } - - /* 5a: EXOR (infix num op) or BUMP( (pseudo-function, no OP_FUNC_LPAR) */ - /* 5d: DIV (infix num op) or RANDOM( (pseudo-func, 1 or 2 num args) */ - if(tok == 0x5a || tok == 0x5d) { - /* XXX: incomplete */ - if(last_cmd_pos == pos - 1) { - /* partial: if the last token was a command, this *can't* be infix.*/ - remove_type(BT_TURBO); - } else if(program[pos - 1] >= 0x80) { - /* partial: if the last token was a variable, this can't - be a function (last token would have to have been a command - or a regular operator). however, Turbo BASIC allows up to 256 - variables, this only catches the first 128. */ - remove_type(BT_BXL_BXE); - } - } - - /* 5b: HEX$ (func, takes 1 num arg) or FIND( (pseudo-func, 3 args */ - if(tok == 0x5b) { - if(nexttok == OP_FUNC_LPAR) { - remove_type(BT_BXL_BXE); - } else { - /* BXL/BXE token FIND( includes the (, there's no OP_FUNC_LPAR */ - remove_type(BT_TURBO); - } - } - - if(tok == 0x5c) { - /* DEC (function, takes str) in TB, HEX$ (function, takes num) in BXL/BXE */ - if(nexttok2 == OP_STRCONST) { - remove_type(BT_BXL_BXE); - } else if(nexttok2 > 0x80 && (get_vartype(nexttok2) == TYPE_STRING)) { - /* TODO: see if this test is actually valid! */ - remove_type(BT_BXL_BXE); - } - } + /* There are 25 extra operators in Turbo, and 20 of them are shared with + BXL/BXE. Of the 20, 6 of them are undecidable, and the rest are + covered here, which means 70% coverage of the shared ops. + Undecidables are: + 0x56 & (logical AND) or % (XOR), both infix numeric ops; can't tell apart + 0x57 ! (logical OR) in both Turbo and BXL/BXE, can't tell apart + 0x5e FRAC (num func, 1 arg) or DPEEK (num func, 1 arg), can't tell apart + 0x63 RND (func, 1 num arg) or ERR (func, 1 num arg), can't tell apart + 0x64 RAND (func, 1 num arg) or TAB (func, 1 num arg), can't tell apart + 0x65 TRUNC (func, 1 num arg) or PEN (func, 1 num arg), can't tell apart + */ - /* 5d: see 5a, above (same logic). */ - /* 5e! FRAC (num func, 1 arg) or DPEEK (num func, 1 arg), can't tell apart :( */ - - /* 5f: TIME$ in TB, SYS (function) in BXL/BXE */ - /* 60: TIME in TB, VSTICK (function) in BXL/BXE */ - /* 61: MOD (infix op) in TB, HSTICK (function) in BXL/BXE */ - /* 62: EXEC (infix op, with ON) in TB, PMADR (function) in BXL/BXE */ - if(tok == 0x5f || tok == 0x60 || tok == 0x61 || tok == 0x62) { - if(nexttok == OP_FUNC_LPAR) { - remove_type(BT_TURBO); - } else { - remove_type(BT_BXL_BXE); - } + switch(tok) { + case 0x55: /* DPEEK (function) TB, USING (infix, not a function) in BXL/BXE */ + case 0x58: /* INSTR (function) or & (infix numeric) */ + case 0x5b: /* HEX$ (func, takes 1 num arg) or FIND( (pseudo-func, 3 args */ + if(nexttok == OP_FUNC_LPAR) { + remove_type(BT_BXL_BXE); + } else { + remove_type(BT_TURBO); + } + break; + case 0x59: /* INKEY$ (0 arg pseudo-func) in TB, string array separator semicolon in BXL/BXE */ + if(nexttok == OP_NUMCONST || nexttok >= 0x80) { + /* INKEY$ may not be followed by a numeric constant or a variable of any kind */ + remove_type(BT_TURBO); + } + break; + case 0x5a: /* EXOR (infix num op) or BUMP( (pseudo-function, no OP_FUNC_LPAR) */ + case 0x5d: /* DIV (infix num op) or RANDOM( (pseudo-func, 1 or 2 num args) */ + /* XXX: incomplete */ + if(last_cmd_pos == pos - 1) { + /* partial: if the last token was a command, this *can't* be infix.*/ + remove_type(BT_TURBO); + } else if(last_op_tok == OP_NUMCONST || last_op_tok == OP_HEXCONST || last_op_tok >= 0x80) { + /* partial: if the last token was a variable or a numeric, this can't + be a function (last token would have to have been a command + or a regular operator). however, Turbo BASIC allows up to 256 + variables, this only catches the first 128. */ + remove_type(BT_BXL_BXE); + } + break; + case 0x5c: /* DEC (function, takes str) in TB, HEX$ (function, takes num) in BXL/BXE */ + if(nexttok2 == OP_STRCONST) { + remove_type(BT_BXL_BXE); + } else if(nexttok2 > 0x80 && (get_vartype(nexttok2) == TYPE_STRING)) { + /* TODO: see if this test is actually valid! */ + remove_type(BT_BXL_BXE); + } + break; + case 0x5f: /* TIME$ in TB, SYS (function) in BXL/BXE */ + case 0x60: /* TIME in TB, VSTICK (function) in BXL/BXE */ + case 0x61: /* MOD (infix op) in TB, HSTICK (function) in BXL/BXE */ + case 0x62: /* EXEC (infix op, with ON) in TB, PMADR (function) in BXL/BXE */ + if(nexttok == OP_FUNC_LPAR) { + remove_type(BT_TURBO); + } else { + remove_type(BT_BXL_BXE); + } + break; + case 0x66: /* %0 in TB, LEFT$ (pseudo-func, takes string) in BXL/BXE */ + case 0x67: /* %1 in TB, RIGHT$ (pseudo-func, takes string) in BXL/BXE */ + case 0x68: /* %2 in TB, MID$ (pseudo-func, takes string) in BXL/BXE */ + if(nexttok == OP_STRCONST || nexttok >= 0x80) { + /* %0 %1 %2 can't be followed by a string constant *or* a variable */ + remove_type(BT_TURBO); + } else { + /* whereas LEFT$ RIGHT$ MID$ can't be followed by anything else */ + remove_type(BT_BXL_BXE); + } + break; + default: + break; } - /* 63! RND (func, 1 num arg) or ERR (func, 1 num arg), can't tell apart */ - /* 64! RAND (func, 1 num arg) or TAB (func, 1 num arg), can't tell apart */ - /* 65! TRUNC (func, 1 num arg) or PEN (func, 1 num arg), can't tell apart */ - - if(tok == 0x66 || tok == 0x67 || tok == 0x68) { - /* either %0 %1 %2 (TB), or LEFT$ RIGHT$ MID$ (BXL/XE, *no* OP_FUNC_LPAR) */ - if(nexttok == OP_STRCONST || nexttok >= 0x80) { - /* %0 %1 %2 can't be followed by a string constant *or* a variable */ - remove_type(BT_TURBO); - } else { - /* whereas LEFT$ RIGHT$ MID$ can't be followed by anything else */ - remove_type(BT_BXL_BXE); - } - } + last_op_tok = tok; if(verbose) fprintf(stderr, " bas_type now %02x\n", bas_type); } -- cgit v1.2.3