aboutsummaryrefslogtreecommitdiff
path: root/linetab.c
diff options
context:
space:
mode:
Diffstat (limited to 'linetab.c')
-rw-r--r--linetab.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/linetab.c b/linetab.c
new file mode 100644
index 0000000..c4fe392
--- /dev/null
+++ b/linetab.c
@@ -0,0 +1,165 @@
+#include "linetab.h"
+
+lineref_t *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 pos) {
+ lineref_t *p;
+ int c;
+ unsigned short to;
+
+ to = fp2int(program + pos);
+ if(to > 32767) return;
+
+ p = linerefs[to];
+ c = refcounts[to];
+
+ if(c) {
+ p = realloc(p, sizeof(lineref_t) * (c + 1));
+ } else {
+ p = malloc(sizeof(lineref_t));
+ }
+
+ if(!p) die("Out of memory.");
+
+ linerefs[to] = p;
+ linerefs[to][c].lineno = from;
+ linerefs[to][c].pos = pos;
+ linerefs[to][c].cmd = last_cmd;
+ 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, pos + 1);
+ } else {
+ computed_msg(lineno);
+ }
+ break;
+ case CMD_IF:
+ if(last_tok == OP_THEN) {
+ add_lineref(lineno, pos + 1);
+ }
+ break;
+ case CMD_ON: {
+ switch(last_tok) {
+ case OP_GOTO:
+ case OP_GOSUB:
+ case OP_COMMA:
+ if(standalone)
+ add_lineref(lineno, 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();
+}
+