aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bcdfp.c32
-rw-r--r--cxrefbas.rst5
-rw-r--r--linetab.c12
-rw-r--r--renumbas.rst5
4 files changed, 47 insertions, 7 deletions
diff --git a/bcdfp.c b/bcdfp.c
index 76157c1..a80e55d 100644
--- a/bcdfp.c
+++ b/bcdfp.c
@@ -1,8 +1,18 @@
#include <string.h>
+#include <stdio.h>
#include "bcdfp.h"
+/* very dumb and limited BCD floating point conversions.
+ they're written this way because they're only required to
+ support line numbers, and I don't want to have to link with
+ the math library (-lm). */
+
extern void die(const char *msg);
+void die_range(void) {
+ die("Line number out of range (>65535)");
+}
+
unsigned char bcd2int(unsigned char bcd) {
return (bcd >> 4) * 10 + (bcd & 0x0f);
}
@@ -12,24 +22,32 @@ unsigned char int2bcd(unsigned char i) {
}
unsigned short fp2int(const unsigned char *fp) {
- unsigned short result = 0;
+ unsigned int result = 0;
/* examine the exponent/sign byte */
if(fp[0] == 0) return 0; /* special case */
- if(fp[0] & 0x80) die("negative numbers not supported");
+ if(fp[0] & 0x80) die("Negative line numbers not supported");
switch(fp[0]) {
case 0x40:
- result = bcd2int(fp[1]); break;
+ result = bcd2int(fp[1]);
+ if(fp[2] >= 0x50) result++;
+ break;
case 0x41:
- result = bcd2int(fp[1]) * 100 + bcd2int(fp[2]); break;
+ result = bcd2int(fp[1]) * 100 + bcd2int(fp[2]);
+ if(fp[3] >= 0x50) result++;
+ break;
case 0x42:
- result = bcd2int(fp[1]) * 10000 + bcd2int(fp[2]) * 100 + bcd2int(fp[3]); break;
+ result = bcd2int(fp[1]) * 10000 + bcd2int(fp[2]) * 100 + bcd2int(fp[3]);
+ if(fp[4] >= 0x50) result++;
+ break;
default:
- die("number out of range"); break;
+ die_range(); break;
}
- return result;
+ if(result > 0xffff) die_range();
+
+ return (unsigned short)result;
}
void int2fp(unsigned short num, unsigned char *fp) {
diff --git a/cxrefbas.rst b/cxrefbas.rst
index d80d818..7004217 100644
--- a/cxrefbas.rst
+++ b/cxrefbas.rst
@@ -58,6 +58,11 @@ warning on standard error, e.g. *GOTO A* or *GOSUB 100\*A*. Even *GOTO
Line numbers above 32767, e.g. *TRAP 40000*, are not listed.
+Atari BASIC allows fractional line numbers, such as *GOTO 123.4*.
+These are rounded to the nearest integer when the program is
+executed. **cxrefbas** handles these correctly, although you're
+not likely to run into them in real-world programs.
+
OPTIONS
=======
diff --git a/linetab.c b/linetab.c
index 0351f59..59a96e3 100644
--- a/linetab.c
+++ b/linetab.c
@@ -93,6 +93,8 @@ void computed_msg(unsigned short lineno) {
CALLBACK(got_var) {
switch(last_cmd) {
+ /* any use of a variable in the arguments to these means
+ we can't renumber that argument. */
case CMD_GOTO:
case CMD_GO_TO:
case CMD_GOSUB:
@@ -102,6 +104,7 @@ CALLBACK(got_var) {
computed_msg(lineno);
break;
case CMD_ON:
+ /* vars are OK in ON, before the GOTO or GOSUB */
if(on_op) computed_msg(lineno);
break;
default:
@@ -119,9 +122,14 @@ CALLBACK(got_exp) {
}
if(tok != OP_NUMCONST) return;
+
+ /* beware: standalone only means nothing *follows* the constant
+ in the same expression. still have to check last_tok to see
+ what came before. */
standalone = is_standalone_num(pos);
switch(last_cmd) {
+ /* these take a single argument */
case CMD_GOTO:
case CMD_GO_TO:
case CMD_GOSUB:
@@ -134,11 +142,14 @@ CALLBACK(got_exp) {
}
break;
case CMD_IF:
+ /* this only applies to bare line numbers, like IF A THEN 1000,
+ not IF A THEN GOTO 1000 (or anything else after THEN). */
if(last_tok == OP_THEN) {
add_lineref(lineno, pos + 1);
}
break;
case CMD_ON: {
+ /* takes arbitrary number of arguments */
switch(last_tok) {
case OP_GOTO:
case OP_GOSUB:
@@ -154,6 +165,7 @@ CALLBACK(got_exp) {
}
break;
case CMD_LIST: {
+ /* takes one or two arguments */
switch(last_tok) {
case CMD_LIST:
case OP_COMMA:
diff --git a/renumbas.rst b/renumbas.rst
index d4b0990..7cef711 100644
--- a/renumbas.rst
+++ b/renumbas.rst
@@ -44,6 +44,11 @@ Remember that the maximum line number for Atari BASIC is 32767.
Renumbering will fail, if the chosen start and increment values
would result in lines with numbers higher than this.
+Atari BASIC allows fractional line numbers, such as *GOTO 123.4*.
+These are rounded to the nearest integer when the program is
+executed. **renumbas** handles these correctly, although you're
+not likely to run into them in real-world programs.
+
OPTIONS
=======