瀏覽代碼

float type

Kajetan Johannes Hammerle 3 年之前
父節點
當前提交
b289719095
共有 11 個文件被更改,包括 113 次插入14 次删除
  1. 9 1
      Compiler.c
  2. 2 1
      Object.h
  3. 1 0
      Operation.h
  4. 44 8
      Script.c
  5. 1 0
      Test.c
  6. 44 4
      Tokenizer.c
  7. 2 0
      Tokenizer.h
  8. 3 0
      tests/calc/adding
  9. 3 0
      tests/calc/adding.out
  10. 2 0
      tests/calc/multiply
  11. 2 0
      tests/calc/multiply.out

+ 9 - 1
Compiler.c

@@ -23,6 +23,10 @@ static void cError(const char* format, ...) {
     va_end(args);
 }
 
+static void cUnexpectedToken(Token t) {
+    cError("unexpected token on line %d: %s", line, tGetTokenName(t));
+}
+
 static bool cAddBytes(const void* data, int length) {
     if(writeIndex + length > MAX_BYTES) {
         cError("the compiler buffer is too small");
@@ -69,6 +73,9 @@ static bool cPrimary() {
     if(cConsumeTokenIf(T_INT)) {
         int value;
         return tReadInt(&value) && cAddOperation(OP_PUSH_INT) && cAddBytes(&value, sizeof(int));
+    } else if(cConsumeTokenIf(T_FLOAT)) {
+        float value;
+        return tReadFloat(&value) && cAddOperation(OP_PUSH_FLOAT) && cAddBytes(&value, sizeof(float));
     } else if(cConsumeTokenIf(T_NULL)) {
         return cAddOperation(OP_PUSH_NULL);
     } else if(cConsumeTokenIf(T_TRUE)) {
@@ -78,6 +85,7 @@ static bool cPrimary() {
     } else if(cConsumeTokenIf(T_OPEN_BRACKET)) {
         return cExpression() && cConsumeToken(T_CLOSE_BRACKET);
     }
+    cUnexpectedToken(tPeekToken());
     return false;
 }
 
@@ -120,7 +128,7 @@ static bool cLine() {
     } else if(t == T_PRINT) {
         return cPrint();
     }
-    cError("unexpected token on line %d: %s", line, tGetTokenName(t));
+    cUnexpectedToken(t);
     return false;
 }
 

+ 2 - 1
Object.h

@@ -1,12 +1,13 @@
 #ifndef OBJECT_H
 #define OBJECT_H
 
-typedef enum ObjectType { OT_INT, OT_NULL, OT_BOOL } ObjectType;
+typedef enum ObjectType { OT_INT, OT_FLOAT, OT_NULL, OT_BOOL } ObjectType;
 
 typedef struct Object {
     ObjectType type;
     union Data {
         int intValue;
+        float floatValue;
     } data;
 } Object;
 

+ 1 - 0
Operation.h

@@ -4,6 +4,7 @@
 typedef enum Operation {
     OP_NOTHING,
     OP_PUSH_INT,
+    OP_PUSH_FLOAT,
     OP_PUSH_NULL,
     OP_PUSH_TRUE,
     OP_PUSH_FALSE,

+ 44 - 8
Script.c

@@ -71,6 +71,16 @@ static void sPushInt(Script* sc) {
     sPush(sc, &o);
 }
 
+static void sPushFloat(Script* sc) {
+    float value = 0;
+    if(sRead(sc, &value, sizeof(float))) {
+        sError(sc, "cannot read a float from the bytecode on line %d", sc->line);
+        return;
+    }
+    Object o = {.type = OT_FLOAT, .data.floatValue = value};
+    sPush(sc, &o);
+}
+
 static void sPushNull(Script* sc) {
     Object o = {.type = OT_NULL};
     sPush(sc, &o);
@@ -81,7 +91,7 @@ static void sPushBool(Script* sc, bool b) {
     sPush(sc, &o);
 }
 
-static void sIntBinary(Script* sc, int (*f)(int, int)) {
+static void sIntBinary(Script* sc, int (*fInt)(int, int), float (*fFloat)(float, float)) {
     Object a;
     if(sPop(sc, &a)) {
         return;
@@ -90,12 +100,29 @@ static void sIntBinary(Script* sc, int (*f)(int, int)) {
     if(sPop(sc, &b)) {
         return;
     }
-    if(a.type != OT_INT || b.type != OT_INT) {
-        sError(sc, "object is not an int on line %d", sc->line);
-        return;
+    if(a.type == OT_INT) {
+        if(b.type == OT_INT) {
+            Object o = {.type = OT_INT, .data.intValue = fInt(a.data.intValue, b.data.intValue)};
+            sPush(sc, &o);
+        } else if(b.type == OT_FLOAT) {
+            Object o = {.type = OT_FLOAT, .data.floatValue = fFloat(a.data.intValue, b.data.floatValue)};
+            sPush(sc, &o);
+        } else {
+            sError(sc, "first object is not a number on line %d", sc->line);
+        }
+    } else if(a.type == OT_FLOAT) {
+        if(b.type == OT_INT) {
+            Object o = {.type = OT_FLOAT, .data.floatValue = fFloat(a.data.floatValue, b.data.intValue)};
+            sPush(sc, &o);
+        } else if(b.type == OT_FLOAT) {
+            Object o = {.type = OT_FLOAT, .data.floatValue = fFloat(a.data.floatValue, b.data.floatValue)};
+            sPush(sc, &o);
+        } else {
+            sError(sc, "first object is not a number on line %d", sc->line);
+        }
+    } else {
+        sError(sc, "second object is not a number on line %d", sc->line);
     }
-    Object o = {.type = OT_INT, .data.intValue = f(a.data.intValue, b.data.intValue)};
-    sPush(sc, &o);
 }
 
 static int sIntAdd(int a, int b) {
@@ -106,6 +133,14 @@ static int sIntMul(int a, int b) {
     return a * b;
 }
 
+static float sFloatAdd(float a, float b) {
+    return a + b;
+}
+
+static float sFloatMul(float a, float b) {
+    return a * b;
+}
+
 static void sPrint(Script* sc) {
     Object o;
     if(sPop(sc, &o)) {
@@ -120,11 +155,12 @@ static void sConsumeInstruction(Script* sc) {
     switch(sReadOperation(sc)) {
         case OP_NOTHING: break;
         case OP_PUSH_INT: sPushInt(sc); break;
+        case OP_PUSH_FLOAT: sPushFloat(sc); break;
         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_ADD: sIntBinary(sc, sIntAdd); break;
-        case OP_MUL: sIntBinary(sc, sIntMul); break;
+        case OP_ADD: sIntBinary(sc, sIntAdd, sFloatAdd); break;
+        case OP_MUL: sIntBinary(sc, sIntMul, sFloatMul); break;
         case OP_PRINT: sPrint(sc); break;
     }
 }

+ 1 - 0
Test.c

@@ -36,6 +36,7 @@ static bool tsPrinter(Object* o) {
     }
     switch(o->type) {
         case OT_INT: tsPrintToBuffer("%d\n", o->data.intValue); return false;
+        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;
     }

+ 44 - 4
Tokenizer.c

@@ -1,5 +1,7 @@
+#include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "Tokenizer.h"
@@ -80,11 +82,41 @@ static bool tParseLiteral(int c) {
 }
 
 static bool tParseNumber(int c) {
-    int sum = c - '0';
-    while(isNumber(tPeek())) {
-        sum = sum * 10 + (tRead() - '0');
+    int index = 1;
+    char buffer[64];
+    buffer[0] = c;
+    bool point = false;
+    while(true) {
+        int c = tPeek();
+        if(c == '.') {
+            point = true;
+        } else if(!isNumber(c)) {
+            break;
+        } else if(index >= 63) {
+            tError("number is too long");
+            return false;
+        }
+        buffer[index++] = tRead();
+    }
+    buffer[index] = '\0';
+    if(point) {
+        char* end = NULL;
+        float f = strtof(buffer, &end);
+        if(end[0] != '\0') {
+            tError("invalid float on line %d", line);
+            return false;
+        }
+        return tAddToken(T_FLOAT) && tAdd(&f, sizeof(float));
+    } else {
+        char* end = NULL;
+        long l = strtol(buffer, &end, 10);
+        if(end[0] != '\0' || l > INT_MAX) {
+            tError("invalid int on line %d", line);
+            return false;
+        }
+        int i = l;
+        return tAddToken(T_INT) && tAdd(&i, sizeof(int));
     }
-    return tAddToken(T_INT) && tAdd(&sum, sizeof(int));
 }
 
 static bool tParseToken() {
@@ -158,9 +190,17 @@ bool tReadInt(int* i) {
     return false;
 }
 
+bool tReadFloat(float* f) {
+    if(tReadTokens(f, sizeof(float))) {
+        return true;
+    }
+    return false;
+}
+
 const char* tGetTokenName(Token token) {
     switch(token) {
         case T_INT: return "int";
+        case T_FLOAT: return "float";
         case T_NULL: return "null";
         case T_TRUE: return "true";
         case T_FALSE: return "false";

+ 2 - 0
Tokenizer.h

@@ -5,6 +5,7 @@
 
 typedef enum Token {
     T_INT,
+    T_FLOAT,
     T_NULL,
     T_TRUE,
     T_FALSE,
@@ -24,6 +25,7 @@ void tResetReader();
 Token tPeekToken();
 Token tReadToken();
 bool tReadInt(int* i);
+bool tReadFloat(float* i);
 
 const char* tGetTokenName(Token token);
 

+ 3 - 0
tests/calc/adding

@@ -2,3 +2,6 @@ print 1;
 print 2 + 3;
 print 3 + 4 + 5;
 print 6 + 7 + 8 + 9;
+print 3.5 + 5.5;
+print 4.0 + 1;
+print 1 + 2.0;

+ 3 - 0
tests/calc/adding.out

@@ -2,3 +2,6 @@
 5
 12
 30
+9.00
+5.00
+3.00

+ 2 - 0
tests/calc/multiply

@@ -3,3 +3,5 @@ print 3 + 4 * 5;
 print 6 + 7 * 8 + 9;
 print (3 + 4) * 5;
 print ((3 + 2) * (5 + 1));
+print ((3 + 2.0) * (5 + 1));
+print ((3 + 2) * (5 + 1.0));

+ 2 - 0
tests/calc/multiply.out

@@ -3,3 +3,5 @@
 71
 35
 30
+30.00
+30.00