-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstack-vm.c
More file actions
636 lines (568 loc) · 23.2 KB
/
stack-vm.c
File metadata and controls
636 lines (568 loc) · 23.2 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "stack-vm.h"
// --------------- 常量定义 ---------------
#define MAX_PROPS 64 // 每个对象的最大属性数
#define MAX_VARS 32 // 每个环境的最大变量数
// --------------- 函数原型声明 ---------------
void val_free(Value v);
// --------------- 内存管理工具函数 ---------------
// 创建对象头
ObjectHeader* create_object(ValueType type, size_t size) {
ObjectHeader* obj = malloc(size);
if (!obj) {
fprintf(stderr, "内存分配失败!\n");
exit(1);
}
obj->ref_count = 1;
obj->type = type;
return obj;
}
// 增加引用计数
void gc_inc_ref(ObjectHeader* obj) {
if (obj) obj->ref_count++;
}
// 减少引用计数,如果引用为0则释放
void gc_dec_ref(ObjectHeader* obj) {
if (!obj) return;
if (--obj->ref_count == 0) {
switch (obj->type) {
case VAL_STRING: {
StringObject* str_obj = (StringObject*)obj;
free(str_obj->chars);
break;
}
case VAL_OBJECT: {
Object* obj_obj = (Object*)obj;
for (int i = 0; i < obj_obj->property_count; i++) {
free(obj_obj->prop_names[i]);
val_free(obj_obj->prop_values[i]);
}
free(obj_obj->prop_names);
free(obj_obj->prop_values);
break;
}
default:
break;
}
free(obj);
}
}
// --------------- 工具函数(类型创建/销毁、变量查找)---------------
Value val_number(double num) {
Value v = {.type = VAL_NUMBER};
v.data.number = num;
return v;
}
Value val_boolean(bool b) {
Value v = {.type = VAL_BOOLEAN};
v.data.boolean = b;
return v;
}
Value val_undefined() {
Value v = {.type = VAL_UNDEFINED};
return v;
}
Value val_null() {
Value v = {.type = VAL_NULL};
return v;
}
Value val_string(const char* str) {
Value v = {.type = VAL_STRING};
size_t len = strlen(str);
StringObject* str_obj = (StringObject*)create_object(VAL_STRING, sizeof(StringObject));
str_obj->length = len;
str_obj->chars = malloc(len + 1);
strcpy(str_obj->chars, str);
v.data.obj = (ObjectHeader*)str_obj;
return v;
}
// 创建一个新对象
Value val_object() {
Value v = {.type = VAL_OBJECT};
Object* obj = (Object*)create_object(VAL_OBJECT, sizeof(Object));
obj->property_count = 0;
obj->prop_names = NULL;
obj->prop_values = NULL;
v.data.obj = (ObjectHeader*)obj;
return v;
}
// 释放值
void val_free(Value v) {
switch (v.type) {
case VAL_STRING:
case VAL_OBJECT:
gc_dec_ref(v.data.obj);
break;
default:
break;
}
}
// 查找变量(沿作用域链查找,不存在返回undefined)
Value env_get(Env* env, const char* name) {
Env* current = env;
while (current != NULL) {
for (int i = 0; i < current->var_count; i++) {
if (strcmp(current->names[i], name) == 0) {
Value val = current->values[i];
// 增加引用计数,因为返回的是新的引用
if (val.type == VAL_STRING || val.type == VAL_OBJECT) {
gc_inc_ref(val.data.obj);
}
return val;
}
}
current = current->parent; // 继续查找父环境
}
return val_undefined();
}
// 存储变量(只在当前环境中设置,已存在则覆盖,不存在则新增)
void env_set(Env* env, const char* name, Value val) {
for (int i = 0; i < env->var_count; i++) {
if (strcmp(env->names[i], name) == 0) {
val_free(env->values[i]); // 释放旧值
// 增加新值的引用计数,因为它被环境持有
if (val.type == VAL_STRING || val.type == VAL_OBJECT) {
gc_inc_ref(val.data.obj);
}
env->values[i] = val;
return;
}
}
if (env->var_count >= MAX_VARS) {
fprintf(stderr, "变量数量超限!\n");
exit(1);
}
env->names[env->var_count] = strdup(name);
// 增加引用计数,因为它被环境持有
if (val.type == VAL_STRING || val.type == VAL_OBJECT) {
gc_inc_ref(val.data.obj);
}
env->values[env->var_count] = val;
env->var_count++;
}
// --------------- 虚拟机核心操作 ---------------
// 创建新环境
Env* create_env(Env* parent) {
Env* env = malloc(sizeof(Env));
if (!env) {
fprintf(stderr, "内存分配失败!\n");
exit(1);
}
env->var_count = 0;
env->parent = parent;
return env;
}
// 释放环境
void free_env(Env* env) {
for (int i = 0; i < env->var_count; i++) {
free(env->names[i]);
val_free(env->values[i]);
}
free(env);
}
void vm_init(StackVM* vm) {
vm->sp = 0;
vm->call_sp = 0;
vm->current_env = create_env(NULL); // 创建全局环境
}
void vm_push(StackVM* vm, Value val) {
if (vm->sp >= 64) {fprintf(stderr, "栈溢出!\n"); exit(1);}
// 增加引用计数,因为值现在被栈持有
if (val.type == VAL_STRING || val.type == VAL_OBJECT) {
gc_inc_ref(val.data.obj);
}
vm->stack[vm->sp++] = val;
}
Value vm_pop(StackVM* vm) {
if (vm->sp <= 0) {fprintf(stderr, "栈下溢!\n"); exit(1);}
return vm->stack[--vm->sp];
}
// 直接从栈中弹出并释放值(用于不需要返回值的情况)
void vm_pop_free(StackVM* vm) {
Value val = vm_pop(vm);
val_free(val);
}
// 函数调用:保存当前 ip 到调用栈,跳转到函数起始位置
void vm_call(StackVM* vm, int func_ip) {
if (vm->call_sp >= 16) {fprintf(stderr, "调用栈溢出!\n"); exit(1);}
vm->call_stack[vm->call_sp++] = func_ip;
}
// 函数返回:从调用栈恢复 ip
int vm_ret(StackVM* vm) {
if (vm->call_sp <= 0) {fprintf(stderr, "无函数可返回!\n"); exit(1);}
return vm->call_stack[--vm->call_sp];
}
// --------------- 解释器(支持多类型运算、变量、函数)---------------
void vm_execute(StackVM* vm, const uint8_t* bytecode, int len) {
int ip = 0;
while (ip < len) {
OpCode op = (OpCode)bytecode[ip++];
switch (op) {
// 压入数值:后续 8 字节为 double
case OP_PUSH_NUM: {
double num;
memcpy(&num, &bytecode[ip], sizeof(double));
vm_push(vm, val_number(num));
ip += sizeof(double);
break;
}
// 压入字符串:1字节长度 + N字节字符串
case OP_PUSH_STR: {
uint8_t str_len = bytecode[ip++];
char str[str_len + 1];
memcpy(str, &bytecode[ip], str_len);
str[str_len] = '\0';
vm_push(vm, val_string(str));
ip += str_len;
break;
}
// 压入布尔值:后续1字节表示布尔值
case OP_PUSH_BOOL: {
bool b = bytecode[ip++];
vm_push(vm, val_boolean(b));
break;
}
// 压入undefined
case OP_PUSH_UNDEFINED: {
vm_push(vm, val_undefined());
break;
}
// 压入null
case OP_PUSH_NULL: {
vm_push(vm, val_null());
break;
}
// 创建新对象
case OP_NEW_OBJECT: {
vm_push(vm, val_object());
break;
}
// 设置对象属性:栈顶是值,栈次顶是对象,后续是属性名
case OP_SET_PROP: {
// 读取属性名
uint8_t prop_len = bytecode[ip++];
char prop_name[prop_len + 1];
memcpy(prop_name, &bytecode[ip], prop_len);
prop_name[prop_len] = '\0';
ip += prop_len;
// 弹出栈顶值(属性值)和对象
Value value = vm_pop(vm);
Value obj_val = vm_pop(vm);
if (obj_val.type != VAL_OBJECT) {
fprintf(stderr, "设置属性的目标不是对象!\n");
exit(1);
}
Object* obj = (Object*)obj_val.data.obj;
// 查找属性是否已存在
int index = -1;
for (int i = 0; i < obj->property_count; i++) {
if (strcmp(obj->prop_names[i], prop_name) == 0) {
index = i;
break;
}
}
if (index == -1) {
// 添加新属性
if (obj->property_count >= MAX_PROPS) {
fprintf(stderr, "对象属性数量超限!\n");
exit(1);
}
obj->prop_names = realloc(obj->prop_names, (obj->property_count + 1) * sizeof(uint8_t*));
obj->prop_values = realloc(obj->prop_values, (obj->property_count + 1) * sizeof(Value));
obj->prop_names[obj->property_count] = strdup(prop_name);
// 增加引用计数,因为对象现在持有这个值
if (value.type == VAL_STRING || value.type == VAL_OBJECT) {
gc_inc_ref(value.data.obj);
}
obj->prop_values[obj->property_count] = value;
obj->property_count++;
} else {
// 更新现有属性
// 先释放旧值
val_free(obj->prop_values[index]);
// 增加新值的引用计数
if (value.type == VAL_STRING || value.type == VAL_OBJECT) {
gc_inc_ref(value.data.obj);
}
obj->prop_values[index] = value;
}
// 将对象重新压回栈顶
vm_push(vm, obj_val);
break;
}
// 获取对象属性:栈顶是对象,后续是属性名
case OP_GET_PROP: {
// 读取属性名
uint8_t prop_len = bytecode[ip++];
char prop_name[prop_len + 1];
memcpy(prop_name, &bytecode[ip], prop_len);
prop_name[prop_len] = '\0';
ip += prop_len;
// 弹出栈顶对象
Value obj_val = vm_pop(vm);
if (obj_val.type != VAL_OBJECT) {
fprintf(stderr, "获取属性的目标不是对象!\n");
exit(1);
}
Object* obj = (Object*)obj_val.data.obj;
// 查找属性
Value result = val_undefined();
for (int i = 0; i < obj->property_count; i++) {
if (strcmp(obj->prop_names[i], prop_name) == 0) {
result = obj->prop_values[i];
// 增加引用计数,因为我们将返回这个值的引用
if (result.type == VAL_STRING || result.type == VAL_OBJECT) {
gc_inc_ref(result.data.obj);
}
break;
}
}
// 将对象重新压回栈顶,保持引用计数平衡
vm_push(vm, obj_val);
// 将属性值压入栈顶
vm_push(vm, result);
break;
}
// 压入变量:1字节长度 + N字节变量名
case OP_PUSH_VAR: {
uint8_t name_len = bytecode[ip++];
char name[name_len + 1];
memcpy(name, &bytecode[ip], name_len);
name[name_len] = '\0';
Value val = env_get(vm->current_env, name);
if (val.type == VAL_UNDEFINED) {
fprintf(stderr, "未定义变量:%s\n", name);
exit(1);
}
vm_push(vm, val);
ip += name_len;
break;
}
// 存储变量:栈顶值 → 变量(变量名在栈顶值之后)
case OP_STORE_VAR: {
uint8_t name_len = bytecode[ip++];
char name[name_len + 1];
memcpy(name, &bytecode[ip], name_len);
name[name_len] = '\0';
Value val = vm_pop(vm);
env_set(vm->current_env, name, val);
ip += name_len;
break;
}
// 创建新作用域
case OP_PUSH_ENV: {
// 创建新环境,将当前环境作为父环境
vm->current_env = create_env(vm->current_env);
break;
}
// 退出当前作用域
case OP_POP_ENV: {
Env *old_env = vm->current_env;
vm->current_env = vm->current_env->parent;
// 释放当前环境
free_env(old_env);
break;
}
// 加法:支持数值+数值、字符串+字符串、字符串+数值(类似 JS 隐式转换)
case OP_ADD: {
Value b = vm_pop(vm);
Value a = vm_pop(vm);
if (a.type == VAL_NUMBER && b.type == VAL_NUMBER) {
vm_push(vm, val_number(a.data.number + b.data.number));
} else if (a.type == VAL_STRING || b.type == VAL_STRING) {
// 任何一方为字符串,都将另一方转换为字符串后拼接
char* str_a;
size_t len_a;
char* str_b;
size_t len_b;
// 转换a为字符串
if (a.type == VAL_STRING) {
StringObject* sobj_a = (StringObject*)a.data.obj;
len_a = sobj_a->length;
str_a = sobj_a->chars;
} else if (a.type == VAL_NUMBER) {
char num_str[32];
sprintf(num_str, "%.2f", a.data.number);
len_a = strlen(num_str);
str_a = num_str;
} else if (a.type == VAL_BOOLEAN) {
str_a = a.data.boolean ? "true" : "false";
len_a = strlen(str_a);
} else if (a.type == VAL_UNDEFINED) {
str_a = "undefined";
len_a = strlen(str_a);
} else if (a.type == VAL_NULL) {
str_a = "null";
len_a = strlen(str_a);
} else {
str_a = "[object Object]";
len_a = strlen(str_a);
}
// 转换b为字符串
if (b.type == VAL_STRING) {
StringObject* sobj_b = (StringObject*)b.data.obj;
len_b = sobj_b->length;
str_b = sobj_b->chars;
} else if (b.type == VAL_NUMBER) {
char num_str[32];
sprintf(num_str, "%.2f", b.data.number);
len_b = strlen(num_str);
str_b = num_str;
} else if (b.type == VAL_BOOLEAN) {
str_b = b.data.boolean ? "true" : "false";
len_b = strlen(str_b);
} else if (b.type == VAL_UNDEFINED) {
str_b = "undefined";
len_b = strlen(str_b);
} else if (b.type == VAL_NULL) {
str_b = "null";
len_b = strlen(str_b);
} else {
str_b = "[object Object]";
len_b = strlen(str_b);
}
// 拼接字符串
size_t total_len = len_a + len_b;
char* new_chars = malloc(total_len + 1);
strcpy(new_chars, str_a);
strcat(new_chars, str_b);
// 创建新字符串对象
StringObject* new_str = (StringObject*)create_object(VAL_STRING, sizeof(StringObject));
new_str->length = total_len;
new_str->chars = new_chars;
Value res = {.type = VAL_STRING, .data.obj = (ObjectHeader*)new_str};
vm_push(vm, res);
} else {
fprintf(stderr, "不支持的加法类型!\n");
exit(1);
}
val_free(a);
val_free(b);
break;
}
// 函数调用:后续 4 字节为函数起始指令偏移(小端)
case OP_CALL: {
int func_offset;
memcpy(&func_offset, &bytecode[ip + 1], sizeof(int));
ip += sizeof(int) + 1; // +1 是跳过 OP_CALL 指令本身
vm_call(vm, ip); // 保存当前 ip(函数执行完后返回此处)
ip = func_offset; // 跳转到函数起始位置
break;
}
// 函数返回:恢复 ip 到调用前位置,保持返回值在栈上
case OP_RET: {
ip = vm_ret(vm);
break;
}
// 打印:支持多类型输出和多个参数
case OP_PRINT: {
// 读取参数数量
uint8_t arg_count = bytecode[ip++];
// ip++ 是因为参数数量占用一个字节
// 从栈中弹出所有参数(注意顺序是倒序)
Value* args = malloc(sizeof(Value) * arg_count);
for (int i = arg_count - 1; i >= 0; i--) {
args[i] = vm_pop(vm);
}
// 打印所有参数
printf("输出:");
for (int i = 0; i < arg_count; i++) {
Value val = args[i];
switch (val.type) {
case VAL_NUMBER:
printf("%g", val.data.number);
break;
case VAL_STRING: {
StringObject* str_obj = (StringObject*)val.data.obj;
printf("%s", str_obj->chars);
break;
}
case VAL_BOOLEAN:
printf("%s", val.data.boolean ? "true" : "false");
break;
case VAL_UNDEFINED:
printf("undefined");
break;
case VAL_NULL:
printf("null");
break;
case VAL_OBJECT:
printf("[object Object]");
break;
default:
printf("未知类型");
break;
}
// 在参数之间添加空格(如果不是最后一个参数)
if (i < arg_count - 1) {
printf(" ");
}
}
// 打印换行符
printf("\n");
// 释放参数占用的内存
for (int i = 0; i < arg_count; i++) {
val_free(args[i]);
}
free(args);
break;
}
case OP_EXIT:
return;
default:
fprintf(stderr, "未知指令:%d\n", op);
exit(1);
}
}
}
// 测试:执行「变量赋值 + 函数调用 + 字符串拼接 + 数值运算 + 新类型测试」
#ifndef COMPILER_TEST
int main() {
StackVM vm;
vm_init(&vm);
// 测试作用域功能
uint8_t bytecode[] = {
// 全局作用域:定义全局变量
OP_PUSH_STR, 4, 'x','=','1','0', // 压入字符串 "10"
OP_STORE_VAR, 1, 'x', // 存储到全局变量 x = "10"
OP_PUSH_STR, 8,'s','=','g','l','o','b','a','l', // 压入字符串 "global"
OP_STORE_VAR, 1, 's', // 存储到全局变量 s = "global"
// 打印全局变量
OP_PUSH_VAR, 1, 'x', // 加载全局变量 x
OP_PRINT, // 打印 x (预期: 10)
OP_PUSH_VAR, 1, 's', // 加载全局变量 s
OP_PRINT, // 打印 s (预期: global)
// 创建局部作用域
OP_PUSH_ENV, // 进入局部作用域
// 局部作用域:定义局部变量,覆盖全局变量
OP_PUSH_STR, 4, 'x','=','2','0', // 压入字符串 "20"
OP_STORE_VAR, 1, 'x', // 存储到局部变量 x = "20"
OP_PUSH_STR, 7, 'y', '=','l','o','c','a','l', // 压入字符串 "local"
OP_STORE_VAR, 1, 'y', // 存储到局部变量 y = "local"
// 打印局部变量和全局变量
OP_PUSH_VAR, 1, 'x', // 加载局部变量 x
OP_PRINT, // 打印 x (预期: 20)
OP_PUSH_VAR, 1, 'y', // 加载局部变量 y
OP_PRINT, // 打印 y (预期: local)
OP_PUSH_VAR, 1, 's', // 加载全局变量 s (从作用域链查找)
OP_PRINT, // 打印 s (预期: global)
// 退出局部作用域
OP_POP_ENV, // 退出局部作用域
// 验证变量恢复到全局作用域
OP_PUSH_VAR, 1, 'x', // 加载全局变量 x
OP_PRINT, // 打印 x (预期: 10)
// 验证局部变量y已不存在
OP_PUSH_VAR, 1, 'y', // 尝试加载局部变量 y
OP_PRINT, // 这里应该报错,因为y已不存在
OP_EXIT // 退出程序
};
vm_execute(&vm, bytecode, sizeof(bytecode));
// 释放全局环境内存
free_env(vm.current_env);
return 0;
}
#endif