summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2017-11-19 21:07:00 -0800
committerKeith Packard <keithp@keithp.com>2017-11-19 21:07:00 -0800
commit6d2f271a45759bd792d299f04a424d3382ef4798 (patch)
treea8a3e2f8538ab70a828f47f3ed87e62e2a0c5adc /src
parent12a1f6ad48f2b924f71239effeb90afca75a090f (diff)
altos/lisp: Add floats
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src')
-rw-r--r--src/lisp/Makefile2
-rw-r--r--src/lisp/Makefile-inc1
-rw-r--r--src/lisp/ao_lisp.h48
-rw-r--r--src/lisp/ao_lisp_builtin.c119
-rw-r--r--src/lisp/ao_lisp_builtin.txt7
-rw-r--r--src/lisp/ao_lisp_cons.c13
-rw-r--r--src/lisp/ao_lisp_const.lisp3
-rw-r--r--src/lisp/ao_lisp_eval.c1
-rw-r--r--src/lisp/ao_lisp_float.c148
-rw-r--r--src/lisp/ao_lisp_mem.c1
-rw-r--r--src/lisp/ao_lisp_poly.c4
-rw-r--r--src/lisp/ao_lisp_read.c77
-rw-r--r--src/lisp/ao_lisp_read.h24
13 files changed, 384 insertions, 64 deletions
diff --git a/src/lisp/Makefile b/src/lisp/Makefile
index 4563dad3..05f54550 100644
--- a/src/lisp/Makefile
+++ b/src/lisp/Makefile
@@ -19,6 +19,6 @@ OBJS=$(SRCS:.c=.o)
CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra -no-pie
ao_lisp_make_const: $(OBJS)
- $(CC) $(CFLAGS) -o $@ $(OBJS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) -lm
$(OBJS): $(HDRS)
diff --git a/src/lisp/Makefile-inc b/src/lisp/Makefile-inc
index 6c8702fb..a097f1be 100644
--- a/src/lisp/Makefile-inc
+++ b/src/lisp/Makefile-inc
@@ -6,6 +6,7 @@ LISP_SRCS=\
ao_lisp_int.c \
ao_lisp_poly.c \
ao_lisp_bool.c \
+ ao_lisp_float.c \
ao_lisp_builtin.c \
ao_lisp_read.c \
ao_lisp_frame.c \
diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h
index 08278fe7..cbbbe9a4 100644
--- a/src/lisp/ao_lisp.h
+++ b/src/lisp/ao_lisp.h
@@ -96,7 +96,8 @@ extern uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((a
#define AO_LISP_STACK 8
#define AO_LISP_BOOL 9
#define AO_LISP_BIGINT 10
-#define AO_LISP_NUM_TYPE 11
+#define AO_LISP_FLOAT 11
+#define AO_LISP_NUM_TYPE 12
/* Leave two bits for types to use as they please */
#define AO_LISP_OTHER_TYPE_MASK 0x3f
@@ -170,6 +171,13 @@ struct ao_lisp_bigint {
uint32_t value;
};
+struct ao_lisp_float {
+ uint8_t type;
+ uint8_t pad1;
+ uint16_t pad2;
+ float value;
+};
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
static inline uint32_t
ao_lisp_int_bigint(int32_t i) {
@@ -442,6 +450,22 @@ ao_lisp_poly_bool(ao_poly poly)
{
return ao_lisp_ref(poly);
}
+
+static inline ao_poly
+ao_lisp_float_poly(struct ao_lisp_float *f)
+{
+ return ao_lisp_poly(f, AO_LISP_OTHER);
+}
+
+static inline struct ao_lisp_float *
+ao_lisp_poly_float(ao_poly poly)
+{
+ return ao_lisp_ref(poly);
+}
+
+float
+ao_lisp_poly_number(ao_poly p);
+
/* memory functions */
extern int ao_lisp_collects[2];
@@ -524,6 +548,10 @@ extern const struct ao_lisp_type ao_lisp_cons_type;
struct ao_lisp_cons *
ao_lisp_cons_cons(ao_poly car, ao_poly cdr);
+/* Return a cons or NULL for a proper list, else error */
+struct ao_lisp_cons *
+ao_lisp_cons_cdr(struct ao_lisp_cons *cons);
+
ao_poly
ao_lisp__cons(ao_poly car, ao_poly cdr);
@@ -632,6 +660,24 @@ ao_lisp_eval(ao_poly p);
ao_poly
ao_lisp_set_cond(struct ao_lisp_cons *cons);
+/* float */
+extern const struct ao_lisp_type ao_lisp_float_type;
+
+void
+ao_lisp_float_write(ao_poly p);
+
+ao_poly
+ao_lisp_float_get(float value);
+
+static inline uint8_t
+ao_lisp_number_typep(uint8_t t)
+{
+ return ao_lisp_integer_typep(t) || (t == AO_LISP_FLOAT);
+}
+
+float
+ao_lisp_poly_number(ao_poly p);
+
/* builtin */
void
ao_lisp_builtin_write(ao_poly b);
diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c
index e5370f90..d4dc8a86 100644
--- a/src/lisp/ao_lisp_builtin.c
+++ b/src/lisp/ao_lisp_builtin.c
@@ -14,6 +14,7 @@
#include "ao_lisp.h"
#include <limits.h>
+#include <math.h>
static int
builtin_size(void *addr)
@@ -98,7 +99,7 @@ ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max)
while (cons && argc <= max) {
argc++;
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
}
if (argc < min || argc > max)
return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name);
@@ -113,7 +114,7 @@ ao_lisp_arg(struct ao_lisp_cons *cons, int argc)
while (argc--) {
if (!cons)
return AO_LISP_NIL;
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
}
return cons->car;
}
@@ -162,17 +163,17 @@ ao_lisp_do_cons(struct ao_lisp_cons *cons)
ao_poly
ao_lisp_do_last(struct ao_lisp_cons *cons)
{
- ao_poly l;
+ struct ao_lisp_cons *list;
if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1))
return AO_LISP_NIL;
if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1))
return AO_LISP_NIL;
- l = ao_lisp_arg(cons, 0);
- while (l) {
- struct ao_lisp_cons *list = ao_lisp_poly_cons(l);
+ for (list = ao_lisp_poly_cons(ao_lisp_arg(cons, 0));
+ list;
+ list = ao_lisp_cons_cdr(list))
+ {
if (!list->cdr)
return list->car;
- l = list->cdr;
}
return AO_LISP_NIL;
}
@@ -253,7 +254,7 @@ ao_lisp_do_write(struct ao_lisp_cons *cons)
while (cons) {
val = cons->car;
ao_lisp_poly_write(val);
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
if (cons)
printf(" ");
}
@@ -268,39 +269,38 @@ ao_lisp_do_display(struct ao_lisp_cons *cons)
while (cons) {
val = cons->car;
ao_lisp_poly_display(val);
- cons = ao_lisp_poly_cons(cons->cdr);
+ cons = ao_lisp_cons_cdr(cons);
}
return _ao_lisp_bool_true;
}
ao_poly
-ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
+ao_lisp_math(struct ao_lisp_cons *orig_cons, enum ao_lisp_builtin_id op)
{
- struct ao_lisp_cons *orig_cons = cons;
+ struct ao_lisp_cons *cons = cons;
ao_poly ret = AO_LISP_NIL;
- while (cons) {
+ for (cons = orig_cons; cons; cons = ao_lisp_cons_cdr(cons)) {
ao_poly car = cons->car;
- ao_poly cdr;
uint8_t rt = ao_lisp_poly_type(ret);
uint8_t ct = ao_lisp_poly_type(car);
if (cons == orig_cons) {
ret = car;
- if (cons->cdr == AO_LISP_NIL && ct == AO_LISP_INT) {
+ if (cons->cdr == AO_LISP_NIL) {
switch (op) {
case builtin_minus:
- ret = ao_lisp_integer_poly(-ao_lisp_poly_integer(ret));
+ if (ao_lisp_integer_typep(ct))
+ ret = ao_lisp_integer_poly(-ao_lisp_poly_integer(ret));
+ else if (ct == AO_LISP_FLOAT)
+ ret = ao_lisp_float_get(-ao_lisp_poly_number(ret));
break;
case builtin_divide:
- switch (ao_lisp_poly_integer(ret)) {
- case 0:
- return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
- case 1:
- break;
- default:
- ret = ao_lisp_int_poly(0);
- break;
+ if (ao_lisp_integer_typep(ct) && ao_lisp_poly_integer(ret) == 1)
+ ;
+ else if (ao_lisp_number_typep(ct)) {
+ float v = ao_lisp_poly_number(ret);
+ ret = ao_lisp_float_get(1/v);
}
break;
default:
@@ -322,10 +322,54 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
r *= c;
break;
case builtin_divide:
+ if (c != 0 && (r % c) == 0)
+ r /= c;
+ else {
+ ret = ao_lisp_float_get((float) r / (float) c);
+ continue;
+ }
+ break;
+ case builtin_quotient:
+ if (c == 0)
+ return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
+ if (r % c != 0 && (c < 0) != (r < 0))
+ r = r / c - 1;
+ else
+ r = r / c;
+ break;
+ case builtin_remainder:
if (c == 0)
- return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero");
+ return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "remainder by zero");
+ r %= c;
+ break;
+ case builtin_modulo:
+ if (c == 0)
+ return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "modulo by zero");
+ r %= c;
+ if ((r < 0) != (c < 0))
+ r += c;
+ break;
+ default:
+ break;
+ }
+ ret = ao_lisp_integer_poly(r);
+ } else if (ao_lisp_number_typep(rt) && ao_lisp_number_typep(ct)) {
+ float r = ao_lisp_poly_number(ret);
+ float c = ao_lisp_poly_number(car);
+ switch(op) {
+ case builtin_plus:
+ r += c;
+ break;
+ case builtin_minus:
+ r -= c;
+ break;
+ case builtin_times:
+ r *= c;
+ break;
+ case builtin_divide:
r /= c;
break;
+#if 0
case builtin_quotient:
if (c == 0)
return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "quotient by zero");
@@ -346,10 +390,11 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
if ((r < 0) != (c < 0))
r += c;
break;
+#endif
default:
break;
}
- ret = ao_lisp_integer_poly(r);
+ ret = ao_lisp_float_get(r);
}
else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus)
@@ -357,11 +402,6 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
ao_lisp_poly_string(car)));
else
return ao_lisp_error(AO_LISP_INVALID, "invalid args");
-
- cdr = cons->cdr;
- if (cdr != AO_LISP_NIL && ao_lisp_poly_type(cdr) != AO_LISP_CONS)
- return ao_lisp_error(AO_LISP_INVALID, "improper list");
- cons = ao_lisp_poly_cons(cdr);
}
return ret;
}
@@ -417,8 +457,7 @@ ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
return _ao_lisp_bool_true;
left = cons->car;
- cons = ao_lisp_poly_cons(cons->cdr);
- while (cons) {
+ for (cons = ao_lisp_cons_cdr(cons); cons; cons = ao_lisp_cons_cdr(cons)) {
ao_poly right = cons->car;
if (op == builtin_equal) {
@@ -477,7 +516,6 @@ ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op)
}
}
left = right;
- cons = ao_lisp_poly_cons(cons->cdr);
}
return _ao_lisp_bool_true;
}
@@ -641,6 +679,20 @@ ao_lisp_do_pairp(struct ao_lisp_cons *cons)
}
ao_poly
+ao_lisp_do_integerp(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
+ case AO_LISP_INT:
+ case AO_LISP_BIGINT:
+ return _ao_lisp_bool_true;
+ default:
+ return _ao_lisp_bool_false;
+ }
+}
+
+ao_poly
ao_lisp_do_numberp(struct ao_lisp_cons *cons)
{
if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
@@ -648,6 +700,7 @@ ao_lisp_do_numberp(struct ao_lisp_cons *cons)
switch (ao_lisp_poly_type(ao_lisp_arg(cons, 0))) {
case AO_LISP_INT:
case AO_LISP_BIGINT:
+ case AO_LISP_FLOAT:
return _ao_lisp_bool_true;
default:
return _ao_lisp_bool_false;
diff --git a/src/lisp/ao_lisp_builtin.txt b/src/lisp/ao_lisp_builtin.txt
index c324ca67..2e11bdad 100644
--- a/src/lisp/ao_lisp_builtin.txt
+++ b/src/lisp/ao_lisp_builtin.txt
@@ -42,7 +42,8 @@ f_lambda nullp null?
f_lambda not
f_lambda listp list?
f_lambda pairp pair?
-f_lambda numberp number? integer?
+f_lambda integerp integer? exact? exact-integer?
+f_lambda numberp number? real?
f_lambda booleanp boolean?
f_lambda set_car set-car!
f_lambda set_cdr set-cdr!
@@ -58,3 +59,7 @@ f_lambda exit
f_lambda current_jiffy current-jiffy
f_lambda current_second current-second
f_lambda jiffies_per_second jiffies-per-second
+f_lambda finitep finite?
+f_lambda infinitep infinite?
+f_lambda inexactp inexact?
+f_lambda sqrt
diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c
index 9379597c..c70aa1ca 100644
--- a/src/lisp/ao_lisp_cons.c
+++ b/src/lisp/ao_lisp_cons.c
@@ -105,6 +105,19 @@ ao_lisp_cons_cons(ao_poly car, ao_poly cdr)
return cons;
}
+struct ao_lisp_cons *
+ao_lisp_cons_cdr(struct ao_lisp_cons *cons)
+{
+ ao_poly cdr = cons->cdr;
+ if (cdr == AO_LISP_NIL)
+ return NULL;
+ if (ao_lisp_poly_type(cdr) != AO_LISP_CONS) {
+ (void) ao_lisp_error(AO_LISP_INVALID, "improper list");
+ return NULL;
+ }
+ return ao_lisp_poly_cons(cdr);
+}
+
ao_poly
ao_lisp__cons(ao_poly car, ao_poly cdr)
{
diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp
index 861a4fc8..9fb7634c 100644
--- a/src/lisp/ao_lisp_const.lisp
+++ b/src/lisp/ao_lisp_const.lisp
@@ -159,9 +159,6 @@
(odd? 3)
(odd? -1)
-(define exact? number?)
-(defun inexact? (x) #f)
-
; (if <condition> <if-true>)
; (if <condition> <if-true> <if-false)
diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c
index 8fa488e2..cfa71fa7 100644
--- a/src/lisp/ao_lisp_eval.c
+++ b/src/lisp/ao_lisp_eval.c
@@ -111,6 +111,7 @@ ao_lisp_eval_sexpr(void)
case AO_LISP_BOOL:
case AO_LISP_INT:
case AO_LISP_BIGINT:
+ case AO_LISP_FLOAT:
case AO_LISP_STRING:
case AO_LISP_BUILTIN:
case AO_LISP_LAMBDA:
diff --git a/src/lisp/ao_lisp_float.c b/src/lisp/ao_lisp_float.c
new file mode 100644
index 00000000..0aa6f2ea
--- /dev/null
+++ b/src/lisp/ao_lisp_float.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2017 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include "ao_lisp.h"
+#include <math.h>
+
+static void float_mark(void *addr)
+{
+ (void) addr;
+}
+
+static int float_size(void *addr)
+{
+ if (!addr)
+ return 0;
+ return sizeof (struct ao_lisp_float);
+}
+
+static void float_move(void *addr)
+{
+ (void) addr;
+}
+
+const struct ao_lisp_type ao_lisp_float_type = {
+ .mark = float_mark,
+ .size = float_size,
+ .move = float_move,
+ .name = "float",
+};
+
+void
+ao_lisp_float_write(ao_poly p)
+{
+ struct ao_lisp_float *f = ao_lisp_poly_float(p);
+ float v = f->value;
+
+ if (isnanf(v))
+ printf("+nan.0");
+ else if (isinff(v)) {
+ if (v < 0)
+ printf("-");
+ else
+ printf("+");
+ printf("inf.0");
+ } else
+ printf ("%g", f->value);
+}
+
+float
+ao_lisp_poly_number(ao_poly p)
+{
+ switch (ao_lisp_poly_base_type(p)) {
+ case AO_LISP_INT:
+ return ao_lisp_poly_int(p);
+ case AO_LISP_OTHER:
+ switch (ao_lisp_other_type(ao_lisp_poly_other(p))) {
+ case AO_LISP_BIGINT:
+ return ao_lisp_bigint_int(ao_lisp_poly_bigint(p)->value);
+ case AO_LISP_FLOAT:
+ return ao_lisp_poly_float(p)->value;
+ }
+ }
+ return NAN;
+}
+
+ao_poly
+ao_lisp_float_get(float value)
+{
+ struct ao_lisp_float *f;
+
+ f = ao_lisp_alloc(sizeof (struct ao_lisp_float));
+ f->type = AO_LISP_FLOAT;
+ f->value = value;
+ return ao_lisp_float_poly(f);
+}
+
+ao_poly
+ao_lisp_do_inexactp(struct ao_lisp_cons *cons)
+{
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ if (ao_lisp_poly_type(ao_lisp_arg(cons, 0)) == AO_LISP_FLOAT)
+ return _ao_lisp_bool_true;
+ return _ao_lisp_bool_false;
+}
+
+ao_poly
+ao_lisp_do_finitep(struct ao_lisp_cons *cons)
+{
+ ao_poly value;
+ float f;
+
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ value = ao_lisp_arg(cons, 0);
+ switch (ao_lisp_poly_type(value)) {
+ case AO_LISP_INT:
+ case AO_LISP_BIGINT:
+ return _ao_lisp_bool_true;
+ case AO_LISP_FLOAT:
+ f = ao_lisp_poly_float(value)->value;
+ if (!isnan(f) && !isinf(f))
+ return _ao_lisp_bool_true;
+ }
+ return _ao_lisp_bool_false;
+}
+
+ao_poly
+ao_lisp_do_infinitep(struct ao_lisp_cons *cons)
+{
+ ao_poly value;
+ float f;
+
+ if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1))
+ return AO_LISP_NIL;
+ value = ao_lisp_arg(cons, 0);
+ switch (ao_lisp_poly_type(value)) {
+ case AO_LISP_FLOAT:
+ f = ao_lisp_poly_float(value)->value;
+ if (isinf(f))
+ return _ao_lisp_bool_true;
+ }
+ return _ao_lisp_bool_false;
+}
+
+ao_poly
+ao_lisp_do_sqrt(struct ao_lisp_cons *cons)
+{
+ ao_poly value;
+
+ if (!ao_lisp_check_argc(_ao_lisp_atom_sqrt, cons, 1, 1))
+ return AO_LISP_NIL;
+ value = ao_lisp_arg(cons, 0);
+ if (!ao_lisp_number_typep(ao_lisp_poly_type(value)))
+ return ao_lisp_error(AO_LISP_INVALID, "%s: non-numeric", ao_lisp_poly_atom(_ao_lisp_atom_sqrt)->name);
+ return ao_lisp_float_get(sqrtf(ao_lisp_poly_number(value)));
+}
diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c
index f333073a..dc0008c4 100644
--- a/src/lisp/ao_lisp_mem.c
+++ b/src/lisp/ao_lisp_mem.c
@@ -459,6 +459,7 @@ static const struct ao_lisp_type *ao_lisp_types[AO_LISP_NUM_TYPE] = {
[AO_LISP_STACK] = &ao_lisp_stack_type,
[AO_LISP_BOOL] = &ao_lisp_bool_type,
[AO_LISP_BIGINT] = &ao_lisp_bigint_type,
+ [AO_LISP_FLOAT] = &ao_lisp_float_type,
};
static int
diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c
index 94ecd042..e93e1192 100644
--- a/src/lisp/ao_lisp_poly.c
+++ b/src/lisp/ao_lisp_poly.c
@@ -60,6 +60,10 @@ static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = {
.write = ao_lisp_bigint_write,
.display = ao_lisp_bigint_write,
},
+ [AO_LISP_FLOAT] = {
+ .write = ao_lisp_float_write,
+ .display = ao_lisp_float_write,
+ },
};
static const struct ao_lisp_funcs *
diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c
index 5115f46e..c5a238cc 100644
--- a/src/lisp/ao_lisp_read.c
+++ b/src/lisp/ao_lisp_read.c
@@ -14,6 +14,7 @@
#include "ao_lisp.h"
#include "ao_lisp_read.h"
+#include <math.h>
static const uint16_t lex_classes[128] = {
IGNORE, /* ^@ */
@@ -62,7 +63,7 @@ static const uint16_t lex_classes[128] = {
PRINTABLE|SIGN, /* + */
PRINTABLE, /* , */
PRINTABLE|SIGN, /* - */
- PRINTABLE|SPECIAL, /* . */
+ PRINTABLE|DOTC|FLOATC, /* . */
PRINTABLE, /* / */
PRINTABLE|DIGIT, /* 0 */
PRINTABLE|DIGIT, /* 1 */
@@ -85,7 +86,7 @@ static const uint16_t lex_classes[128] = {
PRINTABLE, /* B */
PRINTABLE, /* C */
PRINTABLE, /* D */
- PRINTABLE, /* E */
+ PRINTABLE|FLOATC, /* E */
PRINTABLE, /* F */
PRINTABLE, /* G */
PRINTABLE, /* H */
@@ -117,7 +118,7 @@ static const uint16_t lex_classes[128] = {
PRINTABLE, /* b */
PRINTABLE, /* c */
PRINTABLE, /* d */
- PRINTABLE, /* e */
+ PRINTABLE|FLOATC, /* e */
PRINTABLE, /* f */
PRINTABLE, /* g */
PRINTABLE, /* h */
@@ -140,7 +141,7 @@ static const uint16_t lex_classes[128] = {
PRINTABLE, /* y */
PRINTABLE, /* z */
PRINTABLE, /* { */
- PRINTABLE|VBAR, /* | */
+ PRINTABLE, /* | */
PRINTABLE, /* } */
PRINTABLE, /* ~ */
IGNORE, /* ^? */
@@ -247,16 +248,36 @@ lex_quoted(void)
static char token_string[AO_LISP_TOKEN_MAX];
static int32_t token_int;
static int token_len;
+static float token_float;
static inline void add_token(int c) {
if (c && token_len < AO_LISP_TOKEN_MAX - 1)
token_string[token_len++] = c;
}
+static inline void del_token(void) {
+ if (token_len > 0)
+ token_len--;
+}
+
static inline void end_token(void) {
token_string[token_len] = '\0';
}
+struct namedfloat {
+ const char *name;
+ float value;
+};
+
+static const struct namedfloat namedfloats[] = {
+ { .name = "+inf.0", .value = INFINITY },
+ { .name = "-inf.0", .value = -INFINITY },
+ { .name = "+nan.0", .value = NAN },
+ { .name = "-nan.0", .value = NAN },
+};
+
+#define NUM_NAMED_FLOATS (sizeof namedfloats / sizeof namedfloats[0])
+
static int
_lex(void)
{
@@ -279,7 +300,7 @@ _lex(void)
continue;
}
- if (lex_class & SPECIAL) {
+ if (lex_class & (SPECIAL|DOTC)) {
add_token(c);
end_token();
switch (c) {
@@ -357,47 +378,72 @@ _lex(void)
}
}
if (lex_class & PRINTABLE) {
- int isnum;
+ int isfloat;
int hasdigit;
int isneg;
+ int isint;
+ int epos;
- isnum = 1;
+ isfloat = 1;
+ isint = 1;
hasdigit = 0;
token_int = 0;
isneg = 0;
+ epos = 0;
for (;;) {
if (!(lex_class & NUMBER)) {
- isnum = 0;
+ isint = 0;
+ isfloat = 0;
} else {
- if (token_len != 0 &&
+ if (!(lex_class & INTEGER))
+ isint = 0;
+ if (token_len != epos &&
(lex_class & SIGN))
{
- isnum = 0;
+ isint = 0;
+ isfloat = 0;
}
if (c == '-')
isneg = 1;
+ if (c == '.' && epos != 0)
+ isfloat = 0;
+ if (c == 'e' || c == 'E') {
+ if (token_len == 0)
+ isfloat = 0;
+ else
+ epos = token_len + 1;
+ }
if (lex_class & DIGIT) {
hasdigit = 1;
- if (isnum)
+ if (isint)
token_int = token_int * 10 + c - '0';
}
}
add_token (c);
c = lexc ();
- if (lex_class & (NOTNAME)) {
+ if ((lex_class & (NOTNAME)) && (c != '.' || !isfloat)) {
+ unsigned int u;
// if (lex_class & ENDOFFILE)
// clearerr (f);
lex_unget(c);
end_token ();
- if (isnum && hasdigit) {
+ if (isint && hasdigit) {
if (isneg)
token_int = -token_int;
return NUM;
}
+ if (isfloat && hasdigit) {
+ token_float = atof(token_string);
+ return FLOAT;
+ }
+ for (u = 0; u < NUM_NAMED_FLOATS; u++)
+ if (!strcmp(namedfloats[u].name, token_string)) {
+ token_float = namedfloats[u].value;
+ return FLOAT;
+ }
return NAME;
}
}
-
}
}
}
@@ -499,6 +545,9 @@ ao_lisp_read(void)
case NUM:
v = ao_lisp_integer_poly(token_int);
break;
+ case FLOAT:
+ v = ao_lisp_float_get(token_float);
+ break;
case BOOL:
if (token_string[0] == 't')
v = _ao_lisp_bool_true;
diff --git a/src/lisp/ao_lisp_read.h b/src/lisp/ao_lisp_read.h
index fc74a8e4..20c9c18a 100644
--- a/src/lisp/ao_lisp_read.h
+++ b/src/lisp/ao_lisp_read.h
@@ -26,28 +26,30 @@
# define QUOTE 4
# define STRING 5
# define NUM 6
-# define DOT 7
-# define BOOL 8
+# define FLOAT 7
+# define DOT 8
+# define BOOL 9
/*
* character classes
*/
# define PRINTABLE 0x0001 /* \t \n ' ' - '~' */
-# define QUOTED 0x0002 /* \ anything */
-# define SPECIAL 0x0004 /* ( [ { ) ] } ' . */
+# define SPECIAL 0x0002 /* ( [ { ) ] } ' */
+# define DOTC 0x0004 /* . */
# define WHITE 0x0008 /* ' ' \t \n */
# define DIGIT 0x0010 /* [0-9] */
# define SIGN 0x0020 /* +- */
-# define ENDOFFILE 0x0040 /* end of file */
-# define COMMENT 0x0080 /* ; */
-# define IGNORE 0x0100 /* \0 - ' ' */
-# define BACKSLASH 0x0200 /* \ */
-# define VBAR 0x0400 /* | */
+# define FLOATC 0x0040 /* . e E */
+# define ENDOFFILE 0x0080 /* end of file */
+# define COMMENT 0x0100 /* ; */
+# define IGNORE 0x0200 /* \0 - ' ' */
+# define BACKSLASH 0x0400 /* \ */
# define STRINGC 0x0800 /* " */
# define POUND 0x1000 /* # */
-# define NOTNAME (STRINGC|VBAR|COMMENT|ENDOFFILE|WHITE|SPECIAL)
-# define NUMBER (DIGIT|SIGN)
+# define NOTNAME (STRINGC|COMMENT|ENDOFFILE|WHITE|SPECIAL)
+# define INTEGER (DIGIT|SIGN)
+# define NUMBER (INTEGER|FLOATC)
#endif /* _AO_LISP_READ_H_ */