aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--any_sexp.h127
-rw-r--r--test/sexp.c5
2 files changed, 95 insertions, 37 deletions
diff --git a/any_sexp.h b/any_sexp.h
index b36689f..534c455 100644
--- a/any_sexp.h
+++ b/any_sexp.h
@@ -33,7 +33,9 @@ typedef enum {
ANY_SEXP_TAG_NIL = 0,
ANY_SEXP_TAG_CONS = 1 << 0,
ANY_SEXP_TAG_SYMBOL = 1 << 1,
+#ifndef ANY_SEXP_NO_STRING
ANY_SEXP_TAG_STRING = 1 << 2,
+#endif
} any_sexp_tag_t;
#ifdef ANY_SEXP_NO_BOXING
@@ -52,7 +54,10 @@ typedef struct any_sexp {
#define ANY_SEXP_GET_TAG(sexp) ((sexp).tag)
#define ANY_SEXP_GET_CONS(sexp) ((sexp).cons)
#define ANY_SEXP_GET_SYMBOL(sexp) ((sexp).symbol)
+
+#ifndef ANY_SEXP_NO_STRING
#define ANY_SEXP_GET_STRING(sexp) ((sexp).symbol)
+#endif
#else
@@ -68,7 +73,10 @@ typedef void *any_sexp_t;
#define ANY_SEXP_GET_TAG(sexp) (((uintptr_t)(sexp) >> ANY_SEXP_BITS_SHIFT) & 0xf)
#define ANY_SEXP_GET_CONS(sexp) ((any_sexp_cons_t *)ANY_SEXP_UNTAG(sexp))
#define ANY_SEXP_GET_SYMBOL(sexp) (((char *)ANY_SEXP_UNTAG(sexp)))
+
+#ifndef ANY_SEXP_NO_STRING
#define ANY_SEXP_GET_STRING(sexp) (((char *)ANY_SEXP_UNTAG(sexp)))
+#endif
#endif
@@ -85,9 +93,9 @@ typedef struct any_sexp_cons {
any_sexp_t cdr;
} any_sexp_cons_t;
-typedef char (*any_sexp_getchar_t)(void *stream);
+typedef int (*any_sexp_getchar_t)(void *stream);
-typedef int (*any_sexp_fprintf_t)(void *stream, const char *format, ...);
+typedef int (*any_sexp_putchar_t)(int c, FILE *stream);
#ifndef ANY_SEXP_NO_READER
@@ -98,7 +106,7 @@ typedef int (*any_sexp_fprintf_t)(void *stream, const char *format, ...);
typedef struct {
any_sexp_getchar_t getc;
void *stream;
- char c;
+ int c;
} any_sexp_reader_t;
typedef struct {
@@ -120,11 +128,11 @@ any_sexp_t any_sexp_read(any_sexp_reader_t *reader);
#ifndef ANY_SEXP_NO_WRITER
typedef struct {
- any_sexp_fprintf_t fprintf;
+ any_sexp_putchar_t putc;
void *stream;
} any_sexp_writer_t;
-void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_fprintf_t fprintf, void *stream);
+void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_putchar_t putc, void *stream);
int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp);
@@ -140,8 +148,12 @@ any_sexp_t any_sexp_nil(void);
any_sexp_t any_sexp_symbol(char *symbol, size_t length);
+#ifndef ANY_SEXP_NO_STRING
+
any_sexp_t any_sexp_string(char *string, size_t length);
+#endif
+
any_sexp_t any_sexp_quote(any_sexp_t sexp);
any_sexp_t any_sexp_cons(any_sexp_t car, any_sexp_t cdr);
@@ -362,9 +374,19 @@ any_sexp_t any_sexp_read(any_sexp_reader_t *reader)
#ifndef ANY_SEXP_NO_WRITER
-void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_fprintf_t fprintf, void *stream)
+static int any_sexp_writer_puts(any_sexp_writer_t *writer, const char *string)
+{
+ int i;
+ for (i = 0; string[i] != '\0', i++) {
+ if (writer->putc(string[i], writer->stream) == EOF)
+ return EOF;
+ }
+ return i;
+}
+
+void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_putchar_t putc, void *stream)
{
- writer->fprintf = fprintf;
+ writer->putc = putc;
writer->stream = stream;
}
@@ -372,36 +394,64 @@ int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp)
{
switch (ANY_SEXP_GET_TAG(sexp)) {
case ANY_SEXP_TAG_ERROR:
- return writer->fprintf(writer->stream, "<error>");
+ return any_sexp_writer_puts(writer, "<error>");
case ANY_SEXP_TAG_NIL:
- return writer->fprintf(writer->stream, "()");
+ return writer->putc(ANY_SEXP_CHAR_OPEN, writer->stream) == EOF
+ || writer->putc(ANY_SEXP_CHAR_CLOSE, writer->stream) == EOF
+ ? EOF : 2;
case ANY_SEXP_TAG_CONS: {
- int c = writer->fprintf(writer->stream, "(");
+ if (writer->putc(ANY_SEXP_CHAR_OPEN, writer->stream) == EOF)
+ return EOF;
+
+ int c = 2, tmp;
while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) {
- c += any_sexp_write(writer, any_sexp_car(sexp));
+ tmp = any_sexp_write(writer, any_sexp_car(sexp));
sexp = any_sexp_cdr(sexp);
- if (!ANY_SEXP_IS_NIL(sexp))
- c += writer->fprintf(writer->stream, " ");
+ if (tmp == EOF)
+ return EOF;
+
+ if (!ANY_SEXP_IS_NIL(sexp)) {
+ if (writer->putc(' ', writer->stream) == EOF)
+ return EOF;
+ tmp++;
+ }
+ c += tmp;
}
- c += writer->fprintf(writer->stream, ")");
+
+ if (writer->putc(ANY_SEXP_CHAR_CLOSE, writer->stream) == EOF)
+ return EOF;
+
return c;
}
case ANY_SEXP_TAG_SYMBOL:
- return writer->fprintf(writer->stream, "%s", ANY_SEXP_GET_SYMBOL(sexp));
+ return any_sexp_writer_puts(writer, ANY_SEXP_GET_SYMBOL(sexp));
- case ANY_SEXP_TAG_STRING:
- return writer->fprintf(writer->stream, "\"%s\"", ANY_SEXP_GET_STRING(sexp));
+#ifndef ANY_SEXP_NO_STRING
+ case ANY_SEXP_TAG_STRING: {
+ if (writer->putc(ANY_SEXP_CHAR_STRING, writer->stream) == EOF)
+ return EOF;
+
+ int c = any_sexp_writer_puts(writer, ANY_SEXP_GET_STRING(sexp));
+ if (c == EOF)
+ return EOF;
+
+ if (writer->putc(ANY_SEXP_CHAR_STRING, writer->stream) == EOF)
+ return EOF;
+
+ return c + 2;
+ }
+#endif
}
}
int any_sexp_fprint(any_sexp_t sexp, FILE *file)
{
any_sexp_writer_t writer;
- any_sexp_writer_init(&writer, (any_sexp_fprintf_t)fprintf, file);
+ any_sexp_writer_init(&writer, (any_sexp_putchar_t)fputc, file);
return any_sexp_write(&writer, sexp);
}
@@ -438,42 +488,47 @@ any_sexp_t any_sexp_nil(void)
any_sexp_t any_sexp_symbol(char *symbol, size_t length)
{
- any_sexp_t sexp = any_sexp_string(symbol, length);
- if (ANY_SEXP_IS_ERROR(sexp))
+ if (symbol == NULL)
return ANY_SEXP_ERROR;
- // Override tag
+ char *copy = ANY_SEXP_MALLOC(length + 1);
+ if (copy == NULL)
+ return ANY_SEXP_ERROR;
+
+ memcpy(copy, symbol, length);
+ copy[length] = '\0';
+
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_TAG(ANY_SEXP_UNTAG(sexp), ANY_SEXP_TAG_SYMBOL);
+ return ANY_SEXP_TAG(copy, ANY_SEXP_TAG_SYMBOL);
#else
- sexp.tag = ANY_SEXP_TAG_SYMBOL;
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_SYMBOL,
+ .symbol = copy,
+ };
return sexp;
#endif
}
+#ifndef ANY_SEXP_NO_STRING
+
any_sexp_t any_sexp_string(char *string, size_t length)
{
- if (string == NULL)
- return ANY_SEXP_ERROR;
- char *copy = ANY_SEXP_MALLOC(length + 1);
- if (copy == NULL)
+ any_sexp_t sexp = any_sexp_symbol(string, length);
+ if (ANY_SEXP_IS_ERROR(sexp))
return ANY_SEXP_ERROR;
- memcpy(copy, string, length);
- copy[length] = '\0';
-
+ // Override the tag
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_TAG(copy, ANY_SEXP_TAG_STRING);
+ return ANY_SEXP_TAG(ANY_SEXP_UNTAG(sexp), ANY_SEXP_TAG_STRING);
#else
- any_sexp_t sexp = {
- .tag = ANY_SEXP_TAG_STRING,
- .symbol = copy,
- };
+ sexp.tag = ANY_SEXP_TAG_STRING;
return sexp;
#endif
}
+#endif
+
any_sexp_t any_sexp_quote(any_sexp_t sexp)
{
any_sexp_t quote = any_sexp_symbol(ANY_SEXP_QUOTE_SYMBOL, strlen(ANY_SEXP_QUOTE_SYMBOL));
@@ -553,7 +608,9 @@ void any_sexp_free(any_sexp_t sexp)
break;
case ANY_SEXP_TAG_SYMBOL:
+#ifndef ANY_SEXP_NO_STRING
case ANY_SEXP_TAG_STRING:
+#endif
ANY_SEXP_FREE(ANY_SEXP_GET_SYMBOL(sexp));
break;
}
diff --git a/test/sexp.c b/test/sexp.c
index c15b53e..6f8dfc5 100644
--- a/test/sexp.c
+++ b/test/sexp.c
@@ -2,7 +2,8 @@
#include <string.h>
#define ANY_SEXP_IMPLEMENT
-#define ANY_SEXP_NO_BOXING
+//#define ANY_SEXP_NO_BOXING
+//#define ANY_SEXP_NO_STRING
#include "any_sexp.h"
int main()
@@ -21,7 +22,7 @@ int main()
any_sexp_t sexp = any_sexp_read(&reader);
while (!ANY_SEXP_IS_ERROR(sexp)) {
- any_sexp_print(sexp);
+ printf(" %d ", any_sexp_print(sexp));
putchar('\n');
any_sexp_free(sexp);
sexp = any_sexp_read(&reader);