Quellcode durchsuchen

compiling expression

runningwater vor 2 Jahren
Ursprung
Commit
34560a567d
2 geänderte Dateien mit 151 neuen und 2 gelöschten Zeilen
  1. 1 0
      common.h
  2. 150 2
      compiler.c

+ 1 - 0
common.h

@@ -12,6 +12,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#define DEBUG_PRINT_CODE
 #define DEBUG_TRACE_EXECUTION
 
 #endif//CLOX__COMMON_H_

+ 150 - 2
compiler.c

@@ -10,6 +10,9 @@
 #include "common.h"
 #include "compiler.h"
 #include "scanner.h"
+#ifdef DEBUG_PRINT_CODE
+#include "debug.h"
+#endif
 
 typedef struct {
   Token current;
@@ -18,9 +21,34 @@ typedef struct {
   bool panicMode;
 } Parser;
 
+typedef enum {
+  PREC_NONE,
+  PREC_ASSIGNMENT, // =
+  PREC_OR,    // or
+  PREC_AND,   // and
+  PREC_EQUALITY, // == !=
+  PREC_COMPARISON, // < > <= >=
+  PREC_TERM,  // + -
+  PREC_FACTOR, // * /
+  PREC_UNARY,  // ! -
+  PREC_CALL, // . ()
+  PREC_PRIMARY
+} Precedence;
+
+typedef void (*ParseFn)();
+
+typedef struct {
+  ParseFn prefix;
+  ParseFn infix;
+  Precedence precedence;
+} ParseRule;
+
 Parser parser;
 Chunk *compilingChunk;
 
+static void parsePrecedence(Precedence);
+static ParseRule *getRule(TokenType);
+
 static Chunk *currentChunk() {
   return compilingChunk;
 }
@@ -75,11 +103,131 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) {
 static void emitReturn() {
   emitByte(OP_RETURN);
 }
+static uint8_t makeConstant(double value) {
+  int constant = addConstant(currentChunk(), value);
+  if (constant > UINT8_MAX) {
+    error("Too many constants in one chunk.");
+    return 0;
+  }
+  return (uint8_t) constant;
+}
+static void expression() {
+  parsePrecedence(PREC_ASSIGNMENT);
+}
+static void emitConstant(double value) {
+  emitBytes(OP_CONSTANT, makeConstant(value));
+}
 static void endCompiler() {
   emitReturn();
+#ifdef DEBUG_PRINT_CODE
+  if (!parser.hadError) {
+    disassembleChunk(currentChunk(), "code");
+  }
+#endif
 }
-static void expression() {
-  ///! TODO
+static void grouping() {
+  expression();
+  consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
+}
+/// \brief parse number token
+static void number() {
+  double value = strtod(parser.previous.start, NULL);
+  emitConstant(value);
+}
+static void unary() {
+  TokenType operatorType = parser.previous.type;
+
+  // Compile the operand.
+  parsePrecedence(PREC_UNARY);
+
+  // Emit the operator instruction.
+  switch (operatorType) {
+    case TOKEN_MINUS: emitByte(OP_NEGATE);
+      break;
+    default: return; // Unreachable.
+  }
+}
+/// \brief infix parser
+static void binary() {
+  TokenType operatorType = parser.previous.type;
+  ParseRule *rule = getRule(operatorType);
+  parsePrecedence((Precedence) rule->precedence + 1);
+
+  switch (operatorType) {
+    case TOKEN_PLUS: emitByte(OP_ADD);
+      break;
+    case TOKEN_MINUS: emitByte(OP_SUBTRACT);
+      break;
+    case TOKEN_STAR: emitByte(OP_MULTIPLY);
+      break;
+    case TOKEN_SLASH: emitByte(OP_DIVIDE);
+      break;
+    default: return; // Unreachable.
+  }
+}
+ParseRule rules[] = {
+    [TOKEN_LEFT_PAREN] = {grouping, NULL, PREC_NONE},
+    [TOKEN_RIGHT_PAREN]   = {NULL, NULL, PREC_NONE},
+    [TOKEN_LEFT_BRACE]    = {NULL, NULL, PREC_NONE},
+    [TOKEN_RIGHT_BRACE]   = {NULL, NULL, PREC_NONE},
+    [TOKEN_COMMA]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_DOT]           = {NULL, NULL, PREC_NONE},
+    [TOKEN_MINUS]         = {unary, binary, PREC_TERM},
+    [TOKEN_PLUS]          = {NULL, binary, PREC_TERM},
+    [TOKEN_SEMICOLON]     = {NULL, NULL, PREC_NONE},
+    [TOKEN_SLASH]         = {NULL, binary, PREC_FACTOR},
+    [TOKEN_STAR]          = {NULL, binary, PREC_FACTOR},
+    [TOKEN_BANG]          = {NULL, NULL, PREC_NONE},
+    [TOKEN_BANG_EQUAL]    = {NULL, NULL, PREC_NONE},
+    [TOKEN_EQUAL]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_EQUAL_EQUAL]   = {NULL, NULL, PREC_NONE},
+    [TOKEN_GREATER]       = {NULL, NULL, PREC_NONE},
+    [TOKEN_GREATER_EQUAL] = {NULL, NULL, PREC_NONE},
+    [TOKEN_LESS]          = {NULL, NULL, PREC_NONE},
+    [TOKEN_LESS_EQUAL]    = {NULL, NULL, PREC_NONE},
+    [TOKEN_IDENTIFIER]    = {NULL, NULL, PREC_NONE},
+    [TOKEN_STRING]        = {NULL, NULL, PREC_NONE},
+    [TOKEN_NUMBER]        = {number, NULL, PREC_NONE},
+    [TOKEN_AND]           = {NULL, NULL, PREC_NONE},
+    [TOKEN_CLASS]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_ELSE]          = {NULL, NULL, PREC_NONE},
+    [TOKEN_FALSE]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_FOR]           = {NULL, NULL, PREC_NONE},
+    [TOKEN_FUN]           = {NULL, NULL, PREC_NONE},
+    [TOKEN_IF]            = {NULL, NULL, PREC_NONE},
+    [TOKEN_NIL]           = {NULL, NULL, PREC_NONE},
+    [TOKEN_OR]            = {NULL, NULL, PREC_NONE},
+    [TOKEN_PRINT]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_RETURN]        = {NULL, NULL, PREC_NONE},
+    [TOKEN_SUPER]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_THIS]          = {NULL, NULL, PREC_NONE},
+    [TOKEN_TRUE]          = {NULL, NULL, PREC_NONE},
+    [TOKEN_VAR]           = {NULL, NULL, PREC_NONE},
+    [TOKEN_WHILE]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_ERROR]         = {NULL, NULL, PREC_NONE},
+    [TOKEN_EOF]           = {NULL, NULL, PREC_NONE},
+};
+
+/// \brief 优先级处理
+/// \param precedence
+static void parsePrecedence(Precedence precedence) {
+  advance();
+  ParseFn prefixRule = getRule(parser.previous.type)->prefix;
+  if (prefixRule == NULL) {
+    error("Expect expression.");
+    return;
+  }
+
+  prefixRule(); ///! 执行具体函数
+
+  while (precedence <= getRule(parser.current.type)->precedence) {
+    advance();
+    ParseFn infixRule = getRule(parser.previous.type)->infix;
+    infixRule(); ///! 执行具体函数
+  }
+}
+static ParseRule *getRule(TokenType type) {
+  return &rules[type];
 }
 bool compile(const char *source, Chunk *chunk) {
   initScanner(source);