vm.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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_STRING() AS_STRING(READ_CONSTANT())
  64. #define BINARY_OP(valueType, op) \
  65. do { \
  66. if (!IS_NUMBER(peek(0)) || !IS_NUMBER(peek(1))) { \
  67. runtimeError("Operands must be numbers."); \
  68. return INTERPRET_RUNTIME_ERROR; \
  69. } \
  70. double b = AS_NUMBER(pop()); \
  71. double a = AS_NUMBER(pop()); \
  72. push(valueType(a op b)); \
  73. } while (false)
  74. #ifdef DEBUG_TRACE_EXECUTION
  75. printf("!!! <Stack tracing> start\n");
  76. #endif
  77. for (;;) {
  78. #ifdef DEBUG_TRACE_EXECUTION
  79. //! <Stack tracing> start
  80. printf("------------------------\n|");
  81. for (Value *slot = vm.stack; slot < vm.stackTop; slot++) {
  82. printf("[ ");
  83. printValue(*slot);
  84. printf(" ]");
  85. }
  86. printf("\n------------------------");
  87. printf("\n");
  88. //! <Stack tracing> end
  89. disassembleInstruction(vm.chunk, (int) (vm.ip - vm.chunk->code));
  90. #endif
  91. switch (READ_BYTE()) {
  92. case OP_CONSTANT: {
  93. Value constant = READ_CONSTANT();
  94. push(constant);
  95. break;
  96. }
  97. case OP_NIL:
  98. push(NIL_VAL);
  99. break;
  100. case OP_TRUE:
  101. push(BOOL_VAL(true));
  102. break;
  103. case OP_FALSE:
  104. push(BOOL_VAL(false));
  105. break;
  106. case OP_POP:
  107. pop();
  108. break;
  109. case OP_DEFINE_GLOBAL: {
  110. ObjString *name = READ_STRING();
  111. tableSet(&vm.globals, name, peek(0));
  112. pop();
  113. break;
  114. }
  115. case OP_GET_GLOBAL: {
  116. ObjString *name = READ_STRING();
  117. Value value;
  118. if (!tableGet(&vm.globals, name, &value)) {
  119. runtimeError("Undefined variable '%s'.", name->chars);
  120. return INTERPRET_RUNTIME_ERROR;
  121. }
  122. push(value);
  123. break;
  124. }
  125. case OP_SET_GLOBAL: {
  126. ObjString *name = READ_STRING();
  127. if (tableSet(&vm.globals, name, peek(0))) {
  128. tableDelete(&vm.globals, name);
  129. runtimeError("Undefined variable '%s'.", name->chars);
  130. return INTERPRET_RUNTIME_ERROR;
  131. }
  132. break;
  133. }
  134. case OP_GET_LOCAL: {
  135. uint8_t slot = READ_BYTE();
  136. push(vm.stack[slot]);
  137. break;
  138. }
  139. case OP_SET_LOCAL: {
  140. uint8_t slot = READ_BYTE();
  141. vm.stack[slot] = peek(0);
  142. break;
  143. }
  144. case OP_ADD: {
  145. if (IS_STRING(peek(0)) && IS_STRING(peek(1))) {
  146. // 字串拼接
  147. concatenate();
  148. } else if (IS_NUMBER(peek(0)) && IS_NUMBER(peek(1))) {
  149. double b = AS_NUMBER(pop());
  150. double a = AS_NUMBER(pop());
  151. push(NUMBER_VAL(a + b));
  152. } else {
  153. runtimeError("Operands must be two numbers or two strings.");
  154. return INTERPRET_RUNTIME_ERROR;
  155. }
  156. break;
  157. }
  158. case OP_SUBTRACT:
  159. BINARY_OP(NUMBER_VAL, -);
  160. break;
  161. case OP_MULTIPLY:
  162. BINARY_OP(NUMBER_VAL, *);
  163. break;
  164. case OP_DIVIDE:
  165. BINARY_OP(NUMBER_VAL, /);
  166. break;
  167. case OP_NOT:
  168. push(BOOL_VAL(isFalse(pop())));
  169. break;
  170. case OP_NEGATE:
  171. if (!IS_NUMBER(peek(0))) {
  172. runtimeError("Operand must be a number.");
  173. return INTERPRET_RUNTIME_ERROR;
  174. }
  175. push(NUMBER_VAL(-AS_NUMBER(pop())));
  176. break;
  177. case OP_EQUAL: {
  178. Value b = pop();
  179. Value a = pop();
  180. push(BOOL_VAL(valuesEqual(a, b)));
  181. break;
  182. }
  183. case OP_GREATER:
  184. BINARY_OP(BOOL_VAL, >);
  185. break;
  186. case OP_LESS:
  187. BINARY_OP(BOOL_VAL, <);
  188. break;
  189. case OP_PRINT:
  190. printValue(pop());
  191. printf("\n");
  192. break;
  193. case OP_RETURN: {
  194. // Exit interpreter.
  195. return INTERPRET_OK;
  196. }
  197. }
  198. #ifdef DEBUG_TRACE_EXECUTION
  199. printf("!!! <Stack tracing> end\n");
  200. #endif
  201. }
  202. #undef READ_BYTE
  203. #undef READ_CONSTANT
  204. #undef READ_STRING
  205. #undef BINARY_OP
  206. }
  207. void freeVM() {
  208. freeTable(&vm.globals);
  209. freeTable(&vm.strings);
  210. freeObjects();
  211. }
  212. InterpretResult interpret(const char *source) {
  213. Chunk chunk;
  214. initChunk(&chunk);
  215. if (!compile(source, &chunk)) {
  216. freeChunk(&chunk);
  217. return INTERPRET_COMPILE_ERROR;
  218. }
  219. vm.chunk = &chunk;
  220. vm.ip = vm.chunk->code;
  221. InterpretResult result = run();
  222. freeChunk(&chunk);
  223. return result;
  224. }
  225. void push(Value value) {
  226. *vm.stackTop = value;
  227. vm.stackTop++;
  228. }
  229. Value pop() {
  230. vm.stackTop--;
  231. //! NOTE: 出栈后,里面的值没有清除
  232. return *vm.stackTop;
  233. }