/*
 * LANGUAGE - Language support
 *
 * Author:
 * Emile van Bergen, emile@evbergen.xs4all.nl
 *
 * Permission to redistribute an original or modified version of this program
 * in source, intermediate or object code form is hereby granted exclusively
 * under the terms of the GNU General Public License, version 2. Please see the
 * file COPYING for details, or refer to http://www.gnu.org/copyleft/gpl.html.
 *
 * History:
 * 2001/05/06 - EvB - Created
 */


/*
 * INCLUDES & DEFINES
 */


#include <sys/types.h>		/* For ssize_t */

#include <metaops.h>		/* For META, META_AV */


/* Stack machine result codes */

#define VM_CONTINUE		0
#define VM_HALTED		1
#define VM_ABORTED		2
#define VM_OVERFLOW		3
#define VM_UNDERFLOW		4
#define VM_NOMEM		5
#define VM_INVALIDOP		6
#define VM_INVALIDARG		7
#define VM_IFACETRAP		8


/* Stack machine opcodes */

/* Low nibble opcode type specifiers. Note that if any of these are different,
 * the opcode is also *called* differently, so don't misuse the type flags as 
 * some form of immediate operand!
 *
 * (bits 0-1: stack requirements)
 *   0		= nothing needed
 *   1		= fixup one
 *   2		= fixup two, discard one
 *   3		= discard one
 *
 * (bit 2: if fixup two, default list for left (2nd) arg, reserved otherwise)
 *   0		= default for left term is request list
 *   1		= default for left term is reply list
 *
 * (bit 3: reserved)
 */

#define OP_FIXCNT(opcode)	(((opcode) & 3) <= 2 ? ((opcode) & 3) : 0)
#define OP_DSCCNT(opcode)	(((opcode) >> 1) & 1)
#define OP_USEREP(opcode, arg)	(((opcode) >> 2) & ((arg) == ((opcode) & 3)))
	/* arg: l=2, r=1, so the above applies for opcode's highest arg. */

#define OP_HALT		0x00000
#define OP_ABORT	0xffff0
#define OP_ACCEPT	0xf0000
#define OP_REJECT	0xf0010
#define OP_ACCTRESP	0xf0020
#define OP_NOP		0x00010
#define OP_PUSHINT	0x00020
#define OP_PUSHSTR	0x00030
#define OP_PUSHAV	0x00040		/* ref to first/last atr from req/rep */
#define OP_POP		0x00053		/* discard */

#define OP_NEG		0x00061
#define OP_NOT		0x00071
#define OP_MUL		0x00082
#define OP_DIV		0x00092
#define OP_CIDRMASK	0x000a2		/* mask address using CIDR netmask */
#define OP_MOD		0x000b2
#define OP_ADD		0x000c2
#define OP_SUB		0x000d2
#define OP_SHL		0x000e2
#define OP_SHR		0x000f2
#define OP_XOR		0x00102
#define OP_AND		0x00112
#define OP_OR		0x00122
#define OP_GE		0x00132
#define OP_LE		0x00142
#define OP_GT		0x00152
#define OP_LT		0x00162
#define OP_EQ		0x00172
#define OP_NE		0x00182

#define OP_BF		0x00192		/* before first */
#define OP_AF		0x001a2		/* after first */
#define OP_BL		0x001b2		/* before last */
#define OP_AL		0x001c2		/* after last */
#define OP_FO		0x001d2		/* first of */
#define OP_LO		0x001e2		/* last of */
#define OP_MD5		0x001f1
#define OP_HEX		0x00201
#define OP_UPPER	0x00211
#define OP_LOWER	0x00221
#define OP_RANDOM	0x00231
#define OP_DICTENC	0x00240		/* encode rep using given dict. space */

#define OP_XORSTR	0x00262
#define OP_CONCAT	0x00272
#define OP_GESTR	0x00282
#define OP_LESTR	0x00292
#define OP_GTSTR	0x002a2
#define OP_LTSTR	0x002b2
#define OP_EQSTR	0x002c2
#define OP_NESTR	0x002d2

#define OP_OCTSTR2ORD	0x00301
#define OP_DECSTR2ORD	0x00311
#define OP_HEXSTR2ORD	0x00321
#define OP_RAWSTR2ORD	0x00331		/* binary value in network order */

