1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
/* bas.h - API for writing standalone programs that deal with
tokenized Atari 8-bit BASIC program. */
/* maximum size of the program in memory. 64KB is actually way overkill. */
#define BUFSIZE 65536
/* the difference between the VVTP and VNTP values in the file, and the
actual file positions of the variable names and values. */
#define TBL_OFFSET 0xf2
/* minimum program size, for a program that has no variables and
only one line of code (the immediate line 32768, consisting only of
one token, which would be CSAVE). anything smaller than this, we
can't process. */
#define MIN_PROG_SIZE 21
/* maximum practical size for a BASIC program. if a file exceeds this
size, we warn about it, but otherwise process it normally.
this value is derived by subtracting the default LOMEM without DOS
($0700) from the start of the display list in GR.0 ($9c20, on a 48K Atari).
*/
#define MAX_PROG_SIZE 38176
/* maximum number of variables in the variable name and value tables. this
could be 128, but "ERROR- 4" still expands the tables. Entries >128
don't have tokens, can't be referred to in code, but we'll preserve
them anyway. */
#define MAXVARS 256
/* BASIC tokens. Full set, taken from Chapter 10 of De Re Atari.
I used a paper copy, but you can also find it on the web:
https://www.atariarchives.org/dere/chapt10.php
BASIC uses 2 sets of tokens, one for commands and the other for
operators (which is to say, everything *not* a command).
See tokens.h for the actual names. */
/* commands (every statement begins with one of these) */
#define CMD_REM 0x00
#define CMD_DATA 0x01
#define CMD_INPUT 0x02
#define CMD_COLOR 0x03
#define CMD_LIST 0x04
#define CMD_ENTER 0x05
#define CMD_LET 0x06
#define CMD_IF 0x07
#define CMD_FOR 0x08
#define CMD_NEXT 0x09
#define CMD_GOTO 0x0a
#define CMD_GO_TO 0x0b
#define CMD_GOSUB 0x0c
#define CMD_TRAP 0x0d
#define CMD_BYE 0x0e
#define CMD_CONT 0x0f
#define CMD_COM 0x10
#define CMD_CLOSE 0x11
#define CMD_CLR 0x12
#define CMD_DEG 0x13
#define CMD_DIM 0x14
#define CMD_END 0x15
#define CMD_NEW 0x16
#define CMD_OPEN 0x17
#define CMD_LOAD 0x18
#define CMD_SAVE 0x19
#define CMD_STATUS 0x1a
#define CMD_NOTE 0x1b
#define CMD_POINT 0x1c
#define CMD_XIO 0x1d
#define CMD_ON 0x1e
#define CMD_POKE 0x1f
#define CMD_PRINT 0x20
#define CMD_RAD 0x21
#define CMD_READ 0x22
#define CMD_RESTORE 0x23
#define CMD_RETURN 0x24
#define CMD_RUN 0x25
#define CMD_STOP 0x26
#define CMD_POP 0x27
#define CMD_QMARK 0x28 /* ? for PRINT */
#define CMD_GET 0x29
#define CMD_PUT 0x2a
#define CMD_GRAPHICS 0x2b
#define CMD_PLOT 0x2c
#define CMD_POSITION 0x2d
#define CMD_DOS 0x2e
#define CMD_DRAWTO 0x2f
#define CMD_SETCOLOR 0x30
#define CMD_LOCATE 0x31
#define CMD_SOUND 0x32
#define CMD_LPRINT 0x33
#define CMD_CSAVE 0x34
#define CMD_CLOAD 0x35
#define CMD_ILET 0x36 /* implied LET */
#define CMD_ERROR 0x37
/* operators. 0x00-0x0d and 0x0a-0x11 are not used.
0x3d-0x54 are functions. */
#define OP_NUMCONST 0x0e
#define OP_STRCONST 0x0f
#define OP_COMMA 0x12
#define OP_DOLLAR 0x13
#define OP_EOS 0x14 /* two names: "end of statement"... */
#define OP_COLON 0x14 /* ...and "colon" */
#define OP_SEMICOLON 0x15
#define OP_EOL 0x16
#define OP_GOTO 0x17
#define OP_GOSUB 0x18
#define OP_TO 0x19
#define OP_STEP 0x1a
#define OP_THEN 0x1b
#define OP_HASH 0x1c
#define OP_NUM_LE 0x1d
#define OP_NUM_NE 0x1e
#define OP_NUM_GE 0x1f
#define OP_NUM_LT 0x20
#define OP_NUM_GT 0x21
#define OP_NUM_EQ 0x22
#define OP_POWER 0x23
#define OP_MULT 0x24
#define OP_PLUS 0x25
#define OP_MINUS 0x26
#define OP_DIVIDE 0x27
#define OP_NOT 0x28
#define OP_OR 0x29
#define OP_AND 0x2a
#define OP_GRP_LPAR 0x2b
#define OP_GRP_RPAR 0x2c
#define OP_NUM_ASSIGN 0x2d
#define OP_STR_ASSIGN 0x2e
#define OP_STR_LE 0x2f
#define OP_STR_NE 0x30
#define OP_STR_GE 0x31
#define OP_STR_LT 0x32
#define OP_STR_GT 0x33
#define OP_STR_EQ 0x34
#define OP_UPLUS 0x35
#define OP_UMINUS 0x36
#define OP_STR_LPAR 0x37
#define OP_ARR_LPAR 0x38
#define OP_DIM_ARR_LPAR 0x39
#define OP_FUNC_LPAR 0x3a
#define OP_DIM_STR_LPAR 0x3b
#define OP_ARR_COMMA 0x3c /* used for A(1,1) or A$(1,1) (also in DIM) */
#define OP_FUNC_STR 0x3d /* the rest are functions */
#define OP_FUNC_CHR 0x3e
#define OP_FUNC_USR 0x3f
#define OP_FUNC_ASC 0x40
#define OP_FUNC_VAL 0x41
#define OP_FUNC_LEN 0x42
#define OP_FUNC_ADR 0x43
#define OP_FUNC_ATN 0x44
#define OP_FUNC_COS 0x45
#define OP_FUNC_PEEK 0x46
#define OP_FUNC_SIN 0x47
#define OP_FUNC_RND 0x48
#define OP_FUNC_FRE 0x49
#define OP_FUNC_EXP 0x4a
#define OP_FUNC_LOG 0x4b
#define OP_FUNC_CLOG 0x4c
#define OP_FUNC_SQR 0x4d
#define OP_FUNC_SGN 0x4e
#define OP_FUNC_ABS 0x4f
#define OP_FUNC_INT 0x50
#define OP_FUNC_PADDLE 0x51
#define OP_FUNC_STICK 0x52
#define OP_FUNC_PTRIG 0x53
#define OP_FUNC_STRIG 0x54
/* variable types, bits 6-7 of byte 0 of each vvtable entry. */
#define TYPE_SCALAR 0
#define TYPE_ARRAY 1
#define TYPE_STRING 2
/* BASIC 14-byte header values */
extern unsigned short lomem;
extern unsigned short vntp;
extern unsigned short vntd;
extern unsigned short vvtp;
extern unsigned short stmtab;
extern unsigned short stmcur;
extern unsigned short starp;
/* positions where various parts of the file start,
derived from the header vars above. */
extern unsigned short codestart;
extern unsigned short code_end;
extern unsigned short vnstart;
extern unsigned short vvstart;
extern int filelen;
/* name of executable, taken from argv[0] */
extern const char *self;
/* entire file gets read into memory (for now) */
extern unsigned char program[BUFSIZE];
/* file handles */
extern FILE *input_file;
extern FILE *output_file;
extern char *output_filename;
extern int verbose;
extern void set_self(const char *argv0);
extern void die(const char *msg);
extern void parse_general_args(int argc, char **argv, void (*helpfunc)());
extern int writefile(void);
extern void readfile(void);
extern unsigned short getword(int addr);
extern void setword(int addr, int value);
extern void dump_header_vars(void);
extern void parse_header(void);
extern void update_header(void);
extern void move_code(int offset);
extern void adjust_vntable_size(int oldsize, int newsize);
extern int vntable_ok(void);
extern unsigned char get_vartype(unsigned char tok);
extern void invalid_args(const char *arg);
extern FILE *open_file(const char *name, const char *mode);
extern void open_input(const char *name);
extern void open_output(const char *name);
/* callback API begins here.
callbacks for walk_code(): */
#define CALLBACK(x) void x(unsigned int lineno, unsigned int pos, unsigned int tok, unsigned int end)
#define CALLBACK_PTR(x) void (*x)(unsigned int lineno, unsigned int pos, unsigned int tok, unsigned int end)
/* main entry point for callback API: */
void walk_code(unsigned int startlineno, unsigned int endlineno);
#define walk_all_code() walk_code(0, 32768)
/* available callbacks: */
extern CALLBACK_PTR(on_start_line);
extern CALLBACK_PTR(on_bad_line_length);
extern CALLBACK_PTR(on_end_line);
extern CALLBACK_PTR(on_start_stmt);
extern CALLBACK_PTR(on_end_stmt);
extern CALLBACK_PTR(on_cmd_token);
extern CALLBACK_PTR(on_text);
extern CALLBACK_PTR(on_exp_token);
extern CALLBACK_PTR(on_var_token);
extern CALLBACK_PTR(on_string_const);
extern CALLBACK_PTR(on_num_const);
extern CALLBACK_PTR(on_trailing_garbage);
|