OBFI

Brainfuck Interpreter
git clone http://git.omkov.net/OBFI
Log | Tree | Refs | README | LICENCE | Download

AuthorJakob Wakeling <[email protected]>
Date2020-07-01 11:50:21
Commit6fb8c64b9e1d312272eafaf3ddddbaa9b7969ff5
Parent177d490ae0f49c270608ece44b871c8efd18bd79

Fix linking order having an effect on performance

The array being in global space was having an effect on performance when the object files were linked in a certain order. Moving the array into the execution scope, and onto the stack, solves this issue. In addition to this fix, I have made a number of smaller optimisations and improvements, to both the performance of the interpreter, as well as its error handling.

Diffstat

M CMakeLists.txt | 2 +-
M src/main.c | 69 +++++++++++++++++++++++++++++++++++++++------------------------------
M src/parse.c | 11 +++++------
M src/parse.h | 6 +-----

4 files changed, 46 insertions, 42 deletions

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7d59a99..cac770c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
 SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
 SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
 
-ADD_COMPILE_DEFINITIONS(VERSION="1.0.0")
+ADD_COMPILE_DEFINITIONS(VERSION="1.0.1")
 
 FILE(GLOB SOURCES ${CMAKE_SOURCE_DIR}/src/*)
 
diff --git a/src/main.c b/src/main.c
index 22adaf8..119d803 100644
--- a/src/main.c
+++ b/src/main.c
@@ -42,12 +42,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 #include <errno.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-static char arr[30000] = { 0 }, *ptr = arr;
-static tok_t **dat; static size_t cap, top;
+static int execute(tok_t *toks);
 
 static void help(void);
 static void version(void);
@@ -68,44 +68,54 @@ int main(int argc, char *argv[]) {
 
 	if (opt.ind == argc) { error(1, "%s: missing operand", argv[0]); }
 
-	char *file = argv[opt.ind]; struct stat fs; stat(file, &fs);
+	char *file = argv[opt.ind]; struct stat fs;
+	if (stat(file, &fs)) { error(1, "%s: %s: %s", argv[0], file, serrno); }
+	
 	char *fb = malloc(sizeof (*fb) * fs.st_size + 1); fb[fs.st_size] = 0;
 	if (!fb) { error(1, "%s: %s", argv[0], serrno); }
 
-	FILE *fi = fopen(file, "r"); fread(fb, fs.st_size, 1, fi); fclose(fi);
+	FILE *fi = fopen(file, "r");
+	if (!fi) { free(fb); error(1, "%s: %s: %s", argv[0], file, serrno); }
+	
+	fread(fb, 1, fs.st_size, fi); fclose(fi);
+	if (errno) { free(fb); error(1, "%s: %s: %s", argv[0], file, serrno); }
 
 	tok_t *toks = parse(fb, fs.st_size); free(fb);
+	if (!toks) { error(1, "%s: %s", argv[0], serrno); }
 
-	cap = 64; top = 0; dat = malloc(sizeof (*dat) * cap);
-	if (!dat) { error(1, "%s: %s", argv[0], serrno); }
+	if (execute(toks)) { free(toks); error(1, "%s: %s", argv[0], serrno); }
 
-	for (tok_t *t = toks; t->typ != EOF; ++t) {
-start:	switch (t->typ) {
-		case RGT: { ptr += t->num; break; }
-		case LFT: { ptr -= t->num; break; }
-		case ADD: { *ptr += t->num; break; }
-		case SUB: { *ptr -= t->num; break; }
-		case PUT: { fputc(*ptr, stdout); break; }
-		case GET: { *ptr = fgetc(stdin); break; }
-		case OPN: {
-			if (!*ptr) {
-				register size_t i = 1; for (++t; i != 0; ++t) {
-					if (t->typ == OPN) { ++i; } else if (t->typ == CLS) { --i; }
-				} goto start;
-			}
-			
-			if (top == cap) {
-				register tok_t **old = dat; cap *= 2; dat = realloc(dat, cap);
-				if (!dat) { free(old); error(1, "%s: %s", argv[0], serrno); }
-			} dat[top++] = t; break;
-		}
-		case CLS: {
-			if (*ptr) { t = dat[top - 1]; } else { dat[--top] = 0; } break;
-		}
-		}
+	free(toks); return 0;
+}
+
+static int execute(tok_t *toks) {
+	uint8_t arr[30000] = { 0 }, *ptr = arr;
+	
+	size_t cap = 64, top = 0; tok_t **dat;
+	if (!(dat = malloc(sizeof (*dat) * cap))) { return 1; }
+	
+	for (tok_t *t = toks; t->typ != EOF; ++t) switch (t->typ) {
+	case RGT: { ptr += t->num; break; }
+	case LFT: { ptr -= t->num; break; }
+	case ADD: { *ptr += t->num; break; }
+	case SUB: { *ptr -= t->num; break; }
+	case PUT: { fputc(*ptr, stdout); break; }
+	case GET: { *ptr = fgetc(stdin); break; }
+	case OPN: {
+		if (!*ptr) { for (size_t i = 1; i != 0; ++t) {
+			if ((t + 1)->typ == OPN) { ++i; }
+			else if ((t + 1)->typ == CLS) { --i; }
+		} break; }
+		
+		if (top == cap) {
+			tok_t **old = dat; cap *= 2; dat = realloc(dat, cap);
+			if (!dat) { free(old); return 1; }
+		} dat[top++] = t; break;
+	}
+	case CLS: { if (*ptr) { t = dat[top - 1]; } else { --top; } break; }
 	}
 
-	free(dat); free(toks); return 0;
+	free(dat); return 0;
 }
 
 static void help(void) {
diff --git a/src/parse.c b/src/parse.c
index 3021504..154453a 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -42,7 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 #define TOKSET(type) tok.typ = type; tok.ln = line; tok.cl = col
 
-tok_t lex(char *str) {
+static inline tok_t lex(char *str) {
 	static char *p; static size_t line, col; tok_t tok;
 	if (str) { p = str; line = 0; col = 0; } tok.num = 1;
 
@@ -69,11 +69,10 @@ tok_t lex(char *str) {
 
 tok_t *parse(char *str, size_t len) {
 	tok_t *toks = malloc(sizeof (*toks) * len);
-	register tok_t *p = toks;
+	if (!toks) { return NULL; }
 
-	tok_t tok = lex(str); if (tok.typ == EOF) { goto end; }
-	do { *p++ = tok; } while ((tok = lex(NULL)).typ != EOF);
+	register tok_t *p = toks;
+	*p = lex(str); while (p->typ != EOF) { *++p = lex(NULL); }
 
-end:
-	*p = tok; return toks;
+	return toks;
 }
diff --git a/src/parse.h b/src/parse.h
index 25fe480..306636d 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -41,7 +41,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 enum {
 	END = EOF, // EOF
-	ERR = 0,   // ERROR
 	RGT = 1,   // '>'
 	LFT = 2,   // '<'
 	ADD = 3,   // '+'
@@ -50,12 +49,10 @@ enum {
 	GET = 6,   // ','
 	OPN = 7,   // '['
 	CLS = 8,   // ']'
-	SET = 9,   // '[-]', '[+]'
 };
 
 typedef struct { int typ; size_t num, ln, cl; } tok_t;
 
-tok_t  lex(char *str);
-tok_t *parse(char *str, size_t len);
+extern tok_t *parse(char *str, size_t len);
 
 #endif // OMKOV_OBFI_LEX_H_AD07BU3C