Browse Source

function calls can be used before the function is declared

Kajetan Johannes Hammerle 4 years ago
parent
commit
b998245f8d
5 changed files with 62 additions and 3 deletions
  1. 15 3
      Compiler.c
  2. 16 0
      FunctionMap.c
  3. 11 0
      FunctionMap.h
  4. 14 0
      tests/functions/forward
  5. 6 0
      tests/functions/forward.out

+ 15 - 3
Compiler.c

@@ -198,11 +198,12 @@ static void cCallFunction(const char* literal) {
     cAddInt(0);
     int arguments = cCallFunctionArguments();
     int address = fmSearchAddress(&functions, literal, arguments);
+    cAddOperation(OP_GOSUB);
     if(address == -1) {
-        cError("unknown function on line %d", line);
+        fmEnqueue(&functions, literal, arguments, line, cReserveInt());
+    } else {
+        cAddInt(address);
     }
-    cAddOperation(OP_GOSUB);
-    cAddInt(address);
     cAddInt(arguments);
     cConsumeToken(T_SEMICOLON);
 }
@@ -314,6 +315,16 @@ 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) {
+            cError("unknown function on line %d", functions.queue[i].line);
+        }
+        cSetInt(functions.queue[i].reserved, address);
+    }
+}
+
 static void cAllocAndCompile() {
     varIndex = 0;
     returnIndex = 0;
@@ -324,6 +335,7 @@ static void cAllocAndCompile() {
         int p = cAddPush(0);
         cForEachLine();
         cAddPop(p, vars[varIndex].entries);
+        cLinkQueuedFunctions();
     }
     fmDelete(&functions);
     simDelete(vars + 1);

+ 16 - 0
FunctionMap.c

@@ -7,10 +7,14 @@ void fmInit(FunctionMap* fm) {
     fm->capacity = 16;
     fm->entries = 0;
     fm->data = malloc(sizeof(Function) * fm->capacity);
+    fm->queueCapacity = 16;
+    fm->queueEntries = 0;
+    fm->queue = malloc(sizeof(LingeringFunction) * fm->queueCapacity);
 }
 
 void fmDelete(FunctionMap* fm) {
     free(fm->data);
+    free(fm->queue);
 }
 
 int fmSearchAddress(FunctionMap* fm, const char* name, int arguments) {
@@ -35,4 +39,16 @@ bool fmAdd(FunctionMap* fm, const char* name, int arguments, int address) {
     fm->data[index].arguments = arguments;
     fm->data[index].address = address;
     return true;
+}
+
+void fmEnqueue(FunctionMap* fm, const char* name, int arguments, int line, int reserved) {
+    if(fm->queueEntries >= fm->queueCapacity) {
+        fm->queueCapacity *= 2;
+        fm->queue = realloc(fm->queue, sizeof(LingeringFunction) * fm->queueCapacity);
+    }
+    int index = fm->queueEntries++;
+    fm->queue[index].name = name;
+    fm->queue[index].arguments = arguments;
+    fm->queue[index].line = line;
+    fm->queue[index].reserved = reserved;
 }

+ 11 - 0
FunctionMap.h

@@ -9,15 +9,26 @@ typedef struct Function {
     int address;
 } Function;
 
+typedef struct LingeringFunction {
+    const char* name;
+    int arguments;
+    int line;
+    int reserved;
+} LingeringFunction;
+
 typedef struct FunctionMap {
     int capacity;
     int entries;
     Function* data;
+    int queueCapacity;
+    int queueEntries;
+    LingeringFunction* queue;
 } 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);
 
 #endif

+ 14 - 0
tests/functions/forward

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

+ 6 - 0
tests/functions/forward.out

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