aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--any_sexp.h138
-rw-r--r--test/sexp.c8
2 files changed, 117 insertions, 29 deletions
diff --git a/any_sexp.h b/any_sexp.h
index 6e7ea6b..516b9e5 100644
--- a/any_sexp.h
+++ b/any_sexp.h
@@ -5,29 +5,48 @@
#include <stddef.h>
#include <stdbool.h>
-#define ANY_SEXP_NIL (any_sexp_t)NULL
-#define ANY_SEXP_ERROR (any_sexp_t)UINTPTR_MAX
-
-#ifdef ANY_SEXP_NO_TAGGING
-typedef struct {
+typedef enum {
+ ANY_SEXP_TAG_ERROR = 0xf,
+ ANY_SEXP_TAG_NIL = 0,
+ ANY_SEXP_TAG_CONS = 1 << 0,
+ ANY_SEXP_TAG_SYMBOL = 1 << 1,
+ ANY_SEXP_TAG_QUOTE = 1 << 2,
+} any_sexp_tag_t;
+
+#ifdef ANY_SEXP_NO_BOXING
+
+typedef struct any_sexp {
+ any_sexp_tag_t tag;
+ union {
+ struct any_sexp_cons *cons;
+ char *symbol;
+ struct any_sexp *quote;
+ };
} any_sexp_t;
+#define ANY_SEXP_NIL ((any_sexp_t){ ANY_SEXP_TAG_NIL })
+#define ANY_SEXP_ERROR ((any_sexp_t){ ANY_SEXP_TAG_ERROR })
+
+#define ANY_SEXP_GET_TAG(sexp) ((sexp).tag)
+
#else
typedef void *any_sexp_t;
+#define ANY_SEXP_NIL (any_sexp_t)NULL
+#define ANY_SEXP_ERROR (any_sexp_t)UINTPTR_MAX
#define ANY_SEXP_UNTAG(sexp) (any_sexp_t)((uintptr_t)(sexp) & 0x0fffffffffffffff)
#define ANY_SEXP_TAG(sexp, tag) (any_sexp_t)((uintptr_t)(sexp) | ((uintptr_t)tag << 60))
#define ANY_SEXP_GET_TAG(sexp) (((uintptr_t)(sexp) >> 60) & 0xf)
-
-#define ANY_SEXP_TAG_ERROR 0xf
-#define ANY_SEXP_TAG_NIL 0
-#define ANY_SEXP_TAG_CONS (1 << 0)
-#define ANY_SEXP_TAG_SYMBOL (1 << 1)
-#define ANY_SEXP_TAG_QUOTE (1 << 2)
#endif
-typedef struct {
+#define ANY_SEXP_IS_TAG(sexp, tag) (ANY_SEXP_GET_TAG(sexp) == (tag))
+#define ANY_SEXP_IS_ERROR(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_ERROR))
+#define ANY_SEXP_IS_NIL(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_NIL))
+#define ANY_SEXP_IS_CONS(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_CONS))
+#define ANY_SEXP_IS_QUOTE(sexp) (ANY_SEXP_IS_TAG(sexp, ANY_SEXP_TAG_QUOTE))
+
+typedef struct any_sexp_cons {
any_sexp_t car;
any_sexp_t cdr;
} any_sexp_cons_t;
@@ -130,7 +149,15 @@ static any_sexp_t any_sexp_parser_symbol(any_sexp_parser_t *parser)
memcpy(sym, parser->source + cursor, length);
sym[length] = '\0';
+#ifndef ANY_SEXP_NO_BOXING
return ANY_SEXP_TAG(sym, ANY_SEXP_TAG_SYMBOL);
+#else
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_SYMBOL,
+ .symbol = sym,
+ };
+ return sexp;
+#endif
}
static any_sexp_t any_sexp_parser_quote(any_sexp_parser_t *parser)
@@ -139,8 +166,18 @@ static any_sexp_t any_sexp_parser_quote(any_sexp_parser_t *parser)
parser->cursor++;
any_sexp_t *quote = ANY_SEXP_MALLOC(sizeof(any_sexp_t));
+ if (quote == NULL) return ANY_SEXP_ERROR;
*quote = any_sexp_parser_next(parser);
+
+#ifndef ANY_SEXP_NO_BOXING
return (any_sexp_t )ANY_SEXP_TAG(quote, ANY_SEXP_TAG_QUOTE);
+#else
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_QUOTE,
+ .quote = quote,
+ };
+ return sexp;
+#endif
}
any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser)
@@ -168,7 +205,7 @@ any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser)
any_sexp_t sub = any_sexp_parser_next(parser);
sexp = any_sexp_cons(sub, sexp); // reversed
- if (sub == ANY_SEXP_ERROR || sexp == ANY_SEXP_NIL) {
+ if (ANY_SEXP_IS_ERROR(sub) || ANY_SEXP_IS_ERROR(sexp)) {
any_sexp_free(sexp);
return ANY_SEXP_ERROR;
}
@@ -183,55 +220,84 @@ any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser)
any_sexp_t any_sexp_cons(any_sexp_t car, any_sexp_t cdr)
{
any_sexp_cons_t *cons = ANY_SEXP_MALLOC(sizeof(any_sexp_cons_t));
+ if (cons == NULL) return ANY_SEXP_ERROR;
+
cons->car = car;
cons->cdr = cdr;
+
+#ifndef ANY_SEXP_NO_BOXING
return ANY_SEXP_TAG(cons, ANY_SEXP_TAG_CONS);
+#else
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_CONS,
+ .cons = cons,
+ };
+ return sexp;
+#endif
}
any_sexp_t any_sexp_car(any_sexp_t sexp)
{
- if (ANY_SEXP_GET_TAG(sexp) != ANY_SEXP_TAG_CONS)
+ if (!ANY_SEXP_IS_CONS(sexp))
return ANY_SEXP_ERROR;
+#ifndef ANY_SEXP_NO_BOXING
any_sexp_cons_t *cons = (any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp);
return cons->car;
+#else
+ return sexp.cons->car;
+#endif
}
any_sexp_t any_sexp_cdr(any_sexp_t sexp)
{
- if (ANY_SEXP_GET_TAG(sexp) != ANY_SEXP_TAG_CONS)
+ if (!ANY_SEXP_IS_CONS(sexp))
return ANY_SEXP_ERROR;
+#ifndef ANY_SEXP_NO_BOXING
any_sexp_cons_t *cons = (any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp);
return cons->cdr;
+#else
+ return sexp.cons->cdr;
+#endif
}
any_sexp_t any_sexp_reverse(any_sexp_t sexp)
{
- if (sexp == ANY_SEXP_NIL)
+ if (ANY_SEXP_IS_NIL(sexp))
return sexp;
- if (ANY_SEXP_GET_TAG(sexp) != ANY_SEXP_TAG_CONS)
+ if (!ANY_SEXP_IS_CONS(sexp))
return ANY_SEXP_ERROR;
+#ifndef ANY_SEXP_NO_BOXING
any_sexp_cons_t *cons = (any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp);
any_sexp_t prev = ANY_SEXP_NIL, next = ANY_SEXP_NIL;
while (cons != NULL) {
-
- if (cons->cdr != ANY_SEXP_NIL && ANY_SEXP_GET_TAG(cons->cdr) != ANY_SEXP_TAG_CONS)
+ if (!ANY_SEXP_IS_NIL(cons) && !ANY_SEXP_IS_CONS(cons))
return ANY_SEXP_ERROR;
next = (any_sexp_cons_t *)ANY_SEXP_UNTAG(cons->cdr);
- cons->cdr = prev == ANY_SEXP_NIL
- ? ANY_SEXP_NIL
- : ANY_SEXP_TAG(prev, ANY_SEXP_TAG_CONS);
-
- prev = cons;
+ cons->cdr = prev;
+ prev = ANY_SEXP_TAG(cons, ANY_SEXP_TAG_CONS);
cons = next;
}
+#else
+ any_sexp_t cons = sexp, prev = ANY_SEXP_NIL, next = ANY_SEXP_NIL;
+
+ while (cons.cons != NULL) {
+ if (!ANY_SEXP_IS_NIL(cons) && !ANY_SEXP_IS_CONS(cons))
+ return ANY_SEXP_ERROR;
+
+ memcpy(&next, &cons.cons->cdr, sizeof(any_sexp_t));
+ memcpy(&cons.cons->cdr, &prev, sizeof(any_sexp_t));
+ memcpy(&prev, &cons, sizeof(any_sexp_t));
+ memcpy(&cons, &next, sizeof(any_sexp_t));
+ }
+#endif
- return ANY_SEXP_TAG(prev, ANY_SEXP_TAG_CONS);
+ return prev;
}
void any_sexp_print(any_sexp_t sexp)
@@ -247,21 +313,29 @@ void any_sexp_print(any_sexp_t sexp)
case ANY_SEXP_TAG_CONS:
putchar('(');
- while (sexp != ANY_SEXP_NIL && sexp != ANY_SEXP_ERROR) {
+ while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) {
any_sexp_print(any_sexp_car(sexp));
sexp = any_sexp_cdr(sexp);
- if (sexp != ANY_SEXP_NIL) putchar(' ');
+ if (!ANY_SEXP_IS_NIL(sexp)) putchar(' ');
}
putchar(')');
break;
case ANY_SEXP_TAG_SYMBOL:
+#ifndef ANY_SEXP_NO_BOXING
printf("%s", (char *)ANY_SEXP_UNTAG(sexp));
+#else
+ printf("%s", sexp.symbol);
+#endif
break;
case ANY_SEXP_TAG_QUOTE:
putchar('\'');
+#ifndef ANY_SEXP_NO_BOXING
any_sexp_print(*(any_sexp_t *)ANY_SEXP_UNTAG(sexp));
+#else
+ any_sexp_print(*sexp.quote);
+#endif
break;
}
}
@@ -276,16 +350,26 @@ void any_sexp_free(any_sexp_t sexp)
case ANY_SEXP_TAG_CONS:
any_sexp_free(any_sexp_car(sexp));
any_sexp_free(any_sexp_cdr(sexp));
+#ifndef ANY_SEXP_NO_BOXING
ANY_SEXP_FREE(ANY_SEXP_UNTAG(sexp));
+#endif
break;
case ANY_SEXP_TAG_SYMBOL:
+#ifndef ANY_SEXP_NO_BOXING
ANY_SEXP_FREE(ANY_SEXP_UNTAG(sexp));
+#else
+ ANY_SEXP_FREE(sexp.symbol);
+#endif
break;
case ANY_SEXP_TAG_QUOTE:
+#ifndef ANY_SEXP_NO_BOXING
any_sexp_free(*(any_sexp_t *)ANY_SEXP_UNTAG(sexp));
ANY_SEXP_FREE(ANY_SEXP_UNTAG(sexp));
+#else
+ any_sexp_free(*sexp.quote);
+#endif
break;
}
}
diff --git a/test/sexp.c b/test/sexp.c
index 85f80f9..c71d4fa 100644
--- a/test/sexp.c
+++ b/test/sexp.c
@@ -2,6 +2,7 @@
#include <string.h>
#define ANY_SEXP_IMPLEMENT
+#define ANY_SEXP_NO_BOXING
#include "any_sexp.h"
int main()
@@ -16,12 +17,15 @@ int main()
any_sexp_parser_t parser;
any_sexp_parser_init(&parser, s, strlen(s));
- any_sexp_t *sexp;
- while ((sexp = any_sexp_parser_next(&parser)) != ANY_SEXP_ERROR) {
+ any_sexp_t sexp = any_sexp_parser_next(&parser);
+ while (!ANY_SEXP_IS_ERROR(sexp)) {
any_sexp_print(sexp);
putchar('\n');
any_sexp_free(sexp);
+ sexp = any_sexp_parser_next(&parser);
}
+ printf("%zu\n", sizeof(any_sexp_t));
+
return 0;
}