#define OP_IPASTR2ORD	0x00341		/* n.n.n.n */
#define OP_DATSTR2ORD	0x00351		/* YYYYMMDDhhmmss */
#define OP_INTSTR2ORD	0x00361		/* leading 0 = oct, leading 0x = hex */

#define OP_ORD2OCTSTR	0x00381
#define OP_ORD2DECSTR	0x00391
#define OP_ORD2HEXSTR	0x003a1
#define OP_ORD2RAWSTR	0x003b1		/* binary value in network order */

#define OP_ORD2IPASTR	0x003c1		/* n.n.n.n */
#define OP_ORD2DATSTR	0x003d1		/* YYYYMMDDhhmmss */
#define OP_ORD2DFMSTR	0x003e2		/* formatted date using strftime() */
#define OP_STR2MAC	0x003f2		/* canonicalized MAC address */
#define OP_PAPDECR	0x00402		/* decrypt/encrypt with PAP method */
#define OP_PAPENCR	0x00412		/* using Secret . Authenticator */
#define OP_UNIXCRYPT	0x00422		/* unix crypt(3) using given salt */
#define OP_HMACMD5	0x00432		/* HMAC using MD5 with given key */
#define OP_DICTDEC	0x00442		/* decode using given dict. space */

#define OP_EXISTS	0x00481		/* returns 1 if resolved */
#define OP_BOOLNOT	0x00491		/* boolean not, returns 1 when false */
#define OP_JMPZ		0x004a1		/* jmp if zero (false) */
#define OP_JMPNZ	0x004b1		/* jmp if nonzero (true) */

#define OP_ADDAV	0x00506		/* add referenced AV based on term */
#define OP_REPLACEAV	0x00516		/* replace referenced AV with term */
#define OP_POKEAV	0x00526		/* poke at referenced AV's memory */
#define OP_DELAV	0x00535		/* delete referenced AV (see code) */
#define OP_DELALLAV	0x00540		/* delete all inst. of referenced AV */
#define OP_MOVEALLAV	0x00550		/* copy all inst. of referenced AV */
#define OP_JOINSTR	0x00560		/* join all inst. of referenced AV into
					   stack item */

#define OP_CALLIFACE	0x00600		/* call external interface */


/* Request and Reply list indexes for head and tail arrays */

#define VM_REQ		0
#define VM_REP		1


/*
 * TYPES
 */


typedef struct insn {
	int op;			/* Opcode */
	union {
		META_ORD ord;
		struct {
			short disp;	/* Displacement for jmpXX and pushstr */
			short str_len;	/* String length in bytes for pushstr */
		} d;
		struct {
			META_ITEM *item;
			int flags;	/* Flags for META_AV object on stack */
		} i;
		struct iface *iface;
	} imm;			/* Immediate operand */
} INSN;


typedef struct vm {
	INSN *ip, *codeend;
	META_AV *stk, *head[2], *tail[2];	/* 0 =  req, 1 = rep */
	int sp, stackend;	/* sp is index in stack array; stack grows up */
} VM;


/*
 * PROTOTYPES
 */


/* langcompile.c */
#ifdef COMP_MEM
ssize_t lang_compile(META *m, struct iface *ifaces, char *source, 
		     INSN *buf, ssize_t bufsize);
#else
struct text;

ssize_t lang_compile(META *m, struct iface *ifaces, struct text *source,
		     INSN *buf, ssize_t bufsize);
#endif

/* langdisasm.c */
void lang_disassemble(META *m, INSN *i, ssize_t bufsize);

/* langvm.c */
VM *vm_new(INSN *code, ssize_t len, int stackend, 
	   META_AV *reqhead, META_AV *reqtail, 
	   META_AV *rephead, META_AV *reptail);
void vm_chgcode(VM *vm, INSN *code, ssize_t len);
void vm_popall(VM *vm);
void vm_del(VM *vm);
int vm_run(META *m, VM *vm);
struct iface *vm_getiface(VM *vm);
void vm_dumptrace(VM *vm, META *m, INSN *codestart);
void vm_dumpstack(VM *vm, META *m);



syntax highlighted by Code2HTML, v. 0.9.1