diff options
author | B. Watson <urchlay@slackware.uk> | 2024-06-17 21:57:50 -0400 |
---|---|---|
committer | B. Watson <urchlay@slackware.uk> | 2024-06-17 21:57:50 -0400 |
commit | 6d78097ac8f1a7f9bc02e68514cb9aad1a08d306 (patch) | |
tree | 2ad1a2470ab3bf8806c8b676fb2a5748d4512b85 | |
parent | a7ee96f24543d6382f09a51418391b9b8a957fda (diff) | |
download | bw-atari8-tools-6d78097ac8f1a7f9bc02e68514cb9aad1a08d306.tar.gz |
renumbas: rewrite with callback API.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | linetab.c | 1 | ||||
-rw-r--r-- | renumbas.c | 379 |
3 files changed, 50 insertions, 332 deletions
@@ -53,7 +53,7 @@ unprotbas: bas.o protbas: bas.o -renumbas: bas.o +renumbas: bas.o bcdfp.o linetab.o dumpbas: bas.o @@ -161,5 +161,6 @@ void build_ref_table(void) { on_exp_token = got_exp; on_var_token = got_var; walk_all_code(); + on_start_stmt = on_cmd_token = on_exp_token = on_var_token = 0; } @@ -6,50 +6,41 @@ #include <time.h> #include "bas.h" +#include "bcdfp.h" +#include "linetab.h" -/* remove/comment to turn off debug printing */ -#define DEBUG - -#ifdef DEBUG -# define IFDEBUG(x) x -#else -# define IFDEBUG(x) -#endif - -int startlineno = 10; -int increment = 10; -int limit = 0; - -unsigned short *linerefs[32768]; -int linerefcounts[32768]; +unsigned short startlineno = 10; +unsigned short increment = 10; +unsigned short limit = 0; +unsigned short newno; void print_help(void) { - fprintf(stderr, "Usage: %s [-v] [-s start-lineno] [-i increment] [-f first-lineno] <inputfile> <outputfile>\n", self); - fprintf(stderr, " -v: Verbose.\n"); - fprintf(stderr, " -s <num>: Starting line number (default: 10).\n"); - fprintf(stderr, " -i <num>: Increment (default: 10).\n"); - fprintf(stderr, " -f <num>: Don't renumber lines less than <num> (default: 0).\n"); + fprintf(stderr, "Usage: %s [-v] [-s start-lineno] [-i increment] [-f first-lineno] <inputfile> <outputfile>\n", self); + fprintf(stderr, " -v: Verbose.\n"); + fprintf(stderr, " -s <num>: Starting line number (default: 10).\n"); + fprintf(stderr, " -i <num>: Increment (default: 10).\n"); + fprintf(stderr, " -f <num>: Don't renumber lines less than <num> (default: 0).\n"); } unsigned short getlineno(char opt, const char *arg) { - int lineno; - char *e; + int lineno; + char *e; - lineno = (int)strtol(arg, &e, 10); + lineno = (int)strtol(arg, &e, 10); - if(*e) { - fprintf(stderr, "%s: Invalid line number for -%c option: %s is not a number.\n", - self, opt, arg); - exit(1); - } + if(*e) { + fprintf(stderr, "%s: Invalid line number for -%c option: %s is not a number.\n", + self, opt, arg); + exit(1); + } - if(lineno < 0 || lineno > 32767) { - fprintf(stderr, "%s: Invalid line number for -%c option: %d > 32767.\n", - self, opt, lineno); - exit(1); - } + if(lineno < 0 || lineno > 32767) { + fprintf(stderr, "%s: Invalid line number for -%c option: %d > 32767.\n", + self, opt, lineno); + exit(1); + } - return ((unsigned short)lineno); + return ((unsigned short)lineno); } void parse_args(int argc, char **argv) { @@ -62,8 +53,8 @@ void parse_args(int argc, char **argv) { case 'i': increment = getlineno(opt, optarg); break; case 'f': limit = getlineno(opt, optarg); break; default: - print_help(); - exit(1); + print_help(); + exit(1); } } @@ -78,312 +69,37 @@ void parse_args(int argc, char **argv) { output_filename = argv[optind]; } -unsigned char bcd2int(unsigned char bcd) { - return (bcd >> 4) * 10 + (bcd & 0x0f); -} - -unsigned char int2bcd(unsigned char i) { - return ((i / 10) << 4) | (i % 10); -} - -unsigned short fp2int(const unsigned char *fp) { - unsigned short result = 0; - - /* examine the exponent/sign byte */ - if(fp[0] == 0) return 0; /* special case */ - if(fp[0] & 0x80) die("negative numbers not supported"); - - switch(fp[0]) { - case 0x40: - result = bcd2int(fp[1]); break; - case 0x41: - result = bcd2int(fp[1]) * 100 + bcd2int(fp[2]); break; - case 0x42: - result = bcd2int(fp[1]) * 10000 + bcd2int(fp[2]) * 100 + bcd2int(fp[3]); break; - default: - die("number out of range"); break; - } - - return result; -} - -void int2fp(unsigned short num, unsigned char *fp) { - memset(fp, 0, 6); - - if(num == 0) return; - - if(num >= 10000) { - fp[0] = 0x42; - fp[3] = int2bcd(num % 100); - num /= 100; - fp[2] = int2bcd(num % 100); - num /= 100; - fp[1] = int2bcd(num); - } else if(num >= 100) { - fp[0] = 0x41; - fp[2] = int2bcd(num % 100); - num /= 100; - fp[1] = int2bcd(num); - } else { - fp[0] = 0x40; - fp[1] = int2bcd(num); - } -} - -void addlineref(unsigned short refaddr) { - int target = fp2int(program + refaddr); - unsigned short *p = linerefs[target]; - int c = linerefcounts[target]; - - IFDEBUG(printf("addlineref: target=%d, 0x%04x\n", target, refaddr)); - - if(c) { - p = realloc(p, sizeof(unsigned short) * (c + 1)); - } else { - p = malloc(sizeof(unsigned short)); - } - - if(!p) die("Out of memory."); - - linerefs[target] = p; - p[c] = refaddr; - c++; - linerefcounts[target] = c; -} - -void printlinerefs(void) { - int i, j; - printf("linerefs:\n"); - for(i = 0; i < 32768; i++) { - if(linerefcounts[i]) { - printf("%d: ", i); - for(j = 0; j < linerefcounts[i]; j++) { - printf("%04x ", linerefs[i][j]); - } - putchar('\n'); - } - } -} - -void freelinerefs(void) { +CALLBACK(renumber_line) { int i; - for(i = 0; i < 32768; i++) { - if(linerefcounts[i]) { - free(linerefs[i]); - } - } -} - -/* tokens that can take line numbers: - Commands: - GOTO 0x0a - GO TO 0x0b - GOSUB 0x0c - TRAP 0x0d - LIST 0x04 (but don't bother) - RESTORE 0x23 - - Operators: - GOTO 0x17 (as in, ON (0x1e) GOTO) - GOSUB 0x18 (ON = 0x1e again) - THEN 0x1b (but not really!) - - beware: e.g. GOTO 1000+A should not have the 1000 changed. - - numeric constant introduced with 0x0e, followed by 6 BCD bytes. - string constant 0x0f, length byte, then (length) bytes. -*/ - -int is_xfer_cmd(unsigned char tok) { - int ret; - switch(tok) { - case CMD_GOTO: - case CMD_GO_TO: - case CMD_GOSUB: - case CMD_TRAP: - case CMD_LIST: - case CMD_RESTORE: - ret = 1; break; - default: - ret = 0; break; - } - IFDEBUG(printf("is_xfer_cmd(%02x) == %d\n", tok, ret)); - return ret; -} - -int skip_op_token(int pos) { - switch(program[pos]) { - case OP_EOS: - return pos + 2; /* skip next-statement offset */ - case OP_EOL: - return pos + 3; /* skip 2-byte line number */ - case OP_NUMCONST: - return pos + 7; /* skip 6-byte BCD float */ - case OP_STRCONST: - return pos + 2 + program[pos + 1]; /* 2nd byte is string len */ - default: - return pos + 1; - } -} - -/* ON/GOTO and ON/GOSUB can have any number of arguments, separated - by OP_COMMA. *Normally* these are simple FP constants, since the - whole point of ON is to avoid computed line numbers... but they're - allowed to be expressions so we have to check. */ -int handle_on_goto(int lineno, int pos) { - unsigned char tok, nexttok, main_tok; - - IFDEBUG(printf("handle_on_goto(%02x)\n", pos)); - - main_tok = program[pos]; /* save this, for use in 'computed' warning */ - - pos++; /* skip GOTO/GOSUB token */ + unsigned char fpnewno[6]; - while(1) { - tok = program[pos]; - if(tok == OP_EOS || tok == OP_EOL) - break; - if(tok == OP_COMMA) { - pos++; - continue; - } - nexttok = program[pos + 7]; - if(tok != OP_NUMCONST || !(nexttok == OP_COMMA || nexttok == OP_EOS || nexttok == OP_EOL)) { - fprintf(stderr, "Computed line number in ON/%s at line %d.\n", - (main_tok == OP_GOTO ? "GOTO" : "GOSUB"), lineno); - break; - } - addlineref(pos + 1); - pos += 7; + if(lineno < limit || lineno == 32768) return; + if(newno >= 32768) { + fprintf(stderr, "New line number %d out of range, renumber failed.", newno); + exit(1); } - return pos; -} + if(verbose) + fprintf(stderr, "renumbering line %d as %d, %d refs\n", lineno, newno, refcounts[lineno]); -/* IF/THEN can be followed by a simple line number (not a full expression) - or a statement offset (*without* an OP_EOS token!) followed by a - statement. - The right way to do this would be to track the statement offsets, but - this works fine. It relies on the fact that line numbers always have - an exponent byte of 0x40 to 0x42, and the fact that 0x40 to 0x42 are - not valid command tokens. - */ -int handle_then(int pos) { - unsigned char tok1 = program[pos + 1]; - unsigned char tok2 = program[pos + 2]; - if(tok1 == OP_NUMCONST && (tok2 >= 0x40 && tok2 <= 0x42)) { - addlineref(pos + 2); - return pos + 7; - } else { - return 0; - } + int2fp(newno, fpnewno); + for(i = 0; i < refcounts[lineno]; i++) + memmove(program + linerefs[lineno][i].pos, fpnewno, 6); + setword(pos, newno); + newno += increment; } void renumber(void) { - int pos = codestart, nextpos; - int lineno, offset; - int newno, i; - unsigned char tok; - unsigned char fpnewno[6]; - - /* pass 1: find references to line numbers, flag them. */ - while(pos < filelen) { - lineno = getword(pos); - if(lineno == 32768) break; - offset = program[pos + 2]; - IFDEBUG(printf("checking line %d, pos %04x...\n", lineno, pos)); - if(offset < 6) - die("Can't renumber a code-protected program, unprotect it first."); - nextpos = pos + offset; - - pos += 4; /* skip line number, line length, 1st statement length */ - - /* loop over the statements in this line */ - while(pos < nextpos) { - /* every statement starts with a command token */ - tok = program[pos]; - - if(tok == CMD_REM || tok == CMD_DATA || tok == CMD_ERROR) - break; /* ignore rest of line */ - - if(is_xfer_cmd(tok)) { - unsigned char nexttok = program[pos + 8]; - if(program[pos + 1] == OP_NUMCONST && (nexttok == OP_EOS || nexttok == OP_EOL)) { - addlineref(pos + 2); - } else { - fprintf(stderr, "Computed line number at line %d.\n", lineno); - } - } - - pos++; - - /* rest of statement is expressions/operators */ - while(pos < nextpos) { - tok = program[pos]; - - if(tok == OP_EOL) break; - - if(tok == OP_EOS) { - pos += 2; /* end statement, skip statement length of next one */ - break; - } - - if(tok == OP_GOTO || tok == OP_GOSUB) { - pos = handle_on_goto(lineno, pos); - continue; - } else if(tok == OP_THEN) { - i = handle_then(pos); - if(i) { - pos = i; - continue; - } else { - pos += 2; /* skip statement length */ - break; - } - } - - IFDEBUG(printf("tok is %02x, pos was %02x before skip_op_token... ", tok, pos)); - pos = skip_op_token(pos); - IFDEBUG(printf("pos now %02x\n", pos)); - } - } + int i; - pos = nextpos; /* point to next line */ + for(i = 0; i < 32768; i++) { + if(refcounts[i] && !lines_exist[i]) + fprintf(stderr, "Warning: Line %d is referenced, but does not exist.\n", i); } - IFDEBUG(printlinerefs()); - - /* pass 2: renumber the lines, and update the references in other lines */ newno = startlineno; - pos = codestart; - while(pos < filelen) { - if(newno >= 32768) { - fprintf(stderr, "New line number %d out of range, renumber failed.", newno); - exit(1); - } - - lineno = getword(pos); - offset = program[pos + 2]; - - if(lineno >= limit) { - if(lineno == 32768) break; - - IFDEBUG(printf("renumbering line %d as %d, %d refs\n", lineno, newno, linerefcounts[lineno])); - - /* update refs to old line number with new one */ - int2fp(newno, fpnewno); - for(i = 0; i < linerefcounts[lineno]; i++) - memmove(program + linerefs[lineno][i], fpnewno, 6); - - /* update the actual line number */ - setword(pos, newno); - - newno += increment; - } - pos += offset; - } - - freelinerefs(); + on_start_line = renumber_line; + walk_all_code(); } int main(int argc, char **argv) { @@ -394,10 +110,11 @@ int main(int argc, char **argv) { readfile(); parse_header(); + build_ref_table(); renumber(); open_output(output_filename); - writefile(); + writefile(); return 0; } |