Преглед изворни кода

function can have return values

Kajetan Johannes Hammerle пре 4 година
родитељ
комит
ef662f8df9
8 измењених фајлова са 134 додато и 38 уклоњено
  1. 47 33
      Compiler.c
  2. 1 1
      Object.h
  3. 1 0
      Operation.h
  4. 66 0
      Script.c
  5. 3 0
      Script.h
  6. 8 4
      Test.c
  7. 6 0
      tests/functions/return_value
  8. 2 0
      tests/functions/return_value.out

+ 47 - 33
Compiler.c

@@ -130,13 +130,48 @@ static const char* cReadString() {
     return literal;
 }
 
-static void cGetVar() {
+static void cGetVar(const char* var) {
     cAddOperation(OP_GET);
-    cAddInt(cAddVar(cReadString()));
+    cAddInt(cAddVar(var));
 }
 
 static void cExpression();
 
+static int cCallFunctionArguments() {
+    int arguments = 0;
+    while(!cConsumeTokenIf(T_CLOSE_BRACKET)) {
+        arguments++;
+        cExpression();
+        if(cConsumeTokenIf(T_COMMA) && tPeekToken() == T_CLOSE_BRACKET) {
+            cUnexpectedToken(tPeekToken());
+        }
+    }
+    return arguments;
+}
+
+static void cCallFunction(const char* literal) {
+    cAddOperation(OP_PUSH_INT);
+    cAddInt(0);
+    int arguments = cCallFunctionArguments();
+    int address = fmSearchAddress(&functions, literal, arguments);
+    cAddOperation(OP_GOSUB);
+    if(address == -1) {
+        fmEnqueue(&functions, literal, arguments, line, cReserveInt());
+    } else {
+        cAddInt(address);
+    }
+    cAddInt(arguments);
+}
+
+static void cLiteral() {
+    const char* literal = cReadString();
+    if(cConsumeTokenIf(T_OPEN_BRACKET)) {
+        cCallFunction(literal);
+    } else {
+        cGetVar(literal);
+    }
+}
+
 static void cPrimary() {
     Token t = cReadTokenAndLine();
     switch(t) {
@@ -149,7 +184,7 @@ static void cPrimary() {
             cExpression();
             cConsumeToken(T_CLOSE_BRACKET);
             break;
-        case T_LITERAL: cGetVar(); break;
+        case T_LITERAL: cLiteral(); break;
         default: cUnexpectedToken(t); break;
     }
 }
@@ -181,39 +216,15 @@ static void cSetVar(const char* literal) {
     cAddInt(cAddVar(literal));
 }
 
-static int cCallFunctionArguments() {
-    int arguments = 0;
-    while(!cConsumeTokenIf(T_CLOSE_BRACKET)) {
-        arguments++;
-        cExpression();
-        if(cConsumeTokenIf(T_COMMA) && tPeekToken() == T_CLOSE_BRACKET) {
-            cUnexpectedToken(tPeekToken());
-        }
-    }
-    return arguments;
-}
-
-static void cCallFunction(const char* literal) {
-    cAddOperation(OP_PUSH_INT);
-    cAddInt(0);
-    int arguments = cCallFunctionArguments();
-    int address = fmSearchAddress(&functions, literal, arguments);
-    cAddOperation(OP_GOSUB);
-    if(address == -1) {
-        fmEnqueue(&functions, literal, arguments, line, cReserveInt());
-    } else {
-        cAddInt(address);
-    }
-    cAddInt(arguments);
-    cConsumeToken(T_SEMICOLON);
-}
-
-static void cLiteral() {
+static void cLineLiteral() {
     const char* literal = cReadString();
     Token t = cReadTokenAndLine();
     switch(t) {
         case T_SET: cSetVar(literal); break;
-        case T_OPEN_BRACKET: cCallFunction(literal); break;
+        case T_OPEN_BRACKET:
+            cCallFunction(literal);
+            cConsumeToken(T_SEMICOLON);
+            break;
         default: cUnexpectedToken(t);
     }
 }
@@ -282,6 +293,9 @@ static void cReturn() {
         cError("return without a function on line %d", line);
     } else if(returnIndex >= RETURN_BUFFER) {
         cError("too much returns in function around line %d", line);
+    } else if(tPeekToken() != T_SEMICOLON) {
+        cExpression();
+        cAddOperation(OP_SET_RETURN);
     }
     cAddOperation(OP_POP);
     returns[returnIndex++] = cReserveInt(vars);
@@ -300,7 +314,7 @@ static void cLine(Token t) {
     cAddInt16(line);
     switch(t) {
         case T_PRINT: cPrint(); break;
-        case T_LITERAL: cLiteral(); break;
+        case T_LITERAL: cLineLiteral(); break;
         case T_FUNCTION: cFunction(); break;
         case T_RETURN: cReturn(); break;
         default: cUnexpectedToken(t);

+ 1 - 1
Object.h

@@ -1,7 +1,7 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
-typedef enum ObjectType { OT_INT, OT_FLOAT, OT_NULL, OT_BOOL } ObjectType;
+typedef enum ObjectType { OT_INT, OT_FLOAT, OT_NULL, OT_BOOL, OT_VOID } ObjectType;
 
 typedef struct Object {
     ObjectType type;

+ 1 - 0
Operation.h

@@ -18,6 +18,7 @@ typedef enum Operation {
     OP_LINE,
     OP_GOTO,
     OP_GOSUB,
+    OP_SET_RETURN,
     OP_RETURN
 } Operation;
 

+ 66 - 0
Script.c

@@ -20,6 +20,7 @@ static bool sPrinter(Object* o) {
         case OT_FLOAT: printf("%.2f\n", o->data.floatValue); return false;
         case OT_NULL: printf("null\n"); return false;
         case OT_BOOL: printf(o->data.intValue ? "true\n" : "false\n"); return false;
+        case OT_VOID: printf("void\n"); return false;
     }
     return true;
 }
@@ -223,6 +224,10 @@ static void sGoSub(Script* sc) {
     }
 }
 
+static void sSetReturn(Script* sc) {
+    sPop(sc, &sc->returnValue);
+}
+
 static void sReturn(Script* sc) {
     Object o;
     if(sPop(sc, &o)) {
@@ -232,6 +237,10 @@ static void sReturn(Script* sc) {
         return;
     }
     sc->readIndex = o.data.intValue;
+    if(sc->returnValue.type != OT_VOID) {
+        sPush(sc, &sc->returnValue);
+        sc->returnValue.type = OT_VOID;
+    }
 }
 
 static void sConsumeInstruction(Script* sc) {
@@ -252,6 +261,7 @@ static void sConsumeInstruction(Script* sc) {
         case OP_LINE: sLine(sc); break;
         case OP_GOTO: sGoTo(sc); break;
         case OP_GOSUB: sGoSub(sc); break;
+        case OP_SET_RETURN: sSetReturn(sc); break;
         case OP_RETURN: sReturn(sc); break;
     }
 }
@@ -265,6 +275,7 @@ Script* sInit(ByteCode* code) {
     sc->error[0] = '\0';
     sc->code = code;
     sc->readIndex = 0;
+    sc->returnValue.type = OT_VOID;
     sc->stackIndex = 0;
     sc->stackVarIndex = 0;
     sc->line = 0;
@@ -288,4 +299,59 @@ void sRun(Script* sc) {
 
 void sSetPrinter(ObjectPrinter p) {
     printer = p;
+}
+
+static void sPrintInt(Script* sc, const char* msg) {
+    int value = 0;
+    sReadInt(sc, &value);
+    printf("%s %d\n", msg, value);
+}
+
+static void sPrint2Int(Script* sc, const char* msg) {
+    int a = 0;
+    sReadInt(sc, &a);
+    int b = 0;
+    sReadInt(sc, &b);
+    printf("%s %d %d\n", msg, a, b);
+}
+
+static void sPrintInt16(Script* sc, const char* msg) {
+    int value = 0;
+    sRead(sc, &value, 2);
+    printf("%s %d\n", msg, value);
+}
+
+static void sPrintFloat(Script* sc, const char* msg) {
+    float value = 0;
+    sRead(sc, &value, sizeof(float));
+    printf("%s %.2f\n", msg, value);
+}
+
+void sPrintCode(Script* sc) {
+    int oldRead = sc->readIndex;
+    sc->readIndex = 0;
+    while(sHasData(sc)) {
+        printf(" %3d | ", sc->readIndex);
+        switch(sReadOperation(sc)) {
+            case OP_NOTHING: puts("Nothing"); break;
+            case OP_PUSH_INT: sPrintInt(sc, "Push Int"); break;
+            case OP_PUSH_FLOAT: sPrintFloat(sc, "Push Float"); break;
+            case OP_PUSH_NULL: puts("Push null"); break;
+            case OP_PUSH_TRUE: puts("Push true"); break;
+            case OP_PUSH_FALSE: puts("Push false"); break;
+            case OP_PUSH: sPrint2Int(sc, "Push"); break;
+            case OP_POP: sPrintInt(sc, "Pop"); break;
+            case OP_SET: sPrintInt(sc, "Set"); break;
+            case OP_GET: sPrintInt(sc, "Get"); break;
+            case OP_ADD: puts("Add"); break;
+            case OP_MUL: puts("Mul"); break;
+            case OP_PRINT: puts("Print"); break;
+            case OP_LINE: sPrintInt16(sc, "------------ Line"); break;
+            case OP_GOTO: sPrintInt(sc, "GoTo"); break;
+            case OP_GOSUB: sPrint2Int(sc, "GoSub"); break;
+            case OP_SET_RETURN: puts("Set Return"); break;
+            case OP_RETURN: puts("Return"); break;
+        }
+    }
+    sc->readIndex = oldRead;
 }

+ 3 - 0
Script.h

@@ -13,6 +13,7 @@ typedef struct Script {
     char error[SCRIPT_ERROR_SIZE];
     ByteCode* code;
     int readIndex;
+    Object returnValue;
     Object stack[SCRIPT_STACK_SIZE];
     int stackIndex;
     int stackVarIndex;
@@ -27,4 +28,6 @@ void sRun(Script* sc);
 typedef bool (*ObjectPrinter)(Object*);
 void sSetPrinter(ObjectPrinter p);
 
+void sPrintCode(Script* sc);
+
 #endif

+ 8 - 4
Test.c

@@ -39,6 +39,7 @@ static bool tsPrinter(Object* o) {
         case OT_FLOAT: tsPrintToBuffer("%.2f\n", o->data.floatValue); return false;
         case OT_NULL: tsPrintToBuffer("null\n"); return false;
         case OT_BOOL: tsPrintToBuffer(o->data.intValue ? "true\n" : "false\n"); return false;
+        case OT_VOID: tsPrintToBuffer("void\n"); return false;
     }
     return true;
 }
@@ -62,20 +63,21 @@ static void tsReset(int marker) {
     pathIndex = marker;
 }
 
-static void tsCompareResults(FILE* file) {
+static bool tsCompareResults(FILE* file) {
     for(int i = 0; i < testBufferIndex; i++) {
         char a = fgetc(file);
         char b = testBuffer[i];
         if(a != b) {
             printf("error in '%s': expected %c, got:\n%s", path, a, testBuffer + i);
-            return;
+            return true;
         }
     }
     if(fgetc(file) != EOF) {
         printf("error in '%s': no full read\n", path);
-        return;
+        return true;
     }
     doneTests++;
+    return false;
 }
 
 static void tsCheckScript(Script* sc) {
@@ -88,7 +90,9 @@ static void tsCheckScript(Script* sc) {
         printf("cannot open result file '%s'\n", path);
         return;
     }
-    tsCompareResults(file);
+    if(tsCompareResults(file)) {
+        sPrintCode(sc);
+    }
     fclose(file);
 }
 

+ 6 - 0
tests/functions/return_value

@@ -0,0 +1,6 @@
+function test(a, b) {
+    print 5;
+    return a + b;
+}
+
+print test(2, 4);

+ 2 - 0
tests/functions/return_value.out

@@ -0,0 +1,2 @@
+5
+6