Browse Source

Implement some bonus marks

T. Meissner 7 months ago
parent
commit
64721ec25b
1 changed files with 59 additions and 18 deletions
  1. 59
    18
      chapter_08/lispy.c

+ 59
- 18
chapter_08/lispy.c View File

@@ -34,17 +34,20 @@ void add_history(char* unused) {}
34 34
 /* Declare new lval struct */
35 35
 typedef struct {
36 36
     int type;
37
-    long num;
37
+    union {
38
+        long num;
39
+        double dec;
40
+    };
38 41
     int err;
39 42
 } lval;
40 43
 
41 44
 
42 45
 /* Create enumeration of possible lval types */
43
-enum {LVAL_NUM, LVAL_ERR};
46
+enum lval_types {LVAL_NUM, LVAL_DEC, LVAL_ERR};
44 47
 
45 48
 
46 49
 /* Create enumeration of possible error types */
47
-enum {LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM};
50
+enum lval_errors {LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM};
48 51
 
49 52
 
50 53
 /* Create a new number of type lval */
@@ -56,6 +59,15 @@ lval lval_num(long x) {
56 59
 }
57 60
 
58 61
 
62
+/* Create a new decimal of type lval */
63
+lval lval_dec(double x) {
64
+    lval v;
65
+    v.type = LVAL_DEC;
66
+    v.dec = x;
67
+    return v;
68
+}
69
+
70
+
59 71
 /* Create a new error type lval */
60 72
 lval lval_err(int x) {
61 73
     lval v;
@@ -73,6 +85,11 @@ void lval_print(lval v) {
73 85
         case LVAL_NUM:
74 86
             printf("%li", v.num);
75 87
             break;
88
+        /* In the case the type is a decimal print it
89
+           Then break out of the switch */
90
+        case LVAL_DEC:
91
+            printf("%.2f", v.dec);
92
+            break;
76 93
         /* In the case the type is an error */
77 94
         case LVAL_ERR:
78 95
             /* Check what type of error it is & print it */
@@ -127,19 +144,37 @@ lval eval_op(lval x, char* op, lval y) {
127 144
     }
128 145
 
129 146
     /* Otherwise do maths on the number values */
130
-
131
-    if (strcmp(op, "+") == 0) {return lval_num(x.num + y.num);}
132
-    if (strcmp(op, "-") == 0) {return lval_num(x.num - y.num);}
133
-    if (strcmp(op, "*") == 0) {return lval_num(x.num * y.num);}
134
-    if (strcmp(op, "/") == 0) {
135
-        /* If second operand is zero return error */
136
-        return y.num == 0 ? lval_err(LERR_DIV_ZERO)
137
-                          : lval_num(x.num / y.num);
147
+    if (x.type == LVAL_NUM && y.type == LVAL_NUM) {
148
+        if (strcmp(op, "+") == 0) {return lval_num(x.num + y.num);}
149
+        if (strcmp(op, "-") == 0) {return lval_num(x.num - y.num);}
150
+        if (strcmp(op, "*") == 0) {return lval_num(x.num * y.num);}
151
+        if (strcmp(op, "/") == 0) {
152
+            /* If second operand is zero return error */
153
+            return y.num == 0 ? lval_err(LERR_DIV_ZERO)
154
+                              : lval_num(x.num / y.num);
155
+        }
156
+        if (strcmp(op, "%") == 0) {return lval_num(x.num % y.num);}
157
+        if (strcmp(op, "^") == 0) {return lval_num(pow(x.num, y.num));}
158
+        if (strcmp(op, "min") == 0) {return lval_num(min(x.num, y.num));}
159
+        if (strcmp(op, "max") == 0) {return lval_num(max(x.num, y.num));}
160
+    } else {
161
+        /* Cast integer number into double if necessary */
162
+        double a = x.type == LVAL_NUM ? (double) x.num : x.dec;
163
+        double b = y.type == LVAL_NUM ? (double) y.num : y.dec;
164
+        /* Perform all operations on double */
165
+        if (strcmp(op, "+") == 0) {return lval_dec(a + b);}
166
+        if (strcmp(op, "-") == 0) {return lval_dec(a - b);}
167
+        if (strcmp(op, "*") == 0) {return lval_dec(a * b);}
168
+        if (strcmp(op, "/") == 0) {
169
+            /* If second operand is zero return error */
170
+            return b == 0 ? lval_err(LERR_DIV_ZERO)
171
+                          : lval_dec(a / b);
172
+        }
173
+        if (strcmp(op, "%") == 0) {return lval_dec(fmod(a, b));}
174
+        if (strcmp(op, "^") == 0) {return lval_dec(pow(a, b));}
175
+        if (strcmp(op, "min") == 0) {return lval_dec(fmin(a, b));}
176
+        if (strcmp(op, "max") == 0) {return lval_dec(fmax(a, b));}
138 177
     }
139
-    if (strcmp(op, "%") == 0) {return lval_num(x.num % y.num);}
140
-    if (strcmp(op, "^") == 0) {return lval_num(pow(x.num, y.num));}
141
-    if (strcmp(op, "min") == 0) {return lval_num(min(x.num, y.num));}
142
-    if (strcmp(op, "max") == 0) {return lval_num(max(x.num, y.num));}
143 178
 
144 179
     return lval_err(LERR_BAD_OP);
145 180
 }
@@ -150,8 +185,14 @@ lval eval(mpc_ast_t* t) {
150 185
     if (strstr(t->tag, "number")) {
151 186
         /* Check if there is some error in conversion */
152 187
         errno = 0;
153
-        long x = strtol(t->contents, NULL, 10);
154
-        return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM);
188
+        /* Check for decimal or integer number */
189
+        if (strstr(t->contents, ".")) {
190
+            double x = strtof(t->contents, NULL);
191
+            return errno != ERANGE ? lval_dec(x) : lval_err(LERR_BAD_NUM);
192
+        } else {
193
+            long x = strtol(t->contents, NULL, 10);
194
+            return errno != ERANGE ? lval_num(x) : lval_err(LERR_BAD_NUM);
195
+        }
155 196
     }
156 197
 
157 198
     /* The operator is always second child */
@@ -182,7 +223,7 @@ int main(int argc, char const *argv[]) {
182 223
     /* Define them with the following language */
183 224
     mpca_lang(MPCA_LANG_DEFAULT,
184 225
         "                                                       \
185
-            number   : /-?[0-9]+/ ;                             \
226
+            number   : /-?[0-9]+([.][0-9]*|[0-9]*)/ ;           \
186 227
             operator : '+' | '-' | '*' | '/' | '%' | '^' |      \
187 228
             \"min\" | \"max\" ;                                 \
188 229
             expr     : <number> | '(' <operator> <expr>+ ')' ;  \