Ver código fonte

functions can have arguments (no check for number of arguments)

Kajetan Johannes Hammerle 4 anos atrás
pai
commit
eb04b88a27
6 arquivos alterados com 109 adições e 22 exclusões
  1. 49 14
      Compiler.c
  2. 33 8
      Script.c
  3. 2 0
      Tokenizer.c
  4. 1 0
      Tokenizer.h
  5. 16 0
      tests/functions/arguments
  6. 8 0
      tests/functions/arguments.out

+ 49 - 14
Compiler.c

@@ -62,7 +62,7 @@ static void cAddFloat(float f) {
     bcAddBytes(code, &f, sizeof(float));
 }
 
-static Token tReadTokenAndLine() {
+static Token cReadTokenAndLine() {
     Token t = tReadToken();
     if(tReadInt16(&line)) {
         return t;
@@ -71,7 +71,7 @@ static Token tReadTokenAndLine() {
 }
 
 static bool cConsumeToken(Token wanted) {
-    Token t = tReadTokenAndLine();
+    Token t = cReadTokenAndLine();
     if(wanted == t) {
         return true;
     }
@@ -81,7 +81,7 @@ static bool cConsumeToken(Token wanted) {
 
 static bool cConsumeTokenIf(Token t) {
     if(tPeekToken() == t) {
-        tReadTokenAndLine();
+        cReadTokenAndLine();
         return true;
     }
     return false;
@@ -121,7 +121,7 @@ static bool cGetVar() {
 }
 
 static bool cPrimary() {
-    Token t = tReadTokenAndLine();
+    Token t = cReadTokenAndLine();
     switch(t) {
         case T_INT: return cConstantInt();
         case T_FLOAT: return cConstantFloat();
@@ -173,14 +173,24 @@ static bool cSetVar(const char* literal) {
 
 static bool cCallFunction(const char* literal) {
     int index;
-    if(simSearch(&functions, literal, &index)) {
-        cAddOperation(OP_GOSUB);
-        cAddInt(index);
-    } else {
+    if(!simSearch(&functions, literal, &index)) {
         cError("unknown function on line %d", line);
         return false;
     }
-    return cConsumeToken(T_CLOSE_BRACKET) && cConsumeToken(T_SEMICOLON);
+    int arguments = 0;
+    while(!cConsumeTokenIf(T_CLOSE_BRACKET)) {
+        arguments++;
+        if(!cExpression()) {
+            return false;
+        } else if(cConsumeTokenIf(T_COMMA) && tPeekToken() == T_CLOSE_BRACKET) {
+            cUnexpectedToken(tPeekToken());
+            return false;
+        }
+    }
+    cAddOperation(OP_GOSUB);
+    cAddInt(index);
+    cAddInt(arguments);
+    return cConsumeToken(T_SEMICOLON);
 }
 
 static bool cLiteral() {
@@ -189,7 +199,7 @@ static bool cLiteral() {
         cError("literal without string on line %d", line);
         return false;
     }
-    Token t = tReadTokenAndLine();
+    Token t = cReadTokenAndLine();
     if(t == T_SET) {
         return cSetVar(literal);
     } else if(t == T_OPEN_BRACKET) {
@@ -214,7 +224,32 @@ static bool cFunction() {
         cError("function literal without a function name on line %d", line);
         return false;
     }
-    if(!cConsumeToken(T_OPEN_BRACKET) || !cConsumeToken(T_CLOSE_BRACKET) || !cConsumeToken(T_OPEN_CURVED_BRACKET)) {
+    if(!cConsumeToken(T_OPEN_BRACKET)) {
+        return false;
+    }
+
+    varIndex = 1;
+    vars[1].entries = 0;
+
+    int arguments = 0;
+    while(!cConsumeTokenIf(T_CLOSE_BRACKET)) {
+        if(!cConsumeToken(T_LITERAL)) {
+            return false;
+        }
+        arguments++;
+        const char* arg = tReadString();
+        if(arg == NULL) {
+            cError("function argument literal without string on line %d", line);
+            return false;
+        }
+        cAddVar(arg);
+        if(cConsumeTokenIf(T_COMMA) && tPeekToken() != T_LITERAL) {
+            cUnexpectedToken(tPeekToken());
+            return false;
+        }
+    }
+
+    if(!cConsumeToken(T_OPEN_CURVED_BRACKET)) {
         return false;
     }
     cAddOperation(OP_GOTO);
@@ -226,10 +261,9 @@ static bool cFunction() {
         return false;
     }
 
-    varIndex = 1;
-    vars[1].entries = 0;
     cAddOperation(OP_PUSH);
     int pushIndex = cReserveInt();
+    cAddInt(arguments);
 
     int oldLine = line;
     while(!cConsumeTokenIf(T_CLOSE_CURVED_BRACKET)) {
@@ -257,7 +291,7 @@ static bool cPrint() {
 }
 
 static bool cLine() {
-    Token t = tReadTokenAndLine();
+    Token t = cReadTokenAndLine();
     if(t == T_END) {
         return false;
     }
@@ -277,6 +311,7 @@ static bool cLine() {
 static void cForEachLine() {
     cAddOperation(OP_PUSH);
     int globalVars = cReserveInt();
+    cAddInt(0);
     while(cLine()) {
     }
     cAddOperation(OP_POP);

+ 33 - 8
Script.c

@@ -15,9 +15,11 @@ static void sError(Script* sc, const char* format, ...) {
 }
 
 static bool sPrinter(Object* o) {
-    if(o->type == OT_INT) {
-        printf("%d\n", o->data.intValue);
-        return false;
+    switch(o->type) {
+        case OT_INT: printf("%d\n", o->data.intValue); return false;
+        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;
     }
     return true;
 }
@@ -46,6 +48,22 @@ static bool sReadInt(Script* sc, int* i) {
     return !sRead(sc, i, sizeof(int));
 }
 
+static bool sShiftPush(Script* sc, Object* o, int shift) {
+    if(sc->stackIndex >= SCRIPT_STACK_SIZE) {
+        sError(sc, "stack overflow on line %d", sc->line);
+        return false;
+    } else if(sc->stackIndex < shift) {
+        sError(sc, "stack shift underflow overflow on line %d", sc->line);
+        return false;
+    }
+    for(int i = sc->stackIndex; i > sc->stackIndex - shift; i--) {
+        sc->stack[i] = sc->stack[i - 1];
+    }
+    sc->stack[sc->stackIndex - shift] = *o;
+    sc->stackIndex++;
+    return true;
+}
+
 static bool sPush(Script* sc, Object* o) {
     if(sc->stackIndex >= SCRIPT_STACK_SIZE) {
         sError(sc, "stack overflow on line %d", sc->line);
@@ -69,6 +87,11 @@ static bool sPushInt(Script* sc, int value) {
     return sPush(sc, &o);
 }
 
+static bool sShiftPushInt(Script* sc, int value, int shift) {
+    Object o = {.type = OT_INT, .data.intValue = value};
+    return sShiftPush(sc, &o, shift);
+}
+
 static void sPushFloat(Script* sc, float value) {
     Object o = {.type = OT_FLOAT, .data.floatValue = value};
     sPush(sc, &o);
@@ -85,11 +108,12 @@ static void sPushBool(Script* sc, bool value) {
 }
 
 static void sPushVars(Script* sc) {
-    int value = 0;
-    if(sReadInt(sc, &value)) {
+    int vars = 0;
+    int offset = 0;
+    if(sReadInt(sc, &vars) && sReadInt(sc, &offset)) {
         int stackVarIndex = sc->stackVarIndex;
-        sc->stackVarIndex = sc->stackIndex;
-        for(int i = 0; i < value; i++) {
+        sc->stackVarIndex = sc->stackIndex - offset;
+        for(int i = 0; i < vars - offset; i++) {
             sPushNull(sc);
         }
         sPushInt(sc, stackVarIndex);
@@ -208,7 +232,8 @@ static void sGoTo(Script* sc) {
 
 static void sGoSub(Script* sc) {
     int gotoIndex;
-    if(sReadInt(sc, &gotoIndex) && sPushInt(sc, sc->readIndex)) {
+    int arguments;
+    if(sReadInt(sc, &gotoIndex) && sReadInt(sc, &arguments) && sShiftPushInt(sc, sc->readIndex, arguments)) {
         sc->readIndex = gotoIndex;
     }
 }

+ 2 - 0
Tokenizer.c

@@ -137,6 +137,7 @@ static bool tParseToken() {
         case '+': return tAddToken(T_ADD);
         case '*': return tAddToken(T_MUL);
         case '=': return tAddToken(T_SET);
+        case ',': return tAddToken(T_COMMA);
         case ';': return tAddToken(T_SEMICOLON);
         case '(': return tAddToken(T_OPEN_BRACKET);
         case ')': return tAddToken(T_CLOSE_BRACKET);
@@ -235,6 +236,7 @@ const char* tGetTokenName(Token token) {
         case T_LITERAL: return "literal";
         case T_PRINT: return "print";
         case T_FUNCTION: return "function";
+        case T_COMMA: return ",";
         case T_SEMICOLON: return ";";
         case T_OPEN_BRACKET: return "(";
         case T_CLOSE_BRACKET: return ")";

+ 1 - 0
Tokenizer.h

@@ -16,6 +16,7 @@ typedef enum Token {
     T_LITERAL,
     T_PRINT,
     T_FUNCTION,
+    T_COMMA,
     T_SEMICOLON,
     T_OPEN_BRACKET,
     T_CLOSE_BRACKET,

+ 16 - 0
tests/functions/arguments

@@ -0,0 +1,16 @@
+a = 2;
+b = 3;
+
+function test(c, d) {
+    print a;
+    print b;
+    print c;
+    print d;
+}
+
+test(a, b);
+
+print a;
+print b;
+print c;
+print d;

+ 8 - 0
tests/functions/arguments.out

@@ -0,0 +1,8 @@
+null
+null
+2
+3
+2
+3
+null
+null