-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsina_interpreter.c
141 lines (124 loc) · 3.96 KB
/
sina_interpreter.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "sina_interpreter.h"
#include "sina_types.h"
#include "sinavm.h"
#include "sina_error.h"
#include <stdio.h>
void interpret_chunk(sinavm_data* vm, chunk_header* node);
void interpret_symbol(sinavm_data* vm, int symbol);
void execute_block(sinavm_data* vm, block_chunk* block);
/*
* sina_interpreter.c
*
* implements the sina interpreter. See the header file
* sina_interpreter.h for overview on how the interpreter
* works.
*/
void sina_interpret(sinavm_data* vm, block_chunk* code)
{
allocate_push_register((chunk_header*) code);
sinavm_push_front(vm->cs, (chunk_header*) code); /* invalidates code */
code = (block_chunk*) allocate_pop_register();
while ( ! sinavm_list_empty(vm->cs))
{
if (sinavm_trace_get(vm))
{
printf("-------------------------------------------------------\n");
pprint_vm_state(vm);
}
block_chunk* current_block = (block_chunk*) vm->cs->first->data;
if (NULL == current_block->current)
{
/* block is now interpreted, pop it off stack */
sinavm_pop_front(vm->cs);
}
else
{
allocate_push_register((chunk_header*) current_block);
list_node_chunk* current = current_block->current;
/* invalidates current and current_block */
interpret_chunk(vm, current->data);
current_block = (block_chunk*) allocate_pop_register();
if (sinavm_flowcontrol_get(vm))
{
/* something we executed did it's own flow control -
the vm is set to execute the correct block on next
iteration.
*/
sinavm_flowcontrol_unset(vm);
}
else
{
/* only do this, if we did not execute any flow control */
current_block->current = current_block->current->next;
}
}
}
}
void interpret_chunk(sinavm_data* vm, chunk_header* header)
{
escaped_symbol_chunk* esym = NULL;
symbol_chunk* symbol = NULL;
native_chunk* native = NULL;
if (sinavm_trace_get(vm))
{
printf("interpret_chunk: interpreting ");
pprint(header); printf(" ds="); pprint(vm->ds);
printf("\n");
}
switch (header->type)
{
case INTEGER_CHUNK:
case LIST_HEAD_CHUNK:
sinavm_push_front(vm->ds, header); /* invalidates header */
break;
case BLOCK_CHUNK:
/* push block onto ds, to execute a block_chunk: use 'call' or
* bind symbol
*/
sinavm_push_front(vm->ds, header); /* invalidates header */
break;
case ESCAPED_SYMBOL_CHUNK:
/* push symbol onto DS */
esym = (escaped_symbol_chunk*) header;
symbol = sinavm_new_symbol(esym->symbol); /* invalidates header */
sinavm_push_front(vm->ds, (chunk_header*) symbol);
break;
case SYMBOL_CHUNK:
symbol = (symbol_chunk*) header;
sina_interpret_symbol(vm, symbol->symbol);
break;
case NATIVE_CHUNK:
native = (native_chunk*) header;
native->func(vm);
break;
default:
printf("interpret_chunk: unknown type=%s, colour=%s\n",
header->type, header->colour);
error_exit("cannot interpret chunk with unknown type.");
}
if (sinavm_trace_get(vm))
{
printf("interpret_chunk: done.\n");
pprint(vm->ds); printf("\n:)%d\n", sinavm_list_empty(vm->cs));
}
}
/* symbols need to be interpreted specially (see sina_interpreter.h) */
void sina_interpret_symbol(sinavm_data* vm, int symbol)
{
chunk_header* header = sinavm_dereference_symbol(vm, symbol);
if (NULL == header)
{
error_exit("cannot interpret unbound symbol");
}
else
{
if (BLOCK_CHUNK == header->type)
{
sinavm_execute_block(vm, (block_chunk*) header);
}
else
{
interpret_chunk(vm, header);
}
}
}