Browse Source

value does not use bitfields any more

Kajetan Johannes Hammerle 1 year ago
parent
commit
5542196c0e
10 changed files with 171 additions and 77 deletions
  1. 19 0
      Check.h
  2. 5 3
      Compiler.c
  3. 41 0
      DataType.c
  4. 19 9
      DataType.h
  5. 4 1
      Error.h
  6. 5 0
      Types.h
  7. 0 2
      meson.build
  8. 3 2
      tokenizer/Tokenizer.c
  9. 72 58
      vm/Script.c
  10. 3 2
      vm/Script.h

+ 19 - 0
Check.h

@@ -0,0 +1,19 @@
+#ifndef CHECK_H
+#define CHECK_H
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 202300L
+#define check_return [[nodiscard]]
+#elif defined(__GNUC__)
+#define check_return __attribute__((warn_unused_result))
+#else
+#error "please add a 'check_return' option"
+#endif
+
+#if defined(__GNUC__)
+#define check_format(format_index, arg_start_index)                            \
+    __attribute__((format(printf, format_index, arg_start_index)))
+#else
+#error "please add a 'check_format' option"
+#endif
+
+#endif

+ 5 - 3
Compiler.c

@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "Check.h"
 #include "Compiler.h"
 #include "DataType.h"
 #include "tokenizer/Tokenizer.h"
@@ -73,7 +74,7 @@ TYPE_OP(BIT_AND, NOTHING, NOTHING, "&")
 TYPE_OP(LEFT_SHIFT, NOTHING, NOTHING, "<<")
 TYPE_OP(RIGHT_SHIFT, NOTHING, NOTHING, ">>")
 
