#include #include #include #include #include #include #include "bas.h" #include "bcdfp.h" /* not yet... typedef struct { unsigned short lineno; unsigned short pos; unsigned char type; } lineref_t; */ unsigned short *linerefs[32769]; int refcounts[32769]; int lines_exist[32769]; unsigned char last_cmd, on_op; 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; on_op = 0; } void computed_msg(unsigned short lineno) { static int last_lineno = -1; char *cmd; /* avoid duplicate warnings */ if(lineno == last_lineno) return; last_lineno = lineno; switch(last_cmd) { 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_IF: cmd = "IF/THEN"; break; */ case CMD_ON: if(on_op == OP_GOSUB) cmd = "ON/GOSUB"; else cmd = "ON/GOTO"; 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(lineno); break; default: break; } } CALLBACK(got_exp) { unsigned char last_tok = program[pos - 1]; int standalone; if(last_cmd == CMD_ON) { if(tok == OP_GOTO || tok == OP_GOSUB) on_op = tok; } 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(lineno); } break; case CMD_IF: if(last_tok == OP_THEN) { add_lineref(lineno, fp2int(program + pos + 1)); } break; case CMD_ON: { switch(last_tok) { case OP_GOTO: case OP_GOSUB: case OP_COMMA: if(standalone) add_lineref(lineno, fp2int(program + pos + 1)); else computed_msg(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; }