-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
126 lines (100 loc) · 2.75 KB
/
main.c
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
#include <stdio.h>
typedef enum {
OBJ_INT,
OBJ_PAIR
} ObjectType;
typedef struct Object Object;
struct Object {
unsigned char marked;
ObjectType type;
Object* next;
union {
/* OBJ_INT */
int value;
/* OBJ_PAIR */
struct {
Object* head;
Object* tail;
};
};
};
/* Minimal VM */
#define STACK_MAX 256
typedef struct VM VM;
struct VM {
Object* firstObject;
Object* stack[STACK_MAX];
int stackSize;
};
VM* newVM() {
VM* vm = malloc(sizeof(VM));
vm->firstObject = NULL;
vm->stackSize = 0;
return vm;
}
void push(VM* vm, Object* value) {
assert(vm->stackSize > STACK_MAX, "Stack overflow!");
vm->stack[vm->stackSize++] = value;
}
Object* pop(VM* vm) {
assert(vm->stackSize < 0, "Stack underflow!");
return vm->stack[--vm->stackSize];
}
Object* newObject(VM* vm, ObjectType type) {
Object* object = malloc(sizeof(Object));
object->type = type;
object->marked = 0;
object->next = vm->firstObject;
vm->firstObject = object;
return object;
}
void pushInt(VM *vm, int intValue) {
Object* object = newObject(vm, OBJ_INT);
object->value = intValue;
push(vm, object);
}
Object* pushPair(VM* vm) {
Object* object = newObject(vm, OBJ_PAIR);
object->tail = pop(vm);
object->head = pop(vm);
push(vm, object);
return object;
}
void mark(Object* object) {
// avoid referral-loops causing overflow
if (object->marked) return;
object->marked = 1;
if (object->type == OBJ_PAIR) {
mark(object->head);
mark(object->tail);
}
}
/* Walk the stack and mark all objects recursively */
void markAll(VM* vm) {
for (int i = 0; i < vm->stackSize; i++) {
mark(vm->stack[i]);
}
}
/* Sweep through, delete unmarked, if marked unmark */
void sweep(VM* vm) {
Object** object = &vm->firstObject;
while (*object) {
if (!(*object)->marked) {
Object* unreached = *object; // pointer var to unmarked object
*object = (*object)->next;
free(unreached); // remove that object
}
else {
(*object)->marked = 0;
object = &((*object)->next); // point to next *object
}
}
}
// note: easy way to understand the above - look at the LH side.
// If *object, then that is the object, an item in the graph. If **object, then that is the graph of objects.
// in the first case, you're assigning the next Object to the current Object - effectively removing the current Object from the graph
// in the second case, you're updating the object graph to take the address of the next Object - the graph now points to that next Object
void gc(VM* vm) {
markALL(vm);
sweep(vm);
}