/* bob.h - bob definitions */
/*
        Copyright (c) 1991, by David Michael Betz
        All rights reserved.

        Alterations and additions, 1994, by G.C.Wraith
*/

#include <stdio.h>
#include <ctype.h>

/* limits */
#define TKNSIZE         128      /* maximum token size */
#define SMAX            1024     /* runtime stack size for RISC OS */

/* useful definitions */
#define TRUE            1
#define FALSE           0

/* argument check macros */
#define argcount(n,cnt) { if ((n) != (cnt)) wrongcnt(n,cnt); }

/* stack manipulation macros */
#define check(n)         { if (sp - (n) < stkbase) stackover(); }
#define chktype(o,t)     { if (sp[o].v_type != t) badtype(o,t); }
#define push(x,t,f)      (--sp, sp->v_type = (t), sp->v.f = (x))
#define push_integer(x)  push(x,DT_INTEGER,v_integer)
#define push_real(x)     push(x,DT_REAL,v_real)
#define push_string(x)   push(x,DT_STRING,v_string)
#define push_class(x)    push(x,DT_CLASS,v_class)
#define push_object(x)   push(x,DT_OBJECT,v_object)
#define push_bytecode(x) push(x,DT_BYTECODE,v_vector)
#define push_var(x)      push(x,DT_VAR,v_var)
#define push_nil()       (--sp, sp->v_type = DT_NIL)

/* macros to set values */
#define set(s,x,t,f)        ((s)->v.f = (x), (s)->v_type = (t))
#define set_integer(s,x)    set(s,x,DT_INTEGER,v_integer)
#define set_real(s,x)       set(s,x,DT_REAL,v_real)
#define set_class(s,x)      set(s,x,DT_CLASS,v_class)
#define set_object(s,x)     set(s,x,DT_OBJECT,v_object)
#define set_code(s,x)       set(s,x,DT_CODE,v_code)
#define set_bytecode(s,x)   set(s,x,DT_BYTECODE,v_vector)
#define set_dictionary(s,x) set(s,x,DT_DICTIONARY,v_dictionary)
#define set_var(s,x)        set(s,x,DT_VAR,v_var)
#define set_string(s,x)     set(s,x,DT_STRING,v_string)
#define set_vector(s,x)     set(s,x,DT_VECTOR,v_vector)
#define set_iostream(s,x)   set(s,x,DT_IOSTREAM,v_iostream)
#define set_nil(s)          ((s)->v_type = DT_NIL)

/* value field access macros */
#define valtype(x)              ((x)->v_type)
#define isnil(x)                ((x)->v_type == DT_NIL)

/* class field access macros */
#define claddr(x)               ((x)->v.v_class)
#define clgetname(x)            (&claddr(x)->cl_name)
#define clgetbase(x)            (&claddr(x)->cl_base)
#define clgetmembers(x)         (&claddr(x)->cl_members)
#define clgetfunctions(x)       (&claddr(x)->cl_functions)
#define clgetsize(x)            (claddr(x)->cl_size)

/* object field access macros */
#define objaddr(x)              ((x)->v.v_object)
#define objgetclass(x)          (&objaddr(x)->obj_class)
#define objgetmember(x,i)       (&objaddr(x)->obj_members[i])
#define objsetmember(x,i,v)     (objaddr(x)->obj_members[i] = (v))

/* vector field access macros */
#define vecaddr(x)              ((x)->v.v_vector)
#define vecgetsize(x)           (vecaddr(x)->vec_size)
#define vecgetelement(x,i)      (&vecaddr(x)->vec_data[i])
#define vecsetelement(x,i,v)    (vecaddr(x)->vec_data[i] = (v))

/* string field access macros */
#define straddr(x)              ((x)->v.v_string)
#define strgetsize(x)           (straddr(x)->str_size)
#define strgetdata(x)           (straddr(x)->str_data)

/* dictionary field access macros */
#define diaddr(x)               ((x)->v.v_dictionary)
#define digetclass(x)           (&diaddr(x)->di_class)
#define digetcontents(x)        (&diaddr(x)->di_contents)

/* dictionary entry field access macros */
#define deaddr(x)               ((x)->v.v_var)
#define degetdictionary(x)      (&deaddr(x)->de_dictionary)
#define degetkey(x)             (&deaddr(x)->de_key)
#define degetvalue(x)           (&deaddr(x)->de_value)
#define degetnext(x)            (&deaddr(x)->de_next)
#define degettype(x)            (deaddr(x)->de_type)

