Pārlūkot izejas kodu

not used return values of functions are popped

Kajetan Johannes Hammerle 3 gadi atpakaļ
vecāks
revīzija
07c762063d
7 mainītis faili ar 80 papildinājumiem un 34 dzēšanām
  1. 46 20
      Compiler.c
  2. 8 6
      FunctionMap.c
  3. 5 3
      FunctionMap.h
  4. 2 1
      Operation.h
  5. 11 4
      Script.c
  6. 3 0
      Test.c
  7. 5 0
      tests/functions/return_value

+ 46 - 20
Compiler.c

@@ -24,6 +24,7 @@ static FunctionMap functions;
 
 static int returns[RETURN_BUFFER];
 static int returnIndex = 0;
+static int returnState = 0;
 
 static void cError(const char* format, ...) {
     va_list args;
@@ -69,14 +70,14 @@ static void cAddFloat(float f) {
 }
 
 static int cAddPush(int offset) {
-    cAddOperation(OP_PUSH);
+    cAddOperation(OP_PUSH_VARS);
     int p = cReserveInt();
     cAddInt(offset);
     return p;
 }
 
 static void cAddPop(int p, int vars) {
-    cAddOperation(OP_POP);
+    cAddOperation(OP_POP_VARS);
     cAddInt(vars);
     cSetInt(p, vars);
 }
@@ -149,24 +150,29 @@ static int cCallFunctionArguments() {
     return arguments;
 }
 
-static void cCallFunction(const char* literal) {
+static void cCallFunction(const char* literal, bool noReturn) {
     cAddOperation(OP_PUSH_INT);
     cAddInt(0);
     int arguments = cCallFunctionArguments();
-    int address = fmSearchAddress(&functions, literal, arguments);
+    Function* f = fmSearch(&functions, literal, arguments);
     cAddOperation(OP_GOSUB);
-    if(address == -1) {
-        fmEnqueue(&functions, literal, arguments, line, cReserveInt());
+    if(f == NULL) {
+        fmEnqueue(&functions, literal, arguments, line, cReserveInt(), noReturn);
+        cAddInt(arguments);
+        cAddOperation(OP_NOTHING);
     } else {
-        cAddInt(address);
+        cAddInt(f->address);
+        cAddInt(arguments);
+        if(f->returns && noReturn) {
+            cAddOperation(OP_POP);
+        }
     }
-    cAddInt(arguments);
 }
 
 static void cLiteral() {
     const char* literal = cReadString();
     if(cConsumeTokenIf(T_OPEN_BRACKET)) {
-        cCallFunction(literal);
+        cCallFunction(literal, false);
     } else {
         cGetVar(literal);
     }
@@ -222,7 +228,7 @@ static void cLineLiteral() {
     switch(t) {
         case T_SET: cSetVar(literal); break;
         case T_OPEN_BRACKET:
-            cCallFunction(literal);
+            cCallFunction(literal, true);
             cConsumeToken(T_SEMICOLON);
             break;
         default: cUnexpectedToken(t);
@@ -266,10 +272,12 @@ static void cFunctionBody(const char* name, int arguments) {
     cAddOperation(OP_GOTO);
     int gotoIndex = cReserveInt();
 
-    if(!fmAdd(&functions, name, arguments, code->length)) {
+    int address = code->length;
+    returnState = 0;
+    cFunctionInnerBody(arguments);
+    if(!fmAdd(&functions, name, arguments, address, returnState == 2)) {
         cError("function registered twice on line %d", line);
     }
-    cFunctionInnerBody(arguments);
 
     cAddOperation(OP_RETURN);
     cSetInt(gotoIndex, code->length);
@@ -288,19 +296,34 @@ static void cFunction() {
     varIndex = 0;
 }
 
+static void cAddReturn() {
+    cAddOperation(OP_POP_VARS);
+    returns[returnIndex++] = cReserveInt(vars);
+    cAddOperation(OP_RETURN);
+}
+
 static void cReturn() {
     if(varIndex == 0) {
         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) {
+    }
+    if(cConsumeTokenIf(T_SEMICOLON)) {
+        if(returnState == 2) {
+            cError("mixed return type on line %d", line);
+        }
+        returnState = 1;
+        cAddReturn();
+    } else {
+        if(returnState == 1) {
+            cError("mixed return type on line %d", line);
+        }
+        returnState = 2;
         cExpression();
         cAddOperation(OP_SET_RETURN);
+        cAddReturn();
+        cConsumeToken(T_SEMICOLON);
     }
-    cAddOperation(OP_POP);
-    returns[returnIndex++] = cReserveInt(vars);
-    cAddOperation(OP_RETURN);
-    cConsumeToken(T_SEMICOLON);
 }
 
 static void cPrint() {
@@ -331,11 +354,14 @@ static void cForEachLine() {
 
 static void cLinkQueuedFunctions() {
     for(int i = 0; i < functions.queueEntries; i++) {
-        int address = fmSearchAddress(&functions, functions.queue[i].name, functions.queue[i].arguments);
-        if(address == -1) {
+        Function* f = fmSearch(&functions, functions.queue[i].name, functions.queue[i].arguments);
+        if(f == NULL) {
             cError("unknown function on line %d", functions.queue[i].line);
         }
-        cSetInt(functions.queue[i].reserved, address);
+        cSetInt(functions.queue[i].reserved, f->address);
+        if(functions.queue[i].noReturn && f->returns) {
+            code->code[functions.queue[i].reserved + sizeof(int) * 2] = OP_POP;
+        }
     }
 }
 

+ 8 - 6
FunctionMap.c

@@ -17,17 +17,17 @@ void fmDelete(FunctionMap* fm) {
     free(fm->queue);
 }
 
-int fmSearchAddress(FunctionMap* fm, const char* name, int arguments) {
+Function* fmSearch(FunctionMap* fm, const char* name, int arguments) {
     for(int i = 0; i < fm->entries; i++) {
         if(fm->data[i].arguments == arguments && strcmp(fm->data[i].name, name) == 0) {
-            return fm->data[i].address;
+            return fm->data + i;
         }
     }
-    return -1;
+    return NULL;
 }
 
-bool fmAdd(FunctionMap* fm, const char* name, int arguments, int address) {
-    if(fmSearchAddress(fm, name, arguments) != -1) {
+bool fmAdd(FunctionMap* fm, const char* name, int arguments, int address, bool returns) {
+    if(fmSearch(fm, name, arguments) != NULL) {
         return false;
     }
     if(fm->entries >= fm->capacity) {
@@ -38,10 +38,11 @@ bool fmAdd(FunctionMap* fm, const char* name, int arguments, int address) {
     fm->data[index].name = name;
     fm->data[index].arguments = arguments;
     fm->data[index].address = address;
+    fm->data[index].returns = returns;
     return true;
 }
 
-void fmEnqueue(FunctionMap* fm, const char* name, int arguments, int line, int reserved) {
+void fmEnqueue(FunctionMap* fm, const char* name, int arguments, int line, int reserved, bool noReturn) {
     if(fm->queueEntries >= fm->queueCapacity) {
         fm->queueCapacity *= 2;
         fm->queue = realloc(fm->queue, sizeof(LingeringFunction) * fm->queueCapacity);
@@ -51,4 +52,5 @@ void fmEnqueue(FunctionMap* fm, const char* name, int arguments, int line, int r
     fm->queue[index].arguments = arguments;
     fm->queue[index].line = line;
     fm->queue[index].reserved = reserved;
+    fm->queue[index].noReturn = noReturn;
 }

+ 5 - 3
FunctionMap.h

@@ -7,6 +7,7 @@ typedef struct Function {
     const char* name;
     int arguments;
     int address;
+    bool returns;
 } Function;
 
 typedef struct LingeringFunction {
@@ -14,6 +15,7 @@ typedef struct LingeringFunction {
     int arguments;
     int line;
     int reserved;
+    bool noReturn;
 } LingeringFunction;
 
 typedef struct FunctionMap {
@@ -27,8 +29,8 @@ typedef struct FunctionMap {
 
 void fmInit(FunctionMap* fm);
 void fmDelete(FunctionMap* fm);
-int fmSearchAddress(FunctionMap* fm, const char* name, int arguments);
-bool fmAdd(FunctionMap* fm, const char* name, int arguments, int address);
-void fmEnqueue(FunctionMap* fm, const char* name, int arguments, int line, int reserved);
+Function* fmSearch(FunctionMap* fm, const char* name, int arguments);
+bool fmAdd(FunctionMap* fm, const char* name, int arguments, int address, bool returns);
+void fmEnqueue(FunctionMap* fm, const char* name, int arguments, int line, int reserved, bool noReturn);
 
 #endif

+ 2 - 1
Operation.h

@@ -8,7 +8,8 @@ typedef enum Operation {
     OP_PUSH_NULL,
     OP_PUSH_TRUE,
     OP_PUSH_FALSE,
-    OP_PUSH,
+    OP_PUSH_VARS,
+    OP_POP_VARS,
     OP_POP,
     OP_SET,
     OP_GET,

+ 11 - 4
Script.c

@@ -67,6 +67,11 @@ static bool sPop(Script* sc, Object* o) {
     return false;
 }
 
+static void sPopEmpty(Script* sc) {
+    Object o;
+    sPop(sc, &o);
+}
+
 static bool sPushInt(Script* sc, int value) {
     Object o = {.type = OT_INT, .data.intValue = value};
     return sPush(sc, &o);
@@ -251,8 +256,9 @@ static void sConsumeInstruction(Script* sc) {
         case OP_PUSH_NULL: sPushNull(sc); break;
         case OP_PUSH_TRUE: sPushBool(sc, true); break;
         case OP_PUSH_FALSE: sPushBool(sc, false); break;
-        case OP_PUSH: sPushVars(sc); break;
-        case OP_POP: sPopVars(sc); break;
+        case OP_PUSH_VARS: sPushVars(sc); break;
+        case OP_POP_VARS: sPopVars(sc); break;
+        case OP_POP: sPopEmpty(sc); break;
         case OP_SET: sSet(sc); break;
         case OP_GET: sGet(sc); break;
         case OP_ADD: sIntBinary(sc, sIntAdd, sFloatAdd); break;
@@ -339,8 +345,9 @@ void sPrintCode(Script* sc) {
             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_PUSH_VARS: sPrint2Int(sc, "Push Vars"); break;
+            case OP_POP_VARS: sPrintInt(sc, "Pop Vars"); break;
+            case OP_POP: puts("Pop"); break;
             case OP_SET: sPrintInt(sc, "Set"); break;
             case OP_GET: sPrintInt(sc, "Get"); break;
             case OP_ADD: puts("Add"); break;

+ 3 - 0
Test.c

@@ -92,6 +92,9 @@ static void tsCheckScript(Script* sc) {
     }
     if(tsCompareResults(file)) {
         sPrintCode(sc);
+    } else if(sc->stackIndex != 0) {
+        printf("%s has non empty stack: %d\n", path, sc->stackIndex);
+        sPrintCode(sc);
     }
     fclose(file);
 }

+ 5 - 0
tests/functions/return_value

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