/* 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 in Atari BASIC;
   0x0d is used (in the same way) in both Turbo BASIC and BXL/BXE.
   0x3d-0x54 are functions. */
#define OP_HEXCONST     0x0d
#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 int allow_hex_const;
extern int aplus_errtok_hack;
extern int bxl_exttok_hack;

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);
