summaryrefslogtreecommitdiff
path: root/dis.c
blob: 2939384b97cfea347218c622ed6a309c87d9eb51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "dis.h"

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

static void print_const(Chunk *ch, uint8_t ix) {
	Val k = ch->consts.d[ix];
	printf("%-4s : ", typename_str(k));
	println_val(k);
}

static void disasm_chunk_h(Chunk *ch, int depth);
void disasm_chunk(Chunk *ch) {
	disasm_chunk_h(ch, 0);
}

static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth);
size_t disasm_instr(Chunk *ch, size_t ip) {
	return disasm_instr_h(ch, ip, 0);
}


static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth) {
	size_t orig_ip = ip;
	uint8_t instr = ch->bc.d[ip];
	printf("%*s%04zd\t%3d ",depth,"",ip,instr);
	ip ++;
	switch (instr) {
	case OP_LOADK: {
		uint8_t ix = ch->bc.d[ip++];
		printf("loadk #%d\t; ",ix);
		print_const(ch, ix);
		break;
	}
	case OP_GETGLOBAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("getglobal #%d\t; ",ix);
		print_const(ch, ix);
		break;
	}
	case OP_GETLOCAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("getlocal #%d\n",ix);
		break;
	}
	case OP_SETLOCAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("setlocal #%d\n",ix);
		break;
	}
	case OP_SETGLOBAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("setglobal #%d\t; ",ix);
		print_const(ch, ix);
		break;
	}
	case OP_CALL: {
		uint8_t nargs = ch->bc.d[ip++];
		printf("call #%hhu\n",nargs);
		break;
	}
	case OP_ENDSCOPE: {
		uint8_t nlocals = ch->bc.d[ip++];
		printf("endscope #%hhu\n",nlocals);
		break;
	}
	#define RSHORT() (uint16_t)( ch->bc.d[ip-2] | ch->bc.d[ip-1] << 8 )
	case OP_SKIP: {
		ip += 2;
		uint16_t offset = RSHORT();
		printf("skip +%5hu\t; -> %04zd\n", offset, ip + offset);
		break;
	}
	case OP_0BRANCH: {
		ip += 2;
		uint16_t offset = RSHORT();
		printf("0branch +%5hu\t; -> %04zd\n", offset, ip + offset);
		break;
	}
	case OP_REDO: {
		ip += 2;
		uint16_t offset = RSHORT();
		printf("redo -%5hu\t; -> %04zd\n", offset, ip - offset);
		break;
	}
	#undef RSHORT

	#define SIMPLE_INSTR(opcode, str) \
		case opcode: puts(str); break;
	SIMPLE_INSTR(OP_RET, "ret")
	SIMPLE_INSTR(OP_DROP, "drop")
	SIMPLE_INSTR(OP_ADD, "add")
	SIMPLE_INSTR(OP_SUB, "sub")
	SIMPLE_INSTR(OP_MUL, "mul")
	SIMPLE_INSTR(OP_DIV, "div")
	SIMPLE_INSTR(OP_MOD, "mod")
	SIMPLE_INSTR(OP_NIL, "nil")
	SIMPLE_INSTR(OP_TRUE, "true")
	SIMPLE_INSTR(OP_FALSE, "false")
	SIMPLE_INSTR(OP_CMP, "cmp")
	SIMPLE_INSTR(OP_EQU, "equ")
	SIMPLE_INSTR(OP_HALT, "halt")
	SIMPLE_INSTR(OP_ARRNEW, "arrnew")
	SIMPLE_INSTR(OP_ARRAPPEND, "arrappend")
	#undef SIMPLE_INSTR

	default:
		printf("unknown opcode %d\n", instr);
		exit(2);

	}

	return ip - orig_ip;

}

static void disasm_chunk_h(Chunk *ch, int depth) {
	#define P(msg) printf("%*s%s\n",depth,"",msg);
	P("constants:");
	for (uint8_t cix = 0; cix < ch->consts.len; cix++) {
		printf("%*s%hd\t",depth,"",cix);
		print_const(ch, cix);
	}

	P("bytecode:");
	#undef P
	for (size_t ip = 0; ip < ch->bc.len; ) {
		ip += disasm_instr_h(ch, ip, depth);
	}
	printf("\n");

	for (uint8_t cix = 0; cix < ch->consts.len; cix++) {
		Val c = ch->consts.d[cix];
		if (IS_FUNC(c)) {
			printf("%*sconst %d is function:\n",depth,"", cix);
			disasm_chunk_h(&AS_FUNC(c)->ch,depth+4);
		}
	}


}