|
@@ -1,4 +1,5 @@
|
|
#include <limits.h>
|
|
#include <limits.h>
|
|
|
|
+#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
@@ -11,6 +12,7 @@
|
|
#define TOKEN_BUFFER_LENGTH (1024 * 1024)
|
|
#define TOKEN_BUFFER_LENGTH (1024 * 1024)
|
|
#define ERROR_LENGTH 256
|
|
#define ERROR_LENGTH 256
|
|
|
|
|
|
|
|
+static jmp_buf errorJump;
|
|
static char tokenBuffer[TOKEN_BUFFER_LENGTH];
|
|
static char tokenBuffer[TOKEN_BUFFER_LENGTH];
|
|
static int writeIndex = 0;
|
|
static int writeIndex = 0;
|
|
static int readIndex = 0;
|
|
static int readIndex = 0;
|
|
@@ -22,21 +24,21 @@ static void tError(const char* format, ...) {
|
|
va_start(args, format);
|
|
va_start(args, format);
|
|
vsnprintf(error, ERROR_LENGTH, format, args);
|
|
vsnprintf(error, ERROR_LENGTH, format, args);
|
|
va_end(args);
|
|
va_end(args);
|
|
|
|
+ longjmp(errorJump, 0);
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAdd(const void* data, int length) {
|
|
|
|
|
|
+static void tAdd(const void* data, int length) {
|
|
if(writeIndex + length > TOKEN_BUFFER_LENGTH) {
|
|
if(writeIndex + length > TOKEN_BUFFER_LENGTH) {
|
|
tError("the token buffer is too small");
|
|
tError("the token buffer is too small");
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
memcpy(tokenBuffer + writeIndex, data, length);
|
|
memcpy(tokenBuffer + writeIndex, data, length);
|
|
writeIndex += length;
|
|
writeIndex += length;
|
|
- return true;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAddToken(Token token) {
|
|
|
|
|
|
+static void tAddToken(Token token) {
|
|
unsigned char c = token;
|
|
unsigned char c = token;
|
|
- return tAdd(&c, 1) && tAdd(&line, sizeof(line));
|
|
|
|
|
|
+ tAdd(&c, 1);
|
|
|
|
+ tAdd(&line, sizeof(line));
|
|
}
|
|
}
|
|
|
|
|
|
static bool tReadTokens(void* dest, int length) {
|
|
static bool tReadTokens(void* dest, int length) {
|
|
@@ -48,26 +50,27 @@ static bool tReadTokens(void* dest, int length) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tParseLiteral(int c) {
|
|
|
|
|
|
+static void tParseLiteral(int c) {
|
|
int index = 1;
|
|
int index = 1;
|
|
char buffer[64];
|
|
char buffer[64];
|
|
buffer[0] = c;
|
|
buffer[0] = c;
|
|
while(isLetter(fPeek())) {
|
|
while(isLetter(fPeek())) {
|
|
if(index >= 63) {
|
|
if(index >= 63) {
|
|
tError("literal is too long");
|
|
tError("literal is too long");
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
buffer[index++] = fRead();
|
|
buffer[index++] = fRead();
|
|
}
|
|
}
|
|
buffer[index] = '\0';
|
|
buffer[index] = '\0';
|
|
Token t = tFromName(buffer);
|
|
Token t = tFromName(buffer);
|
|
if(t != T_END) {
|
|
if(t != T_END) {
|
|
- return tAddToken(t);
|
|
|
|
|
|
+ tAddToken(t);
|
|
|
|
+ } else {
|
|
|
|
+ tAddToken(T_LITERAL);
|
|
|
|
+ tAdd(buffer, index + 1);
|
|
}
|
|
}
|
|
- return tAddToken(T_LITERAL) && tAdd(buffer, index + 1);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tParseNumber(int c) {
|
|
|
|
|
|
+static void tParseNumber(int c) {
|
|
int index = 1;
|
|
int index = 1;
|
|
char buffer[64];
|
|
char buffer[64];
|
|
buffer[0] = c;
|
|
buffer[0] = c;
|
|
@@ -80,7 +83,6 @@ static bool tParseNumber(int c) {
|
|
break;
|
|
break;
|
|
} else if(index >= 63) {
|
|
} else if(index >= 63) {
|
|
tError("number is too long");
|
|
tError("number is too long");
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
buffer[index++] = fRead();
|
|
buffer[index++] = fRead();
|
|
}
|
|
}
|
|
@@ -90,25 +92,23 @@ static bool tParseNumber(int c) {
|
|
float f = strtof(buffer, &end);
|
|
float f = strtof(buffer, &end);
|
|
if(end[0] != '\0') {
|
|
if(end[0] != '\0') {
|
|
tError("invalid float on line %d", line);
|
|
tError("invalid float on line %d", line);
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
- return tAddToken(T_CONST_FLOAT) && tAdd(&f, sizeof(float));
|
|
|
|
|
|
+ tAddToken(T_CONST_FLOAT);
|
|
|
|
+ tAdd(&f, sizeof(float));
|
|
} else {
|
|
} else {
|
|
char* end = NULL;
|
|
char* end = NULL;
|
|
long l = strtol(buffer, &end, 10);
|
|
long l = strtol(buffer, &end, 10);
|
|
if(end[0] != '\0' || l > INT_MAX) {
|
|
if(end[0] != '\0' || l > INT_MAX) {
|
|
tError("invalid int on line %d", line);
|
|
tError("invalid int on line %d", line);
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
int i = l;
|
|
int i = l;
|
|
- return tAddToken(T_CONST_INT) && tAdd(&i, sizeof(int));
|
|
|
|
|
|
+ tAddToken(T_CONST_INT);
|
|
|
|
+ tAdd(&i, sizeof(int));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAddString() {
|
|
|
|
- if(!tAddToken(T_TEXT)) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+static void tAddString() {
|
|
|
|
+ tAddToken(T_TEXT);
|
|
while(true) {
|
|
while(true) {
|
|
int c = fRead();
|
|
int c = fRead();
|
|
if(c == '"') {
|
|
if(c == '"') {
|
|
@@ -117,114 +117,120 @@ static bool tAddString() {
|
|
switch(fRead()) {
|
|
switch(fRead()) {
|
|
case '"': c = '"'; break;
|
|
case '"': c = '"'; break;
|
|
case '\\': c = '\\'; break;
|
|
case '\\': c = '\\'; break;
|
|
- default:
|
|
|
|
- tError("unknown escaped character at line %d", line);
|
|
|
|
- return false;
|
|
|
|
|
|
+ default: tError("unknown escaped character at line %d", line);
|
|
}
|
|
}
|
|
} else if(c == EOF) {
|
|
} else if(c == EOF) {
|
|
tError("unclosed string starting at line %d", line);
|
|
tError("unclosed string starting at line %d", line);
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- if(!tAdd(&c, 1)) {
|
|
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
|
|
+ tAdd(&c, 1);
|
|
}
|
|
}
|
|
char c = '\0';
|
|
char c = '\0';
|
|
- return tAdd(&c, 1);
|
|
|
|
|
|
+ tAdd(&c, 1);
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAddToken2(Token te, Token t) {
|
|
|
|
- return fReadIf('=') ? tAddToken(te) : tAddToken(t);
|
|
|
|
|
|
+static void tAddToken2(Token te, Token t) {
|
|
|
|
+ if(fReadIf('=')) {
|
|
|
|
+ tAddToken(te);
|
|
|
|
+ } else {
|
|
|
|
+ tAddToken(t);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAddToken3(int c, Token tc, Token te, Token t) {
|
|
|
|
- return fReadIf(c) ? tAddToken(tc) : tAddToken2(te, t);
|
|
|
|
|
|
+static void tAddToken3(int c, Token tc, Token te, Token t) {
|
|
|
|
+ if(fReadIf(c)) {
|
|
|
|
+ tAddToken(tc);
|
|
|
|
+ } else {
|
|
|
|
+ tAddToken2(te, t);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAddToken4(int c, Token tce, Token tc, Token te, Token t) {
|
|
|
|
- return fReadIf(c) ? tAddToken2(tce, tc) : tAddToken2(te, t);
|
|
|
|
|
|
+static void tAddToken4(int c, Token tce, Token tc, Token te, Token t) {
|
|
|
|
+ if(fReadIf(c)) {
|
|
|
|
+ tAddToken2(tce, tc);
|
|
|
|
+ } else {
|
|
|
|
+ tAddToken2(te, t);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tAddTokenMinus() {
|
|
|
|
- return tAddToken3('-', T_DECREMENT, T_SUB_SET,
|
|
|
|
- fReadIf('>') ? T_ARROW : T_SUB);
|
|
|
|
|
|
+static void tAddTokenMinus() {
|
|
|
|
+ tAddToken3('-', T_DECREMENT, T_SUB_SET, fReadIf('>') ? T_ARROW : T_SUB);
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tLineComment() {
|
|
|
|
|
|
+static void tLineComment() {
|
|
while(true) {
|
|
while(true) {
|
|
int c = fRead();
|
|
int c = fRead();
|
|
if(c == EOF || c == '\n') {
|
|
if(c == EOF || c == '\n') {
|
|
line++;
|
|
line++;
|
|
- return true;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tMultipleLineComment() {
|
|
|
|
|
|
+static void tMultipleLineComment() {
|
|
while(true) {
|
|
while(true) {
|
|
int c = fRead();
|
|
int c = fRead();
|
|
if(c == EOF) {
|
|
if(c == EOF) {
|
|
tError("unclosed comment at line %d", line);
|
|
tError("unclosed comment at line %d", line);
|
|
- return false;
|
|
|
|
} else if(c == '\n') {
|
|
} else if(c == '\n') {
|
|
line++;
|
|
line++;
|
|
} else if(c == '*' && fReadIf('/')) {
|
|
} else if(c == '*' && fReadIf('/')) {
|
|
- return true;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tSlash() {
|
|
|
|
|
|
+static void tSlash() {
|
|
if(fReadIf('/')) {
|
|
if(fReadIf('/')) {
|
|
- return tLineComment();
|
|
|
|
|
|
+ tLineComment();
|
|
} else if(fReadIf('*')) {
|
|
} else if(fReadIf('*')) {
|
|
- return tMultipleLineComment();
|
|
|
|
|
|
+ tMultipleLineComment();
|
|
|
|
+ } else {
|
|
|
|
+ tAddToken2(T_DIV_SET, T_DIV);
|
|
}
|
|
}
|
|
- return tAddToken2(T_DIV_SET, T_DIV);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-static bool tParseToken() {
|
|
|
|
- int c = fRead();
|
|
|
|
- if(c == EOF) {
|
|
|
|
- return false;
|
|
|
|
- } else if(isLetter(c)) {
|
|
|
|
- return tParseLiteral(c);
|
|
|
|
|
|
+static void tParseToken(int c) {
|
|
|
|
+ if(isLetter(c)) {
|
|
|
|
+ tParseLiteral(c);
|
|
|
|
+ return;
|
|
} else if(isNumber(c)) {
|
|
} else if(isNumber(c)) {
|
|
- return tParseNumber(c);
|
|
|
|
|
|
+ tParseNumber(c);
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
switch(c) {
|
|
switch(c) {
|
|
- case ' ': return true;
|
|
|
|
- case '\n': line++; return true;
|
|
|
|
- case '+': return tAddToken3('+', T_INCREMENT, T_ADD_SET, T_ADD);
|
|
|
|
- case '-': return tAddTokenMinus();
|
|
|
|
- case '*': return tAddToken2(T_MUL_SET, T_MUL);
|
|
|
|
- case '/': return tSlash();
|
|
|
|
- case '%': return tAddToken2(T_MOD_SET, T_MOD);
|
|
|
|
|
|
+ case ' ': return;
|
|
|
|
+ case '\n': line++; return;
|
|
|
|
+ case '+': tAddToken3('+', T_INCREMENT, T_ADD_SET, T_ADD); return;
|
|
|
|
+ case '-': tAddTokenMinus(); return;
|
|
|
|
+ case '*': tAddToken2(T_MUL_SET, T_MUL); return;
|
|
|
|
+ case '/': tSlash(); return;
|
|
|
|
+ case '%': tAddToken2(T_MOD_SET, T_MOD); return;
|
|
case '<':
|
|
case '<':
|
|
- return tAddToken4('<', T_LEFT_SHIFT_SET, T_LEFT_SHIFT, T_LESS_EQUAL,
|
|
|
|
- T_LESS);
|
|
|
|
|
|
+ tAddToken4('<', T_LEFT_SHIFT_SET, T_LEFT_SHIFT, T_LESS_EQUAL,
|
|
|
|
+ T_LESS);
|
|
|
|
+ return;
|
|
case '>':
|
|
case '>':
|
|
- return tAddToken4('>', T_RIGHT_SHIFT_SET, T_RIGHT_SHIFT,
|
|
|
|
- T_GREATER_EQUAL, T_GREATER);
|
|
|
|
- case '=': return tAddToken2(T_EQUAL, T_SET);
|
|
|
|
- case '!': return tAddToken2(T_NOT_EQUAL, T_NOT);
|
|
|
|
- case '&': return tAddToken3('&', T_AND, T_BIT_AND_SET, T_BIT_AND);
|
|
|
|
- case '|': return tAddToken3('|', T_OR, T_BIT_OR_SET, T_BIT_OR);
|
|
|
|
- case '~': return tAddToken(T_BIT_NOT);
|
|
|
|
- case '^': return tAddToken2(T_BIT_XOR_SET, T_BIT_XOR);
|
|
|
|
- case ',': return tAddToken(T_COMMA);
|
|
|
|
- case ';': return tAddToken(T_SEMICOLON);
|
|
|
|
- case '(': return tAddToken(T_OPEN_BRACKET);
|
|
|
|
- case ')': return tAddToken(T_CLOSE_BRACKET);
|
|
|
|
- case '{': return tAddToken(T_OPEN_CURVED_BRACKET);
|
|
|
|
- case '}': return tAddToken(T_CLOSE_CURVED_BRACKET);
|
|
|
|
- case '"': return tAddString();
|
|
|
|
- case '.': return tAddToken(T_POINT);
|
|
|
|
- case '[': return tAddToken(T_OPEN_SQUARE_BRACKET);
|
|
|
|
- case ']': return tAddToken(T_CLOSE_SQUARE_BRACKET);
|
|
|
|
|
|
+ tAddToken4('>', T_RIGHT_SHIFT_SET, T_RIGHT_SHIFT, T_GREATER_EQUAL,
|
|
|
|
+ T_GREATER);
|
|
|
|
+ return;
|
|
|
|
+ case '=': tAddToken2(T_EQUAL, T_SET); return;
|
|
|
|
+ case '!': tAddToken2(T_NOT_EQUAL, T_NOT); return;
|
|
|
|
+ case '&': tAddToken3('&', T_AND, T_BIT_AND_SET, T_BIT_AND); return;
|
|
|
|
+ case '|': tAddToken3('|', T_OR, T_BIT_OR_SET, T_BIT_OR); return;
|
|
|
|
+ case '~': tAddToken(T_BIT_NOT); return;
|
|
|
|
+ case '^': tAddToken2(T_BIT_XOR_SET, T_BIT_XOR); return;
|
|
|
|
+ case ',': tAddToken(T_COMMA); return;
|
|
|
|
+ case ';': tAddToken(T_SEMICOLON); return;
|
|
|
|
+ case '(': tAddToken(T_OPEN_BRACKET); return;
|
|
|
|
+ case ')': tAddToken(T_CLOSE_BRACKET); return;
|
|
|
|
+ case '{': tAddToken(T_OPEN_CURVED_BRACKET); return;
|
|
|
|
+ case '}': tAddToken(T_CLOSE_CURVED_BRACKET); return;
|
|
|
|
+ case '"': tAddString(); return;
|
|
|
|
+ case '.': tAddToken(T_POINT); return;
|
|
|
|
+ case '[': tAddToken(T_OPEN_SQUARE_BRACKET); return;
|
|
|
|
+ case ']': tAddToken(T_CLOSE_SQUARE_BRACKET); return;
|
|
}
|
|
}
|
|
tError("unknown character on line %d: %c", line, c);
|
|
tError("unknown character on line %d: %c", line, c);
|
|
- return false;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void tParseFile() {
|
|
static void tParseFile() {
|
|
@@ -232,16 +238,20 @@ static void tParseFile() {
|
|
writeIndex = 0;
|
|
writeIndex = 0;
|
|
line = 1;
|
|
line = 1;
|
|
error[0] = '\0';
|
|
error[0] = '\0';
|
|
- while(tParseToken()) {
|
|
|
|
|
|
+ while(true) {
|
|
|
|
+ int c = fRead();
|
|
|
|
+ if(c == EOF) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ tParseToken(c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool tTokenize(const char* path) {
|
|
bool tTokenize(const char* path) {
|
|
- if(fOpen(path)) {
|
|
|
|
- tError("cannot read file '%s'", path);
|
|
|
|
- return true;
|
|
|
|
|
|
+ if(!setjmp(errorJump)) {
|
|
|
|
+ fOpen(path, tError);
|
|
|
|
+ tParseFile();
|
|
}
|
|
}
|
|
- tParseFile();
|
|
|
|
fClose();
|
|
fClose();
|
|
return error[0] != '\0';
|
|
return error[0] != '\0';
|
|
}
|
|
}
|