From e2250e5cb71c9a06bf75d59e9c0369efd65b1206 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sun, 16 Jun 2024 17:33:22 -0400 Subject: cxrefbas: added. --- cxrefbas.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 cxrefbas.c (limited to 'cxrefbas.c') diff --git a/cxrefbas.c b/cxrefbas.c new file mode 100644 index 0000000..45369d4 --- /dev/null +++ b/cxrefbas.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include + +#include "bas.h" +#include "bcdfp.h" + +unsigned short *linerefs[32769]; +int refcounts[32769]; +int lines_exist[32769]; +int last_cmd; +int last_cmd_pos; + +void add_lineref(unsigned short from, unsigned short to) { + unsigned short *p; + int c; + + if(to > 32767) return; + + p = linerefs[to]; + c = refcounts[to]; + + if(c) { + p = realloc(p, sizeof(unsigned short) * (c + 1)); + } else { + p = malloc(sizeof(unsigned short)); + } + + if(!p) die("Out of memory."); + + linerefs[to] = p; + p[c] = from; + c++; + refcounts[to] = c; +} + +/* makes sure a numeric constant isn't start of an expression. */ +int is_standalone_num(unsigned short pos) { + if(program[pos] != OP_NUMCONST) return 0; + switch(program[pos + 7]) { + case OP_EOS: + case OP_EOL: + case OP_COMMA: + return 1; + default: + return 0; + } +} + +CALLBACK(start_stmt) { + lines_exist[lineno] = 1; +} + +CALLBACK(got_cmd) { + last_cmd = tok; + last_cmd_pos = pos; +} + +void computed_msg(unsigned char tok, unsigned short lineno) { + static int last_lineno = -1; + char *cmd; + + /* avoid duplicate warnings */ + if(lineno == last_lineno) return; + last_lineno = lineno; + + switch(tok) { + case CMD_GOTO: + cmd = "GOTO"; break; + case CMD_GO_TO: + cmd = "GO TO"; break; + case CMD_GOSUB: + cmd = "GOSUB"; break; + case CMD_RESTORE: + cmd = "RESTORE"; break; + case CMD_TRAP: + cmd = "TRAP"; break; + case CMD_ON: + cmd = "ON"; break; + default: /* should never happen! */ + cmd = "???"; break; + } + + fprintf(stderr, "Computed %s at line %d\n", cmd, lineno); +} + +CALLBACK(got_var) { + switch(last_cmd) { + case CMD_GOTO: + case CMD_GO_TO: + case CMD_GOSUB: + case CMD_RESTORE: + case CMD_TRAP: + computed_msg(last_cmd, lineno); + break; + default: + break; + } +} + +CALLBACK(got_exp) { + int standalone; + + if(tok != OP_NUMCONST) return; + standalone = is_standalone_num(pos); + + switch(last_cmd) { + case CMD_GOTO: + case CMD_GO_TO: + case CMD_GOSUB: + case CMD_RESTORE: + case CMD_TRAP: + if((pos == last_cmd_pos + 1) && standalone) { + add_lineref(lineno, fp2int(program + pos + 1)); + } else { + computed_msg(last_cmd, lineno); + } + break; + case CMD_ON: { + unsigned char last_tok = program[pos - 1]; + switch(last_tok) { + case OP_GOTO: + case OP_GOSUB: + case OP_COMMA: + if(standalone) + add_lineref(lineno, fp2int(program + pos + 1)); + else + computed_msg(last_cmd, lineno); + break; + default: + break; + } + } + break; + default: + break; + } +} + +void build_ref_table(void) { + on_start_stmt = start_stmt; + on_cmd_token = got_cmd; + on_exp_token = got_exp; + on_var_token = got_var; + walk_all_code(); +} + +void print_ref_table(void) { + int i, j; + for(i = 0; i < 32768; i++) { + if(refcounts[i]) { + if(!lines_exist[i]) putchar('!'); + printf("%d: ", i); + for(j = 0; j < refcounts[i]; j++) { + printf("%d ", linerefs[i][j]); + } + putchar('\n'); + } + } +} + +void print_help(void) { + fprintf(stderr, "Usage: %s [-v] program.bas\n", self); + exit(0); +} + +void parse_args(int argc, char **argv) { + int opt; + + while( (opt = getopt(argc, argv, "v")) != -1) { + switch(opt) { + case 'v': verbose = 1; break; + default: print_help(); exit(1); + } + } + + if(optind >= argc) + die("No input file given (use - for stdin)."); + else + open_input(argv[optind]); +} + +int main(int argc, char **argv) { + set_self(*argv); + parse_general_args(argc, argv, print_help); + parse_args(argc, argv); + + readfile(); + parse_header(); + + build_ref_table(); + print_ref_table(); + + return 0; +} -- cgit v1.2.3