|
@@ -129,6 +129,15 @@ static void emitBytes(uint8_t byte1, uint8_t byte2) {
|
|
|
emitByte(byte1);
|
|
emitByte(byte1);
|
|
|
emitByte(byte2);
|
|
emitByte(byte2);
|
|
|
}
|
|
}
|
|
|
|
|
+static void emitLoop(int loopStart) {
|
|
|
|
|
+ emitByte(OP_LOOP);
|
|
|
|
|
+
|
|
|
|
|
+ int offset = currentChunk()->count - loopStart + 2;
|
|
|
|
|
+ if (offset > UINT16_MAX) error("Loop body too large.");
|
|
|
|
|
+
|
|
|
|
|
+ emitByte((offset >> 8) & 0xFF);
|
|
|
|
|
+ emitByte(offset & 0xFF);
|
|
|
|
|
+}
|
|
|
static int emitJump(uint8_t instruction) {
|
|
static int emitJump(uint8_t instruction) {
|
|
|
emitByte(instruction);
|
|
emitByte(instruction);
|
|
|
emitByte(0xff);// 占位字节,后面填入需要跳转的 offset
|
|
emitByte(0xff);// 占位字节,后面填入需要跳转的 offset
|
|
@@ -178,6 +187,71 @@ static void patchJump(int offset) {
|
|
|
currentChunk()->code[offset] = (jump >> 8) & 0xFF;
|
|
currentChunk()->code[offset] = (jump >> 8) & 0xFF;
|
|
|
currentChunk()->code[offset + 1] = jump & 0xFF;
|
|
currentChunk()->code[offset + 1] = jump & 0xFF;
|
|
|
}
|
|
}
|
|
|
|
|
+static void forStatement() {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * *********************************************************
|
|
|
|
|
+ * initializer clause
|
|
|
|
|
+ * L4: condition expression
|
|
|
|
|
+ * OP_JUMP_IF_FALSE L1
|
|
|
|
|
+ * OP_POP
|
|
|
|
|
+ * OP_JUMP L3
|
|
|
|
|
+ * L2: increment expression
|
|
|
|
|
+ * OP_POP
|
|
|
|
|
+ * OP_LOOP L4
|
|
|
|
|
+ * L3: body statement
|
|
|
|
|
+ * OP_LOOP L2
|
|
|
|
|
+ * L1: OP_POP
|
|
|
|
|
+ * continues...
|
|
|
|
|
+ * *********************************************************
|
|
|
|
|
+ */
|
|
|
|
|
+ beginScope();
|
|
|
|
|
+ // for(I;II;III)
|
|
|
|
|
+ consume(TOKEN_LEFT_PAREN, "Expect '(' after 'for'.");
|
|
|
|
|
+
|
|
|
|
|
+ ///! I.<<Initializer Part>>
|
|
|
|
|
+ if (match(TOKEN_SEMICOLON)) {
|
|
|
|
|
+ // No initializer.
|
|
|
|
|
+ } else if (match(TOKEN_VAR)) {
|
|
|
|
|
+ varDeclaration();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ expressionStatement();// ; op_pop
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ///! II.<<Condition Part>>
|
|
|
|
|
+ int loopStart = currentChunk()->count;
|
|
|
|
|
+ int exitJump = -1;
|
|
|
|
|
+ if (!match(TOKEN_SEMICOLON)) {
|
|
|
|
|
+ expression();
|
|
|
|
|
+ consume(TOKEN_SEMICOLON, "Expect ';' after loop conditon. ");
|
|
|
|
|
+
|
|
|
|
|
+ // Jump out of the loop if the condition is false.
|
|
|
|
|
+ exitJump = emitJump(OP_JUMP_IF_FALSE);
|
|
|
|
|
+ emitByte(OP_POP);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ///! III.<<Increment Clause>>
|
|
|
|
|
+ if (!match(TOKEN_RIGHT_PAREN)) {
|
|
|
|
|
+ int bodyJump = emitJump(OP_JUMP);
|
|
|
|
|
+ int incrementStart = currentChunk()->count;
|
|
|
|
|
+ expression();
|
|
|
|
|
+ emitByte(OP_POP);
|
|
|
|
|
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after for clauses.");
|
|
|
|
|
+
|
|
|
|
|
+ emitLoop(loopStart);
|
|
|
|
|
+ loopStart = incrementStart;
|
|
|
|
|
+ patchJump(bodyJump);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ///! <<Body Part>>
|
|
|
|
|
+ statement();
|
|
|
|
|
+ emitLoop(loopStart);
|
|
|
|
|
+
|
|
|
|
|
+ if (exitJump != -1) {
|
|
|
|
|
+ patchJump(exitJump);
|
|
|
|
|
+ emitByte(OP_POP);// Condition.
|
|
|
|
|
+ }
|
|
|
|
|
+ endScope();
|
|
|
|
|
+}
|
|
|
static void ifStatement() {
|
|
static void ifStatement() {
|
|
|
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
|
|
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
|
|
|
expression();
|
|
expression();
|
|
@@ -195,6 +269,21 @@ static void ifStatement() {
|
|
|
if (match(TOKEN_ELSE)) statement();// else branch statement
|
|
if (match(TOKEN_ELSE)) statement();// else branch statement
|
|
|
patchJump(elseJump);
|
|
patchJump(elseJump);
|
|
|
}
|
|
}
|
|
|
|
|
+static void whileStatement() {
|
|
|
|
|
+ int loopStart = currentChunk()->count;
|
|
|
|
|
+ consume(TOKEN_LEFT_PAREN, "Expect '(' after 'while'.");
|
|
|
|
|
+ expression();// while condition.
|
|
|
|
|
+ consume(TOKEN_RIGHT_PAREN, "Expect ')' after condition.");
|
|
|
|
|
+
|
|
|
|
|
+ int exitJump = emitJump(OP_JUMP_IF_FALSE);
|
|
|
|
|
+ emitByte(OP_POP);
|
|
|
|
|
+
|
|
|
|
|
+ statement();// while body.
|
|
|
|
|
+ emitLoop(loopStart);
|
|
|
|
|
+
|
|
|
|
|
+ patchJump(exitJump);
|
|
|
|
|
+ emitByte(OP_POP);
|
|
|
|
|
+}
|
|
|
static void printStatement() {
|
|
static void printStatement() {
|
|
|
expression();
|
|
expression();
|
|
|
consume(TOKEN_SEMICOLON, "Expect ';' after value.");
|
|
consume(TOKEN_SEMICOLON, "Expect ';' after value.");
|
|
@@ -250,8 +339,12 @@ static void block() {
|
|
|
static void statement() {
|
|
static void statement() {
|
|
|
if (match(TOKEN_PRINT)) {
|
|
if (match(TOKEN_PRINT)) {
|
|
|
printStatement();
|
|
printStatement();
|
|
|
|
|
+ } else if (match(TOKEN_FOR)) {
|
|
|
|
|
+ forStatement();
|
|
|
} else if (match(TOKEN_IF)) {
|
|
} else if (match(TOKEN_IF)) {
|
|
|
ifStatement();
|
|
ifStatement();
|
|
|
|
|
+ } else if (match(TOKEN_WHILE)) {
|
|
|
|
|
+ whileStatement();
|
|
|
} else if (match(TOKEN_LEFT_BRACE)) {
|
|
} else if (match(TOKEN_LEFT_BRACE)) {
|
|
|
///! block → "{" declaration* "}" ;
|
|
///! block → "{" declaration* "}" ;
|
|
|
beginScope();
|
|
beginScope();
|
|
@@ -303,6 +396,36 @@ static void string(__attribute__((unused)) bool canAssign) {
|
|
|
emitConstant(OBJ_VAL(copyString(parser.previous.start + 1,
|
|
emitConstant(OBJ_VAL(copyString(parser.previous.start + 1,
|
|
|
parser.previous.length - 2)));
|
|
parser.previous.length - 2)));
|
|
|
}
|
|
}
|
|
|
|
|
+static void and_(__attribute__((unused)) bool canAssign) {
|
|
|
|
|
+ /// left operand expression
|
|
|
|
|
+ /// OP_JUMP_IF_FALSE b
|
|
|
|
|
+ /// OP_POP
|
|
|
|
|
+ /// right operand expression
|
|
|
|
|
+ /// b: continues...
|
|
|
|
|
+ int endJump = emitJump(OP_JUMP_IF_FALSE);
|
|
|
|
|
+
|
|
|
|
|
+ emitByte(OP_POP);
|
|
|
|
|
+
|
|
|
|
|
+ parsePrecedence(PREC_AND);// right operand expression
|
|
|
|
|
+
|
|
|
|
|
+ patchJump(endJump);
|
|
|
|
|
+}
|
|
|
|
|
+static void or_(__attribute__((unused)) bool canAssign) {
|
|
|
|
|
+ /// left operand expression
|
|
|
|
|
+ /// OP_JUMP_IF_FALSE b1
|
|
|
|
|
+ /// OP_JUMP b2
|
|
|
|
|
+ /// b1: OP_POP
|
|
|
|
|
+ /// right operand expression
|
|
|
|
|
+ /// b2: continue
|
|
|
|
|
+ int elseJump = emitJump(OP_JUMP_IF_FALSE);
|
|
|
|
|
+ int endJump = emitJump(OP_JUMP);
|
|
|
|
|
+
|
|
|
|
|
+ patchJump(elseJump);
|
|
|
|
|
+ emitByte(OP_POP);
|
|
|
|
|
+
|
|
|
|
|
+ parsePrecedence(PREC_OR);// right operand expression
|
|
|
|
|
+ patchJump(endJump);
|
|
|
|
|
+}
|
|
|
static int resolveLocal(Compiler *compile, Token *name) {
|
|
static int resolveLocal(Compiler *compile, Token *name) {
|
|
|
for (int i = compile->localCount - 1; i >= 0; i--) {
|
|
for (int i = compile->localCount - 1; i >= 0; i--) {
|
|
|
Local *local = &compile->locals[i];
|
|
Local *local = &compile->locals[i];
|
|
@@ -433,7 +556,7 @@ ParseRule rules[] = {
|
|
|
[TOKEN_IDENTIFIER] = {variable, NULL, PREC_NONE},
|
|
[TOKEN_IDENTIFIER] = {variable, NULL, PREC_NONE},
|
|
|
[TOKEN_STRING] = {string, NULL, PREC_NONE},
|
|
[TOKEN_STRING] = {string, NULL, PREC_NONE},
|
|
|
[TOKEN_NUMBER] = {number, NULL, PREC_NONE},
|
|
[TOKEN_NUMBER] = {number, NULL, PREC_NONE},
|
|
|
- [TOKEN_AND] = {NULL, NULL, PREC_NONE},
|
|
|
|
|
|
|
+ [TOKEN_AND] = {NULL, and_, PREC_AND},
|
|
|
[TOKEN_CLASS] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_CLASS] = {NULL, NULL, PREC_NONE},
|
|
|
[TOKEN_ELSE] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_ELSE] = {NULL, NULL, PREC_NONE},
|
|
|
[TOKEN_FALSE] = {literal, NULL, PREC_NONE},
|
|
[TOKEN_FALSE] = {literal, NULL, PREC_NONE},
|
|
@@ -441,7 +564,7 @@ ParseRule rules[] = {
|
|
|
[TOKEN_FUN] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_FUN] = {NULL, NULL, PREC_NONE},
|
|
|
[TOKEN_IF] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_IF] = {NULL, NULL, PREC_NONE},
|
|
|
[TOKEN_NIL] = {literal, NULL, PREC_NONE},
|
|
[TOKEN_NIL] = {literal, NULL, PREC_NONE},
|
|
|
- [TOKEN_OR] = {NULL, NULL, PREC_NONE},
|
|
|
|
|
|
|
+ [TOKEN_OR] = {NULL, or_, PREC_OR},
|
|
|
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_PRINT] = {NULL, NULL, PREC_NONE},
|
|
|
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_RETURN] = {NULL, NULL, PREC_NONE},
|
|
|
[TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
|
|
[TOKEN_SUPER] = {NULL, NULL, PREC_NONE},
|
|
@@ -532,7 +655,6 @@ static void defineVariable(uint8_t global) {
|
|
|
// 本地变量,直接退出
|
|
// 本地变量,直接退出
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
emitBytes(OP_DEFINE_GLOBAL, global);
|
|
emitBytes(OP_DEFINE_GLOBAL, global);
|
|
|
}
|
|
}
|
|
|
static ParseRule *getRule(TokenType type) {
|
|
static ParseRule *getRule(TokenType type) {
|