forked from proglangclass/vm
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvm.c
More file actions
160 lines (128 loc) · 3.69 KB
/
vm.c
File metadata and controls
160 lines (128 loc) · 3.69 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <stdio.h>
#include <assert.h>
#include "runtime.h"
#include "opcode.h"
// Helpers to play with the stack
#define STACK_MAX 10
#define STACK_PUSH(I) do { \
assert(sp-stack < STACK_MAX); \
*(++sp) = (I); \
retain(*sp); } while(0)
#define STACK_POP() (*sp--)
void run(long literals[], byte instructions[]) {
byte *ip = instructions; // instruction pointer
Object *stack[STACK_MAX]; // the famous stack
Object **sp = stack; // stack pointer
Object *locals[STACK_MAX] = {}; // where we store our local variables
// Setup the runtime
Object *self = Object_new();
retain(self);
// Start processing instructions
while (1) {
switch (*ip) {
case CALL:{
ip++; // move to the method literal index (1st operand)
char *method = (char *)literals[*ip];
ip++; // moving to the number of arguments (2nd operand)
int argc = *ip;
Object *argv[10]; // array of arguments
int i;
for(i = 0; i < argc; ++i) argv[i] = STACK_POP();
Object *receiver = STACK_POP();
Object *result = call(receiver, method, argv, argc);
STACK_PUSH(result);
// Release objects
for(i = 0; i < argc; ++i) release(argv[i]);
release(receiver);
break;
}
case PUSH_NUMBER:
ip++; // index of number literal
STACK_PUSH(Number_new((int)literals[*ip]));
break;
case PUSH_STRING:
ip++; // index of string literal
STACK_PUSH(String_new((char *)literals[*ip]));
break;
case PUSH_SELF:
STACK_PUSH(self);
break;
case PUSH_NIL:
STACK_PUSH(NilObject);
break;
case PUSH_BOOL:
ip++;
if (*ip == 0) {
STACK_PUSH(FalseObject);
} else {
STACK_PUSH(TrueObject);
}
break;
case GET_LOCAL:
ip++; // index of local
STACK_PUSH(locals[*ip]);
break;
case SET_LOCAL:
ip++; // index of local
locals[*ip] = STACK_POP();
break;
case ADD:{
Object *a = STACK_POP();
Object *b = STACK_POP();
STACK_PUSH(Number_new(Number_value(a) + Number_value(b)));
release(a);
release(b);
break;
}
case JUMP_UNLESS:{
ip++; // offset, nb of butes to move forward unless true on stack
byte offset = *ip;
Object *test = STACK_POP();
if (!Object_is_true(test)) ip += offset;
release(test);
break;
}
case RETURN:
goto cleanup;
}
ip++;
}
cleanup:
release(self);
int i;
for(i = 0; i < STACK_MAX; ++i) if (locals[i]) release(locals[i]);
while (sp > stack) release(STACK_POP());
}
int main (int argc, char const *argv[]) {
// long can store a pointer (and numbers too).
long literals[] = {
(long) "the answer is:",
(long) "print",
(long) 30,
(long) 2
};
// print("the answer is:")
// a = 30 + 2
// if false
// print(a)
// end
byte instructions[] = {
PUSH_SELF,
PUSH_STRING, 0, // [self, "the answer is:"]
CALL, 1, 1, // print
PUSH_NUMBER, 2, // [30]
PUSH_NUMBER, 3, // [30, 2]
ADD, // [32]
SET_LOCAL, 0, // a
PUSH_BOOL, 0, // [false]
JUMP_UNLESS, 6,
PUSH_SELF,
GET_LOCAL, 0, // [32]
CALL, 1, 1,
RETURN
};
init_runtime();
run(literals, instructions);
destroy_runtime();
return 0;
}