183 lines
5.6 KiB
C
183 lines
5.6 KiB
C
#ifndef TMPASM_H
|
|
#define TMPASM_H
|
|
#ifndef TMPASM_INSTR_MAXLEN
|
|
#define TMPASM_INSTR_MAXLEN 32
|
|
#endif
|
|
|
|
typedef struct tmpasm_s tmpasm_t;
|
|
|
|
typedef struct tmpasm_arg_s tmpasm_arg_t;
|
|
|
|
struct tmpasm_arg_s {
|
|
tmpasm_arg_t *next; /* block: the resulting string is a list of strings and addresses */
|
|
char is_addr; /* 1: arg is a node address; 0: arg is a string immediate */
|
|
char data[1]; /* arg string - obviously longer than 1 char (but there's not special hack for that in C89), \0 terminated */
|
|
};
|
|
|
|
/* user specified instruction prototype */
|
|
typedef void tmpasm_instr(tmpasm_t *ctx, char *iname, int argc, tmpasm_arg_t *argv[]);
|
|
|
|
|
|
typedef struct tmpasm_cb_s {
|
|
/* return the value of a node at addr - NULL is an error */
|
|
const char *(*get)(tmpasm_t *ctx, const char *addr);
|
|
|
|
/* set the value of a node at addr to data; data may be NULL */
|
|
void (*set)(tmpasm_t *ctx, const char *addr, const char *data);
|
|
|
|
/* return 1 if data is true, 0 otherwise; data may be NULL (if an unknown variable is referenced) */
|
|
int (*is_true)(tmpasm_t *ctx, const char *data);
|
|
|
|
/* return 1 if str matches pat, 0 otherwise; str and pat may be NULL */
|
|
int (*match)(tmpasm_t *ctx, const char *str, const char *pat);
|
|
|
|
/* first iteration over list; return the first element (or NULL to end); the string returned is not free'd by the caller */
|
|
const char *(*first)(tmpasm_t *ctx, void **state, char *list);
|
|
|
|
/* return next element of a list or NULL on end (in which case state shall be also free'd by the caller); the string returned is not free'd by the caller */
|
|
const char *(*next)(tmpasm_t *ctx, void **state);
|
|
|
|
/* resolve an instruction name to a function pointer */
|
|
tmpasm_instr *(*resolve)(tmpasm_t *ctx, const char *name);
|
|
|
|
/* optional: called once before execution of a context starts */
|
|
void (*preexec)(tmpasm_t *ctx);
|
|
|
|
/* optional: called once before execution of a context starts */
|
|
void (*postexec)(tmpasm_t *ctx);
|
|
|
|
/* optional: resolve the current runtime error, called only for negative
|
|
error codes; should return a format string with exactly one %s in it
|
|
or NULL. */
|
|
const char *(*runtime_error_fmt)(tmpasm_t *ctx);
|
|
} tmpasm_cb_t;
|
|
|
|
int tmpasm_gotchar(tmpasm_t *ctx, char c);
|
|
|
|
tmpasm_t *tmpasm_init(const tmpasm_cb_t *cb);
|
|
void tmpasm_uninit(tmpasm_t *ctx);
|
|
|
|
/* return the string version of an arg in a newly malloc()'d string
|
|
if keep_addr is non-zero and a is a single address, no get() is run
|
|
but the address is returned as a string */
|
|
char *tmpasm_arg2str(tmpasm_t *ctx, tmpasm_arg_t *a, int keep_addr);
|
|
|
|
/* execute the code recursively until it exits */
|
|
void tmpasm_execute(tmpasm_t *ctx);
|
|
|
|
/* Set or get the runtime error of a context. 0 means no error, negative
|
|
codes are user errors handled by the runtime_error_fmt() callback
|
|
and positive codes are internal error. */
|
|
void tmpasm_runtime_error(tmpasm_t *ctx, int code, const char *data);
|
|
const char *tmpasm_runtime_error_fmt(tmpasm_t *ctx);
|
|
|
|
/* --- internals: not required for normal use --- */
|
|
typedef enum {
|
|
ST_PRECMD, /* waiting for a command to start - ignore whitespace */
|
|
ST_CMD,
|
|
ST_PREDATA, /* waiting for data */
|
|
ST_PREBLOCKSEP, /* waiting for a block sep when opening a block */
|
|
ST_BLOCKSEP, /* found a block sep within the block - either an address or a termination follows */
|
|
ST_BLOCK, /* in [@ @] block, text part */
|
|
ST_BLOCK_INLINE, /* in [@ @] block, within inline @@ part */
|
|
ST_STRING, /* in {} string */
|
|
ST_STRING_ESCAPE, /* in {} string, right after a \ */
|
|
ST_ADDRESS, /* shifting address bytes */
|
|
ST_COMMENT /* after #, until the next newline */
|
|
} tmpasm_state_t;
|
|
|
|
typedef enum {
|
|
KW_none,
|
|
KW_IF,
|
|
KW_THEN,
|
|
KW_ELSE,
|
|
KW_END,
|
|
KW_FOREACH,
|
|
KW_IN,
|
|
KW_SWITCH,
|
|
KW_CASE,
|
|
KW_DEFAULT,
|
|
|
|
KW_NOP /* virtual instruction */
|
|
} tmpasm_kw_t;
|
|
|
|
/* execution structs */
|
|
typedef struct tmpasm_exec_s tmpasm_exec_t;
|
|
typedef struct tmpasm_case_s tmpasm_case_t;
|
|
|
|
struct tmpasm_case_s {
|
|
tmpasm_arg_t *data;
|
|
tmpasm_exec_t *body;
|
|
tmpasm_case_t *next;
|
|
};
|
|
|
|
|
|
struct tmpasm_exec_s {
|
|
tmpasm_kw_t kw; /* kw_none means a hook instruction */
|
|
union {
|
|
struct { /* normal instruction */
|
|
tmpasm_instr *call;
|
|
char *call_name; /* temporary */
|
|
int argc;
|
|
tmpasm_arg_t **argv;
|
|
} instr;
|
|
struct {
|
|
tmpasm_arg_t *cond;
|
|
tmpasm_exec_t *code_then;
|
|
tmpasm_exec_t *code_else;
|
|
} fc_if;
|
|
struct {
|
|
char *loop_var; /* must be a single address */
|
|
tmpasm_arg_t *data; /* what to loop in */
|
|
tmpasm_exec_t *code_body;
|
|
} fc_foreach;
|
|
struct {
|
|
tmpasm_arg_t *cond;
|
|
tmpasm_case_t *first;
|
|
tmpasm_case_t *last;
|
|
} fc_switch;
|
|
} payload;
|
|
int line, col;
|
|
tmpasm_exec_t *next;
|
|
};
|
|
|
|
|
|
/* parser structs */
|
|
typedef struct stack_s tmpasm_stack_t;
|
|
struct stack_s {
|
|
tmpasm_state_t state;
|
|
/* tmpasm_state_t kwstate; internal states of composite keywords like switch */
|
|
char cmd_buff[TMPASM_INSTR_MAXLEN+1];
|
|
unsigned int cmdi;
|
|
tmpasm_kw_t kw, old_kw;
|
|
char block_sep;
|
|
int kwcol, kwline;
|
|
|
|
int args_used, args_alloced; /* number of arguments in argv[] */
|
|
|
|
tmpasm_arg_t **argv; /* an array of linked lists */
|
|
tmpasm_arg_t **argend; /* each argv[] is a linked list (for blocks); argend points to the tail */
|
|
int *arg_alloced; /* of argend */
|
|
int *arg_used; /* of argend */
|
|
|
|
tmpasm_exec_t *last_code; /* tail of the code list */
|
|
|
|
tmpasm_stack_t *next;
|
|
};
|
|
|
|
struct tmpasm_s {
|
|
tmpasm_stack_t *st;
|
|
int dead;
|
|
int col, line;
|
|
tmpasm_exec_t *code;
|
|
tmpasm_exec_t *executing; /* points to the code most recently executed (or being executed when in callbacks) */
|
|
const tmpasm_cb_t *cb;
|
|
int halt;
|
|
int runtime_error;
|
|
char *runtime_error_data;
|
|
int runtime_error_line;
|
|
int runtime_error_col;
|
|
void *user_data;
|
|
};
|
|
#endif
|