Pārlūkot izejas kodu

library functions, underscore and digit support for literals

Kajetan Johannes Hammerle 3 gadi atpakaļ
vecāks
revīzija
6c83c786f6
18 mainītis faili ar 193 papildinājumiem un 15 dzēšanām
  1. 12 4
      Compiler.c
  2. 12 3
      Main.c
  3. 37 0
      libraries/Time.c
  4. 6 0
      libraries/Time.h
  5. 2 1
      meson.build
  6. 10 0
      tests/system/time
  7. 2 0
      tests/system/time.out
  8. 2 2
      tokenizer/Tokenizer.c
  9. 1 0
      utils/ByteCodePrinter.c
  10. 51 1
      utils/Functions.c
  11. 11 0
      utils/Functions.h
  12. 4 0
      utils/Utils.c
  13. 1 0
      utils/Utils.h
  14. 17 1
      vm/ByteCode.c
  15. 2 0
      vm/ByteCode.h
  16. 1 0
      vm/Operation.h
  17. 12 3
      vm/Script.c
  18. 10 0
      vm/Script.h

+ 12 - 4
Compiler.c

@@ -280,18 +280,24 @@ static void cCallFunctionArguments(Function* f) {
 }
 
 static DataType cCallFunction(const char* name) {
-    cAddIntOperation(OP_PUSH_INT, 0);
+    int returnAddress = bcGetAddress(code);
     Function f;
     fInit(&f, name, line);
     int oldOnLine = onLine;
     onLine = false;
     cCallFunctionArguments(&f);
     onLine = oldOnLine;
-    cAddOperation(OP_GOSUB);
     Function* found = fsSearch(&functions, &f);
     if(found == NULL) {
         cError("unknown function");
-    } else if(found->address == -1) {
+    } else if(found->global) {
+        cAddIntOperation(OP_CALL, found->line);
+        return found->returnType;
+    }
+    char push[1 + sizeof(int)] = {OP_PUSH_INT};
+    bcInsertBytes(code, push, 5, returnAddress);
+    cAddOperation(OP_GOSUB);
+    if(found->address == -1) {
         f.returnType = found->returnType;
         f.address = cReserveInt();
         fsAdd(&functionQueue, &f);
@@ -986,7 +992,9 @@ static void cBuildFunction(Function* f, DataType rType) {
 static void cAddFunction(Function* found, Function* f) {
     if(found == NULL) {
         fsAdd(&functions, f);
-    } else if(found->address != -1 || f->address == -1) {
+    } else if(found->global) {
+        cError("system functions cannot be overwritten");
+    } else if(found->address != -1 || f->address == -1 || found->global) {
         cError("function registered twice");
     } else if(!dtCompare(found->returnType, f->returnType)) {
         cError("function redeclared with different return type");

+ 12 - 3
Main.c

@@ -4,7 +4,9 @@
 
 #include "Compiler.h"
 #include "Test.h"
+#include "libraries/Time.h"
 #include "tokenizer/Tokenizer.h"
+#include "utils/Functions.h"
 #include "vm/Script.h"
 
 long getNanos() {
@@ -13,19 +15,19 @@ long getNanos() {
     return time.tv_nsec + time.tv_sec * 1000000000l;
 }
 
-int main(int argAmount, const char** args) {
+static void start(int argAmount, const char** args) {
     if(argAmount >= 3 && strcmp(args[1], "test") == 0) {
         tsStart(args[2]);
     } else if(argAmount >= 2) {
         if(tTokenize(args[1])) {
             puts(tGetError());
-            return 0;
+            return;
         }
         ByteCode* code = cCompile();
         if(code == NULL) {
             puts(cGetError());
             printf("line: %d\n", cGetLine());
-            return 0;
+            return;
         }
         Script* sc = sInit(code);
         long time = -getNanos();
@@ -34,5 +36,12 @@ int main(int argAmount, const char** args) {
         printf("----------------\n%ld ns\n", time);
         sDelete(sc);
     }
+}
+
+int main(int argAmount, const char** args) {
+    gfsInit();
+    lTimeRegister();
+    start(argAmount, args);
+    gfsDelete();
     return 0;
 }

+ 37 - 0
libraries/Time.c

@@ -0,0 +1,37 @@
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "libraries/Time.h"
+#include "utils/Functions.h"
+
+static void lTimeGetMillis(Script* sc) {
+    struct timespec time;
+    if(clock_gettime(CLOCK_REALTIME, &time)) {
+        sError(sc, "cannot get clock time: %s", strerror(errno));
+        return;
+    }
+    sPushLong(sc, time.tv_nsec / 1000000L + time.tv_sec * 1000L);
+}
+
+static void lTimeGetNanos(Script* sc) {
+    struct timespec time;
+    if(clock_gettime(CLOCK_BOOTTIME, &time)) {
+        sError(sc, "cannot get clock time: %s", strerror(errno));
+        return;
+    }
+    sPushLong(sc, time.tv_nsec + time.tv_sec * 1000000000L);
+}
+
+void lTimeRegister() {
+    Structs sts;
+    stsInit(&sts);
+
+    Function f;
+    gfInit(&f, "getMillis", dtLong(), lTimeGetMillis);
+    gfsAdd(&f);
+
+    gfInit(&f, "getNanos", dtLong(), lTimeGetNanos);
+    gfsAdd(&f);
+}

+ 6 - 0
libraries/Time.h

@@ -0,0 +1,6 @@
+#ifndef TIME_H
+#define TIME_H
+
+void lTimeRegister();
+
+#endif

+ 2 - 1
meson.build

@@ -14,7 +14,8 @@ src = [
     'Test.c', 
     'vm/ByteCode.c',
     'vm/Script.c', 
-    'vm/Arrays.c'
+    'vm/Arrays.c',
+    'libraries/Time.c'
 ]
 
 executable('lonely_tiger', 

+ 10 - 0
tests/system/time

@@ -1,3 +1,13 @@
 void main() {
+    long l1 = getMillis();
+    long l2 = getMillis();
+    long l3 = getMillis();
+    long l4 = getMillis();
+    print l1 <= l2 && l2 <= l3 && l3 <= l4;
     
+    l1 = getNanos();
+    l2 = getNanos();
+    l3 = getNanos();
+    l4 = getNanos();
+    print l1 < l2 && l2 < l3 && l3 < l4;
 }

+ 2 - 0
tests/system/time.out

@@ -0,0 +1,2 @@
+true
+true

+ 2 - 2
tokenizer/Tokenizer.c

@@ -54,7 +54,7 @@ static void tParseLiteral(int c) {
     int index = 1;
     char buffer[64];
     buffer[0] = c;
-    while(isLetter(fPeek())) {
+    while(isAllowedInName(fPeek())) {
         if(index >= 63) {
             tError("literal is too long");
         }
@@ -94,7 +94,7 @@ static void tParseNumber(int c) {
         }
         char* end = NULL;
         long l = strtol(buffer, &end, 10);
-        if(end[0] != '\0' || l > INT_MAX) {
+        if(end[0] != '\0' || l > LONG_MAX) {
             tError("invalid long on line %d", line);
         }
         tAddToken(T_CONST_LONG);

+ 1 - 0
utils/ByteCodePrinter.c

@@ -208,6 +208,7 @@ static void btConsumeOperation() {
         PRINT_OP(OP_LONG_TO_INT);
         PRINT_OP(OP_FLOAT_TO_LONG);
         PRINT_OP(OP_LONG_TO_FLOAT);
+        PRINT_OP_INT(OP_CALL);
         case OP_LINE: sPrintLine(); break;
     }
 }

+ 51 - 1
utils/Functions.c

@@ -3,6 +3,9 @@
 
 #include "utils/Functions.h"
 
+static bool useGlobals = false;
+static Functions globalFunctions;
+
 void fInit(Function* f, const char* name, int line) {
     f->name = name;
     f->arguments = 0;
@@ -10,6 +13,8 @@ void fInit(Function* f, const char* name, int line) {
     f->address = -1;
     f->size = 0;
     f->line = line;
+    f->global = false;
+    f->scriptFunction = NULL;
 }
 
 bool fAddArgument(Function* f, DataType type, Structs* sts) {
@@ -43,7 +48,7 @@ void fsDelete(Functions* fs) {
     free(fs->data);
 }
 
-Function* fsSearch(Functions* fs, Function* f) {
+static Function* fsInternSearch(Functions* fs, Function* f) {
     for(int i = 0; i < fs->entries; i++) {
         if(fCompare(fs->data + i, f)) {
             return fs->data + i;
@@ -52,10 +57,55 @@ Function* fsSearch(Functions* fs, Function* f) {
     return NULL;
 }
 
+Function* fsSearch(Functions* fs, Function* f) {
+    if(useGlobals) {
+        Function* gf = fsInternSearch(&globalFunctions, f);
+        if(gf != NULL) {
+            return gf;
+        }
+    }
+    return fsInternSearch(fs, f);
+}
+
 void fsAdd(Functions* fs, Function* f) {
     if(fs->entries >= fs->capacity) {
         fs->capacity *= 2;
         fs->data = realloc(fs->data, sizeof(Function) * fs->capacity);
     }
     fs->data[fs->entries++] = *f;
+}
+
+void gfInit(Function* f, const char* name, DataType r, ScriptFunction sf) {
+    fInit(f, name, -1);
+    f->returnType = r;
+    f->scriptFunction = sf;
+}
+
+void gfsInit() {
+    fsInit(&globalFunctions);
+    useGlobals = true;
+}
+
+bool gfsAdd(Function* f) {
+    if(fsSearch(&globalFunctions, f) != NULL) {
+        return true;
+    }
+    int index = globalFunctions.entries;
+    fsAdd(&globalFunctions, f);
+    globalFunctions.data[index].line = index;
+    globalFunctions.data[index].global = true;
+    return false;
+}
+
+bool gfsCall(Script* sc, int id) {
+    if(!useGlobals || id < 0 || id >= globalFunctions.entries) {
+        return true;
+    }
+    globalFunctions.data[id].scriptFunction(sc);
+    return false;
+}
+
+void gfsDelete() {
+    fsDelete(&globalFunctions);
+    useGlobals = false;
 }

+ 11 - 0
utils/Functions.h

@@ -4,9 +4,12 @@
 #include <stdbool.h>
 
 #include "DataType.h"
+#include "vm/Script.h"
 
 #define FUNCTION_ARGUMENTS 9
 
+typedef void (*ScriptFunction)(Script*);
+
 typedef struct {
     const char* name;
     int arguments;
@@ -15,6 +18,8 @@ typedef struct {
     int address;
     int size;
     int line;
+    bool global;
+    ScriptFunction scriptFunction;
 } Function;
 
 typedef struct {
@@ -31,4 +36,10 @@ void fsDelete(Functions* fs);
 Function* fsSearch(Functions* fs, Function* f);
 void fsAdd(Functions* fs, Function* f);
 
+void gfInit(Function* f, const char* name, DataType r, ScriptFunction sf);
+void gfsInit();
+bool gfsAdd(Function* f);
+bool gfsCall(Script* sc, int id);
+void gfsDelete();
+
 #endif

+ 4 - 0
utils/Utils.c

@@ -6,4 +6,8 @@ bool isLetter(int c) {
 
 bool isNumber(int c) {
     return c >= '0' && c <= '9';
+}
+
+bool isAllowedInName(int c) {
+    return isLetter(c) || isNumber(c) || c == '_';
 }

+ 1 - 0
utils/Utils.h

@@ -5,5 +5,6 @@
 
 bool isLetter(int c);
 bool isNumber(int c);
+bool isAllowedInName(int c);
 
 #endif

+ 17 - 1
vm/ByteCode.c

@@ -17,11 +17,15 @@ void bcDelete(ByteCode* bc) {
     free(bc);
 }
 
-int bcReserveBytes(ByteCode* bc, int length) {
+static void bcReAlloc(ByteCode* bc, int length) {
     while(bc->length + length > bc->capacity) {
         bc->capacity *= 2;
         bc->code = realloc(bc->code, bc->capacity);
     }
+}
+
+int bcReserveBytes(ByteCode* bc, int length) {
+    bcReAlloc(bc, length);
     int p = bc->length;
     bc->length += length;
     return p;
@@ -33,4 +37,16 @@ void bcSetBytes(ByteCode* bc, int p, const void* data, int length) {
 
 void bcAddBytes(ByteCode* bc, const void* data, int length) {
     bcSetBytes(bc, bcReserveBytes(bc, length), data, length);
+}
+
+int bcGetAddress(ByteCode* bc) {
+    return bc->length;
+}
+
+void bcInsertBytes(ByteCode* bc, const void* data, int length, int address) {
+    bcReAlloc(bc, length);
+    memmove(bc->code + address + length, bc->code + address,
+            bc->length - address);
+    memcpy(bc->code + address, data, length);
+    bc->length += length;
 }

+ 2 - 0
vm/ByteCode.h

@@ -15,5 +15,7 @@ void bcDelete(ByteCode* bc);
 int bcReserveBytes(ByteCode* bc, int length);
 void bcSetBytes(ByteCode* bc, int p, const void* data, int length);
 void bcAddBytes(ByteCode* bc, const void* data, int length);
+int bcGetAddress(ByteCode* bc);
+void bcInsertBytes(ByteCode* bc, const void* data, int length, int address);
 
 #endif

+ 1 - 0
vm/Operation.h

@@ -66,6 +66,7 @@ typedef enum Operation {
     OP_LONG_TO_INT,
     OP_FLOAT_TO_LONG,
     OP_LONG_TO_FLOAT,
+    OP_CALL
 } Operation;
 
 #endif

+ 12 - 3
vm/Script.c

@@ -4,10 +4,11 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "utils/Functions.h"
 #include "vm/Operation.h"
 #include "vm/Script.h"
 
-static void sError(Script* sc, const char* format, ...) {
+void sError(Script* sc, const char* format, ...) {
     va_list args;
     va_start(args, format);
     vsnprintf(sc->error, SCRIPT_ERROR_SIZE, format, args);
@@ -105,10 +106,10 @@ static bool sPeek(Script* sc, void* data, int length) {
 }
 
 #define POP_PUSH(type, Type)                                                   \
-    static bool sPop##Type(Script* sc, type* value) {                          \
+    bool sPop##Type(Script* sc, type* value) {                                 \
         return sPop(sc, value, sizeof(type));                                  \
     }                                                                          \
-    static bool sPush##Type(Script* sc, type value) {                          \
+    bool sPush##Type(Script* sc, type value) {                                 \
         return sPush(sc, &value, sizeof(type));                                \
     }
 
@@ -432,6 +433,13 @@ static void sEqualPointer(Script* sc) {
     }
 }
 
+static void sCall(Script* sc) {
+    int function = 0;
+    if(sReadInt(sc, &function) && gfsCall(sc, function)) {
+        sError(sc, "invalid function call");
+    }
+}
+
 #define CHANGE_OP(type, op)                                                    \
     {                                                                          \
         char c = 0;                                                            \
@@ -553,6 +561,7 @@ static void sConsumeInstruction(Script* sc) {
         case OP_LONG_TO_INT: CAST(Long, long, Int); break;
         case OP_FLOAT_TO_LONG: CAST(Float, float, Long); break;
         case OP_LONG_TO_FLOAT: CAST(Long, long, Float); break;
+        case OP_CALL: sCall(sc); break;
     }
 }
 

+ 10 - 0
vm/Script.h

@@ -25,6 +25,16 @@ void sDelete(Script* sc);
 
 void sRun(Script* sc);
 
+void sError(Script* sc, const char* format, ...);
+bool sPopInt(Script* sc, int* i);
+bool sPushInt(Script* sc, int i);
+bool sPopLong(Script* sc, long* l);
+bool sPushLong(Script* sc, long l);
+bool sPopFloat(Script* sc, float* f);
+bool sPushFloat(Script* sc, float f);
+bool sPopBool(Script* sc, bool* b);
+bool sPushBool(Script* sc, bool b);
+
 typedef void (*IntPrinter)(int);
 void sSetIntPrinter(IntPrinter p);
 typedef void (*LongPrinter)(long);