Procházet zdrojové kódy

System functions, print to system function

Kajetan Johannes Hammerle před 6 dny
rodič
revize
72e582cc4c

+ 1 - 0
CMakeLists.txt

@@ -11,6 +11,7 @@ set(SRC
     "src/Tokenizer.c"
     "src/Buffer.c"
     "src/Memory.c"
+    "src/SystemFunctions.c"
 )
 
 set(COMPILER_ARGUMENTS

+ 40 - 19
src/Code.c

@@ -6,6 +6,7 @@
 #include "Code.h"
 #include "Constants.h"
 #include "Memory.h"
+#include "SystemFunctions.h"
 
 void codeInit(Code* c) {
     *c = (Code){};
@@ -27,7 +28,6 @@ void codeReset(Code* c) {
     if(iPopValue(c, &name)) \
     return true
 
-#define INT_VALUE(value) ((Value){.type = VT_INT32, .data = (value)})
 #define CSTRING_VALUE(value)                               \
     ((Value){.type = VT_CONSTANT_STRING, .data = (value)})
 
@@ -82,6 +82,11 @@ static bool iPopValue(Code* c, Value* v) {
     return false;
 }
 
+static bool iPop(Code* c) {
+    POP_VALUE(a);
+    return false;
+}
+
 static bool iAdd(Code* c) {
     POP_VALUE(a);
     POP_VALUE(b);
@@ -174,20 +179,6 @@ static bool iPushInt(Code* c) {
     return iPushValue(c, INT_VALUE(i));
 }
 
-static bool iPrint(Code* c) {
-    POP_VALUE(a);
-    switch(a.type) {
-        case VT_INT32: printf("%d", a.data); break;
-        case VT_CONSTANT_STRING: printf("%s", c->code.data + a.data); break;
-    }
-    return false;
-}
-
-static bool iPrintNewline() {
-    putchar('\n');
-    return false;
-}
-
 static bool iJump(Code* c) {
     i32 jumpPos = 0;
     if(codeReadI32(c, &jumpPos)) {
@@ -309,6 +300,36 @@ static bool iPushStackVariables(Code* c) {
     return false;
 }
 
+static bool iCallSystem(Code* c) {
+    i32 amountIndex = 0;
+    if(codeReadI32(c, &amountIndex)) {
+        SET_ERROR("CallSystem without argument amount");
+        return true;
+    }
+    i32 amount = amountIndex & 0xFF;
+    i32 index = amountIndex >> 8;
+    if(amount < 0 || amount > (i32)MAX_SYSTEM_FUNCTION_ARGUMENTS) {
+        SET_ERROR("CallSystem with invalid amount");
+        return true;
+    }
+    Value values[MAX_SYSTEM_FUNCTION_ARGUMENTS];
+    for(i32 i = amount - 1; i >= 0; i--) {
+        if(iPopValue(c, values + i)) {
+            return true;
+        }
+    }
+    SystemFunction f = getSystemFunction(index);
+    if(f == nullptr) {
+        SET_ERROR("Invalid system function index");
+        return true;
+    }
+    Value r = {};
+    if(f(c, &r, values, amount)) {
+        return true;
+    }
+    return iPushValue(c, r);
+}
+
 static bool execute(Code* c, Instruction command) {
     switch(command) {
         case ADD: return iAdd(c);
@@ -317,8 +338,7 @@ static bool execute(Code* c, Instruction command) {
         case DIV: return iDiv(c);
         case PUSH_CONSTANT_STRING: return iPushConstantString(c);
         case PUSH_INT32: return iPushInt(c);
-        case PRINT: return iPrint(c);
-        case PRINT_NEWLINE: return iPrintNewline();
+        case POP: return iPop(c);
         case JUMP: return iJump(c);
         case JUMP_ON_0: return iJumpIf(c);
         case JUMP_SUB: return iJumpSub(c);
@@ -335,6 +355,7 @@ static bool execute(Code* c, Instruction command) {
         case SMALLER: return iSmaller(c);
         case GREATER_OR_EQUAL: return iGreaterOrEqual(c);
         case SMALLER_OR_EQUAL: return iSmallerOrEqual(c);
+        case CALL_SYSTEM: return iCallSystem(c);
         case STOP: return true;
     }
     return false;
@@ -390,8 +411,7 @@ void codeDump(const Code* code) {
             DUMP(MUL);
             DUMP(DIV);
             DUMP_INT(PUSH_INT32);
-            DUMP(PRINT);
-            DUMP(PRINT_NEWLINE);
+            DUMP(POP);
             DUMP_INT(JUMP);
             DUMP_INT(JUMP_ON_0);
             DUMP_INT2(JUMP_SUB);
@@ -408,6 +428,7 @@ void codeDump(const Code* code) {
             DUMP(SMALLER);
             DUMP(GREATER_OR_EQUAL);
             DUMP(SMALLER_OR_EQUAL);
+            DUMP_INT(CALL_SYSTEM);
             DUMP(STOP);
             case PUSH_CONSTANT_STRING:
                 fprintf(

+ 4 - 2
src/Code.h

@@ -15,6 +15,8 @@ typedef struct {
     i32 data;
 } Value;
 
+#define INT_VALUE(value) ((Value){.type = VT_INT32, .data = (value)})
+
 static_assert(sizeof(Value) == 8);
 
 typedef enum : u8 {
@@ -24,8 +26,7 @@ typedef enum : u8 {
     DIV,
     PUSH_CONSTANT_STRING,
     PUSH_INT32,
-    PRINT,
-    PRINT_NEWLINE,
+    POP,
     JUMP,
     JUMP_ON_0,
     JUMP_SUB,
@@ -42,6 +43,7 @@ typedef enum : u8 {
     SMALLER,
     GREATER_OR_EQUAL,
     SMALLER_OR_EQUAL,
+    CALL_SYSTEM,
     STOP
 } Instruction;
 

+ 29 - 17
src/Compiler.c

@@ -6,7 +6,9 @@
 #include <string.h>
 
 #include "Code.h"
+#include "Constants.h"
 #include "Memory.h"
+#include "SystemFunctions.h"
 
 typedef struct Variable Variable;
 
@@ -432,11 +434,7 @@ static void compileFunction(Context* c) {
     c->inFunction = false;
 }
 
-static void compileCallFunction(Context* c, Token t) {
-    // used to store return address and variable index
-    codePushInstructionI32(c, PUSH_INT32, 0);
-    codePushInstructionI32(c, PUSH_INT32, 0);
-
+static i32 compileCallFunctionArguments(Context* c) {
     consumeToken(c, TT_OPEN_ROUND_BRACKET);
     i32 offset = 0;
     while(!peekToken(c, TT_CLOSE_ROUND_BRACKET)) {
@@ -447,11 +445,31 @@ static void compileCallFunction(Context* c, Token t) {
         compileExpression(c);
     }
     consumeToken(c, TT_CLOSE_ROUND_BRACKET);
+    return offset;
+}
 
-    codePushInstruction(c, JUMP_SUB);
-    size_t pos = codeGetWritePosition(c);
-    codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos, offset));
-    codePushI32(c, offset);
+static void compileCallFunction(Context* c, Token t) {
+    i32 index = getSystemFunctionIndex(t.stringValue);
+    if(index >= 0) {
+        i32 args = compileCallFunctionArguments(c);
+        i32 wantedArgs = getSystemFunctionArguments(index);
+        if(wantedArgs >= 0 && args != wantedArgs) {
+            THROW_ERROR(
+                "System function '%s' called with invalid amount of arguments",
+                t.stringValue);
+        }
+        static_assert(MAX_SYSTEM_FUNCTION_ARGUMENTS < (1 << 8));
+        codePushInstructionI32(c, CALL_SYSTEM, (index << 8) | args);
+    } else {
+        // used to store return address and variable index
+        codePushInstructionI32(c, PUSH_INT32, 0);
+        codePushInstructionI32(c, PUSH_INT32, 0);
+        i32 offset = compileCallFunctionArguments(c);
+        codePushInstruction(c, JUMP_SUB);
+        size_t pos = codeGetWritePosition(c);
+        codePushI32(c, addCallFunction(c, t.stringValue, (i32)pos, offset));
+        codePushI32(c, offset);
+    }
 }
 
 static void compileReturn(Context* c) {
@@ -467,17 +485,11 @@ static void compileReturn(Context* c) {
 
 static void compileLineLiteral(Context* c, Token token) {
     const char* s = token.stringValue;
-    if(strcmp(s, "print") == 0) {
-        while(!peekToken(c, TT_NEWLINE)) {
-            compileExpression(c);
-            codePushInstruction(c, PRINT);
-        }
-        consumeNewline(c);
-        codePushInstruction(c, PRINT_NEWLINE);
-    } else if(peekToken(c, TT_ASSIGN)) {
+    if(peekToken(c, TT_ASSIGN)) {
         compileSetVariable(c, s, false);
     } else if(peekToken(c, TT_OPEN_ROUND_BRACKET)) {
         compileCallFunction(c, token);
+        codePushInstruction(c, POP);
     } else {
         THROW_ERROR("Unexpected literal(%s)", s);
     }

+ 1 - 0
src/Constants.h

@@ -8,5 +8,6 @@
 [[maybe_unused]] constexpr size_t MAX_LITERAL_LENGTH = 64;
 [[maybe_unused]] constexpr size_t MAX_STRING_LENGTH = 64;
 [[maybe_unused]] constexpr size_t MAX_STACK_VALUES = 4096;
+[[maybe_unused]] constexpr size_t MAX_SYSTEM_FUNCTION_ARGUMENTS = 16;
 
 #endif

+ 1 - 1
src/Main.c

@@ -11,7 +11,7 @@ int main(int argCount, const char** args) {
         return 0;
     }
 
-    static char heap[2000];
+    static char heap[2500];
     memoryInit(heap, sizeof(heap));
     // memoryDump();
 

+ 51 - 0
src/SystemFunctions.c

@@ -0,0 +1,51 @@
+#include "SystemFunctions.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static bool sfPrint(Code* c, Value* r, Value* vs, i32 n) {
+    for(i32 i = 0; i < n; i++) {
+        Value* v = vs + i;
+        switch(v->type) {
+            case VT_INT32: printf("%d", v->data); break;
+            case VT_CONSTANT_STRING:
+                printf("%s", c->code.data + v->data);
+                break;
+        }
+    }
+    putchar('\n');
+    *r = INT_VALUE(0);
+    return false;
+}
+
+typedef struct {
+    SystemFunction function;
+    i32 arguments;
+    const char* name;
+} FunctionEntry;
+
+static FunctionEntry systemFunctions[] = {{sfPrint, -1, "print"}};
+static constexpr i32 amount = sizeof(systemFunctions) / sizeof(FunctionEntry);
+
+i32 getSystemFunctionIndex(const char* s) {
+    for(i32 i = 0; i < amount; i++) {
+        if(strcmp(systemFunctions->name, s) == 0) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+i32 getSystemFunctionArguments(i32 index) {
+    if(index >= 0 && index < amount) {
+        return systemFunctions[index].arguments;
+    }
+    return -1;
+}
+
+SystemFunction getSystemFunction(i32 index) {
+    if(index >= 0 && index < amount) {
+        return systemFunctions[index].function;
+    }
+    return nullptr;
+}

+ 12 - 0
src/SystemFunctions.h

@@ -0,0 +1,12 @@
+#ifndef BASIC_SYSTEM_FUNCTIONS_H
+#define BASIC_SYSTEM_FUNCTIONS_H
+
+#include "Code.h"
+
+typedef bool (*SystemFunction)(Code* c, Value* r, Value* vs, i32 n);
+
+i32 getSystemFunctionIndex(const char* s);
+i32 getSystemFunctionArguments(i32 index);
+SystemFunction getSystemFunction(i32 index);
+
+#endif

+ 7 - 7
test/Add.basic

@@ -1,7 +1,7 @@
-print 1 + 20
-print 1 + 20 + 4
-print 1 + 20 + 4 + 6
-print 5 - 6
-print 5 * 6
-print 16 / 5
-print 1 + 2 * 3
+print(1 + 20)
+print(1 + 20 + 4)
+print(1 + 20 + 4 + 6)
+print(5 - 6)
+print(5 * 6)
+print(16 / 5)
+print(1 + 2 * 3)

+ 18 - 18
test/Condition.basic

@@ -1,23 +1,23 @@
-print 3 < 5
-print 5 < 3
-print 3 < 3
+print(3 < 5)
+print(5 < 3)
+print(3 < 3)
 
-print 3 > 5
-print 5 > 3
-print 3 > 3
+print(3 > 5)
+print(5 > 3)
+print(3 > 3)
 
-print 3 == 5
-print 5 == 3
-print 3 == 3
+print(3 == 5)
+print(5 == 3)
+print(3 == 3)
 
-print 3 != 5
-print 5 != 3
-print 3 != 3
+print(3 != 5)
+print(5 != 3)
+print(3 != 3)
 
-print 3 <= 5
-print 5 <= 3
-print 3 <= 3
+print(3 <= 5)
+print(5 <= 3)
+print(3 <= 3)
 
-print 3 >= 5
-print 5 >= 3
-print 3 >= 3
+print(3 >= 5)
+print(5 >= 3)
+print(3 >= 3)

+ 4 - 4
test/Function.basic

@@ -1,6 +1,6 @@
 function wusi()
-    print "hi there"
-    print "great"
+    print("hi there")
+    print("great")
 end
 
 wusi()
@@ -9,8 +9,8 @@ gusi()
 wusi()
 
 function gusi()
-    print "baum"
-    print "wow"
+    print("baum")
+    print("wow")
 end
 
 gusi()

+ 3 - 3
test/Function2.basic

@@ -3,15 +3,15 @@ d = 5
 
 function wusi(a, b)
     d = 10
-    print a + b + $c + d
+    print(a + b + $c + d)
 end
 
 wusi(5, 6)
-print d
+print(d)
 
 function mod()
     $d = 12
 end
 
 mod()
-print d
+print(d)

+ 6 - 6
test/Function3.basic

@@ -7,8 +7,8 @@ function wusi(a, b)
 end
 
 wusi(5, 6)
-print wusi(3, 4)
-print wusi(5, 4)
+print(wusi(3, 4))
+print(wusi(5, 4))
 
 function fac(n)
     if n == 0
@@ -20,7 +20,7 @@ end
 function baum()
 end
 
-print fac(4)
-print fac(5)
-print baum()
-print baum()
+print(fac(4))
+print(fac(5))
+print(baum())
+print(baum())

+ 7 - 7
test/If.basic

@@ -1,22 +1,22 @@
 if 1
-  print "wusi"
+  print("wusi")
   if 0
-    print "wusi4"
+    print("wusi4")
   end
   if 1
-    print "wusi2"
+    print("wusi2")
   end
 end
 
 if 1 + 1
-  print "wusi3"
+  print("wusi3")
 end
 
 if 0
-  print "gusi"
+  print("gusi")
   if 1
-    print "gusi2"
+    print("gusi2")
   end
 end
 
-print "end"
+print("end")

+ 27 - 27
test/Logic.basic

@@ -1,31 +1,31 @@
-print 0 && 0
-print 1 && 0
-print 0 && 1
-print 1 && 1
+print(0 && 0)
+print(1 && 0)
+print(0 && 1)
+print(1 && 1)
 
-print 0 || 0
-print 1 || 0
-print 0 || 1
-print 1 || 1
+print(0 || 0)
+print(1 || 0)
+print(0 || 1)
+print(1 || 1)
 
-print 0 && 0 && 0
-print 1 && 0 && 0
-print 0 && 1 && 0
-print 1 && 1 && 0
-print 0 && 0 && 1
-print 1 && 0 && 1
-print 0 && 1 && 1
-print 1 && 1 && 1
+print(0 && 0 && 0)
+print(1 && 0 && 0)
+print(0 && 1 && 0)
+print(1 && 1 && 0)
+print(0 && 0 && 1)
+print(1 && 0 && 1)
+print(0 && 1 && 1)
+print(1 && 1 && 1)
 
-print 0 || 0 || 0
-print 1 || 0 || 0
-print 0 || 1 || 0
-print 1 || 1 || 0
-print 0 || 0 || 1
-print 1 || 0 || 1
-print 0 || 1 || 1
-print 1 || 1 || 1
+print(0 || 0 || 0)
+print(1 || 0 || 0)
+print(0 || 1 || 0)
+print(1 || 1 || 0)
+print(0 || 0 || 1)
+print(1 || 0 || 1)
+print(0 || 1 || 1)
+print(1 || 1 || 1)
 
-print !3
-print !!3
-print !!!3
+print(!3)
+print(!!3)
+print(!!!3)

+ 3 - 3
test/Print.basic

@@ -1,3 +1,3 @@
-print "Hi"
-print 6
-print "Hi there " 8 " great"
+print("Hi")
+print(6)
+print("Hi there ", 8, " great")

+ 9 - 9
test/Var.basic

@@ -2,16 +2,16 @@ abc = 5
 wusi = 10
 baum = 12 + wusi
 
-print abc
-print wusi
-print baum
-print nothing
+print(abc)
+print(wusi)
+print(baum)
+print(nothing)
 
 wusi = 6
 
-print abc
-print wusi
-print baum
-print nothing
+print(abc)
+print(wusi)
+print(baum)
+print(nothing)
 
-print abc + wusi + baum
+print(abc + wusi + baum)