Browse Source

global variables

Kajetan Johannes Hammerle 3 years ago
parent
commit
9f7626abc9
6 changed files with 129 additions and 40 deletions
  1. 66 39
      Compiler.c
  2. 25 0
      tests/vars/global
  3. 5 0
      tests/vars/global.out
  4. 2 0
      utils/ByteCodePrinter.c
  5. 2 0
      vm/Operation.h
  6. 29 1
      vm/Script.c

+ 66 - 39
Compiler.c

@@ -32,6 +32,7 @@ static int16 line = 1;
 static bool onLine = false;
 
 static Variables vars;
+static Variables globalVars;
 static Functions functions;
 static Functions functionQueue;
 static Structs structs;
@@ -219,7 +220,7 @@ static DataType cExtendType(DataType dt, bool constant) {
     return dt;
 }
 
-static DataType cReadType(Token t) {
+static DataType cReadType(Token t, bool force) {
     bool c = t == T_CONST;
     if(c) {
         t = cReadTokenAndLine();
@@ -233,11 +234,19 @@ static DataType cReadType(Token t) {
             {
                 Struct* st = stsSearch(&structs, cReadString());
                 if(st == NULL) {
-                    cError("struct %s does not exist");
+                    if(force) {
+                        cError("struct %s does not exist");
+                    } else {
+                        return dtVoid();
+                    }
                 }
                 return cExtendType(dtStruct(st), c);
             }
-        default: cUnexpectedToken(t); return dtVoid();
+        default:
+            if(force) {
+                cUnexpectedToken(t);
+            }
+            return dtVoid();
     }
 }
 
@@ -334,11 +343,15 @@ static DataType cLiteral() {
         return cCallFunction(literal);
     }
     Variable v;
-    if(vsSearch(&vars, &v, literal)) {
-        cNotDeclared(literal);
+    if(!vsSearch(&vars, &v, literal)) {
+        cAddInt32Operation(OP_DEREFERENCE_VAR, v.address);
+        return dtToVariable(v.type);
+    } else if(!vsSearch(&globalVars, &v, literal)) {
+        cAddInt32Operation(OP_DEREFERENCE_GVAR, v.address);
+        return dtToVariable(v.type);
     }
-    cAddInt32Operation(OP_DEREFERENCE_VAR, v.address);
-    return dtToVariable(v.type);
+    cNotDeclared(literal);
+    return dtVoid();
 }
 
 static DataType cText() {
@@ -367,7 +380,7 @@ static void cArrayIndex(const char* name) {
 }
 
 static DataType cAllocArray() {
-    DataType dt = cReadType(cReadTokenAndLine());
+    DataType dt = cReadType(cReadTokenAndLine(), true);
     cConsumeToken(T_OPEN_SQUARE_BRACKET);
     cArrayIndex("size");
     cConsumeToken(T_CLOSE_SQUARE_BRACKET);
@@ -881,8 +894,7 @@ static void cSetVariable() {
     }
 }
 
-static void cDeclare(DataType dt, bool constant) {
-    dt = cExtendType(dt, constant);
+static void cDeclare(DataType dt) {
     cConsumeToken(T_LITERAL);
     const char* var = cReadString();
     if(vsInScope(&vars, var)) {
@@ -901,25 +913,11 @@ static void cDeclare(DataType dt, bool constant) {
 }
 
 static bool cDeclaration(Token t) {
-    bool c = t == T_CONST;
-    if(c) {
-        t = cReadTokenAndLine();
-    }
-    if(t == T_LITERAL) {
-        const char* literal = cReadString();
-        Struct* st = stsSearch(&structs, literal);
-        if(st != NULL) {
-            cDeclare(dtStruct(st), c);
-            return true;
-        }
-    }
-    switch(t) {
-        case T_INT32: cDeclare(dtInt32(), c); break;
-        case T_INT64: cDeclare(dtInt64(), c); break;
-        case T_BOOL: cDeclare(dtBool(), c); break;
-        case T_FLOAT: cDeclare(dtFloat(), c); break;
-        default: return false;
+    DataType dt = cReadType(t, false);
+    if(dtIsVoid(dt)) {
+        return false;
     }
+    cDeclare(dt);
     return true;
 }
 
@@ -1007,9 +1005,8 @@ static void cLine() {
     }
 }
 
-static void cBuildFunction(Function* f, DataType rType) {
-    cConsumeToken(T_LITERAL);
-    fInit(f, cReadString(), line);
+static void cBuildFunction(Function* f, DataType rType, const char* name) {
+    fInit(f, name, line);
     f->returnType = rType;
     vsReset(&vars);
     cConsumeToken(T_OPEN_BRACKET);
@@ -1017,7 +1014,7 @@ static void cBuildFunction(Function* f, DataType rType) {
         return;
     }
     while(true) {
-        DataType dt = cReadType(cReadTokenAndLine());
+        DataType dt = cReadType(cReadTokenAndLine(), true);
         cConsumeToken(T_LITERAL);
         const char* name = cReadString();
         if(vsInScope(&vars, name)) {
@@ -1065,9 +1062,9 @@ static void cInnerFunction(Function* f) {
     returnIndex = 0;
 }
 
-static void cFunction(DataType rType) {
+static void cFunction(DataType rType, const char* name) {
     Function f;
-    cBuildFunction(&f, rType);
+    cBuildFunction(&f, rType, name);
     Function* found = fsSearch(&functions, &f, true);
     if(cConsumeTokenIf(T_SEMICOLON)) {
         cAddFunction(found, &f);
@@ -1093,7 +1090,7 @@ static void cStruct() {
     DataType self = dtStruct(st);
     cConsumeToken(T_OPEN_CURVED_BRACKET);
     while(!cConsumeTokenIf(T_CLOSE_CURVED_BRACKET)) {
-        DataType dt = cReadType(cReadTokenAndLine());
+        DataType dt = cReadType(cReadTokenAndLine(), true);
         if(dtCompare(dt, self)) {
             cError("struct %s contains itself", name);
         }
@@ -1105,11 +1102,35 @@ static void cStruct() {
 }
 
 static void cGlobalScope(Token t) {
-    switch(t) {
-        case T_VOID: cFunction(dtVoid()); break;
-        case T_STRUCT: cStruct(); break;
-        default: cFunction(cReadType(t));
+    if(t == T_STRUCT) {
+        cStruct();
+        return;
+    }
+    DataType dt = dtVoid();
+    if(t != T_VOID) {
+        dt = cReadType(t, true);
     }
+    cConsumeToken(T_LITERAL);
+    const char* name = cReadString();
+    if(tPeekToken() == T_OPEN_BRACKET) {
+        cFunction(dt, name);
+        return;
+    }
+
+    if(vsInScope(&globalVars, name)) {
+        cDeclared(name);
+    }
+    Variable* v = vsAdd(&globalVars, name, dt, &structs);
+    if(dt.type != DT_STRUCT || dtIsPointer(dt)) {
+        cConsumeToken(T_SET);
+        cAddInt32Operation(OP_DEREFERENCE_GVAR, v->address);
+        DataType right = cUnpackedExpression();
+        if(!right.constant) {
+            dt.constant = 0;
+        }
+        cStore(dt, right, "=");
+    }
+    cConsumeToken(T_SEMICOLON);
 }
 
 static void cCallMain() {
@@ -1124,6 +1145,8 @@ static void cCallMain() {
 }
 
 static void cForEachLine() {
+    cAddOperation(OP_GRESERVE);
+    int p = cReserveInt32();
     while(true) {
         Token t = cReadTokenAndLine();
         if(t == T_END) {
@@ -1132,6 +1155,8 @@ static void cForEachLine() {
         cGlobalScope(t);
     }
     cCallMain();
+    cSetInt32(p, globalVars.maxAddress);
+    cAddInt32Operation(OP_GRESERVE, -globalVars.maxAddress);
 }
 
 static void cLinkQueuedFunctions() {
@@ -1152,6 +1177,7 @@ static void cAllocAndCompile() {
     returnType = dtVoid();
     onLine = false;
     vsInit(&vars);
+    vsInit(&globalVars);
     fsInit(&functions);
     fsInit(&functionQueue);
     stsInit(&structs);
@@ -1162,6 +1188,7 @@ static void cAllocAndCompile() {
     stsDelete(&structs);
     fsDelete(&functionQueue);
     fsDelete(&functions);
+    vsDelete(&globalVars);
     vsDelete(&vars);
 }
 

+ 25 - 0
tests/vars/global

@@ -0,0 +1,25 @@
+struct A {
+    int a;
+    int b;
+};
+
+int i = 3;
+int a = 23;
+A c;
+
+void wusi() {
+    int b = 0;
+    test(i);
+    test(c.a);
+    test(c.b);
+    i = 5;
+}
+
+void main() {
+    c.a = 8;
+    c.b = 10;
+    int b = 0;
+    test(i);
+    wusi();
+    test(i);
+}

+ 5 - 0
tests/vars/global.out

@@ -0,0 +1,5 @@
+3
+3
+8
+10
+5

+ 2 - 0
utils/ByteCodePrinter.c

@@ -207,7 +207,9 @@ static void btConsumeOperation() {
         PRINT_OP_INT32(OP_RETURN);
         PRINT_OP_INT32(OP_RETURN_POINTER);
         PRINT_OP_2INT32(OP_RESERVE);
+        PRINT_OP_INT32(OP_GRESERVE);
         PRINT_OP_INT32(OP_DEREFERENCE_VAR);
+        PRINT_OP_INT32(OP_DEREFERENCE_GVAR);
         PRINT_OP(OP_REFERENCE);
         PRINT_OP(OP_DUPLICATE_REFERENCE);
         PRINT_OP_INT32(OP_ADD_REFERENCE);

+ 2 - 0
vm/Operation.h

@@ -49,10 +49,12 @@ typedef enum Operation {
     OP_TYPE(RETURN),
     OP_RETURN_POINTER,
     OP_RESERVE,
+    OP_GRESERVE,
     OP_LOAD,
     OP_TYPE(LOAD),
     OP_TYPE(STORE),
     OP_DEREFERENCE_VAR,
+    OP_DEREFERENCE_GVAR,
     OP_REFERENCE,
     OP_DUPLICATE_REFERENCE,
     OP_ADD_REFERENCE,

+ 29 - 1
vm/Script.c

@@ -34,7 +34,10 @@ static Operation sReadOperation(Script* sc) {
 }
 
 static void* sReserve(Script* sc, int length) {
-    if(sc->stackIndex + length > SCRIPT_STACK_SIZE) {
+    if(length < 0) {
+        sError(sc, "invalid reserve length %d", length);
+        return NULL;
+    } else if(sc->stackIndex + length > SCRIPT_STACK_SIZE) {
         sError(sc, "stack overflow");
         return NULL;
     }
@@ -162,6 +165,21 @@ static void sReserveBytes(Script* sc) {
     }
 }
 
+static void sGlobalReserveBytes(Script* sc) {
+    int32 bytes = 0;
+    if(sReadInt32(sc, &bytes)) {
+        sc->stackVarIndex = sc->stackIndex;
+        if(bytes >= 0) {
+            sReserve(sc, bytes);
+        } else {
+            sc->stackIndex += bytes;
+            if(sc->stackIndex < 0) {
+                sError(sc, "invalid global free %d", bytes);
+            }
+        }
+    }
+}
+
 static int32 sGetTextLength(Script* sc, Pointer* p) {
     const int SIZE = sizeof(int32);
     int sizeAddress = -p->array;
@@ -384,6 +402,14 @@ static void sDereference(Script* sc) {
     }
 }
 
+static void sGlobalDereference(Script* sc) {
+    int32 address = 0;
+    if(sReadInt32(sc, &address)) {
+        Pointer p = {.array = -1, .offset = address};
+        sPushPointer(sc, &p);
+    }
+}
+
 static void sLoad(Script* sc, int length) {
     Pointer p;
     if(sPopPointer(sc, &p)) {
@@ -577,7 +603,9 @@ static void sConsumeInstruction(Script* sc) {
         case OP_RETURN: sReturn(sc); break;
         case OP_RETURN_POINTER: sReturnPointer(sc); break;
         case OP_RESERVE: sReserveBytes(sc); break;
+        case OP_GRESERVE: sGlobalReserveBytes(sc); break;
         case OP_DEREFERENCE_VAR: sDereference(sc); break;
+        case OP_DEREFERENCE_GVAR: sGlobalDereference(sc); break;
         case OP_REFERENCE: sLoad(sc, sizeof(Pointer)); break;
         case OP_DUPLICATE_REFERENCE: sDuplicateReference(sc); break;
         case OP_ADD_REFERENCE: sAddReference(sc); break;