Browse Source

multiply and improved errors

Kajetan Johannes Hammerle 4 years ago
parent
commit
df186d6185
8 changed files with 80 additions and 29 deletions
  1. 32 11
      Compiler.c
  2. 1 1
      Operation.h
  3. 18 0
      Script.c
  4. 1 5
      Test.c
  5. 21 11
      Tokenizer.c
  6. 1 1
      Tokenizer.h
  7. 3 0
      tests/calc/multiply
  8. 3 0
      tests/calc/multiply.out

+ 32 - 11
Compiler.c

@@ -1,3 +1,4 @@
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -7,17 +8,23 @@
 #include "Tokenizer.h"
 
 #define MAX_BYTES (1024 * 1024)
+#define ERROR_LENGTH 256
 
-static const char* UNEXPECTED_TOKEN = "unexpected token";
-static const char* FULL_BUFFER = "the compiler buffer is too small";
-static const char* error = NULL;
+static char error[ERROR_LENGTH] = {'\0'};
 
 static unsigned char byteCode[MAX_BYTES];
 static int writeIndex = 0;
 
+static void cError(const char* format, ...) {
+    va_list args;
+    va_start(args, format);
+    vsnprintf(error, ERROR_LENGTH, format, args);
+    va_end(args);
+}
+
 static bool cAddBytes(const void* data, int length) {
     if(writeIndex + length > MAX_BYTES) {
-        error = FULL_BUFFER;
+        cError("the compiler buffer is too small");
         return false;
     }
     memcpy(byteCode + writeIndex, data, length);
@@ -30,11 +37,12 @@ static bool cAddOperation(Operation token) {
     return cAddBytes(&c, 1);
 }
 
-static bool cConsumeToken(Token t) {
-    if(tReadToken() == t) {
+static bool cConsumeToken(Token wanted) {
+    Token t = tReadToken();
+    if(wanted == t) {
         return true;
     }
-    error = UNEXPECTED_TOKEN;
+    cError("unexpected token: expected '%s' got '%s'", tGetTokenName(wanted), tGetTokenName(t));
     return false;
 }
 
@@ -54,12 +62,24 @@ static bool cConstant() {
     return false;
 }
 
-static bool cAdd() {
+static bool cMul() {
     if(!cConstant()) {
         return false;
     }
+    while(cConsumeTokenIf(T_MUL)) {
+        if(!cConstant() || !cAddOperation(OP_MUL)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool cAdd() {
+    if(!cMul()) {
+        return false;
+    }
     while(cConsumeTokenIf(T_ADD)) {
-        if(!cConstant() || !cAddOperation(OP_ADD)) {
+        if(!cMul() || !cAddOperation(OP_ADD)) {
             return false;
         }
     }
@@ -77,14 +97,15 @@ static bool cLine() {
     } else if(t == T_PRINT) {
         return cPrint();
     }
-    error = UNEXPECTED_TOKEN;
+    cError("unexpected token: %s", tGetTokenName(t));
     return false;
 }
 
 unsigned char* cCompile(int* codeLength) {
+    writeIndex = 0;
     while(cLine()) {
     }
-    if(error != NULL) {
+    if(error[0] != '\0') {
         return NULL;
     }
     unsigned char* bytes = malloc(writeIndex);

+ 1 - 1
Operation.h

@@ -1,6 +1,6 @@
 #ifndef OPERATION_H
 #define OPERATION_H
 
-typedef enum Operation { OP_NOTHING, OP_PUSH_INT, OP_ADD, OP_PRINT } Operation;
+typedef enum Operation { OP_NOTHING, OP_PUSH_INT, OP_ADD, OP_MUL, OP_PRINT } Operation;
 
 #endif

+ 18 - 0
Script.c

@@ -83,6 +83,23 @@ void sAdd(Script* sc) {
     sPush(sc, &o);
 }
 
+void sMul(Script* sc) {
+    Object a;
+    if(sPop(sc, &a)) {
+        return;
+    }
+    Object b;
+    if(sPop(sc, &b)) {
+        return;
+    }
+    if(a.type != OT_INT || b.type != OT_INT) {
+        sc->error = NOT_AN_INT;
+        return;
+    }
+    Object o = {.type = OT_INT, .data.intValue = a.data.intValue * b.data.intValue};
+    sPush(sc, &o);
+}
+
 void sPrint(Script* sc) {
     Object o;
     if(sPop(sc, &o)) {
@@ -98,6 +115,7 @@ static void sConsumeInstruction(Script* sc) {
         case OP_NOTHING: break;
         case OP_PUSH_INT: sPushInt(sc); break;
         case OP_ADD: sAdd(sc); break;
+        case OP_MUL: sMul(sc); break;
         case OP_PRINT: sPrint(sc); break;
     }
 }

+ 1 - 5
Test.c

@@ -95,11 +95,7 @@ static void tsCheckFile() {
     int codeLength;
     unsigned char* code = cCompile(&codeLength);
     if(code == NULL) {
-        if(cGetError() == NULL) {
-            printf("'%s' has error but none was set\n", path);
-        } else {
-            puts(cGetError());
-        }
+        puts(cGetError());
         return;
     }
     Script* sc = sInit(code, codeLength);

+ 21 - 11
Tokenizer.c

@@ -1,3 +1,4 @@
+#include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -5,15 +6,21 @@
 #include "Utils.h"
 
 #define TOKEN_BUFFER_LENGTH (1024 * 1024)
+#define ERROR_LENGTH 256
 
 static char tokenBuffer[TOKEN_BUFFER_LENGTH];
 static int writeIndex = 0;
 static int readIndex = 0;
-
-static const char* TOO_LONG_LITERAL = "literal is too long";
-static const char* UNKNOWN_CHARACTER = "unknown character";
+static int line = 1;
 static FILE* file = NULL;
-static const char* error = NULL;
+static char error[ERROR_LENGTH] = {'\0'};
+
+static void tError(const char* format, ...) {
+    va_list args;
+    va_start(args, format);
+    vsnprintf(error, ERROR_LENGTH, format, args);
+    va_end(args);
+}
 
 static bool tAdd(const void* data, int length) {
     if(writeIndex + length > TOKEN_BUFFER_LENGTH) {
@@ -54,7 +61,7 @@ static bool tParseLiteral(int c) {
     buffer[0] = c;
     while(isLetter(tPeek())) {
         if(index >= 63) {
-            error = TOO_LONG_LITERAL;
+            tError("literal is too long");
             return false;
         }
         buffer[index++] = tRead();
@@ -84,19 +91,21 @@ static bool tParseToken() {
         return tParseNumber(c);
     }
     switch(c) {
-        case ' ':
-        case '\n': return true;
+        case ' ': return true;
+        case '\n': line++; return true;
         case '+': return tAddToken(T_ADD);
+        case '*': return tAddToken(T_MUL);
         case ';': return tAddToken(T_SEMICOLON);
     }
-    error = UNKNOWN_CHARACTER;
+    tError("unknown character on line %d: %c", line, c);
     return false;
 }
 
 static void tParseFile() {
     readIndex = 0;
     writeIndex = 0;
-    error = NULL;
+    line = 1;
+    error[0] = '\0';
     while(tParseToken()) {
     }
 }
@@ -104,12 +113,12 @@ static void tParseFile() {
 bool tTokenize(const char* path) {
     file = fopen(path, "r");
     if(file == NULL) {
-        error = "cannot read file";
+        tError("cannot read file '%s'", path);
         return true;
     }
     tParseFile();
     fclose(file);
-    return error != NULL;
+    return error[0] != '\0';
 }
 
 const char* tGetError() {
@@ -145,6 +154,7 @@ const char* tGetTokenName(Token token) {
     switch(token) {
         case T_INT: return "int";
         case T_ADD: return "+";
+        case T_MUL: return "*";
         case T_PRINT: return "print";
         case T_SEMICOLON: return ";";
         case T_END: return "end";

+ 1 - 1
Tokenizer.h

@@ -3,7 +3,7 @@
 
 #include <stdbool.h>
 
-typedef enum Token { T_INT, T_ADD, T_PRINT, T_SEMICOLON, T_END } Token;
+typedef enum Token { T_INT, T_ADD, T_MUL, T_PRINT, T_SEMICOLON, T_END } Token;
 
 bool tTokenize(const char* path);
 const char* tGetError();

+ 3 - 0
tests/calc/multiply

@@ -0,0 +1,3 @@
+print 2 * 3;
+print 3 + 4 * 5;
+print 6 + 7 * 8 + 9;

+ 3 - 0
tests/calc/multiply.out

@@ -0,0 +1,3 @@
+6
+23
+71