|
|
@@ -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);
|