#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#include "bas.h"

int A, F, N, D, I, R, G, O, L;
int target_var, lastline;
unsigned char last_cmd = 0;
int refcounts[128];

void print_help(void) {
	printf("Usage: %s [-v] program.bas\n", self);
	exit(0);
}

CALLBACK(new_line) {
	A = F = N = D = I = R = G = O = L = 0;
}

CALLBACK(end_line) {
	if(lastline != lineno) return;

	if(A || F || N || D || I || R || G || O || L) {
		putchar('=');
		if(A) putchar('A');
		if(F) putchar('F');
		if(N) putchar('N');
		if(D) putchar('D');
		if(I) putchar('I');
		if(R) putchar('R');
		if(G) putchar('G');
		if(O) putchar('O');
		if(L) putchar('L');
	}

	putchar(' ');
}

CALLBACK(new_command) {
	last_cmd = tok;
}

CALLBACK(end_stmt) {
	last_cmd = 0;
}

CALLBACK(handle_var) {
	unsigned char last_tok, next_tok;
	int was_cmd, was_comma, was_semicolon;

	if(tok != (target_var | 0x80)) return;

	if(lastline != lineno) {
		printf("%d", lineno);
		refcounts[target_var]++;
	}

	lastline = lineno;

	last_tok = program[pos - 1];
	next_tok = program[pos + 1];
	was_cmd = (last_tok == last_cmd);
	was_comma = (last_tok == OP_COMMA);
	was_semicolon = (last_tok == OP_SEMICOLON);

	switch(last_cmd) {
		case CMD_LET:
		case CMD_ILET:
			if(was_cmd) A = 1;
			break;
		case CMD_FOR:
			if(was_cmd) F = 1;
			break;
		case CMD_NEXT:
			if(was_cmd) N = 1;
			break;
		case CMD_DIM:
			if(was_cmd || was_comma) D = 1;
			break;
		case CMD_INPUT: /* INPUT #1;A and INPUT #1,A are both allowed, grr. */
			if(was_cmd || was_comma || was_semicolon) I = 1;
			break;
		case CMD_READ:
			if(was_cmd || was_comma) R = 1;
			break;
		case CMD_GET:
			if(was_comma) G = 1;
			break;
		case CMD_NOTE:
			if(was_comma) O = 1;
			break;
		case CMD_LOCATE:
			if(next_tok == OP_EOS || next_tok == OP_EOL) L = 1;
			break;
	}
}

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) {
	unsigned short pos;
	unsigned short vnpos;
	int unref = 0;

	set_self(*argv);
	parse_general_args(argc, argv, print_help);
	parse_args(argc, argv);

	readfile();
	parse_header();

	if(!vntable_ok())
		die("Program is variable-protected; unprotect it first.");

	on_var_token = handle_var;
	on_start_line = new_line;
	on_end_line = end_line;
	on_cmd_token = new_command;
	on_end_stmt = end_stmt;

	target_var = 0;
	vnpos = vnstart;

	/* walk the variable value table */
	for(pos = vvstart; pos < codestart; pos += 8) {
		/* print the variable name */
		while(program[vnpos] < 0x80)
			putchar(program[vnpos++]);
		putchar(program[vnpos++] & 0x7f);
		printf("/%02x: ", target_var | 0x80);

		lastline = -1;
		walk_all_code();

		if(!refcounts[target_var]) {
			unref++;
			printf("(no references)");
		} else {
			printf("(%d)", refcounts[target_var]);
		}
		putchar('\n');

		/* ignore any ERROR-4 vars, since they don't have tokens anyway. */
		if(++target_var == 128) break;
	}

	printf("  %d variables, %d unreferenced.\n", target_var, unref);
	return 0;
}
