|
@@ -10,6 +10,7 @@
|
|
|
|
|
|
#define ERROR_LENGTH 256
|
|
#define ERROR_LENGTH 256
|
|
#define RETURN_BUFFER 16
|
|
#define RETURN_BUFFER 16
|
|
|
|
+#define BREAK_BUFFER 32
|
|
|
|
|
|
static jmp_buf errorJump;
|
|
static jmp_buf errorJump;
|
|
static char error[ERROR_LENGTH] = {'\0'};
|
|
static char error[ERROR_LENGTH] = {'\0'};
|
|
@@ -26,6 +27,10 @@ static int returns[RETURN_BUFFER];
|
|
static int returnIndex = 0;
|
|
static int returnIndex = 0;
|
|
static int returnState = 0;
|
|
static int returnState = 0;
|
|
|
|
|
|
|
|
+static int breaks[BREAK_BUFFER];
|
|
|
|
+static int breakIndex = 0;
|
|
|
|
+static int forWhileStack = 0;
|
|
|
|
+
|
|
static void cError(const char* format, ...) {
|
|
static void cError(const char* format, ...) {
|
|
va_list args;
|
|
va_list args;
|
|
va_start(args, format);
|
|
va_start(args, format);
|
|
@@ -475,7 +480,7 @@ static void cFunctionBody(const char* name, int arguments) {
|
|
returnState = 0;
|
|
returnState = 0;
|
|
|
|
|
|
int p = cAddPush(arguments);
|
|
int p = cAddPush(arguments);
|
|
- cConsumeBody();
|
|
|
|
|
|
+ cConsumeBody(false);
|
|
cAddPop(p, vars[1].entries);
|
|
cAddPop(p, vars[1].entries);
|
|
|
|
|
|
cLinkReturns();
|
|
cLinkReturns();
|
|
@@ -543,7 +548,7 @@ static void cIf() {
|
|
cConsumeToken(T_CLOSE_BRACKET);
|
|
cConsumeToken(T_CLOSE_BRACKET);
|
|
cAddOperation(OP_IF_GOTO);
|
|
cAddOperation(OP_IF_GOTO);
|
|
int ifP = cReserveInt();
|
|
int ifP = cReserveInt();
|
|
- cConsumeBody();
|
|
|
|
|
|
+ cConsumeBody(false);
|
|
cSetInt(ifP, code->length);
|
|
cSetInt(ifP, code->length);
|
|
|
|
|
|
if(cConsumeTokenIf(T_ELSE)) {
|
|
if(cConsumeTokenIf(T_ELSE)) {
|
|
@@ -553,12 +558,19 @@ static void cIf() {
|
|
if(cConsumeTokenIf(T_IF)) {
|
|
if(cConsumeTokenIf(T_IF)) {
|
|
cIf();
|
|
cIf();
|
|
} else {
|
|
} else {
|
|
- cConsumeBody();
|
|
|
|
|
|
+ cConsumeBody(false);
|
|
}
|
|
}
|
|
cSetInt(elseP, code->length);
|
|
cSetInt(elseP, code->length);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void cConsumeBreaks(int start, int address) {
|
|
|
|
+ for(int i = start; i < breakIndex; i++) {
|
|
|
|
+ cSetInt(breaks[i], address);
|
|
|
|
+ }
|
|
|
|
+ breakIndex = start;
|
|
|
|
+}
|
|
|
|
+
|
|
static void cWhile() {
|
|
static void cWhile() {
|
|
int start = code->length;
|
|
int start = code->length;
|
|
cConsumeToken(T_OPEN_BRACKET);
|
|
cConsumeToken(T_OPEN_BRACKET);
|
|
@@ -566,10 +578,14 @@ static void cWhile() {
|
|
cConsumeToken(T_CLOSE_BRACKET);
|
|
cConsumeToken(T_CLOSE_BRACKET);
|
|
cAddOperation(OP_IF_GOTO);
|
|
cAddOperation(OP_IF_GOTO);
|
|
int ifP = cReserveInt();
|
|
int ifP = cReserveInt();
|
|
- cConsumeBody();
|
|
|
|
|
|
+ int breakStart = breakIndex;
|
|
|
|
+ forWhileStack++;
|
|
|
|
+ cConsumeBody(true);
|
|
|
|
+ forWhileStack--;
|
|
cAddOperation(OP_GOTO);
|
|
cAddOperation(OP_GOTO);
|
|
cAddInt(start);
|
|
cAddInt(start);
|
|
cSetInt(ifP, code->length);
|
|
cSetInt(ifP, code->length);
|
|
|
|
+ cConsumeBreaks(breakStart, code->length);
|
|
}
|
|
}
|
|
|
|
|
|
static void cLineExpression(Token t) {
|
|
static void cLineExpression(Token t) {
|
|
@@ -604,10 +620,25 @@ static void cFor() {
|
|
cAddInt(startCheck);
|
|
cAddInt(startCheck);
|
|
cConsumeToken(T_CLOSE_BRACKET);
|
|
cConsumeToken(T_CLOSE_BRACKET);
|
|
cSetInt(beginBody, code->length);
|
|
cSetInt(beginBody, code->length);
|
|
- cConsumeBody();
|
|
|
|
|
|
+ int breakStart = breakIndex;
|
|
|
|
+ forWhileStack++;
|
|
|
|
+ cConsumeBody(true);
|
|
|
|
+ forWhileStack--;
|
|
cAddOperation(OP_GOTO);
|
|
cAddOperation(OP_GOTO);
|
|
cAddInt(startPerLoop);
|
|
cAddInt(startPerLoop);
|
|
cSetInt(end, code->length);
|
|
cSetInt(end, code->length);
|
|
|
|
+ cConsumeBreaks(breakStart, code->length);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void cBreak() {
|
|
|
|
+ if(forWhileStack == 0) {
|
|
|
|
+ cError("break without for or while on line %d", line);
|
|
|
|
+ } else if(breakIndex >= BREAK_BUFFER) {
|
|
|
|
+ cError("too much breaks around line %d", line);
|
|
|
|
+ }
|
|
|
|
+ cAddOperation(OP_GOTO);
|
|
|
|
+ breaks[breakIndex++] = cReserveInt();
|
|
|
|
+ cConsumeToken(T_SEMICOLON);
|
|
}
|
|
}
|
|
|
|
|
|
static void cLine(Token t) {
|
|
static void cLine(Token t) {
|
|
@@ -620,6 +651,7 @@ static void cLine(Token t) {
|
|
case T_IF: cIf(); break;
|
|
case T_IF: cIf(); break;
|
|
case T_WHILE: cWhile(); break;
|
|
case T_WHILE: cWhile(); break;
|
|
case T_FOR: cFor(); break;
|
|
case T_FOR: cFor(); break;
|
|
|
|
+ case T_BREAK: cBreak(); break;
|
|
default: cLineExpression(t); cConsumeToken(T_SEMICOLON);
|
|
default: cLineExpression(t); cConsumeToken(T_SEMICOLON);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -650,6 +682,9 @@ static void cLinkQueuedFunctions() {
|
|
static void cAllocAndCompile() {
|
|
static void cAllocAndCompile() {
|
|
varIndex = 0;
|
|
varIndex = 0;
|
|
returnIndex = 0;
|
|
returnIndex = 0;
|
|
|
|
+ returnState = 0;
|
|
|
|
+ forWhileStack = 0;
|
|
|
|
+ breakIndex = 0;
|
|
simInit(vars);
|
|
simInit(vars);
|
|
simInit(vars + 1);
|
|
simInit(vars + 1);
|
|
fmInit(&functions);
|
|
fmInit(&functions);
|