/* i/o stream access macros */
#define ios_t(x)                ((x)->v.v_iostream->ios_dispatch)
#define ios_d(x)                ((x)->v.v_iostream->ios_data)
#define iosclose(x)             ((*ios_t(x)->iod_close)(ios_d(x)))
#define iosgetc(x)              ((*ios_t(x)->iod_getc)(ios_d(x)))
#define iosputc(c,x)            ((*ios_t(x)->iod_putc)((c),ios_d(x)))
#define iosputs(s,x)            ((*ios_t(x)->iod_puts)((s),ios_d(x)))

/* value descriptor structure */
typedef struct value {
  int v_type;                           /* data type */
  union {                               /* value */
    struct class *v_class;              /*   class (in heap) */
    struct object *v_object;            /*   object (in heap) */
    struct vector *v_vector;            /*   vector (in heap) */
    struct string *v_string;            /*   string (in heap) */
    struct dictionary *v_dictionary;    /*   dictionary (in heap) */
    struct dict_entry *v_var;           /*   variable (in heap) */
#ifdef __STDC__
    int (*v_code)(int);                /*   code for built-in function */
#else
    int (*v_code)();                    /*   code for built-in function */
#endif
    long v_integer;                     /*   integer */
    float v_real;                       /*   real */
    struct iostream *v_iostream;        /*   i/o stream (in heap) */
    struct hdr *v_hdr;                  /*   (used by garbage collector) */
    struct value *v_chain;              /*   (used by garbage collector) */
  } v;
} VALUE;

typedef struct hdr {
    char hdr_type;
    char hdr_flags;
    VALUE *hdr_chain;
} HDR;

typedef struct class {
    HDR cl_hdr;
    VALUE cl_name;
    VALUE cl_base;
    VALUE cl_members;
    VALUE cl_functions;
    int cl_size;
} CLASS;

typedef struct object {
    HDR obj_hdr;
    VALUE obj_class;
    VALUE obj_members[1];
} OBJECT;

typedef struct vector {
    HDR vec_hdr;
    int vec_size;
    VALUE vec_data[1];
} VECTOR;

typedef struct string {
    HDR str_hdr;
    int str_size;
    char str_data[1];
} STRING;

typedef struct dictionary {
    HDR di_hdr;
    VALUE di_class;
    VALUE di_contents;
} DICTIONARY;

/* dictionary entry structure */
typedef struct dict_entry {
    HDR de_hdr;
    VALUE de_dictionary;        /* backpointer to dictionary */
    VALUE de_key;               /* symbol name */
    int de_type;                /* symbol type */
    VALUE de_value;             /* symbol value */
    VALUE de_next;              /* next entry */
} DICT_ENTRY;

/* i/o stream dispatch structure */
typedef struct iodispatch {
#ifdef __STDC__
    int (*iod_close)(FILE *);
    int (*iod_getc)(FILE *);
    int (*iod_putc)(int,FILE *);
    int (*iod_puts)(const char *,FILE *);
#else
    int (*iod_close)();
    int (*iod_getc)();
    int (*iod_putc)();
    int (*iod_puts)();
#endif
} IODISPATCH;

/* i/o stream structure */
typedef struct iostream {
    HDR ios_hdr;
    IODISPATCH *ios_dispatch;
    void *ios_data;
} IOSTREAM;

/* symbol types */
#define ST_CLASS        1       /* class definition */
#define ST_DATA         2       /* data member */
#define ST_SDATA        3       /* static data member */
#define ST_FUNCTION     4       /* function member */
#define ST_SFUNCTION    5       /* static function member */

/* data types */
#define _DTMIN          0
#define DT_NIL          0
#define DT_CLASS        1
#define DT_OBJECT       2
#define DT_VECTOR       3
#define DT_INTEGER      4
#define DT_STRING       5
#define DT_BYTECODE     6
#define DT_CODE         7
#define DT_DICTIONARY   8
#define DT_VAR          9
#define DT_IOSTREAM     10
#define DT_REAL         11
#define _DTMAX          11

