Browse Source

extended error checking for variables, added code line to errors

Kajetan Johannes Hammerle 2 năm trước cách đây
mục cha
commit
c63fc66b27
11 tập tin đã thay đổi với 245 bổ sung179 xóa
  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
 }