瀏覽代碼

struct support for various cases

Kajetan Johannes Hammerle 3 年之前
父節點
當前提交
e4049c1c5f

+ 162 - 199
Compiler.c

@@ -208,158 +208,104 @@ static DataType cCallFunction(const char* name) {
     return found->returnType;
 }
 
-static void cAddOffset(int offset) {
-    if(offset > 0) {
-        cAddOperation(OP_PUSH_INT);
-        cAddInt(offset);
-        cAddOperation(OP_ADD_INT);
+static void cWalkStruct(Variable* v) {
+    int pointers;
+    if(cConsumeTokenIf(T_ARROW)) {
+        pointers = 1;
+        cAddOperation(OP_REFERENCE);
+    } else if(cConsumeTokenIf(T_POINT)) {
+        pointers = 0;
+    } else {
+        return;
+    }
+    Struct* st = dtGetStruct(&structs, v->type);
+    if(st == NULL || v->type.pointers != pointers) {
+        DataType w = v->type;
+        w.pointers = pointers;
+        cError("%s is not %s but %s", v->name, cGetName(w), cGetName(v->type));
+    }
+    cConsumeToken(T_LITERAL);
+    const char* name = cReadString();
+    Variable inner;
+    if(vSearchStruct(&inner, &structs, st, name)) {
+        cError("%s has no member %s", v->name, name);
     }
+    v->type = inner.type;
+    cAddOperation(OP_PUSH_INT);
+    cAddInt(inner.address);
+    cAddOperation(OP_ADD_INT);
 }
 
-static DataType cLoadRef(Variable* v, Operation op, DataType dt, int offset) {
-    cAddOperation(OP_LOAD_INT);
+static void cReference(Variable* v, int dimension) {
+    cAddOperation(OP_DEREFERENCE_VAR);
     cAddInt(v->address);
-    cAddOffset(offset);
-    cAddOperation(op);
-    return dt;
+    while(dimension > 0) {
+        if(!dtIsPointer(v->type)) {
+            cError("too many *");
+        }
+        v->type = dtReference(v->type);
+        dimension--;
+        cAddOperation(OP_REFERENCE);
+    }
+    cWalkStruct(v);
 }
 
-static DataType cAddVariable(Operation op, Variable* v) {
-    cAddOperation(op);
-    cAddInt(v->address);
-    return v->type;
-}
-
-static DataType cLoadVariable(Variable* v, Variable* sv) {
-    DataType type = v->type;
-    int offset = 0;
-    if(dtIsStruct(type) && sv->type.type != DT_VOID) {
-        sv->address += v->address;
-        return cLoadVariable(sv, sv);
-    } else if(dtIsStructRef(type)) {
-        type = dtToReference(sv->type);
-        offset = sv->address;
-    }
-    if(dtCompare(type, dtToReference(dtInt()))) {
-        return cLoadRef(v, OP_REF_LOAD_INT, dtInt(), offset);
-    } else if(dtCompare(type, dtToReference(dtFloat()))) {
-        return cLoadRef(v, OP_REF_LOAD_FLOAT, dtFloat(), offset);
-    } else if(dtCompare(type, dtToReference(dtBool()))) {
-        return cLoadRef(v, OP_REF_LOAD_BOOL, dtBool(), offset);
-    }
+static void cLoadRef(Variable* v) {
     switch(dtAsInt(v->type)) {
-        case DT_INT: return cAddVariable(OP_LOAD_INT, v);
-        case DT_BOOL: return cAddVariable(OP_LOAD_BOOL, v);
-        case DT_FLOAT: return cAddVariable(OP_LOAD_FLOAT, v);
+        case DT_INT: cAddOperation(OP_REF_LOAD_INT); break;
+        case DT_BOOL: cAddOperation(OP_REF_LOAD_BOOL); break;
+        case DT_FLOAT: cAddOperation(OP_REF_LOAD_FLOAT); break;
         case DT_STRUCT:
             {
                 Struct* st = dtGetStruct(&structs, v->type);
                 if(st == NULL) {
                     cError("compiler struct error");
                 }
-                int address = v->address;
-                for(int i = 0; i < st->amount; i++) {
-                    Variable v = {st->vars[i].name, st->vars[i].type, address};
-                    cLoadVariable(&v, sv);
-                    address += dtGetSize(v.type, &structs);
-                }
-                return v->type;
+                cAddOperation(OP_REF_LOAD);
+                cAddInt(dtGetSize(v->type, &structs));
+                break;
             }
         default:
-            cError("cannot load type %s", cGetName(v->type));
-            return dtVoid();
-    }
-}
-
-static bool cStoreRef(Variable* v, Variable* sv, DataType should, DataType dt,
-                      Operation op) {
-    DataType type = v->type;
-    int offset = 0;
-    if(dtIsStructRef(type)) {
-        type = dtToReference(sv->type);
-        offset = sv->address;
-    }
-    if(dtCompare(type, dtToReference(should)) && dtCompare(dt, should)) {
-        cAddOperation(OP_LOAD_INT);
-        cAddInt(v->address);
-        cAddOffset(offset);
-        cAddOperation(op);
-        return true;
+            if(dtIsPointer(v->type)) {
+                cAddOperation(OP_REF_LOAD_INT);
+            } else {
+                cError("cannot load type %s", cGetName(v->type));
+            }
     }
-    return false;
 }
 
 static void cStore(Variable* v, DataType dt, const char* name) {
     if(!dtCompare(v->type, dt)) {
         cInvalidOperation(v->type, dt, name);
-    } else if(v->type.reference) {
-        cAddOperation(OP_STORE_INT);
-        cAddInt(v->address);
-        return;
     }
     switch(dtAsInt(v->type)) {
         case DT_INT: cAddOperation(OP_STORE_INT); break;
         case DT_BOOL: cAddOperation(OP_STORE_BOOL); break;
         case DT_FLOAT: cAddOperation(OP_STORE_FLOAT); break;
         default:
-            if(dtIsArray(v->type)) {
+            if(dtIsPointer(v->type)) {
                 cAddOperation(OP_STORE_ARRAY);
             } else {
                 cError("cannot store type %s", cGetName(v->type));
             }
     }
-    cAddInt(v->address);
-}
-
-static void cStoreVariable(Variable* v, Variable* sv, DataType dt,
-                           const char* name) {
-    if(cStoreRef(v, sv, dtInt(), dt, OP_REF_STORE_INT) ||
-       cStoreRef(v, sv, dtFloat(), dt, OP_REF_STORE_FLOAT) ||
-       cStoreRef(v, sv, dtBool(), dt, OP_REF_STORE_BOOL)) {
-        return;
-    }
-    if(dtIsStruct(v->type) && sv->type.type != DT_VOID) {
-        sv->address += v->address;
-        cStore(sv, dt, name);
-    } else {
-        cStore(v, dt, name);
-    }
 }
 
 static DataType cPostChange(Variable* v, int change, const char* name) {
     if(!dtCompare(v->type, dtInt())) {
         cError("%s needs an int", name);
     }
-    cAddOperation(OP_LOAD_INT);
-    cAddInt(v->address);
-    cAddOperation(OP_LOAD_INT);
-    cAddInt(v->address);
+    cAddOperation(OP_REF_LOAD_INT);
+    cReference(v, 0);
+    cAddOperation(OP_DUPLICATE_REFERENCE);
+    cAddOperation(OP_REF_LOAD_INT);
     cAddOperation(OP_PUSH_INT);
     cAddInt(change);
     cAddOperation(OP_ADD_INT);
     cAddOperation(OP_STORE_INT);
-    cAddInt(v->address);
     return dtInt();
 }
 
-static void cWalkStruct(Variable* v, Variable* sv) {
-    sv->address = 0;
-    sv->name = "";
-    sv->type = dtVoid();
-    if(!cConsumeTokenIf(T_POINT)) {
-        return;
-    }
-    Struct* st = dtGetStruct(&structs, v->type);
-    if(st == NULL) {
-        cError("%s is not a struct but %s", v->name, cGetName(v->type));
-    }
-    cConsumeToken(T_LITERAL);
-    const char* name = cReadString();
-    if(vSearchStruct(sv, &structs, st, name)) {
-        cError("%s has no member %s", v->name, name);
-    }
-}
-
 static DataType cLiteral() {
     const char* literal = cReadString();
     if(cConsumeTokenIf(T_OPEN_BRACKET)) {
@@ -369,18 +315,18 @@ static DataType cLiteral() {
         }
         return dt;
     }
-    Variable* v = vSearch(&vars, literal);
-    if(v == NULL) {
+    Variable v;
+    if(vsSearch(&vars, &v, literal)) {
         cNotDeclared(literal);
     }
-    Variable sv;
-    cWalkStruct(v, &sv);
+    cReference(&v, 0);
     if(cConsumeTokenIf(T_INCREMENT)) {
-        return cPostChange(v, 1, "++");
+        return cPostChange(&v, 1, "++");
     } else if(cConsumeTokenIf(T_DECREMENT)) {
-        return cPostChange(v, -1, "--");
+        return cPostChange(&v, -1, "--");
     }
-    return cLoadVariable(v, &sv);
+    cLoadRef(&v);
+    return v.type;
 }
 
 static DataType cBracketPrimary() {
@@ -417,21 +363,22 @@ static DataType cPrimary() {
 static DataType cPreChange(int change, const char* name) {
     cConsumeToken(T_LITERAL);
     const char* literal = cReadString();
-    Variable* v = vSearch(&vars, literal);
-    if(v == NULL) {
+    Variable v;
+    if(vsSearch(&vars, &v, literal)) {
         cNotDeclared(literal);
-    } else if(!dtCompare(v->type, dtInt())) {
+    }
+    cReference(&v, 0);
+    if(!dtCompare(v.type, dtInt())) {
         cError("%s needs an int", name);
     }
-    cAddOperation(OP_LOAD_INT);
-    cAddInt(v->address);
+    cAddOperation(OP_DUPLICATE_REFERENCE);
+    cAddOperation(OP_DUPLICATE_REFERENCE);
+    cAddOperation(OP_REF_LOAD_INT);
     cAddOperation(OP_PUSH_INT);
     cAddInt(change);
     cAddOperation(OP_ADD_INT);
     cAddOperation(OP_STORE_INT);
-    cAddInt(v->address);
-    cAddOperation(OP_LOAD_INT);
-    cAddInt(v->address);
+    cAddOperation(OP_REF_LOAD_INT);
     return dtInt();
 }
 
@@ -473,18 +420,26 @@ static DataType cPreUnary() {
     } else if(cConsumeTokenIf(T_BIT_AND)) {
         cConsumeToken(T_LITERAL);
         const char* literal = cReadString();
-        Variable* v = vSearch(&vars, literal);
-        if(v == NULL) {
+        Variable v;
+        if(vsSearch(&vars, &v, literal)) {
             cNotDeclared(literal);
         }
-        if(v->type.reference) {
-            cAddOperation(OP_LOAD_INT);
-            cAddInt(v->address);
-        } else {
-            cAddOperation(OP_VAR_REF);
-            cAddInt(v->address);
+        cReference(&v, 0);
+        return dtDereference(v.type);
+    } else if(cConsumeTokenIf(T_MUL)) {
+        int c = 1;
+        while(cConsumeTokenIf(T_MUL)) {
+            c++;
+        }
+        cConsumeToken(T_LITERAL);
+        const char* literal = cReadString();
+        Variable v;
+        if(vsSearch(&vars, &v, literal)) {
+            cNotDeclared(literal);
         }
-        return dtToReference(v->type);
+        cReference(&v, c);
+        cLoadRef(&v);
+        return v.type;
     }
     return cPrimary();
 }
@@ -650,34 +605,71 @@ static DataType cExpression() {
     return cOr();
 }
 
-static void cOperationSet(Variable* v, Variable* sv, const TypedOp* op) {
-    DataType a = cLoadVariable(v, sv);
-    DataType b = cExpression();
-    cAddTypeOperation(a, b, op);
-    cStoreVariable(v, sv, b, "=");
+static void cOperationSet(Variable* v, const TypedOp* op) {
+    cAddOperation(OP_DUPLICATE_REFERENCE);
+    cLoadRef(v);
+    DataType dt = cExpression();
+    cAddTypeOperation(v->type, dt, op);
+    cStore(v, dt, "=");
 }
 
 static void cAddPostLineChange(Variable* v, int change, const char* name) {
     if(!dtCompare(v->type, dtInt())) {
         cError("%s needs an int", name);
     }
-    cAddOperation(OP_LOAD_INT);
-    cAddInt(v->address);
+    cAddOperation(OP_DUPLICATE_REFERENCE);
+    cAddOperation(OP_REF_LOAD_INT);
     cAddOperation(OP_PUSH_INT);
     cAddInt(change);
     cAddOperation(OP_ADD_INT);
     cAddOperation(OP_STORE_INT);
-    cAddInt(v->address);
+}
+
+static DataType cExtendType(DataType dt) {
+    while(cConsumeTokenIf(T_MUL)) {
+        dt = dtDereference(dt);
+    }
+    return dt;
 }
 
 static void cDeclareStruct(Struct* st) {
+    DataType dt = cExtendType(dtStruct(st));
     cConsumeToken(T_LITERAL);
     const char* var = cReadString();
-    Variable* v = vSearchScope(&vars, var);
-    if(v != NULL) {
+    if(vsInScope(&vars, var)) {
         cDeclared(var);
     }
-    vAdd(&vars, var, dtStruct(st), &structs);
+    Variable* vp = vsAdd(&vars, var, dt, &structs);
+    if(dtIsPointer(dt)) {
+        cConsumeToken(T_SET);
+        cReference(vp, 0);
+        cStore(vp, cExpression(), "=");
+    }
+}
+
+static void cLineVariable(const char* name, int dimension) {
+    Variable v;
+    if(vsSearch(&vars, &v, name)) {
+        cNotDeclared(name);
+    }
+    cReference(&v, dimension);
+    Token t = cReadTokenAndLine();
+    switch(t) {
+        case T_SET: cStore(&v, cExpression(), "="); break;
+        case T_ADD_SET: cOperationSet(&v, &TYPED_ADD); break;
+        case T_SUB_SET: cOperationSet(&v, &TYPED_SUB); break;
+        case T_MUL_SET: cOperationSet(&v, &TYPED_MUL); break;
+        case T_DIV_SET: cOperationSet(&v, &TYPED_DIV); break;
+        case T_MOD_SET: cOperationSet(&v, &TYPED_MOD); break;
+        case T_BIT_AND_SET: cOperationSet(&v, &TYPED_BIT_AND); break;
+        case T_BIT_OR_SET: cOperationSet(&v, &TYPED_BIT_OR); break;
+        case T_BIT_XOR_SET: cOperationSet(&v, &TYPED_BIT_XOR); break;
+        case T_LEFT_SHIFT_SET: cOperationSet(&v, &TYPED_LEFT_SHIFT); break;
+        case T_RIGHT_SHIFT_SET: cOperationSet(&v, &TYPED_RIGHT_SHIFT); break;
+        case T_INCREMENT: cAddPostLineChange(&v, 1, "++"); break;
+        case T_DECREMENT: cAddPostLineChange(&v, -1, "--"); break;
+        default: cUnexpectedToken(t);
+    }
 }
 
 static void cLineLiteral() {
@@ -694,32 +686,7 @@ static void cLineLiteral() {
         cDeclareStruct(st);
         return;
     }
-    Variable* v = vSearch(&vars, literal);
-    if(v == NULL) {
-        cNotDeclared(literal);
-    }
-    Variable sv;
-    sv.type = dtVoid();
-    cWalkStruct(v, &sv);
-    Token t = cReadTokenAndLine();
-    switch(t) {
-        case T_SET: cStoreVariable(v, &sv, cExpression(), "="); break;
-        case T_ADD_SET: cOperationSet(v, &sv, &TYPED_ADD); break;
-        case T_SUB_SET: cOperationSet(v, &sv, &TYPED_SUB); break;
-        case T_MUL_SET: cOperationSet(v, &sv, &TYPED_MUL); break;
-        case T_DIV_SET: cOperationSet(v, &sv, &TYPED_DIV); break;
-        case T_MOD_SET: cOperationSet(v, &sv, &TYPED_MOD); break;
-        case T_BIT_AND_SET: cOperationSet(v, &sv, &TYPED_BIT_AND); break;
-        case T_BIT_OR_SET: cOperationSet(v, &sv, &TYPED_BIT_OR); break;
-        case T_BIT_XOR_SET: cOperationSet(v, &sv, &TYPED_BIT_XOR); break;
-        case T_LEFT_SHIFT_SET: cOperationSet(v, &sv, &TYPED_LEFT_SHIFT); break;
-        case T_RIGHT_SHIFT_SET:
-            cOperationSet(v, &sv, &TYPED_RIGHT_SHIFT);
-            break;
-        case T_INCREMENT: cAddPostLineChange(v, 1, "++"); break;
-        case T_DECREMENT: cAddPostLineChange(v, -1, "--"); break;
-        default: cUnexpectedToken(t);
-    }
+    cLineVariable(literal, 0);
 }
 
 static void cLine(Token t);
@@ -738,9 +705,9 @@ static void cConsumeBody() {
 
 static void cConsumeScope() {
     Scope scope;
-    vEnterScope(&vars, &scope);
+    vsEnterScope(&vars, &scope);
     cConsumeBody();
-    vLeaveScope(&vars, &scope);
+    vsLeaveScope(&vars, &scope);
 }
 
 static void cAddReturn(Operation op) {
@@ -840,41 +807,28 @@ static void cWhile() {
     cConsumeBreaks(breakStart, code->length);
 }
 
-static DataType cExtendType(DataType dt) {
-    int dimension = 0;
-    while(cConsumeTokenIf(T_MUL)) {
-        dimension++;
-    }
-    if(dimension > 0) {
-        dt = dtToArray(dt, dimension);
-    }
-    if(cConsumeTokenIf(T_BIT_AND)) {
-        dt = dtToReference(dt);
-    }
-    return dt;
-}
-
 static void cDeclare(DataType dt) {
     dt = cExtendType(dt);
     cConsumeToken(T_LITERAL);
     const char* var = cReadString();
-    Variable* v = vSearchScope(&vars, var);
-    if(v != NULL) {
+    if(vsInScope(&vars, var)) {
         cDeclared(var);
     }
-    v = vAdd(&vars, var, dt, &structs);
+    Variable* vp = vsAdd(&vars, var, dt, &structs);
     cConsumeToken(T_SET);
-    cStore(v, cExpression(), "=");
+    cReference(vp, 0);
+    cStore(vp, cExpression(), "=");
 }
 
 static void cAddPreLineChange(int change, const char* name) {
     cConsumeToken(T_LITERAL);
     const char* literal = cReadString();
-    Variable* v = vSearch(&vars, literal);
-    if(v == NULL) {
+    Variable v;
+    if(vsSearch(&vars, &v, literal)) {
         cNotDeclared(literal);
     }
-    cAddPostLineChange(v, change, name);
+    cReference(&v, 0);
+    cAddPostLineChange(&v, change, name);
 }
 
 static void cLineExpression(Token t) {
@@ -885,13 +839,23 @@ static void cLineExpression(Token t) {
         case T_FLOAT: cDeclare(dtFloat()); break;
         case T_INCREMENT: cAddPreLineChange(1, "++"); break;
         case T_DECREMENT: cAddPreLineChange(-1, "--"); break;
+        case T_MUL:
+            {
+                int c = 1;
+                while(cConsumeTokenIf(T_MUL)) {
+                    c++;
+                }
+                cConsumeToken(T_LITERAL);
+                cLineVariable(cReadString(), c);
+                break;
+            }
         default: cUnexpectedToken(t);
     }
 }
 
 static void cFor() {
     Scope scope;
-    vEnterScope(&vars, &scope);
+    vsEnterScope(&vars, &scope);
 
     cConsumeToken(T_OPEN_BRACKET);
     cLineExpression(cReadTokenAndLine());
@@ -925,7 +889,7 @@ static void cFor() {
     cSetInt(end, code->length);
     cConsumeBreaks(breakStart, code->length);
 
-    vLeaveScope(&vars, &scope);
+    vsLeaveScope(&vars, &scope);
 }
 
 static void cBreak() {
@@ -979,11 +943,10 @@ static void cFunctionAddArgument(Function* f, DataType dt) {
     dt = cExtendType(dt);
     cConsumeToken(T_LITERAL);
     const char* name = cReadString();
-    Variable* v = vSearchScope(&vars, name);
-    if(v != NULL) {
+    if(vsInScope(&vars, name)) {
         cDeclared(name);
     }
-    vAdd(&vars, name, dt, &structs);
+    vsAdd(&vars, name, dt, &structs);
     if(fAddArgument(f, dt, &structs)) {
         cTooMuchArguments();
     }
@@ -1065,7 +1028,7 @@ static void cBuildFunction(Function* f, DataType rType) {
     cConsumeToken(T_LITERAL);
     fInit(f, cReadString(), line);
     f->returnType = rType;
-    vReset(&vars);
+    vsReset(&vars);
     cFunctionArguments(f);
 }
 
@@ -1173,7 +1136,7 @@ static void cAllocAndCompile() {
     forWhileStack = 0;
     breakIndex = 0;
     returnType = dtVoid();
-    vInit(&vars);
+    vsInit(&vars);
     fsInit(&functions);
     fsInit(&functionQueue);
     stsInit(&structs);
@@ -1184,7 +1147,7 @@ static void cAllocAndCompile() {
     stsDelete(&structs);
     fsDelete(&functionQueue);
     fsDelete(&functions);
-    vDelete(&vars);
+    vsDelete(&vars);
 }
 
 ByteCode* cCompile() {

+ 14 - 20
DataType.c

@@ -34,9 +34,6 @@ const char* dtGetName(Structs* sts, DataType dt) {
     for(unsigned int i = 0; i < dt.pointers; i++) {
         dtAppend("*");
     }
-    if(dt.reference) {
-        dtAppend("&");
-    }
     return typeName[typeNameSwap];
 }
 
@@ -59,32 +56,37 @@ int dtGetSize(DataType dt, Structs* sts) {
 }
 
 DataType dtInt() {
-    DataType dt = {DT_INT, 0, 0, 0};
+    DataType dt = {DT_INT, 0, 0};
     return dt;
 }
 
 DataType dtFloat() {
-    DataType dt = {DT_FLOAT, 0, 0, 0};
+    DataType dt = {DT_FLOAT, 0, 0};
     return dt;
 }
 
 DataType dtBool() {
-    DataType dt = {DT_BOOL, 0, 0, 0};
+    DataType dt = {DT_BOOL, 0, 0};
     return dt;
 }
 
 DataType dtVoid() {
-    DataType dt = {DT_VOID, 0, 0, 0};
+    DataType dt = {DT_VOID, 0, 0};
     return dt;
 }
 
 DataType dtStruct(Struct* st) {
-    DataType dt = {DT_STRUCT, 0, 0, st->id};
+    DataType dt = {DT_STRUCT, 0, st->id};
+    return dt;
+}
+
+DataType dtReference(DataType dt) {
+    dt.pointers--;
     return dt;
 }
 
-DataType dtToReference(DataType dt) {
-    dt.reference = 1;
+DataType dtDereference(DataType dt) {
+    dt.pointers++;
     return dt;
 }
 
@@ -107,20 +109,12 @@ unsigned int dtAsInt(DataType dt) {
     return i;
 }
 
-bool dtIsArray(DataType dt) {
+bool dtIsPointer(DataType dt) {
     return dt.pointers > 0;
 }
 
-bool dtIsStruct(DataType dt) {
-    return dt.type == DT_STRUCT && dt.pointers == 0 && dt.reference == 0;
-}
-
-bool dtIsStructRef(DataType dt) {
-    return dt.type == DT_STRUCT && dt.pointers == 0 && dt.reference == 1;
-}
-
 Struct* dtGetStruct(Structs* sts, DataType dt) {
-    if(dt.type != DT_STRUCT || dt.pointers != 0) {
+    if(dt.type != DT_STRUCT) {
         return NULL;
     }
     return sts->data + dt.structId;

+ 4 - 6
DataType.h

@@ -10,8 +10,7 @@
 #define DT_STRUCT 4
 
 typedef struct {
-    unsigned int type : 3;
-    unsigned int reference : 1;
+    unsigned int type : 4;
     unsigned int pointers : 4;
     unsigned int structId : 24;
 } DataType;
@@ -42,11 +41,10 @@ DataType dtBool();
 DataType dtVoid();
 DataType dtStruct(Struct* st);
 
-DataType dtToReference(DataType dt);
+DataType dtReference(DataType dt);
+DataType dtDereference(DataType dt);
 DataType dtToArray(DataType dt, int dimension);
-bool dtIsArray(DataType dt);
-bool dtIsStruct(DataType dt);
-bool dtIsStructRef(DataType dt);
+bool dtIsPointer(DataType dt);
 Struct* dtGetStruct(Structs* sts, DataType dt);
 
 bool dtCompare(DataType a, DataType b);

+ 6 - 6
tests/struct/bool_reference

@@ -1,15 +1,15 @@
-void test(bool& t) {
-    t = true;
+void test(bool* t) {
+    *t = true;
 }
 
 void main() {
     bool a = true;
-    bool& b = &a;
+    bool* b = &a;
     a = false;
     print a;
-    print b;
+    print *b;
     test(&a);
-    test(&b);
+    test(b);
     print a;
-    print b;
+    print *b;
 }

+ 7 - 7
tests/struct/float_reference

@@ -1,16 +1,16 @@
-void test(float& t) {
-    t = 8.0;
-    t += 1.0;
+void test(float* t) {
+    *t = 8.0;
+    *t += 1.0;
 }
 
 void main() {
     float a = 5.0;
-    float& b = &a;
+    float* b = &a;
     a = 6.0;
     print a;
-    print b;
+    print *b;
     test(&a);
-    test(&b);
+    test(b);
     print a;
-    print b;
+    print *b;
 }

+ 7 - 7
tests/struct/int_reference

@@ -1,16 +1,16 @@
-void test(int& t) {
-    t = 8;
-    t += 1;
+void test(int* t) {
+    *t = 8;
+    *t += 1;
 }
 
 void main() {
     int a = 5;
-    int& b = &a;
+    int* b = &a;
     a = 6;
     print a;
-    print b;
+    print *b;
     test(&a);
-    test(&b);
+    test(b);
     print a;
-    print b;
+    print *b;
 }

+ 9 - 7
tests/struct/pass_struct

@@ -14,15 +14,15 @@ void test(A a) {
     print a.b;
 }
 
-void test(A& a) {
-    print a.i;
-    print a.b;
+void test(A* a) {
+    print a->i;
+    print a->b;
     
-    a.i = 2;
-    a.b = false;
+    a->i = 2;
+    a->b = false;
     
-    print a.i;
-    print a.b;
+    print a->i;
+    print a->b;
 }
 
 void main() {
@@ -35,4 +35,6 @@ void main() {
     test(&a);
     print a.i;
     print a.b;
+    
+    int c = 3;
 }

+ 30 - 0
tests/struct/struct_access

@@ -0,0 +1,30 @@
+struct A {
+    int w;
+};
+
+void main() {
+    A a;
+    a.w = 3;
+    
+    int* ref = &a.w;
+    int** refa = &ref;
+    int*** refb = &refa;
+    A* ap = &a;
+    A** apa = &ap;
+    
+    *ref = 6;
+    **refa = 6;
+    ***refb = 4;
+    ***refb++;
+    
+    *apa->w++;
+    
+    a.w++;
+    ++a.w;
+    a.w--;
+    --a.w;
+    print a.w++;
+    print ++a.w;
+    print a.w--;
+    print --a.w;
+}

+ 4 - 0
tests/struct/struct_access.out

@@ -0,0 +1,4 @@
+6
+8
+8
+6

+ 1 - 0
tokenizer/Token.c

@@ -65,6 +65,7 @@ const char* tGetName(Token token) {
         case T_OPEN_CURVED_BRACKET: return "{";
         case T_CLOSE_CURVED_BRACKET: return "}";
         case T_POINT: return ".";
+        case T_ARROW: return "->";
         case T_OPEN_SQUARE_BRACKET: return "[";
         case T_CLOSE_SQUARE_BRACKET: return "]";
         case T_END: return "end";

+ 1 - 0
tokenizer/Token.h

@@ -62,6 +62,7 @@ typedef enum {
     T_OPEN_CURVED_BRACKET,
     T_CLOSE_CURVED_BRACKET,
     T_POINT,
+    T_ARROW,
     T_OPEN_SQUARE_BRACKET,
     T_CLOSE_SQUARE_BRACKET,
     T_END

+ 6 - 1
tokenizer/Tokenizer.c

@@ -145,6 +145,11 @@ static bool tAddToken4(int c, Token tce, Token tc, Token te, Token t) {
     return fReadIf(c) ? tAddToken2(tce, tc) : tAddToken2(te, t);
 }
 
+static bool tAddTokenMinus() {
+    return tAddToken3('-', T_DECREMENT, T_SUB_SET,
+                      fReadIf('>') ? T_ARROW : T_SUB);
+}
+
 static bool tLineComment() {
     while(true) {
         int c = fRead();
@@ -191,7 +196,7 @@ static bool tParseToken() {
         case ' ': return true;
         case '\n': line++; return true;
         case '+': return tAddToken3('+', T_INCREMENT, T_ADD_SET, T_ADD);
-        case '-': return tAddToken3('-', T_DECREMENT, T_SUB_SET, T_SUB);
+        case '-': return tAddTokenMinus();
         case '*': return tAddToken2(T_MUL_SET, T_MUL);
         case '/': return tSlash();
         case '%': return tAddToken2(T_MOD_SET, T_MOD);

+ 6 - 3
utils/ByteCodePrinter.c

@@ -109,7 +109,7 @@ static void btPrintFloat(const char* op) {
 #define PRINT_NUMBER_OP(op) PRINT_OP(OP_##op##_INT) PRINT_OP(OP_##op##_FLOAT)
 #define PRINT_TYPES(TYPE)                                                      \
     PRINT_OP_INT(OP_LOAD_##TYPE);                                              \
-    PRINT_OP_INT(OP_STORE_##TYPE);                                             \
+    PRINT_OP(OP_STORE_##TYPE);                                                 \
     PRINT_OP(OP_REF_LOAD_##TYPE);                                              \
     PRINT_OP(OP_REF_STORE_##TYPE);                                             \
     PRINT_OP_INT(OP_RETURN_##TYPE);                                            \
@@ -121,6 +121,7 @@ static void btConsumeOperation() {
         PRINT_TYPES(INT);
         PRINT_TYPES(BOOL);
         PRINT_TYPES(FLOAT);
+        PRINT_OP_INT(OP_REF_LOAD);
         PRINT_OP(OP_NOTHING);
         PRINT_OP_INT(OP_PUSH_INT);
         PRINT_OP_BASE(OP_PUSH_FLOAT, Float);
@@ -152,9 +153,11 @@ static void btConsumeOperation() {
         PRINT_OP_INT2(OP_GOSUB);
         PRINT_OP_INT(OP_RETURN);
         PRINT_OP_INT2(OP_RESERVE);
-        PRINT_OP_INT(OP_VAR_REF);
+        PRINT_OP_INT(OP_DEREFERENCE_VAR);
+        PRINT_OP(OP_REFERENCE);
+        PRINT_OP(OP_DUPLICATE_REFERENCE);
         PRINT_OP(OP_INT_ARRAY);
-        PRINT_OP_INT(OP_STORE_ARRAY);
+        PRINT_OP(OP_STORE_ARRAY);
         case OP_LINE: sPrintLine(); break;
     }
 }

+ 21 - 18
utils/Variables.c

@@ -3,34 +3,37 @@
 
 #include "utils/Variables.h"
 
-void vInit(Variables* v) {
+void vsInit(Variables* v) {
     v->capacity = 16;
-    vReset(v);
+    vsReset(v);
     v->data = malloc(sizeof(Variable) * v->capacity);
 }
 
-void vDelete(Variables* v) {
+void vsDelete(Variables* v) {
     free(v->data);
 }
 
-static Variable* vSearchUntil(Variables* v, const char* s, int index) {
-    for(int i = v->entries - 1; i >= index; i--) {
-        if(strcmp(s, v->data[i].name) == 0) {
-            return v->data + i;
+bool vsSearch(const Variables* vs, Variable* v, const char* s) {
+    for(int i = vs->entries - 1; i >= 0; i--) {
+        if(strcmp(s, vs->data[i].name) == 0) {
+            *v = vs->data[i];
+            return false;
         }
     }
-    return NULL;
-}
-
-Variable* vSearch(Variables* v, const char* s) {
-    return vSearchUntil(v, s, 0);
+    return true;
 }
 
-Variable* vSearchScope(Variables* v, const char* s) {
-    return vSearchUntil(v, s, v->scope);
+bool vsInScope(const Variables* vs, const char* s) {
+    for(int i = vs->entries - 1; i >= vs->scope; i--) {
+        if(strcmp(s, vs->data[i].name) == 0) {
+            return true;
+        }
+    }
+    return false;
 }
 
 bool vSearchStruct(Variable* v, Structs* sts, 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;
@@ -42,7 +45,7 @@ bool vSearchStruct(Variable* v, Structs* sts, Struct* st, const char* s) {
     return true;
 }
 
-Variable* vAdd(Variables* v, const char* s, DataType type, Structs* sts) {
+Variable* vsAdd(Variables* v, const char* s, DataType type, Structs* sts) {
     if(v->entries >= v->capacity) {
         v->capacity *= 2;
         v->data = realloc(v->data, sizeof(Variable) * v->capacity);
@@ -56,21 +59,21 @@ Variable* vAdd(Variables* v, const char* s, DataType type, Structs* sts) {
     return v->data + index;
 }
 
-void vReset(Variables* v) {
+void vsReset(Variables* v) {
     v->entries = 0;
     v->address = 0;
     v->scope = 0;
     v->maxAddress = 0;
 }
 
-void vEnterScope(Variables* v, Scope* s) {
+void vsEnterScope(Variables* v, Scope* s) {
     s->address = v->address;
     s->entries = v->entries;
     s->scope = v->scope;
     v->scope = v->entries;
 }
 
-void vLeaveScope(Variables* v, Scope* s) {
+void vsLeaveScope(Variables* v, Scope* s) {
     v->address = s->address;
     v->entries = s->entries;
     v->scope = s->scope;

+ 8 - 8
utils/Variables.h

@@ -26,14 +26,14 @@ typedef struct {
     int maxAddress;
 } Variables;
 
-void vInit(Variables* v);
-void vDelete(Variables* v);
-Variable* vSearch(Variables* v, const char* s);
+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);
-Variable* vSearchScope(Variables* v, const char* s);
-Variable* vAdd(Variables* v, const char* s, DataType type, Structs* sts);
-void vReset(Variables* v);
-void vEnterScope(Variables* v, Scope* s);
-void vLeaveScope(Variables* v, Scope* s);
+bool vsInScope(const Variables* vs, const char* s);
+Variable* vsAdd(Variables* v, const char* s, DataType type, Structs* sts);
+void vsReset(Variables* v);
+void vsEnterScope(Variables* v, Scope* s);
+void vsLeaveScope(Variables* v, Scope* s);
 
 #endif

+ 4 - 1
vm/Operation.h

@@ -41,9 +41,12 @@ typedef enum Operation {
     OP_RESERVE,
     TYPE_OPERATION(LOAD),
     TYPE_OPERATION(REF_LOAD),
+    OP_REF_LOAD,
     TYPE_OPERATION(STORE),
     TYPE_OPERATION(REF_STORE),
-    OP_VAR_REF,
+    OP_DEREFERENCE_VAR,
+    OP_REFERENCE,
+    OP_DUPLICATE_REFERENCE,
     OP_INT_ARRAY,
     OP_STORE_ARRAY
 } Operation;

+ 36 - 6
vm/Script.c

@@ -190,11 +190,15 @@ static void sLoad(Script* sc, int length) {
 
 static void sStore(Script* sc, int length) {
     int address = -1;
-    if(sReadInt(sc, &address)) {
-        address += sc->stackVarIndex;
-        if(sCheckAddress(sc, address, length)) {
-            sPop(sc, sc->stack + address, length);
-        }
+    int index = sc->stackIndex - sizeof(int) - length;
+    if(index < 0) {
+        sError(sc, "stack underflow");
+        return;
+    }
+    memcpy(&address, sc->stack + index, sizeof(int));
+    if(sCheckAddress(sc, address, length)) {
+        sPop(sc, sc->stack + address, length);
+        sc->stackIndex -= sizeof(int);
     }
 }
 
@@ -298,6 +302,29 @@ static void sVarRef(Script* sc) {
     }
 }
 
+static void sReference(Script* sc) {
+    int reference = 0;
+    if(sPopInt(sc, &reference) && sCheckAddress(sc, reference, sizeof(int))) {
+        sPush(sc, sc->stack + reference, sizeof(int));
+    }
+}
+
+static void sDuplicateReference(Script* sc) {
+    int reference = 0;
+    if(sPeek(sc, &reference, sizeof(int))) {
+        sPushInt(sc, reference);
+    }
+}
+
+static void sRefLoad(Script* sc) {
+    int size = 0;
+    int address = 0;
+    if(sReadInt(sc, &size) && sPopInt(sc, &address) &&
+       sCheckAddress(sc, address, size)) {
+        sPush(sc, sc->stack + address, size);
+    }
+}
+
 #define LOAD_REF(type, Type)                                                   \
     {                                                                          \
         int address = 0;                                                       \
@@ -363,7 +390,10 @@ static void sConsumeInstruction(Script* sc) {
         case OP_GOSUB: sGoSub(sc); break;
         case OP_RETURN: sReturn(sc); break;
         case OP_RESERVE: sReserveBytes(sc); break;
-        case OP_VAR_REF: sVarRef(sc); break;
+        case OP_DEREFERENCE_VAR: sVarRef(sc); break;
+        case OP_REFERENCE: sReference(sc); break;
+        case OP_DUPLICATE_REFERENCE: sDuplicateReference(sc); break;
+        case OP_REF_LOAD: sRefLoad(sc); break;
         case OP_INT_ARRAY: sIntArray(sc); break;
         case OP_STORE_ARRAY: sStore(sc, sizeof(int)); break;
     }