/* opcodes */
#define OP_BRT          0x01    /* branch on true */
#define OP_BRF          0x02    /* branch on false */
#define OP_BR           0x03    /* branch unconditionally */
#define OP_NIL          0x04    /* load top of stack with nil */
#define OP_PUSH         0x05    /* push nil onto stack */
#define OP_NOT          0x06    /* logical negate top of stack */
#define OP_NEG          0x07    /* negate top of stack */
#define OP_ADD          0x08    /* add top two stack entries */
#define OP_SUB          0x09    /* subtract top two stack entries */
#define OP_MUL          0x0A    /* multiply top two stack entries */
#define OP_DIV          0x0B    /* divide top two stack entries */
#define OP_REM          0x0C    /* remainder of top two stack entries */
#define OP_BAND         0x0D    /* bitwise and of top two stack entries */
#define OP_BOR          0x0E    /* bitwise or of top two stack entries */
#define OP_XOR          0x0F    /* bitwise xor of top two stack entries */
#define OP_BNOT         0x10    /* bitwise not of top two stack entries */
#define OP_SHL          0x11    /* shift left top two stack entries */
#define OP_SHR          0x12    /* shift right top two stack entries */
#define OP_LT           0x13    /* less than */
#define OP_LE           0x14    /* less than or equal to */
#define OP_EQ           0x15    /* equal to */
#define OP_NE           0x16    /* not equal to */
#define OP_GE           0x17    /* greater than or equal to */
#define OP_GT           0x18    /* greater than */
#define OP_INC          0x19    /* increment */
#define OP_DEC          0x1A    /* decrement */
#define OP_LIT          0x1B    /* load literal */
#define OP_RETURN       0x1C    /* return from interpreter */
#define OP_CALL         0x1D    /* call a function */
#define OP_REF          0x1E    /* load a variable value */
#define OP_SET          0x1F    /* set the value of a variable */
#define OP_VREF         0x20    /* load a vector element */
#define OP_VSET         0x21    /* set a vector element */
#define OP_MREF         0x22    /* load a member variable value */
#define OP_MSET         0x23    /* set a member variable */
#define OP_AREF         0x24    /* load an argument value */
#define OP_ASET         0x25    /* set an argument value */
#define OP_TREF         0x26    /* load a temporary variable value */
#define OP_TSET         0x27    /* set a temporary variable */
#define OP_TSPACE       0x28    /* allocate temporary variable space */
#define OP_SEND         0x29    /* send a message to an object */
#define OP_DUP2         0x2A  /* duplicate top two elements on the stack */
#define OP_NEW          0x2B    /* create a new class object */
/* new opcodes for RISC OS version */
#define OP_DUP          0x2C     /* duplicate top element on stack */
#define OP_DROP         0x2D     /* drop top of stack */
#define OP_ADR          0x2E     /* get address of string */
#define OP_PUTNEXT      0x2F     /* put next values and increment */
#define OP_VECT         0x30     /* pull values off stack to make a vector */

/* external variables */
extern VALUE *stkbase,*sp,*fp,*stktop;
extern VALUE nil;

/* external routines */
#ifdef __STDC__

/* standard stuff 
char *calloc(int,int);
void free(char *);
char *strcpy(char *,char *);
char *strncpy(char *,char *,int);
char *strchr(char *,int);
int strcmp(char *,char *);
int strncmp(char *,char *,int);
int strlen(char *);
void *memcpy(void *,void *,int);
int system(char *); */

/* bobcom.c */
int init_compiler(void);
void mark_compiler(void);
int compile_definitions(int (*getcf)(),void *getcd);
char *getmemory(int size);

/* bob.c */
void compile_file(char *);
void info1(char *fmt,char *s);
void info2(char *fmt,char *s1,char *s2);
void infodss(char *fmt,int n1,int n2,char *s1,char *s2);
void error0(char *fmt);
void error1(char *fmt,char *s);
void error1d(char *fmt,int n);
void errorsd(char *fmt,char * s,int n);
void osputs(char *str);

/* bobscn.c */
int init_scanner(int (*gf)(void *),void *gd);
int token(void);
int stoken(int tkn);
char *tkn_name(int tkn);
int parse_error(char *msg);

/* bobint.c */
int execute(char *name);
int start_call(char *name);
int start_send(OBJECT *obj,char *selector);
int execute_call(int argc);
void badtype(int off,int type);
void stackover(void);

/* bobdbg.c */
int decode_procedure(VALUE *code);
int decode_instruction(VALUE *code,int lc);

/* bobfcn.c */
void init_functions(void);
void add_function(char *name,int (*fcn)());
int print1(VALUE *ios,int qflag,VALUE *val);
void wrongcnt(int n,int cnt);

/* bobmem.c */
int initialize(int smax);
DICT_ENTRY *addentry(VALUE *dict,char *key,int type);
DICT_ENTRY *findentry(VALUE *dict,char *key);
STRING *makestring(char *str);
char *getcstring(char *buf,int max,VALUE *str);
STRING *newstring(int n);
OBJECT *newobject(VALUE *class);
VECTOR *newvector(int n);
CLASS *newclass(char *name,VALUE *base);
DICTIONARY *newdictionary(VALUE *class);
IOSTREAM *newiostream(IODISPATCH *iod,void *data);
void gc(void);
void mark(VALUE *val);

/* real.c */
void init_real_functions(void);

#else
extern CLASS *newclass();
extern OBJECT *newobject();
extern VECTOR *newvector();
extern STRING *newstring();
extern STRING *makestring();
extern DICTIONARY *newdictionary();
extern IOSTREAM *newiostream();
extern DICT_ENTRY *findentry();
extern DICT_ENTRY *addentry();
extern char *getcstring();
#endif