-static void cError(const char* format, ...) {
+static check_format(1, 2) void cError(const char* format, ...) {
     va_list args;
     va_start(args, format);
     eInitErrorV(error, path, line, format, args);
@@ -212,10 +213,11 @@ static DataType cReadType(Token t, bool force) {
         case T_INT: return dtInt();
         case T_FLOAT: return dtFloat();
         case T_LITERAL: {
-            Struct* st = stsSearch(&structs, cReadString());
+            const char* name = cReadString();
+            Struct* st = stsSearch(&structs, name);
             if(st == NULL) {
                 if(force) {
-                    cError("struct %s does not exist");
+                    cError("struct %s does not exist", name);
                 } else {
                     return dtVoid();
                 }

+ 41 - 0
DataType.c

@@ -13,6 +13,47 @@ static char typeName[2][ARRAY_NAME];
 static bool useGlobals = false;
 static Structs globalStructs;
 
+const char* vtGetName(ValueType vt) {
+    switch(vt) {
+        case VT_INVALID: return "invalid";
+        case VT_NOT_SET: return "?";
+        case VT_INT: return "int";
+        case VT_FLOAT: return "float";
+        case VT_POINTER: return "pointer";
+        case VT_ARRAY: return "array";
+        case VT_LAST: return "invalid";
+    }
+    return "invalid";
+}
+
+ValueType vGetType(Value v) {
+    uint32 type = v.typeAndOffset & 0xF;
+    if(type >= VT_LAST) {
+        return VT_INVALID;
+    }
+    return (ValueType)type;
+}
+
+bool vSetType(Value* v, ValueType vt) {
+    if(v == NULL || vt < 0 || vt >= VT_LAST) {
+        return true;
+    }
+    v->typeAndOffset = (v->typeAndOffset & 0xFFFFFFF0) | vt;
+    return false;
+}
+
+uint32 vGetOffset(Value v) {
+    return v.typeAndOffset >> 4;
+}
+
+bool vSetOffset(Value* v, uint32 offset) {
+    if(v == NULL || (offset & 0xF0000000) != 0) {
+        return true;
+    }
+    v->typeAndOffset = (v->typeAndOffset & 0x0000000F) | (offset << 4);
+    return false;
+}
+
 static void dtAppend(const char* s) {
     int index = 0;
     while(typeNameIndex < (ARRAY_NAME - 1) && s[index] != '\0') {

+ 19 - 9
DataType.h

@@ -7,20 +7,24 @@ extern "C" {
 
 #include <stdbool.h>
 
+#include "Check.h"
 #include "Types.h"
 
-#define VT_NOT_SET 0
-#define VT_INT 1
-#define VT_FLOAT 2
-#define VT_POINTER 3
-#define VT_ARRAY 4
+typedef enum {
+    VT_INVALID = 0,
+    VT_NOT_SET,
+    VT_INT,
+    VT_FLOAT,
+    VT_POINTER,
+    VT_ARRAY,
+    VT_LAST
+} ValueType;
 
 typedef struct {
-    unsigned int type : 4;
-    unsigned int offset : 28;
+    uint32 typeAndOffset;
     union {
-        int intValue;
-        float floatValue;
+        int32 intValue;
+        float32 floatValue;
     } data;
 } Value;
 
@@ -56,6 +60,12 @@ typedef struct {
     Struct* data;
 } Structs;
 
+const char* vtGetName(ValueType vt);
+ValueType vGetType(Value v);
+check_return bool vSetType(Value* v, ValueType vt);
+uint32 vGetOffset(Value v);
+check_return bool vSetOffset(Value* v, uint32 offset);
+
 int dtGetSize(DataType dt, const Structs* sts);
 
 DataType dtInt(void);

+ 4 - 1
Error.h

@@ -8,13 +8,16 @@ extern "C" {
 #include <stdarg.h>
 #include <stdbool.h>
 
+#include "Check.h"
+
 typedef struct Error {
     int line;
     char message[256];
     char paths[256];
 } Error;
 
-void eInitError(Error* e, const char* path, int line, const char* format, ...);
+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);
 void eInitSuccess(Error* e);

+ 5 - 0
Types.h

@@ -5,6 +5,8 @@
 extern "C" {
 #endif
 
+#include <assert.h>
+#include <limits.h>
 #include <stdint.h>
 
 typedef int8_t int8;
@@ -17,6 +19,9 @@ typedef uint16_t uint16;
 typedef uint32_t uint32;
 typedef uint64_t uint64;
 
+typedef float float32;
+static_assert(sizeof(float32) * CHAR_BIT == 32, "float is not 32 bit");
+
 #ifdef __cplusplus
 }
 #endif

+ 0 - 2
meson.build

@@ -22,8 +22,6 @@ src = [
 cc = meson.get_compiler('c')
 math_dep = cc.find_library('m', required : true)
 
-#args = ['-Wall', '-Wextra', '-pedantic', '-Werror']
-
 args = cc.get_supported_arguments([
     '-Werror', '-pedantic', '-pedantic-errors', '-Wall', '-Wextra', '-Wdouble-promotion', 
     '-Wformat=2', '-Wformat-signedness', '-Wnull-dereference', '-Winfinite-recursion', 

+ 3 - 2
tokenizer/Tokenizer.c

@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "Check.h"
 #include "tokenizer/FileTokens.h"
 #include "tokenizer/Tokenizer.h"
 #include "utils/SnuviUtils.h"
@@ -31,7 +32,7 @@ static int writeIndex = 0;
 static int readIndex = 0;
 static int16 line = 1;
 
-static void tError(const char* format, ...) {
+static check_format(1, 2) void tError(const char* format, ...) {
     va_list args;
     va_start(args, format);
     const char* path = includeStackIndex > 0
@@ -264,7 +265,7 @@ static void tAddString(void) {
             tError("unclosed string");
         }
     } else {
-        tError("unexpected string file token %d", t);
+        tError("unexpected string file token %u", t->type);
     }
 
     int32 c = 0;

+ 72 - 58
vm/Script.c

@@ -8,9 +8,6 @@
 #include "vm/Operation.h"
 #include "vm/Script.h"
 
-static const char* VALUE_TYPE_NAMES[] = {"?", "int", "float", "pointer",
-                                         "array"};
-
 void sError(Script* sc, const char* format, ...) {
     va_list args;
     va_start(args, format);
@@ -18,9 +15,14 @@ void sError(Script* sc, const char* format, ...) {
     va_end(args);
 }
 
+static void sCannotSetValueType(Script* sc) {
+    sError(sc, "cannot set value type");
+}
+
 static bool sRead(Script* sc, void* buffer, int length) {
     if(sc->readIndex + length > sc->code->length) {
-        sError(sc, "cannot read expected %d bytes of data from bytecode");
+        sError(sc, "cannot read expected %d bytes of data from bytecode",
+               length);
         return true;
     }
     memcpy(buffer, sc->code->code + sc->readIndex, (size_t)length);
@@ -36,15 +38,15 @@ static Operation sReadOperation(Script* sc) {
     return (Operation)c;
 }
 
-static Value* sPeekStack(Script* sc, int type) {
+static Value* sPeekStack(Script* sc, ValueType type) {
     if(sc->stackIndex <= 0) {
         sError(sc, "stack underflow");
         return NULL;
     }
-    int stackType = sc->stack[sc->stackIndex - 1].type;
+    ValueType stackType = vGetType(sc->stack[sc->stackIndex - 1]);
     if(stackType != type) {
-        sError(sc, "expected %s on stack but got %s", VALUE_TYPE_NAMES[type],
-               VALUE_TYPE_NAMES[stackType]);
+        sError(sc, "expected %s on stack but got %s", vtGetName(type),
+               vtGetName(stackType));
         return NULL;
     }
     return sc->stack + (sc->stackIndex - 1);
@@ -85,7 +87,10 @@ static Value* sPushStack(Script* sc, int values) {
     }
     Value* v = sc->stack + sc->stackIndex;
     for(int i = 0; i < values; i++) {
-        v[i].type = VT_NOT_SET;
+        if(vSetType(v + i, VT_NOT_SET)) {
+            sCannotSetValueType(sc);
+            return NULL;
+        }
     }
     sc->stackIndex += values;
     return v;
@@ -93,20 +98,20 @@ static Value* sPushStack(Script* sc, int values) {
 
 bool sPushInt32(Script* sc, int32 i) {
     Value* v = sPushStack(sc, 1);
-    if(v == NULL) {
+    if(vSetType(v, VT_INT)) {
+        sCannotSetValueType(sc);
         return true;
     }
-    v->type = VT_INT;
     v->data.intValue = i;
     return false;
 }
 
 bool sPushFloat(Script* sc, float f) {
     Value* v = sPushStack(sc, 1);
-    if(v == NULL) {
+    if(vSetType(v, VT_FLOAT)) {
+        sCannotSetValueType(sc);
         return true;
     }
-    v->type = VT_FLOAT;
     v->data.floatValue = f;
     return false;
 }
@@ -220,9 +225,9 @@ static void sGoSub(Script* sc) {
     if(index < 0 || index >= SCRIPT_STACK_SIZE) {
         sError(sc, "invalid gosub offset");
         return;
-    } else if(sc->stack[index].type != VT_INT) {
+    } else if(vGetType(sc->stack[index]) != VT_INT) {
         sError(sc, "gosub expects an int got %s",
-               VALUE_TYPE_NAMES[sc->stack[index].type]);
+               vtGetName(vGetType(sc->stack[index])));
         return;
     }
     sc->stack[index].data.intValue = sc->readIndex;
@@ -305,11 +310,10 @@ static void sNewArray(Script* sc) {
         return;
     }
     Value* p = sPushStack(sc, 1);
-    if(p == NULL) {
+    if(vSetType(p, VT_ARRAY) || vSetOffset(p, 0)) {
+        sCannotSetValueType(sc);
         return;
     }
-    p->type = VT_ARRAY;
-    p->offset = 0;
     p->data.intValue = asAllocate(&sc->arrays, size, length);
     if(p->data.intValue == -1) {
         sError(sc, "out of memory");
@@ -339,11 +343,12 @@ static void sDereference(Script* sc) {
         return;
     }
     Value* v = sPushStack(sc, 1);
-    if(v != NULL) {
-        v->type = VT_POINTER;
-        v->offset = ((unsigned int)(address + sc->stackVarIndex)) & 0x0FFFFFFF;
-        v->data.intValue = -1;
+    if(vSetType(v, VT_POINTER) ||
+       vSetOffset(v, (uint32)(address + sc->stackVarIndex))) {
+        sCannotSetValueType(sc);
+        return;
     }
+    v->data.intValue = -1;
 }
 
 static void sGlobalDereference(Script* sc) {
@@ -352,11 +357,11 @@ static void sGlobalDereference(Script* sc) {
         return;
     }
     Value* v = sPushStack(sc, 1);
-    if(v != NULL) {
-        v->type = VT_POINTER;
-        v->offset = ((unsigned int)address) & 0x0FFFFFFF;
-        v->data.intValue = -1;
+    if(vSetType(v, VT_POINTER) || vSetOffset(v, (uint32)address)) {
+        sCannotSetValueType(sc);
+        return;
     }
+    v->data.intValue = -1;
 }
 
 static void sDuplicateReference(Script* sc) {
@@ -377,13 +382,15 @@ static void sAddReference(Script* sc) {
     }
     Value* v = sPeekStack(sc, VT_POINTER);
     if(v != NULL) {
-        v->offset = ((unsigned int)(v->offset + add * size)) & 0x3FFFFFF;
+        if(vSetOffset(v, vGetOffset(*v) + (uint32)(add * size))) {
+            sCannotSetValueType(sc);
+        }
     } else {
         sc->error[0] = '\0';
         v = sPeekStack(sc, VT_ARRAY);
-        if(v != NULL) {
-            v->type = VT_POINTER;
-            v->offset = ((unsigned int)(v->offset + add * size)) & 0x3FFFFFF;
+        if(vSetType(v, VT_POINTER) ||
+           vSetOffset(v, vGetOffset(*v) + (uint32)(add * size))) {
+            sCannotSetValueType(sc);
         }
     }
 }
@@ -404,16 +411,18 @@ static void sPushStructReference(Script* sc) {
     }
 }
 
-static Value* sLoadFromPointer(Script* sc, Value* p, int type) {
+static Value* sLoadFromPointer(Script* sc, Value* p, ValueType wantedType) {
+    uint32 offset = vGetOffset(*p);
     if(p->data.intValue < 0) {
-        if(p->offset < 0 || p->offset >= SCRIPT_STACK_SIZE) {
+        if(offset >= SCRIPT_STACK_SIZE) {
             sError(sc, "load offset overflow");
             return NULL;
         }
-        Value* v = sc->stack + p->offset;
-        if(v->type != type && v->type != VT_NOT_SET) {
-            sError(sc, "pointer did not point to %s but %s",
-                   VALUE_TYPE_NAMES[type], VALUE_TYPE_NAMES[v->type]);
+        Value* v = sc->stack + offset;
+        ValueType type = vGetType(*v);
+        if(type != wantedType && type != VT_NOT_SET) {
+            sError(sc, "pointer did not point to %s but %s", vtGetName(type),
+                   vtGetName(type));
             return NULL;
         }
         return v;
@@ -423,12 +432,11 @@ static Value* sLoadFromPointer(Script* sc, Value* p, int type) {
         sError(sc, "invalid heap pointer %d", p->data.intValue);
         return NULL;
     }
-    if(p->offset < 0 || p->offset >= a->realLength) {
-        sError(sc, "invalid heap pointer offset %d %d", p->offset,
-               a->realLength);
+    if((int32)offset >= a->realLength) {
+        sError(sc, "invalid heap pointer offset %u %d", offset, a->realLength);
         return NULL;
     }
-    return a->data + p->offset;
+    return a->data + offset;
 }
 
 SnuviArray* sGetArray(Script* sc) {
@@ -440,7 +448,7 @@ SnuviArray* sGetArray(Script* sc) {
     return asGet(&sc->arrays, v->data.intValue);
 }
 
-Value* sPopStructPointer(Script* sc, int type) {
+Value* sPopStructPointer(Script* sc, ValueType type) {
     Value* v = sPeekStack(sc, VT_POINTER);
     if(v == NULL) {
         return NULL;
@@ -460,10 +468,11 @@ static void sStoreInt32(Script* sc) {
     }
     sc->stackIndex--;
     v = sLoadFromPointer(sc, v, VT_INT);
-    if(v != NULL) {
-        v->data.intValue = i;
-        v->type = VT_INT;
+    if(vSetType(v, VT_INT)) {
+        sCannotSetValueType(sc);
+        return;
     }
+    v->data.intValue = i;
 }
 
 static void sStoreFloat(Script* sc) {
@@ -477,10 +486,11 @@ static void sStoreFloat(Script* sc) {
     }
     sc->stackIndex--;
     v = sLoadFromPointer(sc, v, VT_FLOAT);
-    if(v != NULL) {
-        v->data.floatValue = f;
-        v->type = VT_FLOAT;
+    if(vSetType(v, VT_FLOAT)) {
+        sCannotSetValueType(sc);
+        return;
     }
+    v->data.floatValue = f;
 }
 
 static void sStoreArray(Script* sc) {
@@ -550,7 +560,7 @@ static void sEqualArrays(Script* sc, bool wanted) {
         return;
     }
     sc->stackIndex--;
-    sPushInt32(sc, (a->offset == b->offset &&
+    sPushInt32(sc, (vGetOffset(*a) == vGetOffset(*b) &&
                     a->data.intValue == b->data.intValue) == wanted);
 }
 
@@ -574,11 +584,10 @@ static void sPushText(Script* sc) {
         return;
     }
     Value* p = sPushStack(sc, 1);
-    if(p == NULL) {
+    if(vSetType(p, VT_ARRAY) || vSetOffset(p, 0)) {
+        sCannotSetValueType(sc);
         return;
     }
-    p->type = VT_ARRAY;
-    p->offset = 0;
     p->data.intValue = asAllocate(&sc->arrays, 1, length);
     if(p->data.intValue == -1) {
         sError(sc, "out of memory");
@@ -594,7 +603,10 @@ static void sPushText(Script* sc) {
     }
     for(int i = 0; i < length; i++) {
         sReadInt32(sc, &(a->data[i].data.intValue));
-        a->data[i].type = VT_INT;
+        if(vSetType(a->data + i, VT_INT)) {
+            sCannotSetValueType(sc);
+            return;
+        }
     }
 }
 
@@ -638,18 +650,20 @@ static void sPushAfterChange(Script* sc) {
 
 static void sFloatToInt32(Script* sc) {
     Value* v = sPeekStack(sc, VT_FLOAT);
-    if(v != NULL) {
-        v->data.intValue = (int)v->data.floatValue;
-        v->type = VT_INT;
+    if(vSetType(v, VT_INT)) {
+        sCannotSetValueType(sc);
+        return;
     }
+    v->data.intValue = (int)v->data.floatValue;
 }
 
 static void sInt32ToFloat(Script* sc) {
     Value* v = sPeekStack(sc, VT_INT);
-    if(v != NULL) {
-        v->data.floatValue = (float)v->data.intValue;
-        v->type = VT_FLOAT;
+    if(vSetType(v, VT_FLOAT)) {
+        sCannotSetValueType(sc);
+        return;
     }
+    v->data.floatValue = (float)v->data.intValue;
 }
 
 #define CASE_NUMBER_OP(name, op)                                               \

+ 3 - 2
vm/Script.h

@@ -29,13 +29,14 @@ void sDelete(Script* sc);
 
 void sRun(Script* sc);
 
-void sError(Script* sc, const char* format, ...);
+check_format(2, 3) void sError(Script* sc, const char* format, ...);
+
 bool sPopInt32(Script* sc, int32* i);
 bool sPushInt32(Script* sc, int32 i);
 bool sPopFloat(Script* sc, float* f);
 bool sPushFloat(Script* sc, float f);
 SnuviArray* sGetArray(Script* sc);
-Value* sPopStructPointer(Script* sc, int type);
+Value* sPopStructPointer(Script* sc, ValueType type);
 
 #ifdef __cplusplus
 }