aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-07-10 04:00:55 -0400
committerB. Watson <urchlay@slackware.uk>2024-07-10 04:00:55 -0400
commit9e49ae687d56f33bb3d47e9f939265bafe44f4f4 (patch)
tree172744bebc3a36e9bdc42bac68adf2527b6b078f
parent251780217201017d4c53f23b228be468350f6f85 (diff)
downloadbw-atari8-tools-9e49ae687d56f33bb3d47e9f939265bafe44f4f4.tar.gz
whichbas: add operator classifications (is_numeric_op() and friends), use them in INKEY$/semicolon logic (cmd 0x59).
-rw-r--r--whichbas.c163
1 files changed, 160 insertions, 3 deletions
diff --git a/whichbas.c b/whichbas.c
index da50998..57e7098 100644
--- a/whichbas.c
+++ b/whichbas.c
@@ -115,6 +115,149 @@ void print_result(void) {
}
}
+/* return true if a token is numeric constant
+ (including TB/BXE/BXL hex) */
+int is_numconst_op(unsigned char tok) {
+ switch(tok) {
+ case OP_NUMCONST:
+ case OP_HEXCONST:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* return true if a token is a function that *returns*
+ a numeric value (says nothing about the argument types,
+ though!) */
+int is_numeric_func(unsigned char tok) {
+ switch(tok) {
+ case OP_FUNC_USR:
+ case OP_FUNC_ASC:
+ case OP_FUNC_VAL:
+ case OP_FUNC_LEN:
+ case OP_FUNC_ADR:
+ case OP_FUNC_ATN:
+ case OP_FUNC_COS:
+ case OP_FUNC_PEEK:
+ case OP_FUNC_SIN:
+ case OP_FUNC_RND:
+ case OP_FUNC_FRE:
+ case OP_FUNC_EXP:
+ case OP_FUNC_LOG:
+ case OP_FUNC_CLOG:
+ case OP_FUNC_SQR:
+ case OP_FUNC_SGN:
+ case OP_FUNC_ABS:
+ case OP_FUNC_INT:
+ case OP_FUNC_PADDLE:
+ case OP_FUNC_STICK:
+ case OP_FUNC_PTRIG:
+ case OP_FUNC_STRIG:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* return true if a token is an arithmetic operator */
+int is_arith_op(unsigned char tok) {
+ switch(tok) {
+ case OP_NUM_LE:
+ case OP_NUM_NE:
+ case OP_NUM_GE:
+ case OP_NUM_LT:
+ case OP_NUM_GT:
+ case OP_NUM_EQ:
+ case OP_POWER:
+ case OP_MULT:
+ case OP_PLUS:
+ case OP_MINUS:
+ case OP_DIVIDE:
+ case OP_NOT:
+ case OP_OR:
+ case OP_AND:
+ case OP_NUM_ASSIGN:
+ case OP_UPLUS:
+ case OP_UMINUS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int is_numeric_var(unsigned char tok) {
+ int vartype;
+
+ if(tok < 0x80)
+ return 0;
+
+ vartype = get_vartype(tok);
+ return (vartype == TYPE_SCALAR || vartype == TYPE_ARRAY);
+}
+
+/* return true if a token is:
+ - a numeric constant (including hex constants),
+ - a numeric variable (including arrays),
+ - a math operator (plus, minus, etc),
+ - a function that returns a numeric (e.g. ASC(), SIN()).
+ for now, only standard Atari BASIC tokens are considered.
+ */
+int is_numeric_op(unsigned char tok) {
+ return
+ is_numconst_op (tok) ||
+ is_arith_op (tok) ||
+ is_numeric_func (tok) ||
+ is_numeric_var (tok) ;
+}
+
+int is_string_var(unsigned char tok) {
+ return (tok >= 0x80 && (get_vartype(tok) == TYPE_STRING));
+}
+
+int is_string_const(unsigned char tok) {
+ return (tok == OP_STRCONST);
+}
+
+int is_string_exp_op(unsigned char tok) {
+ switch(tok) {
+ case OP_STR_ASSIGN:
+ case OP_STR_LE:
+ case OP_STR_NE:
+ case OP_STR_GE:
+ case OP_STR_LT:
+ case OP_STR_GT:
+ case OP_STR_EQ:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int is_string_func(unsigned char tok) {
+ switch(tok) {
+ case OP_FUNC_STR:
+ case OP_FUNC_CHR:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* return true if a token is:
+ - a string constant,
+ - a string variable,
+ - a string expression operator, like OP_STR_LE,
+ - a function that returns a string.
+*/
+int is_string_op(unsigned char tok) {
+ return
+ is_string_const (tok) ||
+ is_string_func (tok) ||
+ is_string_exp_op (tok) ||
+ is_string_var (tok) ;
+}
+
void remove_type(int type) {
bas_type &= ((~type) & 0x0f);
@@ -525,8 +668,7 @@ CALLBACK(handle_op) {
case 0x59: /* INKEY$ (0 arg pseudo-func) in TB, string array separator semicolon in BXL/BXE */
/* PARTIAL: ...but pretty good. we *can't* check nexttok == OP_GRP_RPAR, because
- VAL(INKEY$) or ASC(INKEY$) are legit Turbo code.
- This can fail to catch A$(X;Y) if X and Y are both complex expressions. */
+ VAL(INKEY$) or ASC(INKEY$) are legit Turbo code. */
if(nexttok == OP_EOS || nexttok == OP_EOL) {
/* the semicolon can't be the last token on the line (needs at least
a right-paren), but INKEY$ can. */
@@ -535,6 +677,12 @@ CALLBACK(handle_op) {
/* INKEY$ can be the first operator after the command, e.g if the command
is IF. The semicolon cannot. */
remove_type(BT_BXL_BXE);
+ } else if(is_string_exp_op(last_op_tok) || is_string_exp_op(nexttok)) {
+ /* A$=INKEY$, IF INKEY$=A$, A$(LEN(A$)+1)=INKEY$, INKEY$<>"A"... */
+ remove_type(BT_BXL_BXE);
+ } else if(is_numeric_op(last_op_tok) || is_numeric_op(nexttok)) {
+ remove_type(BT_TURBO);
+#if 0
} else if(last_op_tok == OP_STR_ASSIGN) {
/* catches A$=INKEY$, for what that's worth. */
remove_type(BT_BXL_BXE);
@@ -547,6 +695,7 @@ CALLBACK(handle_op) {
TODO: determine exactly what all it *can* be followed by, check for that.
*/
remove_type(BT_TURBO);
+#endif
}
break;
@@ -623,9 +772,17 @@ CALLBACK(handle_op) {
if(nexttok == OP_STRCONST || nexttok >= 0x80) {
/* %0 %1 %2 can't be followed by a string constant *or* a variable */
remove_type(BT_TURBO);
- /* Can't do, due to LEFT$(HEX$("1234"), 1) (or STR$, etc) */
+ /* Can't do, due to LEFT$(HEX$("1234"), 1) (or STR$, etc): */
/* } else {
remove_type(BT_BXL_BXE); */
+ /* ...but this stuff helps: */
+ } else if(nexttok == OP_EOS || nexttok == OP_EOL) {
+ /* LEFT$ RIGHT$( MID$( can't occur at the end of a statement. */
+ remove_type(BT_BXL_BXE);
+ } else if(pos == (last_cmd_pos + 2) && program[pos - 1] == OP_NUM_ASSIGN) {
+ /* LEFT$ RIGHT$( MID$( return strings, assignment would
+ be OP_STR_ASSIGN. */
+ remove_type(BT_BXL_BXE);
}
break;