/* RAR-VM assembler/disassembler by pancake for rizin with love */
/* this implementation is licensed under LGPLv3 - 2012 */

#include <stdio.h>
#include <string.h>

// XXX little endian only?

/* helpers */
#define eprintf(x, ...) fprintf(stderr, x, ##__VA_ARGS__)
#define SKIPSPACES(x) \
	if (x) \
		while (*x == ' ' || *x == '\t') \
	x++
static const char *skipspaces(const char *x) {
	SKIPSPACES(x);
	return x;
}
//static const char *regs = "r0\x00r1\x00r2\x00r3\x00r4\x00r5\x00r6\x00r7";
//static const char *getregi(int n) { return (n>=0&&n<=7)? regs+(3*n): "r?"; }
static int getreg(const char *s) {
	if (s[0] == 'r' && s[2] == '\0') {
		int n = s[1] - '0';
		if (n < 8)
			return n;
	}
	return -1;
}

// ugly global vars
typedef struct {
	int bits;
	unsigned char *out;
} Bitbuf;

//static void clrbit(Bitbuf *bb) { memset (bb->out, 0, 1+(bb->bits/8)); }

static int bitget(Bitbuf *bb, int bit) {
	if (bit >= bb->bits)
		return -1;
	return (bb->out[bit / 8] & (1 << ((bit % 8)))) ? 1 : 0;
}

static void bitadd(Bitbuf *bb, unsigned int v, int n) {
	int i, b, bit;
	for (i = 0; i < n; i++, bb->bits++) {
		b = (bb->bits + i) / 8;
		bit = (bb->bits + i) % 8;
		//printf ("[%d].%d = %d\n", b, bit, v& (1<<(n-i-1)));
		if (!bit)
			bb->out[b] = 0;
		//printf ("BIT (%d)\n", n-i-1);
		//if (v&(1<<(n-i-1))) bb->out[b] |= 1<<bit;
		if (v & (1 << (n - i - 1)))
			bb->out[b] |= 1 << bit;
		//	printf ("%d", oz);
	}
	//printf ("\n");
}

#define T_BYTE (1 << 2)
#define T_JUMP (1 << 3)
#define T_PROC (1 << 4)

#define NOPS 53
static struct {
	const char *name;
	int flags;
} opcodes[NOPS] = {
	{ "mov", 3 | T_BYTE },
	{ "cmp", 3 | T_BYTE },
	{ "add", 3 | T_BYTE },
	{ "sub", 1 | T_BYTE },
	{ "jz", 1 | T_JUMP },
	{ "jnz", 1 | T_JUMP },
	{ "inc", 1 | T_BYTE },
	{ "dec", 1 | T_BYTE },
	{ "jmp", 1 | T_JUMP },
	{ "xor", 3 | T_BYTE },
	{ "and", 3 | T_BYTE },
	{ "or", 3 | T_BYTE },
	{ "test", 3 | T_BYTE },
	{ "js", 1 | T_JUMP },
	{ "jb", 1 | T_JUMP },
	{ "jbe", 1 | T_JUMP },
	{ "ja", 1 | T_JUMP },
	{ "jae", 1 | T_JUMP },
	{ "push", 1 },
	{ "pop", 1 },
	{ "call", 1 | T_PROC },
	{ "ret", T_PROC },
	{ "not", 1 | T_BYTE },
	{ "shl", 3 | T_BYTE },
	{ "shr", 3 | T_BYTE },
	{ "sar", 3 | T_BYTE },
	{ "neg", 1 | T_BYTE },
	{ "pusha", 0 },
	{ "popa", 0 },
	{ "pushf", 0 },
	{ "popf", 0 },
	{ "movzx", 3 },
	{ "movsx", 3 },
	{ "xchg", 3 | T_BYTE },
	{ "mul", 3 | T_BYTE },
	{ "div", 3 | T_BYTE },
	{ "adc", 3 | T_BYTE },
	{ "sbb", 3 | T_BYTE },
	{ "print", 0 },
	{ "movb", 0 },
	{ "movd", 0 },
	{ "cmpb", 0 },
	{ "cmpd", 0 },
	{ "addb", 0 },
	{ "addd", 0 },
	{ "subb", 0 },
	{ "subd", 0 },
	{ "incb", 0 },
	{ "incd", 0 },
	{ "decb", 0 },
	{ "decd", 0 },
	{ "negb", 0 },
	{ "negd", 0 },
};

#if 0
static int bitnum (Bitbuf *bb, int n, int c) {
	int i, ret = 0;
	if (n<bb->bits)
		for (i=0; i<c; i++)
			if (bitget (bb, n+i)>0)
				ret |= (1<<i);
	return ret;
}
#else
static int bitnum(Bitbuf *bb, int n, int c) {
	int i, ret = 0;
	if (n < bb->bits)
		for (i = 0; i < c; i++)
			if (bitget(bb, n + i) > 0)
				ret |= (1 << (c - i - 1));
	return ret;
}

#endif
static inline const char *opcode_str(int n) {
	if (n >= 0 && n < NOPS)
		return opcodes[n].name;
	return NULL;
}
static inline int opcode_num(const char *s) {
	int i;
	for (i = 0; opcodes[i].name; i++)
		if (!strcmp(s, opcodes[i].name))
			return i;
	return -1;
}
