Browse Source

extended error checking for variables, added code line to errors

Kajetan Johannes Hammerle 1 year ago
parent
commit
c63fc66b27
11 changed files with 245 additions and 179 deletions
  1. 93 66
      Compiler.c
  2. 15 10
      DataType.c
  3. 27 26
      DataType.h
  4. 6 4
      Error.c
  5. 5 4
      Error.h
  6. 2 0
      Test.c
  7. 24 22
      tokenizer/FileTokens.c
  8. 31 25
      tokenizer/Tokenizer.c
  9. 5 1
      utils/Functions.c
  10. 27 16
      utils/Variables.c
  11. 10 5
      utils/Variables.h

+ 93 - 66
Compiler.c

@@ -74,10 +74,10 @@ TYPE_OP(BIT_AND, NOTHING, NOTHING, "&")
 TYPE_OP(LEFT_SHIFT, NOTHING, NOTHING, "<<")
 TYPE_OP(RIGHT_SHIFT, NOTHING, NOTHING, ">>")
 
-static check_format(1, 2) void cError(const char* format, ...) {
+static check_format(2, 3) void cError(int codeLine, const char* format, ...) {
     va_list args;
     va_start(args, format);
-    eInitErrorV(error, path, line, format, args);
+    eInitErrorV(error, path, line, codeLine, format, args);
     va_end(args);
     longjmp(errorJump, 0);
 }
@@ -86,24 +86,30 @@ static const char* cGetName(DataType dt) {
     return dtGetName(&structs, dt);
 }
 
-static void cInvalidOperation(DataType a, DataType b, const char* op) {
-    cError("invalid operation: %s %s %s", cGetName(a), op, cGetName(b));
+static void cInvalidOperation(int codeLine, DataType a, DataType b,
+                              const char* op) {
+    cError(codeLine, "invalid operation: %s %s %s", cGetName(a), op,
+           cGetName(b));
 }
 
-static void cNotDeclared(const char* name) {
-    cError("variable %s has not been declared", name);
+static void cNotDeclared(int codeLine, const char* name) {
+    cError(codeLine, "variable %s has not been declared", name);
 }
 
-static void cDeclared(const char* name) {
-    cError("%s has already been declared", name);
+static void cDeclared(int codeLine, const char* name) {
+    cError(codeLine, "%s has already been declared", name);
 }
 
-static void cTooMuchArguments(void) {
-    cError("too much function arguments");
+static void cTooMuchArguments(int codeLine) {
+    cError(codeLine, "too much function arguments");
 }
 
-static void cUnexpectedToken(Token t) {
-    cError("unexpected token: %s", tGetName(t));
+static void cUnexpectedToken(int codeLine, Token t) {
+    cError(codeLine, "unexpected token: %s", tGetName(t));
+}
+
+static void cCannotGetSize(int codeLine, DataType dt) {
+    cError(codeLine, "cannot get size of data type: %s", cGetName(dt));
 }
 
 #define BUFFER_SIZE 256
@@ -116,7 +122,7 @@ static void cUnknownFunction(Function* f) {
         max += snprintf(buffer + max, (size_t)(BUFFER_SIZE - max),
                         i > 0 ? ", %s" : "%s", name);
     }
-    cError("unknown function: %s(%s)", f->name, buffer);
+    cError(__LINE__, "unknown function: %s(%s)", f->name, buffer);
 }
 
 static void cAddOperation(Operation token) {
@@ -163,7 +169,8 @@ static Token cReadTokenAndLine(void) {
 static void cConsumeToken(Token wanted) {
     Token t = cReadTokenAndLine();
     if(wanted != t) {
-        cError("expected '%s' got '%s'", tGetName(wanted), tGetName(t));
+        cError(__LINE__, "expected '%s' got '%s'", tGetName(wanted),
+               tGetName(t));
     }
 }
 
@@ -174,7 +181,7 @@ static bool cConsumeTokenIf(Token t) {
 static void cConstantInt32(void) {
     int32 value;
     if(tReadInt32(&value)) {
-        cError("int token without an int");
+        cError(__LINE__, "int token without an int");
     }
     cAddInt32Operation(OP_PUSH_INT, value);
 }
@@ -182,7 +189,7 @@ static void cConstantInt32(void) {
 static void cConstantFloat(void) {
     float value;
     if(tReadFloat(&value)) {
-        cError("float token without a float");
+        cError(__LINE__, "float token without a float");
     }
     cAddOperation(OP_PUSH_FLOAT);
     bcAddBytes(code, &value, sizeof(float));
@@ -191,13 +198,17 @@ static void cConstantFloat(void) {
 static const char* cReadString(void) {
     const char* literal = tReadString();
     if(literal == NULL) {
-        cError("literal without string on line %d", line);
+        cError(__LINE__, "literal without string");
     }
     return literal;
 }
 
 static int cGetSize(DataType dt) {
-    return dtGetSize(dt, &structs);
+    int size;
+    if(dtGetSize(dt, &structs, &size)) {
+        cError(__LINE__, "cannot get size of data type");
+    }
+    return size;
 }
 
 static DataType cExtendType(DataType dt) {
@@ -217,7 +228,7 @@ static DataType cReadType(Token t, bool force) {
             Struct* st = stsSearch(&structs, name);
             if(st == NULL) {
                 if(force) {
-                    cError("struct %s does not exist", name);
+                    cError(__LINE__, "struct %s does not exist", name);
                 } else {
                     return dtVoid();
                 }
@@ -226,7 +237,7 @@ static DataType cReadType(Token t, bool force) {
         }
         default:
             if(force) {
-                cUnexpectedToken(t);
+                cUnexpectedToken(__LINE__, t);
             }
             return dtVoid();
     }
@@ -249,7 +260,7 @@ static void cLoadRef(DataType type) {
     }
     switch(dtGetType(type)) {
         DT_OPERATION(LOAD);
-        default: cError("cannot load type %s", cGetName(type));
+        default: cError(__LINE__, "cannot load type %s", cGetName(type));
     }
 }
 
@@ -271,7 +282,7 @@ static void cCallFunctionArguments(Function* f) {
     while(true) {
         DataType dt = cUnpackedExpression();
         if(fAddArgument(f, dt, &structs)) {
-            cTooMuchArguments();
+            cTooMuchArguments(__LINE__);
         } else if(cConsumeTokenIf(T_CLOSE_BRACKET)) {
             return;
         }
@@ -311,17 +322,17 @@ static DataType cCallFunction(const char* name) {
 static void cStore(DataType left, DataType right, const char* name) {
     if(dtIsArray(left)) {
         if(!dtCompare(left, right)) {
-            cInvalidOperation(left, right, name);
+            cInvalidOperation(__LINE__, left, right, name);
         }
         cAddOperation(OP_STORE_ARRAY);
         return;
     }
     if(!dtCompare(left, right)) {
-        cInvalidOperation(left, right, name);
+        cInvalidOperation(__LINE__, left, right, name);
     }
     switch(dtGetType(left)) {
         DT_OPERATION(STORE);
-        default: cError("cannot store type %s", cGetName(left));
+        default: cError(__LINE__, "cannot store type %s", cGetName(left));
     }
 }
 
@@ -334,7 +345,8 @@ static DataType cLiteral(void) {
     if(!vsSearch(&vars, &v, literal)) {
         if(dtIsPointer(v.type)) {
             if(!dtIsStruct(v.type)) {
-                cError("non struct type %s should not be a pointer here",
+                cError(__LINE__,
+                       "non struct type %s should not be a pointer here",
                        cGetName(v.type));
             }
             cAddInt32Operation(OP_PUSH_STRUCT_REFERENCE, v.address);
@@ -346,7 +358,7 @@ static DataType cLiteral(void) {
         cAddInt32Operation(OP_DEREFERENCE_GVAR, v.address);
         return dtToPointer(v.type);
     }
-    cNotDeclared(literal);
+    cNotDeclared(__LINE__, literal);
     return dtVoid();
 }
 
@@ -371,14 +383,14 @@ static DataType cBracketPrimary(void) {
 
 static void cArrayIndex(void) {
     if(!dtIsInt(cUnpackedExpression())) {
-        cError("array index must be an int");
+        cError(__LINE__, "array index must be an int");
     }
 }
 
 static DataType cAllocArray(void) {
     DataType dt = cReadType(cReadTokenAndLine(), true);
     if(dtIsArray(dt)) {
-        cError("array type must not be an array");
+        cError(__LINE__, "array type must not be an array");
     }
     cConsumeToken(T_OPEN_SQUARE_BRACKET);
     cArrayIndex();
@@ -390,7 +402,7 @@ static DataType cAllocArray(void) {
 static DataType cLength(void) {
     DataType array = cUnpackedExpression();
     if(!dtIsArray(array)) {
-        cError("length expects an array");
+        cError(__LINE__, "length expects an array");
     }
     cAddOperation(OP_LENGTH);
     return dtInt();
@@ -406,19 +418,20 @@ static DataType cPrimary(void) {
         case T_LITERAL: return cLiteral();
         case T_NEW: return cAllocArray();
         case T_LENGTH: return cLength();
-        default: cUnexpectedToken(t); return dtVoid();
+        default: cUnexpectedToken(__LINE__, t); return dtVoid();
     }
 }
 
 static void cRemoveReference(DataType* dt, const char* name) {
     if(!dtRemovePointer(dt)) {
-        cError("%s needs a reference not %s", name, cGetName(*dt));
+        cError(__LINE__, "%s needs a reference not %s", name, cGetName(*dt));
     }
 }
 
 static void cExpectType(DataType actual, DataType wanted, const char* name) {
     if(!dtCompare(actual, wanted)) {
-        cError("%s needs %s not %s", name, cGetName(wanted), cGetName(actual));
+        cError(__LINE__, "%s needs %s not %s", name, cGetName(wanted),
+               cGetName(actual));
     }
 }
 
@@ -437,21 +450,26 @@ static void cPostChange(DataType* dt, int8 change, const char* name) {
     if(dtIsInt(*dt)) {
         cChangeType(dt, OP_CHANGE_INT, OP_PUSH_POST_CHANGE_INT, change);
     } else {
-        cError("%s needs an int not %s", name, cGetName(*dt));
+        cError(__LINE__, "%s needs an int not %s", name, cGetName(*dt));
     }
 }
 
 static DataType cStructAccess(DataType dt) {
     Struct* st = dtGetStruct(&structs, dt);
     if(st == NULL) {
-        cError(". expects a struct not %s", cGetName(dt));
+        cError(__LINE__, ". expects a struct not %s", cGetName(dt));
     }
     cConsumeToken(T_LITERAL);
     const char* name = cReadString();
     Variable inner;
-    if(vSearchStruct(&inner, &structs, st, name)) {
-        cError("%s has no member %s", st->name, name);
-    } else if(inner.address > 0) {
+    switch(vSearchStruct(&inner, &structs, st, name)) {
+        case VE_CANNOT_FIND:
+            cError(__LINE__, "%s has no member %s", st->name, name);
+            break;
+        case VE_SIZE_ERROR: cCannotGetSize(__LINE__, dt); break;
+        default: break;
+    }
+    if(inner.address > 0) {
         cAddInt32Operation(OP_PUSH_INT, inner.address);
         cAddInt32Operation(OP_ADD_REFERENCE, 1);
     }
@@ -470,7 +488,7 @@ static DataType cAccess(void) {
             dt = cStructAccess(dt);
         } else if(cConsumeTokenIf(T_OPEN_SQUARE_BRACKET)) {
             if(!dtIsArray(dt)) {
-                cError("[] needs an array");
+                cError(__LINE__, "[] needs an array");
             }
             cAddOperation(OP_LOAD_ARRAY);
             dtRemovePointer(&dt);
@@ -489,7 +507,7 @@ static DataType cPreChange(DataType dt, int8 change, const char* name) {
     if(dtIsInt(dt)) {
         cChangeType(&dt, OP_CHANGE_INT, OP_PUSH_PRE_CHANGE_INT, change);
     } else {
-        cError("%s needs an int not %s", name, cGetName(dt));
+        cError(__LINE__, "%s needs an int not %s", name, cGetName(dt));
     }
     return dt;
 }
@@ -500,7 +518,7 @@ static DataType cInvertSign(DataType dt) {
     } else if(dtIsFloat(dt)) {
         cAddOperation(OP_INVERT_SIGN_FLOAT);
     } else {
-        cError("cannot invert sign of %s", cGetName(dt));
+        cError(__LINE__, "cannot invert sign of %s", cGetName(dt));
     }
     return dt;
 }
@@ -509,7 +527,7 @@ static DataType cCast(DataType in, DataType a, Operation aOp, DataType out) {
     if(dtCompare(in, a)) {
         cAddOperation(aOp);
     } else {
-        cError("cannot cast %s to %s", cGetName(in), cGetName(out));
+        cError(__LINE__, "cannot cast %s to %s", cGetName(in), cGetName(out));
     }
     return out;
 }
@@ -524,7 +542,7 @@ static DataType cUnaryBitNot(DataType dt) {
     if(dtIsInt(dt)) {
         cAddOperation(OP_BIT_NOT_INT);
     } else {
-        cError("~ needs an int not %s", cGetName(dt));
+        cError(__LINE__, "~ needs an int not %s", cGetName(dt));
     }
     return dt;
 }
@@ -559,7 +577,7 @@ static void cAddTypeOperation(DataType* a, Parser bf, const TypedOp* op) {
     *a = cUnpack(*a);
     DataType b = cUnpack(bf());
     if(!dtCompare(*a, b)) {
-        cInvalidOperation(*a, b, op->name);
+        cInvalidOperation(__LINE__, *a, b, op->name);
     } else if(dtIsInt(*a) && op->intOp != OP_NOTHING) {
         cAddOperation(op->intOp);
     } else if(dtIsFloat(*a) && op->floatOp != OP_NOTHING) {
@@ -567,7 +585,7 @@ static void cAddTypeOperation(DataType* a, Parser bf, const TypedOp* op) {
     } else if(dtIsArray(*a) && op->pointerOp != OP_NOTHING) {
         cAddOperation(op->pointerOp);
     } else {
-        cInvalidOperation(*a, b, op->name);
+        cInvalidOperation(__LINE__, *a, b, op->name);
     }
 }
 
@@ -675,7 +693,7 @@ static DataType cLogical(Parser f, Token t, Operation jump, Operation op) {
         int32 p = cReserveInt32();
         DataType b = f();
         if(!dtIsInt(a) || !dtIsInt(b)) {
-            cInvalidOperation(a, b, tGetName(t));
+            cInvalidOperation(__LINE__, a, b, tGetName(t));
         }
         cAddOperation(op);
         cSetInt32(p, code->length);
@@ -698,7 +716,7 @@ static void cConsumeBody(void) {
     while(!cConsumeTokenIf(T_CLOSE_CURVED_BRACKET)) {
         if(tPeekToken() == T_END) {
             line = oldLine;
-            cError("non closed curved bracket");
+            cError(__LINE__, "non closed curved bracket");
         }
         cLine();
     }
@@ -713,7 +731,7 @@ static void cConsumeScope(void) {
 
 static void cAddReturn(Operation op) {
     if(returnIndex >= RETURN_BUFFER) {
-        cError("too much returns in function");
+        cError(__LINE__, "too much returns in function");
     }
     cAddOperation(op);
     returns[returnIndex++] = cReserveInt32();
@@ -728,7 +746,8 @@ static void cReturn(void) {
     }
     DataType dt = cUnpackedExpression();
     if(!dtCompare(returnType, dt)) {
-        cError("wrong return type, should be %s", cGetName(returnType));
+        cError(__LINE__, "wrong return type, should be %s",
+               cGetName(returnType));
     } else if(dtIsInt(dt)) {
         cAddReturn(OP_RETURN_INT);
     } else if(dtIsFloat(dt)) {
@@ -736,7 +755,7 @@ static void cReturn(void) {
     } else if(dtIsArray(dt)) {
         cAddReturn(OP_RETURN_POINTER);
     } else {
-        cError("cannot return %s", cGetName(dt));
+        cError(__LINE__, "cannot return %s", cGetName(dt));
     }
     cConsumeToken(T_SEMICOLON);
     hasReturn = 2;
@@ -820,16 +839,20 @@ static void cSetVariable(void) {
         case T_BIT_XOR_SET: cOperationSet(dt, &TYPED_BIT_XOR); break;
         case T_LEFT_SHIFT_SET: cOperationSet(dt, &TYPED_LEFT_SHIFT); break;
         case T_RIGHT_SHIFT_SET: cOperationSet(dt, &TYPED_RIGHT_SHIFT); break;
-        default: cUnexpectedToken(t);
+        default: cUnexpectedToken(__LINE__, t);
     }
 }
 
 static void cDeclareSet(Variables* vs, DataType dt, const char* var,
                         Operation op) {
     if(vsInScope(vs, var)) {
-        cDeclared(var);
+        cDeclared(__LINE__, var);
+    }
+    Variable* v;
+    switch(vsAdd(vs, var, dt, &structs, &v)) {
+        case VE_SIZE_ERROR: cCannotGetSize(__LINE__, dt); break;
+        default: break;
     }
-    Variable* v = vsAdd(vs, var, dt, &structs);
     if(!dtIsStruct(dt) || dtIsArray(dt)) {
         cConsumeToken(T_SET);
         cAddInt32Operation(op, v->address);
@@ -895,9 +918,9 @@ static void cFor(void) {
 
 static void cBreak(void) {
     if(forWhileStack == 0) {
-        cError("break without for or while");
+        cError(__LINE__, "break without for or while");
     } else if(breakIndex >= BREAK_BUFFER) {
-        cError("too much breaks");
+        cError(__LINE__, "too much breaks");
     }
     cAddOperation(OP_GOTO);
     breaks[breakIndex++] = cReserveInt32();
@@ -906,7 +929,7 @@ static void cBreak(void) {
 
 static void cContinue(void) {
     if(forWhileStack == 0) {
-        cError("continue without for or while");
+        cError(__LINE__, "continue without for or while");
     }
     cAddInt32Operation(OP_GOTO, continueAt);
     cConsumeToken(T_SEMICOLON);
@@ -933,7 +956,7 @@ static void cLine(void) {
 
 static void cBuildFunction(Function* f, DataType rType, const char* fName) {
     if(dtIsStruct(rType) && !dtIsArray(rType)) {
-        cError("structs cannot be returned");
+        cError(__LINE__, "structs cannot be returned");
     }
     fInit(f, fName, line);
     f->returnType = rType;
@@ -947,14 +970,18 @@ static void cBuildFunction(Function* f, DataType rType, const char* fName) {
         cConsumeToken(T_LITERAL);
         const char* name = cReadString();
         if(vsInScope(&vars, name)) {
-            cDeclared(name);
+            cDeclared(__LINE__, name);
         }
         if(dtIsStruct(dt)) {
             dt = dtToPointer(dt);
         }
-        vsAdd(&vars, name, dt, &structs);
+        Variable* v;
+        switch(vsAdd(&vars, name, dt, &structs, &v)) {
+            case VE_SIZE_ERROR: cCannotGetSize(__LINE__, dt); break;
+            default: break;
+        }
         if(fAddArgument(f, dt, &structs)) {
-            cTooMuchArguments();
+            cTooMuchArguments(__LINE__);
         } else if(cConsumeTokenIf(T_CLOSE_BRACKET)) {
             return;
         }
@@ -966,11 +993,11 @@ static void cAddFunction(Function* found, Function* f) {
     if(found == NULL) {
         fsAdd(&functions, f);
     } else if(found->global) {
-        cError("system functions cannot be overwritten");
+        cError(__LINE__, "system functions cannot be overwritten");
     } else if(found->address != -1 || f->address == -1 || found->global) {
-        cError("function registered twice");
+        cError(__LINE__, "function registered twice");
     } else if(!dtCompare(found->returnType, f->returnType)) {
-        cError("function redeclared with different return type");
+        cError(__LINE__, "function redeclared with different return type");
     } else {
         found->address = f->address;
     }
@@ -984,7 +1011,7 @@ static void cInnerFunction(Function* f) {
     returnIndex = 0;
     cConsumeScope();
     if(!dtIsVoid(returnType) && hasReturn <= 0) {
-        cError("missing return");
+        cError(__LINE__, "missing return");
     }
     cAddInt32Operation(OP_RETURN, vars.maxAddress);
     cSetInt32(p, vars.maxAddress);
@@ -1016,7 +1043,7 @@ static void cStruct(void) {
     cConsumeToken(T_LITERAL);
     const char* name = cReadString();
     if(stsSearch(&structs, name) != NULL) {
-        cError("struct '%s' registered twice", name);
+        cError(__LINE__, "struct '%s' registered twice", name);
     }
     Struct* st = stsAdd(&structs, name);
     DataType self = dtStruct(st);
@@ -1024,7 +1051,7 @@ static void cStruct(void) {
     while(!cConsumeTokenIf(T_CLOSE_CURVED_BRACKET)) {
         DataType dt = cReadExtendedType(cReadTokenAndLine(), true);
         if(dtCompare(dt, self)) {
-            cError("struct %s contains itself", name);
+            cError(__LINE__, "struct %s contains itself", name);
         }
         cConsumeToken(T_LITERAL);
         stAddVariable(st, cReadString(), dt);

+ 15 - 10
DataType.c

@@ -96,29 +96,34 @@ const char* dtGetName(const Structs* sts, DataType dt) {
     return typeName[typeNameSwap];
 }
 
-int dtGetSize(DataType dt, const Structs* sts) {
+bool dtGetSize(DataType dt, const Structs* sts, int* size) {
     if(dtIsPointer(dt)) {
-        return 1;
+        *size = 1;
+        return false;
     }
     switch(dtGetType(dt)) {
-        case RDT_INT: return 1;
-        case RDT_FLOAT: return 1;
+        case RDT_INT: *size = 1; return false;
+        case RDT_FLOAT: *size = 1; return false;
         case RDT_STRUCT: {
-            int size = 0;
+            *size = 0;
             Struct* st = dtGetStruct(sts, dt);
             if(st == NULL) {
-                return 0;
+                return true;
             }
             for(int i = 0; i < st->amount; i++) {
-                size += dtGetSize(st->vars[i].type, sts);
+                int add = 0;
+                if(dtGetSize(st->vars[i].type, sts, &add)) {
+                    return true;
+                }
+                *size += add;
             }
-            return size;
+            return false;
         }
         case RDT_LAST:
         case RDT_VOID:
-        case RDT_INVALID: return 0;
+        case RDT_INVALID: return true;
     }
-    return 0;
+    return true;
 }
 
 static DataType dtBuild(RawDataType rdt, bool isPointer, bool isArray,

+ 27 - 26
DataType.h

@@ -79,49 +79,50 @@ typedef struct {
     Struct* data;
 } Structs;
 
-const char* vtGetName(ValueType vt);
-ValueType vGetType(Value v);
+check_return const char* vtGetName(ValueType vt);
+
+check_return ValueType vGetType(Value v);
 check_return bool vSetType(Value* v, ValueType vt);
-int32 vGetOffset(Value v);
+check_return int32 vGetOffset(Value v);
 check_return bool vSetOffset(Value* v, int32 offset);
 
-int dtGetSize(DataType dt, const Structs* sts);
+check_return bool dtGetSize(DataType dt, const Structs* sts, int* size);
 
-DataType dtInt(void);
-DataType dtFloat(void);
-DataType dtVoid(void);
-DataType dtStruct(const Struct* st);
-DataType dtText(void);
+check_return DataType dtInt(void);
+check_return DataType dtFloat(void);
+check_return DataType dtVoid(void);
+check_return DataType dtStruct(const Struct* st);
+check_return DataType dtText(void);
 
-DataType dtToArray(DataType dt);
-DataType dtRemoveArray(DataType dt);
-Struct* dtGetStruct(const Structs* sts, DataType dt);
+check_return DataType dtToArray(DataType dt);
+check_return DataType dtRemoveArray(DataType dt);
+check_return Struct* dtGetStruct(const Structs* sts, DataType dt);
 
-DataType dtToPointer(DataType dt);
+check_return DataType dtToPointer(DataType dt);
 bool dtRemovePointer(DataType* dt);
 
-RawDataType dtGetType(DataType dt);
-bool dtCompare(DataType a, DataType b);
-bool dtIsInt(DataType dt);
-bool dtIsFloat(DataType dt);
-bool dtIsVoid(DataType dt);
-bool dtIsArray(DataType dt);
-bool dtIsStruct(DataType dt);
-bool dtIsPointer(DataType dt);
+check_return RawDataType dtGetType(DataType dt);
+check_return bool dtCompare(DataType a, DataType b);
+check_return bool dtIsInt(DataType dt);
+check_return bool dtIsFloat(DataType dt);
+check_return bool dtIsVoid(DataType dt);
+check_return bool dtIsArray(DataType dt);
+check_return bool dtIsStruct(DataType dt);
+check_return bool dtIsPointer(DataType dt);
 
-const char* dtGetName(const Structs* sts, DataType dt);
+check_return const char* dtGetName(const Structs* sts, DataType dt);
 
 void stAddVariable(Struct* st, const char* name, DataType type);
 
 void stsInit(Structs* sts);
 void stsDelete(Structs* sts);
-Struct* stsSearch(Structs* sts, const char* name);
-Struct* stsAdd(Structs* sts, const char* name);
+check_return Struct* stsSearch(Structs* sts, const char* name);
+check_return Struct* stsAdd(Structs* sts, const char* name);
 
 void gstsInit(void);
 void gstsDelete(void);
-Structs* gstsGet(void);
-Struct* gstsAdd(const char* name);
+check_return Structs* gstsGet(void);
+check_return Struct* gstsAdd(const char* name);
 
 #ifdef __cplusplus
 }

+ 6 - 4
Error.c

@@ -4,16 +4,18 @@
 
 #include "Error.h"
 
-void eInitError(Error* e, const char* path, int line, const char* format, ...) {
+void eInitError(Error* e, const char* path, int line, int codeLine,
+                const char* format, ...) {
     va_list args;
     va_start(args, format);
-    eInitErrorV(e, path, line, format, args);
+    eInitErrorV(e, path, line, codeLine, format, args);
     va_end(args);
 }
 
-void eInitErrorV(Error* e, const char* path, int line, const char* format,
-                 va_list ap) {
+void eInitErrorV(Error* e, const char* path, int line, int codeLine,
+                 const char* format, va_list ap) {
     e->line = line;
+    e->codeLine = codeLine;
     vsnprintf(e->message, sizeof(e->message), format, ap);
     snprintf(e->paths, sizeof(e->paths), "%s", path);
 }

+ 5 - 4
Error.h

@@ -12,14 +12,15 @@ extern "C" {
 
 typedef struct Error {
     int line;
+    int codeLine;
     char message[256];
     char paths[256];
 } Error;
 
-check_format(4, 5) void eInitError(Error* e, const char* path, int line,
-                                   const char* format, ...);
-void eInitErrorV(Error* e, const char* path, int line, const char* format,
-                 va_list ap);
+check_format(5, 6) void eInitError(Error* e, const char* path, int line,
+                                   int codeLine, const char* format, ...);
+void eInitErrorV(Error* e, const char* path, int codeLine, int line,
+                 const char* format, va_list ap);
 void eInitSuccess(Error* e);
 void eAddPath(Error* e, const char* path);
 bool eHasError(const Error* e);

+ 2 - 0
Test.c

@@ -130,6 +130,7 @@ static void tsCheckFile(void) {
     if(eHasError(&e)) {
         puts(e.message);
         printf("line: %d\n", e.line);
+        printf("code line: %d\n", e.codeLine);
         printf("path: %s\n", e.paths);
         return;
     }
@@ -137,6 +138,7 @@ static void tsCheckFile(void) {
     if(bc == NULL) {
         puts(e.message);
         printf("line: %d\n", e.line);
+        printf("code line: %d\n", e.codeLine);
         printf("path: %s\n", e.paths);
         return;
     }

+ 24 - 22
tokenizer/FileTokens.c

@@ -55,10 +55,11 @@ static const char* ftGetPath(const FileTokens* ft, int index) {
     return "unknown path";
 }
 
-static void ftError(const FileTokens* ft, int index, const char* format, ...) {
+static void ftError(const FileTokens* ft, int codeLine, int index,
+                    const char* format, ...) {
     va_list args;
     va_start(args, format);
-    eInitErrorV(error, "", ftGetLine(ft, index), format, args);
+    eInitErrorV(error, "", ftGetLine(ft, index), codeLine, format, args);
 
     int fileLayer = 0;
     for(int i = index; i >= 0; i--) {
@@ -78,8 +79,8 @@ static void ftError(const FileTokens* ft, int index, const char* format, ...) {
 }
 
 static void ftSystemError(const char* msg, const FileTokens* parent,
-                          const FileTokens* ft, int index) {
-    ftError(parent, index, "%s '%s': %s", msg, ftGetPath(ft, 0),
+                          const FileTokens* ft, int codeLine, int index) {
+    ftError(parent, codeLine, index, "%s '%s': %s", msg, ftGetPath(ft, 0),
             strerror(errno));
 }
 
@@ -208,7 +209,7 @@ static void ftTokenize(FileTokens* ft, unsigned char* data) {
             index += 2;
             while(true) {
                 if(data[index] == '\0') {
-                    ftError(ft, startIndex, "test");
+                    ftError(ft, __LINE__, startIndex, "test");
                     return;
                 } else if(data[index] == '\n') {
                     ftAddNewline(ft);
@@ -229,12 +230,12 @@ static void ftTokenize(FileTokens* ft, unsigned char* data) {
 static void ftReadFull(FILE* file, FileTokens* parent, FileTokens* ft,
                        int index) {
     if(fseek(file, 0, SEEK_END)) {
-        ftSystemError("cannot seek end of file", parent, ft, index);
+        ftSystemError("cannot seek end of file", parent, ft, __LINE__, index);
         return;
     }
     long signedLength = ftell(file);
     if(signedLength < 0) {
-        ftSystemError("cannot tell end of file", parent, ft, index);
+        ftSystemError("cannot tell end of file", parent, ft, __LINE__, index);
         return;
     }
     size_t length = (size_t)signedLength;
@@ -243,7 +244,7 @@ static void ftReadFull(FILE* file, FileTokens* parent, FileTokens* ft,
     unsigned char* data = (unsigned char*)malloc(length + 1);
     size_t readValues = fread(data, 1, length, file);
     if(readValues != length) {
-        ftSystemError("cannot read file", parent, ft, index);
+        ftSystemError("cannot read file", parent, ft, __LINE__, index);
         free(data);
         return;
     }
@@ -256,12 +257,12 @@ static void ftReadFull(FILE* file, FileTokens* parent, FileTokens* ft,
 static void ftReadFullFile(FileTokens* parent, FileTokens* ft, int index) {
     FILE* file = fopen(ftGetPath(ft, 0), "r");
     if(file == NULL) {
-        ftSystemError("cannot open file", parent, ft, index);
+        ftSystemError("cannot open file", parent, ft, __LINE__, index);
         return;
     }
     ftReadFull(file, parent, ft, index);
     if(fclose(file) < 0) {
-        ftSystemError("cannot close file", parent, ft, index);
+        ftSystemError("cannot close file", parent, ft, __LINE__, index);
     }
 }
 
@@ -309,7 +310,7 @@ const char* INCLUDE_ERROR = "include path must be a string";
 static bool ftIncludeDoubleQuote(int* index, FileTokens* ft) {
     if(*index >= ft->length || ft->tokens[*index].type != FT_SINGLE ||
        ft->tokens[*index].single != '"') {
-        ftError(ft, *index - 1, INCLUDE_ERROR);
+        ftError(ft, __LINE__, *index - 1, INCLUDE_ERROR);
         return true;
     }
     (*index)++;
@@ -322,7 +323,7 @@ static void ftHandleInclude(int* index, int start, FileTokens* ft) {
         return;
     }
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        ftError(ft, *index - 1, INCLUDE_ERROR);
+        ftError(ft, __LINE__, *index - 1, INCLUDE_ERROR);
         return;
     }
     const char* path = ft->tokens[(*index)++].literal;
@@ -389,13 +390,13 @@ static int ftFindEndIf(int from, FileTokens* ft) {
 static void ftHandleIfNotDefined(int* index, int start, FileTokens* ft) {
     ftSkipSpaces(index, ft);
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        ftError(ft, start, "ifndef expects a literal");
+        ftError(ft, __LINE__, start, "ifndef expects a literal");
         return;
     }
     const char* check = ft->tokens[(*index)++].literal;
     int endIf = ftFindEndIf(*index, ft);
     if(endIf == -1) {
-        ftError(ft, start, "cannot find #endif");
+        ftError(ft, __LINE__, start, "cannot find #endif");
         return;
     }
     if(ftIsDefined(check)) {
@@ -414,12 +415,12 @@ static void ftHandleIfNotDefined(int* index, int start, FileTokens* ft) {
 
 static void ftHandleDefine(int* index, int start, FileTokens* ft) {
     if(defineIndex >= DEFINES) {
-        ftError(ft, *index - 1, "too much defines");
+        ftError(ft, __LINE__, *index - 1, "too much defines");
         return;
     }
     ftSkipSpaces(index, ft);
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        ftError(ft, *index - 1, "define expects a literal");
+        ftError(ft, __LINE__, *index - 1, "define expects a literal");
         return;
     }
     const char* defineName = ft->tokens[(*index)++].literal;
@@ -439,7 +440,7 @@ static void ftHandleDefine(int* index, int start, FileTokens* ft) {
                 break;
             }
         } else if(skip) {
-            ftError(ft, *index - 1, "expected newline after \\");
+            ftError(ft, __LINE__, *index - 1, "expected newline after \\");
             return;
         }
         (*index)++;
@@ -447,7 +448,7 @@ static void ftHandleDefine(int* index, int start, FileTokens* ft) {
 
     int foundIndex = ftGetDefineIndex(defineName);
     if(foundIndex != -1) {
-        ftError(ft, *index - 1, "'%s' redefined", defineName);
+        ftError(ft, __LINE__, *index - 1, "'%s' redefined", defineName);
         return;
     }
     Define* define = NULL;
@@ -478,7 +479,7 @@ static void ftHandleDefine(int* index, int start, FileTokens* ft) {
 static void ftHandleUndefine(int* index, int start, FileTokens* ft) {
     ftSkipSpaces(index, ft);
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        ftError(ft, *index - 1, "undefine expects a literal");
+        ftError(ft, __LINE__, *index - 1, "undefine expects a literal");
         return;
     }
     const char* defineName = ft->tokens[(*index)++].literal;
@@ -501,7 +502,7 @@ static void ftParseInstruction(int* index, FileTokens* ft) {
     int start = *index;
     (*index)++;
     if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
-        ftError(ft, *index - 1, "expected literal after #");
+        ftError(ft, __LINE__, *index - 1, "expected literal after #");
         return;
     }
     const char* name = ft->tokens[(*index)++].literal;
@@ -514,9 +515,10 @@ static void ftParseInstruction(int* index, FileTokens* ft) {
     } else if(ftStringCompare(name, "undef")) {
         ftHandleUndefine(index, start, ft);
     } else if(ftStringCompare(name, "endif")) {
-        ftError(ft, *index - 1, "endif without if");
+        ftError(ft, __LINE__, *index - 1, "endif without if");
     } else {
-        ftError(ft, *index - 1, "unknown preprocessor literal '%s'", name);
+        ftError(ft, __LINE__, *index - 1, "unknown preprocessor literal '%s'",
+                name);
     }
 }
 

+ 31 - 25
tokenizer/Tokenizer.c

@@ -32,13 +32,13 @@ static int writeIndex = 0;
 static int readIndex = 0;
 static int16 line = 1;
 
-static check_format(1, 2) void tError(const char* format, ...) {
+static check_format(2, 3) void tError(int codeLine, const char* format, ...) {
     va_list args;
     va_start(args, format);
     const char* path = includeStackIndex > 0
                            ? includeStack[includeStackIndex - 1].path
                            : "path not set";
-    eInitErrorV(error, path, line, format, args);
+    eInitErrorV(error, path, line, codeLine, format, args);
     for(int i = includeStackIndex - 2; i >= 0; i--) {
         eAddPath(error, includeStack[i].path);
     }
@@ -48,7 +48,7 @@ static check_format(1, 2) void tError(const char* format, ...) {
 
 static void tAdd(const void* data, int length) {
     if(writeIndex + length > TOKEN_BUFFER_LENGTH) {
-        tError("the token buffer is too small");
+        tError(__LINE__, "the token buffer is too small");
     }
     memcpy(tokenBuffer + writeIndex, data, (size_t)length);
     writeIndex += length;
@@ -71,7 +71,7 @@ static bool tReadTokens(void* dest, int length) {
 
 static FileToken* tNextToken(void) {
     if(fileTokenIndex >= fileTokens.length) {
-        tError("unexpected end of file");
+        tError(__LINE__, "unexpected end of file");
     }
     return fileTokens.tokens + fileTokenIndex++;
 }
@@ -131,15 +131,16 @@ static long long tParseInt(const char* s) {
     long long l = 0;
     for(int i = 0; s[i] != '\0'; i++) {
         if(l > (LLONG_MAX / 10)) {
-            tError("invalid number on line %d", line);
+            tError(__LINE__, "invalid number on line %d", line);
         }
         l *= 10;
         if(!isNumber(s[i])) {
-            tError("invalid character in number '%c' on line %d", s[i], line);
+            tError(__LINE__, "invalid character in number '%c' on line %d",
+                   s[i], line);
         }
         int digit = s[i] - '0';
         if(l > LLONG_MAX - digit) {
-            tError("invalid number on line %d", line);
+            tError(__LINE__, "invalid number on line %d", line);
         }
         l += digit;
     }
@@ -151,7 +152,8 @@ static void tParseNumber(const char* buffer) {
     if(tReadSingleIf('.')) {
         FileToken* t = tNextToken();
         if(t->type != FT_LITERAL) {
-            tError("expected literal after comma of number on line %d", line);
+            tError(__LINE__,
+                   "expected literal after comma of number on line %d", line);
         }
         long long comma = tParseInt(t->literal);
 
@@ -164,7 +166,7 @@ static void tParseNumber(const char* buffer) {
         tAdd(&f, sizeof(float));
     } else {
         if(l > INT32_MAX) {
-            tError("invalid int on line %d", line);
+            tError(__LINE__, "invalid int on line %d", line);
         }
         int32 i = (int)l;
         tAddToken(T_INT_VALUE);
@@ -179,11 +181,12 @@ static int32 tNextUnicodePart(void) {
     } else if(t->type == FT_LITERAL) {
         int length = (int)strlen(t->literal);
         if(length != 1) {
-            tError("unicode literal has wrong length %d", length);
+            tError(__LINE__, "unicode literal has wrong length %d", length);
         }
         return t->literal[0];
     } else {
-        tError("cannot read next unicode character part on line %d", line);
+        tError(__LINE__, "cannot read next unicode character part on line %d",
+               line);
         return 0;
     }
 }
@@ -196,7 +199,8 @@ static int32 tUnicode(int32 c) {
             case 'n': c = '\n'; break;
             case 'r': c = '\r'; break;
             case 't': c = '\t'; break;
-            default: tError("unknown escaped character at line %d", line);
+            default:
+                tError(__LINE__, "unknown escaped character at line %d", line);
         }
     }
     if((c & 0xE0) == 0xC0) {
@@ -214,7 +218,7 @@ static int32 tUnicode(int32 c) {
 
 static int32 tReadNextPart(const char* s, int* index, int length) {
     if(*index >= length) {
-        tError("missing escape character");
+        tError(__LINE__, "missing escape character");
     }
     return s[(*index)++];
 }
@@ -228,7 +232,8 @@ static int32 tStringUnicode(const char* s, int* index, int length) {
             case 'n': c = '\n'; break;
             case 'r': c = '\r'; break;
             case 't': c = '\t'; break;
-            default: tError("unknown escaped character at line %d", line);
+            default:
+                tError(__LINE__, "unknown escaped character at line %d", line);
         }
     }
     if((c & 0xE0) == 0xC0) {
@@ -251,7 +256,7 @@ static void tAddString(void) {
     FileToken* t = tNextToken();
     if(t->type == FT_SINGLE) {
         if(t->single != '"') {
-            tError("unexpected single '%d'", t->single);
+            tError(__LINE__, "unexpected single '%d'", t->single);
         }
     } else if(t->type == FT_LITERAL) {
         int length = (int)strlen(t->literal);
@@ -262,10 +267,10 @@ static void tAddString(void) {
             tAdd(&c, sizeof(int32));
         }
         if(!tReadSingleIf('"')) {
-            tError("unclosed string");
+            tError(__LINE__, "unclosed string");
         }
     } else {
-        tError("unexpected string file token %u", t->type);
+        tError(__LINE__, "unexpected string file token %u", t->type);
     }
 
     int32 c = 0;
@@ -277,7 +282,7 @@ static void tAddUnicode(void) {
     if(t->type == FT_LITERAL) {
         int length = (int)strlen(t->literal);
         if(length != 1) {
-            tError("invalid character on line %d", line);
+            tError(__LINE__, "invalid character on line %d", line);
         }
         int32 c = t->literal[0];
         tAddToken(T_INT_VALUE);
@@ -287,10 +292,10 @@ static void tAddUnicode(void) {
         tAddToken(T_INT_VALUE);
         tAdd(&c, sizeof(int32));
     } else {
-        tError("invalid character on line %d", line);
+        tError(__LINE__, "invalid character on line %d", line);
     }
     if(!tReadSingleIf('\'')) {
-        tError("expecting unicode end");
+        tError(__LINE__, "expecting unicode end");
     }
 }
 
@@ -322,7 +327,7 @@ static void tParseToken(FileToken* t) {
     switch(t->type) {
         case FT_PATH: {
             if(includeStackIndex >= INCLUDE_STACK_LENGTH) {
-                tError("include stack overflow");
+                tError(__LINE__, "include stack overflow");
             }
             includeStack[includeStackIndex].path = t->literal;
             includeStack[includeStackIndex].line = line;
@@ -334,7 +339,7 @@ static void tParseToken(FileToken* t) {
         }
         case FT_END_PATH: {
             if(includeStackIndex <= 0) {
-                tError("include stack underflow");
+                tError(__LINE__, "include stack underflow");
             }
             includeStackIndex--;
             line = includeStack[includeStackIndex].line;
@@ -353,7 +358,7 @@ static void tParseToken(FileToken* t) {
             } else if(isNumber(buffer[0])) {
                 tParseNumber(buffer);
             } else {
-                tError("invalid literal string '%s'", buffer);
+                tError(__LINE__, "invalid literal string '%s'", buffer);
             }
             return;
         }
@@ -400,9 +405,10 @@ static void tParseToken(FileToken* t) {
                 case ']': tAddToken(T_CLOSE_SQUARE_BRACKET); return;
             }
             if(isprint(c)) {
-                tError("unknown character on line %d: %c", line, c);
+                tError(__LINE__, "unknown character on line %d: %c", line, c);
             } else {
-                tError("unknown character on line %d: %d", line, (int)c);
+                tError(__LINE__, "unknown character on line %d: %d", line,
+                       (int)c);
             }
         }
     }

+ 5 - 1
utils/Functions.c

@@ -21,7 +21,11 @@ bool fAddArgument(Function* f, DataType type, Structs* sts) {
     if(f->arguments >= FUNCTION_ARGUMENTS) {
         return true;
     }
-    f->size += dtGetSize(type, sts);
+    int add;
+    if(dtGetSize(type, sts, &add)) {
+        return true;
+    }
+    f->size += add;
     f->argumentTypes[f->arguments++] = type;
     return false;
 }

+ 27 - 16
utils/Variables.c

@@ -32,32 +32,43 @@ bool vsInScope(const Variables* vs, const char* s) {
     return false;
 }
 
-bool vSearchStruct(Variable* v, Structs* sts, Struct* st, const char* s) {
+VariableError vSearchStruct(Variable* v, const Structs* sts, const Struct* st,
+                            const char* s) {
     v->address = 0;
     for(int i = 0; i < st->amount; i++) {
         if(strcmp(st->vars[i].name, s) == 0) {
             v->name = s;
             v->type = st->vars[i].type;
-            return false;
+            return VE_OK;
+        }
+        int add;
+        if(dtGetSize(st->vars[i].type, sts, &add)) {
+            return VE_SIZE_ERROR;
         }
-        v->address += dtGetSize(st->vars[i].type, sts);
+        v->address += add;
     }
-    return true;
+    return VE_CANNOT_FIND;
 }
 
-Variable* vsAdd(Variables* v, const char* s, DataType type, Structs* sts) {
-    if(v->entries >= v->capacity) {
-        v->capacity *= 2;
-        v->data =
-            (Variable*)realloc(v->data, sizeof(Variable) * (size_t)v->capacity);
+VariableError vsAdd(Variables* vs, const char* s, DataType type,
+                    const Structs* sts, Variable** v) {
+    if(vs->entries >= vs->capacity) {
+        vs->capacity *= 2;
+        vs->data = (Variable*)realloc(vs->data,
+                                      sizeof(Variable) * (size_t)vs->capacity);
+    }
+    int size;
+    if(dtGetSize(type, sts, &size)) {
+        return VE_SIZE_ERROR;
     }
-    int index = v->entries++;
-    v->data[index] = (Variable){s, type, v->address};
-    v->address += dtGetSize(type, sts);
-    if(v->address > v->maxAddress) {
-        v->maxAddress = v->address;
+    int index = vs->entries++;
+    vs->data[index] = (Variable){s, type, vs->address};
+    vs->address += size;
+    if(vs->address > vs->maxAddress) {
+        vs->maxAddress = vs->address;
     }
-    return v->data + index;
+    *v = vs->data + index;
+    return VE_OK;
 }
 
 void vsReset(Variables* v) {
@@ -74,7 +85,7 @@ void vsEnterScope(Variables* v, Scope* s) {
     v->scope = v->entries;
 }
 
-void vsLeaveScope(Variables* v, Scope* s) {
+void vsLeaveScope(Variables* v, const Scope* s) {
     v->address = s->address;
     v->entries = s->entries;
     v->scope = s->scope;

+ 10 - 5
utils/Variables.h

@@ -7,8 +7,11 @@ extern "C" {
 
 #include <stdbool.h>
 
+#include "Check.h"
 #include "DataType.h"
 
+typedef enum { VE_OK, VE_CANNOT_FIND, VE_SIZE_ERROR } VariableError;
+
 typedef struct {
     int address;
     int entries;
@@ -33,13 +36,15 @@ typedef struct {
 
 void vsInit(Variables* v);
 void vsDelete(Variables* v);
-bool vsSearch(const Variables* vs, Variable* v, const char* s);
-bool vSearchStruct(Variable* v, Structs* sts, Struct* st, const char* s);
-bool vsInScope(const Variables* vs, const char* s);
-Variable* vsAdd(Variables* v, const char* s, DataType type, Structs* sts);
+check_return bool vsSearch(const Variables* vs, Variable* v, const char* s);
+check_return VariableError vSearchStruct(Variable* v, const Structs* sts,
+                                         const Struct* st, const char* s);
+check_return bool vsInScope(const Variables* vs, const char* s);
+check_return VariableError vsAdd(Variables* vs, const char* s, DataType type,
+                                 const Structs* sts, Variable** v);
 void vsReset(Variables* v);
 void vsEnterScope(Variables* v, Scope* s);
-void vsLeaveScope(Variables* v, Scope* s);
+void vsLeaveScope(Variables* v, const Scope* s);
 
 #ifdef __cplusplus
 }