ソースを参照

Parsing Tokens and emitting Bytecode

runningwater 2 年 前
コミット
5b68e3fd20
4 ファイル変更98 行追加28 行削除
  1. 80 23
      compiler.c
  2. 2 1
      compiler.h
  3. 1 2
      scanner.c
  4. 15 2
      vm.c

+ 80 - 23
compiler.c

@@ -11,29 +11,86 @@
 #include "compiler.h"
 #include "scanner.h"
 
-void compile(const char *source) {
-  initScanner(source);
-  int line = -1;
-  /// \brief 如 print 1 + 2; 则会输出
-  ///   1 31 'print'
-  ///   | 21 '1'
-  ///   |  7 '+'
-  ///   | 21 '2'
-  ///   |  8 ';'
-  ///   2 39 ''       // <EOF token>
+typedef struct {
+  Token current;
+  Token previous;
+  bool hadError;
+  bool panicMode;
+} Parser;
+
+Parser parser;
+Chunk *compilingChunk;
+
+static Chunk *currentChunk() {
+  return compilingChunk;
+}
+
+static void errorAt(Token *token, const char *message) {
+  if (parser.panicMode) return;
+  parser.panicMode = true;
+  fprintf(stderr, "[line %d] Error", token->line);
+
+  if (token->type == TOKEN_EOF) {
+    fprintf(stderr, " at end");
+  } else if (token->type == TOKEN_ERROR) {
+    ///! Nothing.
+  } else {
+    fprintf(stderr, " at '%.*s'", token->length, token->start);
+  }
+
+  fprintf(stderr, ": %s\n", message);
+  parser.hadError = true;
+}
+static void error(const char *message) {
+  errorAt(&parser.previous, message);
+}
+static void errorAtCurrent(const char *message) {
+  errorAt(&parser.current, message);
+}
+static void advance() {
+  parser.previous = parser.current;
+
   for (;;) {
-    Token token = scanToken();
-    if (token.line != line) {
-      printf("%4d ", token.line);
-      line = token.line;
-    } else {
-      printf("   | ");
-    }
-    /// %.*s: *用来指定宽度,对应一个整数。
-    /// .(点)与后面的数合起来 是指定必须输出这个宽度,
-    /// 如果所输出的字符串长度大于这个数,则按此宽度输出,如果小于,则输出实际长度
-    printf("%2d '%.*s'\n", token.type, token.length, token.start);
-
-    if (token.type == TOKEN_EOF) break;
+    parser.current = scanToken();
+    if (parser.current.type != TOKEN_ERROR) break;
+
+    errorAtCurrent(parser.current.start);
   }
 }
+void consume(TokenType type, const char *message) {
+  if (parser.current.type == type) {
+    advance();
+    return;
+  }
+
+  errorAtCurrent(message);
+}
+static void emitByte(uint8_t byte) {
+  writeChunk(currentChunk(), byte, parser.previous.line);
+}
+static void emitBytes(uint8_t byte1, uint8_t byte2) {
+  emitByte(byte1);
+  emitByte(byte2);
+}
+static void emitReturn() {
+  emitByte(OP_RETURN);
+}
+static void endCompiler() {
+  emitReturn();
+}
+static void expression() {
+  ///! TODO
+}
+bool compile(const char *source, Chunk *chunk) {
+  initScanner(source);
+  compilingChunk = chunk;
+
+  parser.hadError = false;
+  parser.panicMode = false;
+
+  advance();
+  expression();
+  consume(TOKEN_EOF, "Expect end of expression");
+  endCompiler(); //! return opcode
+  return !parser.hadError;
+}

+ 2 - 1
compiler.h

@@ -10,9 +10,10 @@
 
 #ifndef CLOX__COMPILER_H_
 #define CLOX__COMPILER_H_
+#include "vm.h"
 
 /// \brief 编译
 /// \param source 源代码
-void compile(const char *source);
+bool compile(const char *source, Chunk *chunk);
 
 #endif //CLOX__COMPILER_H_

+ 1 - 2
scanner.c

@@ -191,7 +191,6 @@ Token scanToken() {
     case '<': return makeToken(match('=') ? TOKEN_LESS_EQUAL : TOKEN_LESS);
     case '>': return makeToken(match('=') ? TOKEN_GREATER_EQUAL : TOKEN_GREATER);
     case '"': return string();
+    default: return errorToken("Unexpected character.");
   }
-
-  return errorToken("Unexpected character.");
 }

+ 15 - 2
vm.c

@@ -83,8 +83,21 @@ void freeVM() {
 
 }
 InterpretResult interpret(const char *source) {
-  compile(source);
-  return INTERPRET_OK;
+  Chunk chunk;
+  initChunk(&chunk);
+
+  if (!compile(source, &chunk)) {
+    freeChunk(&chunk);
+    return INTERPRET_COMPILE_ERROR;
+  }
+
+  vm.chunk = &chunk;
+  vm.ip = vm.chunk->code;
+
+  InterpretResult result = run();
+
+  freeChunk(&chunk);
+  return result;
 }
 void push(Value value) {
   *vm.stackTop = value;