vm.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /**
  2. ******************************************************************************
  3. * @file : vm.c
  4. * @author : simon
  5. * @brief : Interpret the bytecode from chunk
  6. * @attention : None
  7. * @date : 2023/8/17
  8. ******************************************************************************
  9. */
  10. #include "vm.h"
  11. #include "common.h"
  12. #include "compiler.h"
  13. #include "debug.h"
  14. #include "memory.h"
  15. #include <stdarg.h>
  16. VM vm;
  17. /// \brief 重置栈
  18. static void resetStack() {
  19. vm.stackTop = vm.stack;// 指针指向栈底
  20. }
  21. static void runtimeError(const char *format, ...) {
  22. va_list args;
  23. va_start(args, format);
  24. vfprintf(stderr, format, args);
  25. va_end(args);
  26. fputs("\n", stderr);
  27. size_t instruction = vm.ip - vm.chunk->code - 1;
  28. int line = vm.chunk->lines[instruction];
  29. fprintf(stderr, "[line %d] in script\n", line);
  30. resetStack();
  31. }
  32. void initVM() {
  33. resetStack();
  34. vm.objects = NULL;
  35. initTable(&vm.globals);
  36. initTable(&vm.strings);
  37. }
  38. static Value peek(int distance) {
  39. return vm.stackTop[-1 - distance];
  40. }
  41. static bool isFalse(Value value) {
  42. // the nil and false will return true
  43. return IS_NIL(value) || (IS_BOOL(value) && !AS_BOOL(value));
  44. }
  45. static void concatenate() {
  46. ObjString *b = AS_STRING(pop());
  47. ObjString *a = AS_STRING(pop());
  48. int length = a->length + b->length;
  49. char *chars = ALLOCATE(char, length + 1);
  50. memcpy(chars, a->chars, a->length);
  51. memcpy(chars + a->length, b->chars, b->length);
  52. chars[length] = '\0';
  53. ObjString *result = takeString(chars, length);
  54. push(OBJ_VAL(result));
  55. }
  56. static InterpretResult run() {
  57. //! <macro> reads the byte currently pointed at by ip
  58. //! and then advances the instruction pointer
  59. #define READ_BYTE() (*vm.ip++)
  60. //! reads the next byte from the bytecode
  61. //! treats the resulting number as an index
  62. #define READ_CONSTANT() (vm.chunk->constants.values[READ_BYTE()])
  63. #define READ_SHORT() \
  64. (vm.ip += 2, (uint16_t) ((vm.ip[-2] << 8) | vm.ip[-1]))
  65. #define READ_STRING() AS_STRING(READ_CONSTANT())
  66. #define BINARY_OP(valueType, op) \
  67. do { \
  68. if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \
  69. runtimeError("Operands must be numbers."); \
  70. return INTERPRET_RUNTIME_ERROR; \
  71. } \
  72. double b = AS_NUMBER(pop()); \
  73. double a = AS_NUMBER(pop()); \
  74. push(valueType(a op b)); \
  75. } while (false)
  76. #ifdef DEBUG_TRACE_EXECUTION
  77. printf("!!! <Stack tracing> start\n");
  78. #endif
  79. for (;;) {
  80. #ifdef DEBUG_TRACE_EXECUTION
  81. //! <Stack tracing> start
  82. printf("------------------------\n|");
  83. for (Value *slot = vm.stack; slot < vm.stackTop; slot++) {
  84. printf("[ ");
  85. printValue(*slot);
  86. printf(" ]");
  87. }
  88. printf("\n------------------------");
  89. printf("\n");
  90. //! <Stack tracing> end
  91. disassembleInstruction(vm.chunk, (int) (vm.ip - vm.chunk->code));
  92. #endif
  93. switch (READ_BYTE()) {
  94. case OP_CONSTANT: {
  95. Value constant = READ_CONSTANT();
  96. push(constant);
  97. break;
  98. }
  99. case OP_NIL:
  100. push(NIL_VAL);
  101. break;
  102. case OP_TRUE:
  103. push(BOOL_VAL(true));
  104. break;
  105. case OP_FALSE:
  106. push(BOOL_VAL(false));
  107. break;
  108. case OP_POP:
  109. pop();
  110. break;
  111. case OP_DEFINE_GLOBAL: {
  112. ObjString *name = READ_STRING();
  113. tableSet(&vm.globals, name, peek(0));
  114. pop();
  115. break;
  116. }
  117. case OP_GET_GLOBAL: {
  118. ObjString *name = READ_STRING();
  119. Value value;
  120. if (!tableGet(&vm.globals, name, &value)) {
  121. runtimeError("Undefined variable '%s'.", name->chars);
  122. return INTERPRET_RUNTIME_ERROR;
  123. }
  124. push(value);
  125. break;
  126. }
  127. case OP_SET_GLOBAL: {
  128. ObjString *name = READ_STRING();
  129. if (tableSet(&vm.globals, name, peek(0))) {
  130. tableDelete(&vm.globals, name);
  131. runtimeError("Undefined variable '%s'.", name->chars);
  132. return INTERPRET_RUNTIME_ERROR;
  133. }
  134. break;
  135. }
  136. case OP_GET_LOCAL: {
  137. uint8_t slot = READ_BYTE();
  138. push(vm.stack[slot]);
  139. break;
  140. }
  141. case OP_SET_LOCAL: {
  142. uint8_t slot = READ_BYTE();
  143. vm.stack[slot] = peek(0);
  144. break;
  145. }
  146. case OP_ADD: {
  147. if (IS_STRING(peek(0)) && IS_STRING(peek(1))) {
  148. // 字串拼接
  149. concatenate();
  150. } else if (IS_NUMBER(peek(0)) && IS_NUMBER(peek(1))) {
  151. double b = AS_NUMBER(pop());
  152. double a = AS_NUMBER(pop());
  153. push(NUMBER_VAL(a + b));
  154. } else {
  155. runtimeError("Operands must be two numbers or two strings.");
  156. return INTERPRET_RUNTIME_ERROR;
  157. }
  158. break;
  159. }
  160. case OP_SUBTRACT:
  161. BINARY_OP(NUMBER_VAL, -);
  162. break;
  163. case OP_MULTIPLY:
  164. BINARY_OP(NUMBER_VAL, *);
  165. break;
  166. case OP_DIVIDE:
  167. BINARY_OP(NUMBER_VAL, /);
  168. break;
  169. case OP_NOT:
  170. push(BOOL_VAL(isFalse(pop())));
  171. break;
  172. case OP_NEGATE:
  173. if (!IS_NUMBER(peek(0))) {
  174. runtimeError("Operand must be a number.");
  175. return INTERPRET_RUNTIME_ERROR;
  176. }
  177. push(NUMBER_VAL(-AS_NUMBER(pop())));
  178. break;
  179. case OP_EQUAL: {
  180. Value b = pop();
  181. Value a = pop();
  182. push(BOOL_VAL(valuesEqual(a, b)));
  183. break;
  184. }
  185. case OP_GREATER:
  186. BINARY_OP(BOOL_VAL, >);
  187. break;
  188. case OP_LESS:
  189. BINARY_OP(BOOL_VAL, <);
  190. break;
  191. case OP_PRINT: {
  192. printValue(pop());
  193. printf("\n");
  194. break;
  195. }
  196. case OP_JUMP_IF_FALSE: {
  197. uint16_t offset = READ_SHORT();
  198. if (isFalse(peek(0))) vm.ip += offset;
  199. break;
  200. }
  201. case OP_JUMP: {
  202. uint16_t offset = READ_SHORT();
  203. vm.ip += offset;
  204. break;
  205. }
  206. case OP_RETURN: {
  207. // Exit interpreter.
  208. return INTERPRET_OK;
  209. }
  210. }
  211. #ifdef DEBUG_TRACE_EXECUTION
  212. printf("!!! <Stack tracing> end\n");
  213. #endif
  214. }
  215. #undef READ_BYTE
  216. #undef READ_CONSTANT
  217. #undef READ_SHORT
  218. #undef READ_STRING
  219. #undef BINARY_OP
  220. }
  221. void freeVM() {
  222. freeTable(&vm.globals);
  223. freeTable(&vm.strings);
  224. freeObjects();
  225. }
  226. InterpretResult interpret(const char *source) {
  227. Chunk chunk;
  228. initChunk(&chunk);
  229. if (!compile(source, &chunk)) {
  230. freeChunk(&chunk);
  231. return INTERPRET_COMPILE_ERROR;
  232. }
  233. vm.chunk = &chunk;
  234. vm.ip = vm.chunk->code;
  235. InterpretResult result = run();
  236. freeChunk(&chunk);
  237. return result;
  238. }
  239. void push(Value value) {
  240. *vm.stackTop = value;
  241. vm.stackTop++;
  242. }
  243. Value pop() {
  244. vm.stackTop--;
  245. //! NOTE: 出栈后,里面的值没有清除
  246. return *vm.stackTop;
  247. }