aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-06-06 00:04:14 +0200
committerFederico Angelilli <code@fedang.net>2024-06-06 00:04:14 +0200
commita210631a55c97b64125b28ecc4bbffdc8a3bfe5f (patch)
tree5103844af19bceec75c5adf606d47caf73ee3a5b
parent9d52b7cef8ad29fca25cbd1527dbf3337c8526c6 (diff)
Refactor any_sexp
-rw-r--r--any_sexp.h552
-rw-r--r--test/sexp.c38
2 files changed, 315 insertions, 275 deletions
diff --git a/any_sexp.h b/any_sexp.h
index bbb186f..b36689f 100644
--- a/any_sexp.h
+++ b/any_sexp.h
@@ -3,8 +3,9 @@
// A single-file library that provides a simple and somewhat opinionated
// interface for parsing and manipulating s-expressions.
//
-// Note that the library does not offer anything that can evaluate the
-// s-expressions, but that can be easily implemented separately.
+// Note that the library does not offer the means to evaluate the
+// s-expressions. That can be easily implemented separately using the
+// provided any_sexp_t type and helper functions.
//
// To use this library you should choose a suitable file to put the
// implementation and define ANY_SEXP_IMPLEMENT. For example
@@ -28,21 +29,21 @@
#include <stdbool.h>
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_STRING = 1 << 2,
+ 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_STRING = 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;
- };
+ any_sexp_tag_t tag;
+ union {
+ struct any_sexp_cons *cons;
+ char *symbol;
+ };
} any_sexp_t;
#define ANY_SEXP_ERROR (any_sexp_error())
@@ -76,44 +77,62 @@ typedef void *any_sexp_t;
#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))
-// NOTE: Use it only after checking the tag!
#define ANY_SEXP_GET_CAR(sexp) (ANY_SEXP_GET_CONS(sexp)->car)
#define ANY_SEXP_GET_CDR(sexp) (ANY_SEXP_GET_CONS(sexp)->cdr)
typedef struct any_sexp_cons {
- any_sexp_t car;
- any_sexp_t cdr;
+ any_sexp_t car;
+ any_sexp_t cdr;
} any_sexp_cons_t;
-#ifndef ANY_SEXP_BUFFER_SIZE
-#define ANY_SEXP_BUFFER_SIZE 512
-#endif
-
typedef char (*any_sexp_getchar_t)(void *stream);
typedef int (*any_sexp_fprintf_t)(void *stream, const char *format, ...);
+#ifndef ANY_SEXP_NO_READER
+
+#ifndef ANY_SEXP_READER_BUFFER_LENGTH
+#define ANY_SEXP_READER_BUFFER_LENGTH 512
+#endif
+
+typedef struct {
+ any_sexp_getchar_t getc;
+ void *stream;
+ char c;
+} any_sexp_reader_t;
+
typedef struct {
- const char *source;
- size_t length;
- size_t cursor;
-} any_sexp_string_stream_t;
+ const char *source;
+ size_t length;
+ size_t cursor;
+} any_sexp_reader_string_t;
+
+void any_sexp_reader_init(any_sexp_reader_t *reader, any_sexp_getchar_t getc, void *stream);
-char any_sexp_string_getc(any_sexp_string_stream_t *stream);
+void any_sexp_reader_string_init(any_sexp_reader_t *reader, any_sexp_reader_string_t *string, const char *source, size_t length);
+
+bool any_sexp_reader_end(any_sexp_reader_t *reader);
+
+any_sexp_t any_sexp_read(any_sexp_reader_t *reader);
+
+#endif
+
+#ifndef ANY_SEXP_NO_WRITER
typedef struct {
- any_sexp_getchar_t getc;
- void *stream;
- char c;
-} any_sexp_parser_t;
+ any_sexp_fprintf_t fprintf;
+ 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_parser_init(any_sexp_parser_t *parser, any_sexp_getchar_t getc, void *stream);
+int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp);
-void any_sexp_parser_init_string(any_sexp_parser_t *parser, any_sexp_string_stream_t *stream, const char *source, size_t length);
+int any_sexp_fprint(any_sexp_t sexp, FILE *file);
-bool any_sexp_parser_eof(any_sexp_parser_t *parser);
+int any_sexp_print(any_sexp_t sexp);
-any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser);
+#endif
any_sexp_t any_sexp_error(void);
@@ -133,12 +152,6 @@ any_sexp_t any_sexp_cdr(any_sexp_t sexp);
any_sexp_t any_sexp_reverse(any_sexp_t sexp);
-int any_sexp_stream_print(any_sexp_t sexp, any_sexp_fprintf_t fprintf, void *stream);
-
-int any_sexp_fprint(any_sexp_t sexp, FILE *file);
-
-int any_sexp_print(any_sexp_t sexp);
-
void any_sexp_free(any_sexp_t sexp);
#endif
@@ -181,342 +194,369 @@ void any_sexp_free(any_sexp_t sexp);
#define ANY_SEXP_QUOTE_SYMBOL "quote"
#endif
-// Extended alphabetic characters
-// ! $ % & * + - . / : < = > ? @ ^ _ ~
+#ifndef ANY_SEXP_NO_READER
+
+// For the scheme specification these are the extended characters
+// to be accepted in addition to the alphanumeric ones in a symbol.
+// ! $ % & * + - . / : < = > ? @ ^ _ ~
+//
+// However here we allow any character except the ones used by
+// other syntactic constructs.
//
static inline bool any_sexp_issym(char c)
{
- switch (c) {
- case '!': case '$': case '%':
- case '&': case '*': case '+':
- case '-': case '.': case '/':
- case ':': case '<': case '=':
- case '>': case '?': case '@':
- case '^': case '_': case '~':
-
- case '|': // TODO: Multiword symbols (CL)
- return true;
-
- default:
- return isalnum(c);
- }
+#ifndef ANY_SEXP_NO_COMMENT
+ if (c == ANY_SEXP_CHAR_COMMENT)
+ return false;
+#endif
+
+#ifndef ANY_SEXP_NO_STRING
+ if (c == ANY_SEXP_CHAR_STRING)
+ return false;
+#endif
+
+#ifndef ANY_SEXP_NO_QUOTE
+ if (c == ANY_SEXP_CHAR_QUOTE)
+ return false;
+#endif
+
+ if (c == ANY_SEXP_CHAR_QUOTE)
+ return false;
+
+ return c != EOF
+ && c != ANY_SEXP_CHAR_OPEN
+ && c != ANY_SEXP_CHAR_CLOSE
+ && !isspace(c);
}
-static inline char any_sexp_parser_advance(any_sexp_parser_t *parser)
+static inline char any_sexp_reader_advance(any_sexp_reader_t *reader)
{
- parser->c = parser->getc(parser->stream);
- return parser->c;
+ reader->c = reader->getc(reader->stream);
+ return reader->c;
}
-static void any_sexp_parser_skip(any_sexp_parser_t *parser)
+static void any_sexp_reader_skip(any_sexp_reader_t *reader)
{
- while (!any_sexp_parser_eof(parser)) {
+ while (!any_sexp_reader_end(reader)) {
#ifndef ANY_SEXP_NO_COMMENT
- if (parser->c == ANY_SEXP_CHAR_COMMENT) {
- while (!any_sexp_parser_eof(parser) && parser->c != '\n')
- any_sexp_parser_advance(parser);
- }
+ if (reader->c == ANY_SEXP_CHAR_COMMENT) {
+ while (!any_sexp_reader_end(reader) && reader->c != '\n')
+ any_sexp_reader_advance(reader);
+ }
#endif
- if (!isspace(parser->c))
- return;
+ if (!isspace(reader->c))
+ return;
+
+ any_sexp_reader_advance(reader);
+ }
+}
- any_sexp_parser_advance(parser);
- }
+static char any_sexp_reader_string_getc(any_sexp_reader_string_t *string)
+{
+ if (string->cursor >= string->length)
+ return EOF;
+ return string->source[string->cursor++];
}
-void any_sexp_parser_init(any_sexp_parser_t *parser, any_sexp_getchar_t getc, void *stream)
+void any_sexp_reader_init(any_sexp_reader_t *reader, any_sexp_getchar_t getc, void *stream)
{
- parser->getc = getc;
- parser->stream = stream;
- any_sexp_parser_advance(parser);
+ reader->getc = getc;
+ reader->stream = stream;
+ any_sexp_reader_advance(reader);
}
-void any_sexp_parser_init_string(any_sexp_parser_t *parser, any_sexp_string_stream_t *stream, const char *source, size_t length)
+void any_sexp_reader_string_init(any_sexp_reader_t *reader, any_sexp_reader_string_t *string, const char *source, size_t length)
{
- stream->source = source;
- stream->length = length;
- stream->cursor = 0;
- any_sexp_parser_init(parser, (any_sexp_getchar_t)any_sexp_string_getc, stream);
+ string->source = source;
+ string->length = length;
+ string->cursor = 0;
+ any_sexp_reader_init(reader, (any_sexp_getchar_t)any_sexp_reader_string_getc, string);
}
-bool any_sexp_parser_eof(any_sexp_parser_t *parser)
+bool any_sexp_reader_end(any_sexp_reader_t *reader)
{
- return parser->c == EOF;
+ return reader->c == EOF;
}
-any_sexp_t any_sexp_parser_next(any_sexp_parser_t *parser)
+any_sexp_t any_sexp_read(any_sexp_reader_t *reader)
{
- char buffer[ANY_SEXP_BUFFER_SIZE + 1];
+ char buffer[ANY_SEXP_READER_BUFFER_LENGTH + 1];
- any_sexp_parser_skip(parser);
+ any_sexp_reader_skip(reader);
- // Symbol
- if (any_sexp_issym(parser->c)) {
- size_t length = 0;
+ // Symbol
+ if (any_sexp_issym(reader->c)) {
+ size_t length = 0;
- do {
- if (length < ANY_SEXP_BUFFER_SIZE)
- buffer[length++] = parser->c;
+ do {
+ if (length < ANY_SEXP_READER_BUFFER_LENGTH)
+ buffer[length++] = reader->c;
- any_sexp_parser_advance(parser);
- } while (any_sexp_issym(parser->c));
+ any_sexp_reader_advance(reader);
+ } while (any_sexp_issym(reader->c));
- return any_sexp_symbol(buffer, length);
- }
+ return any_sexp_symbol(buffer, length);
+ }
#ifndef ANY_SEXP_NO_STRING
- // String
- if (parser->c == ANY_SEXP_CHAR_STRING) {
- any_sexp_parser_advance(parser);
+ // String
+ if (reader->c == ANY_SEXP_CHAR_STRING) {
+ any_sexp_reader_advance(reader);
- size_t length = 0;
- char prev = '\0';
+ size_t length = 0;
+ char prev = '\0';
- while (!any_sexp_parser_eof(parser)) {
- if (parser->c == ANY_SEXP_CHAR_STRING && prev != ANY_SEXP_CHAR_ESCAPE)
- break;
+ while (!any_sexp_reader_end(reader)) {
+ if (reader->c == ANY_SEXP_CHAR_STRING && prev != ANY_SEXP_CHAR_ESCAPE)
+ break;
- if (length < ANY_SEXP_BUFFER_SIZE)
- buffer[length++] = parser->c;
+ if (length < ANY_SEXP_READER_BUFFER_LENGTH)
+ buffer[length++] = reader->c;
- prev = parser->c;
- any_sexp_parser_advance(parser);
- }
+ prev = reader->c;
+ any_sexp_reader_advance(reader);
+ }
- any_sexp_parser_advance(parser);
- return any_sexp_string(buffer, length);
- }
+ any_sexp_reader_advance(reader);
+ return any_sexp_string(buffer, length);
+ }
#endif
#ifndef ANY_SEXP_NO_QUOTE
- // Quote
- if (parser->c == ANY_SEXP_CHAR_QUOTE) {
- any_sexp_parser_advance(parser);
- return any_sexp_quote(any_sexp_parser_next(parser));
- }
+ // Quote
+ if (reader->c == ANY_SEXP_CHAR_QUOTE) {
+ any_sexp_reader_advance(reader);
+ return any_sexp_quote(any_sexp_read(reader));
+ }
#endif
- // List
- if (parser->c == ANY_SEXP_CHAR_OPEN) {
- any_sexp_parser_advance(parser);
+ // List
+ if (reader->c == ANY_SEXP_CHAR_OPEN) {
+ any_sexp_reader_advance(reader);
+
+ any_sexp_t sexp = ANY_SEXP_NIL;
+
+ while (!any_sexp_reader_end(reader)) {
+ any_sexp_reader_skip(reader);
+
+ if (reader->c == ANY_SEXP_CHAR_CLOSE)
+ break;
- any_sexp_t sexp = ANY_SEXP_NIL;
+ any_sexp_t sub = any_sexp_read(reader);
+ sexp = any_sexp_cons(sub, sexp); // reversed
- while (!any_sexp_parser_eof(parser)) {
- any_sexp_parser_skip(parser);
+ if (ANY_SEXP_IS_ERROR(sub) || ANY_SEXP_IS_ERROR(sexp)) {
+ any_sexp_free(sexp);
+ return ANY_SEXP_ERROR;
+ }
+ }
- if (parser->c == ANY_SEXP_CHAR_CLOSE)
- break;
+ any_sexp_reader_advance(reader);
+ return any_sexp_reverse(sexp);
+ }
- any_sexp_t sub = any_sexp_parser_next(parser);
- sexp = any_sexp_cons(sub, sexp); // reversed
+ return ANY_SEXP_ERROR;
+}
- if (ANY_SEXP_IS_ERROR(sub) || ANY_SEXP_IS_ERROR(sexp)) {
- any_sexp_free(sexp);
- return ANY_SEXP_ERROR;
- }
- }
+#endif
- any_sexp_parser_advance(parser);
- return any_sexp_reverse(sexp);
- }
+#ifndef ANY_SEXP_NO_WRITER
- return ANY_SEXP_ERROR;
+void any_sexp_writer_init(any_sexp_writer_t *writer, any_sexp_fprintf_t fprintf, void *stream)
+{
+ writer->fprintf = fprintf;
+ writer->stream = stream;
}
-char any_sexp_string_getc(any_sexp_string_stream_t *stream)
+int any_sexp_write(any_sexp_writer_t *writer, any_sexp_t sexp)
{
- if (stream->cursor >= stream->length)
- return EOF;
+ switch (ANY_SEXP_GET_TAG(sexp)) {
+ case ANY_SEXP_TAG_ERROR:
+ return writer->fprintf(writer->stream, "<error>");
+
+ case ANY_SEXP_TAG_NIL:
+ return writer->fprintf(writer->stream, "()");
+
+ case ANY_SEXP_TAG_CONS: {
+ int c = writer->fprintf(writer->stream, "(");
+ while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) {
+ c += any_sexp_write(writer, any_sexp_car(sexp));
+ sexp = any_sexp_cdr(sexp);
+
+ if (!ANY_SEXP_IS_NIL(sexp))
+ c += writer->fprintf(writer->stream, " ");
+ }
+ c += writer->fprintf(writer->stream, ")");
+ return c;
+ }
+
+ case ANY_SEXP_TAG_SYMBOL:
+ return writer->fprintf(writer->stream, "%s", ANY_SEXP_GET_SYMBOL(sexp));
+
+ case ANY_SEXP_TAG_STRING:
+ return writer->fprintf(writer->stream, "\"%s\"", ANY_SEXP_GET_STRING(sexp));
+ }
+}
- return stream->source[stream->cursor++];
+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);
+ return any_sexp_write(&writer, sexp);
}
+int any_sexp_print(any_sexp_t sexp)
+{
+ return any_sexp_fprint(sexp, stdout);
+}
+
+#endif
+
any_sexp_t any_sexp_error(void)
{
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_ERROR;
+ return ANY_SEXP_ERROR;
#else
- any_sexp_t sexp = {
- .tag = ANY_SEXP_TAG_ERROR,
- };
- return sexp;
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_ERROR,
+ };
+ return sexp;
#endif
}
any_sexp_t any_sexp_nil(void)
{
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_NIL;
+ return ANY_SEXP_NIL;
#else
- any_sexp_t sexp = {
- .tag = ANY_SEXP_TAG_NIL,
- };
- return sexp;
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_NIL,
+ };
+ return sexp;
#endif
}
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))
- return ANY_SEXP_ERROR;
+ any_sexp_t sexp = any_sexp_string(symbol, length);
+ if (ANY_SEXP_IS_ERROR(sexp))
+ return ANY_SEXP_ERROR;
- // Override tag
+ // Override tag
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_TAG(ANY_SEXP_UNTAG(sexp), ANY_SEXP_TAG_SYMBOL);
+ return ANY_SEXP_TAG(ANY_SEXP_UNTAG(sexp), ANY_SEXP_TAG_SYMBOL);
#else
- sexp.tag = ANY_SEXP_TAG_SYMBOL;
- return sexp;
+ sexp.tag = ANY_SEXP_TAG_SYMBOL;
+ return sexp;
#endif
}
any_sexp_t any_sexp_string(char *string, size_t length)
{
- if (string == NULL)
- return ANY_SEXP_ERROR;
+ if (string == NULL)
+ return ANY_SEXP_ERROR;
- char *copy = ANY_SEXP_MALLOC(length + 1);
- if (copy == NULL)
- return ANY_SEXP_ERROR;
+ char *copy = ANY_SEXP_MALLOC(length + 1);
+ if (copy == NULL)
+ return ANY_SEXP_ERROR;
- memcpy(copy, string, length);
- copy[length] = '\0';
+ memcpy(copy, string, length);
+ copy[length] = '\0';
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_TAG(copy, ANY_SEXP_TAG_STRING);
+ return ANY_SEXP_TAG(copy, ANY_SEXP_TAG_STRING);
#else
- any_sexp_t sexp = {
- .tag = ANY_SEXP_TAG_STRING,
- .symbol = copy,
- };
- return sexp;
+ any_sexp_t sexp = {
+ .tag = ANY_SEXP_TAG_STRING,
+ .symbol = copy,
+ };
+ return sexp;
#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));
- return any_sexp_cons(quote, any_sexp_cons(sexp, ANY_SEXP_NIL));
+ any_sexp_t quote = any_sexp_symbol(ANY_SEXP_QUOTE_SYMBOL, strlen(ANY_SEXP_QUOTE_SYMBOL));
+ return any_sexp_cons(quote, any_sexp_cons(sexp, ANY_SEXP_NIL));
}
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;
+ 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;
+ cons->car = car;
+ cons->cdr = cdr;
#ifndef ANY_SEXP_NO_BOXING
- return ANY_SEXP_TAG(cons, ANY_SEXP_TAG_CONS);
+ return ANY_SEXP_TAG(cons, ANY_SEXP_TAG_CONS);
#else
- any_sexp_t sexp = {
- .tag = ANY_SEXP_TAG_CONS,
- .cons = cons,
- };
- return sexp;
+ 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_IS_CONS(sexp))
- return ANY_SEXP_ERROR;
- return ANY_SEXP_GET_CAR(sexp);
+ if (!ANY_SEXP_IS_CONS(sexp))
+ return ANY_SEXP_ERROR;
+ return ANY_SEXP_GET_CAR(sexp);
}
any_sexp_t any_sexp_cdr(any_sexp_t sexp)
{
- if (!ANY_SEXP_IS_CONS(sexp))
- return ANY_SEXP_ERROR;
- return ANY_SEXP_GET_CDR(sexp);
+ if (!ANY_SEXP_IS_CONS(sexp))
+ return ANY_SEXP_ERROR;
+ return ANY_SEXP_GET_CDR(sexp);
}
any_sexp_t any_sexp_reverse(any_sexp_t sexp)
{
- if (ANY_SEXP_IS_NIL(sexp))
- return sexp;
+ if (ANY_SEXP_IS_NIL(sexp))
+ return sexp;
- if (!ANY_SEXP_IS_CONS(sexp))
- return ANY_SEXP_ERROR;
+ if (!ANY_SEXP_IS_CONS(sexp))
+ return ANY_SEXP_ERROR;
- any_sexp_t cons = sexp,
- prev = ANY_SEXP_NIL,
- next = ANY_SEXP_NIL;
+ any_sexp_t cons = sexp,
+ prev = ANY_SEXP_NIL,
+ next = ANY_SEXP_NIL;
- while (ANY_SEXP_GET_CONS(cons) != NULL) {
- if (!ANY_SEXP_IS_NIL(cons) && !ANY_SEXP_IS_CONS(cons))
- return ANY_SEXP_ERROR;
+ while (ANY_SEXP_GET_CONS(cons) != NULL) {
+ if (!ANY_SEXP_IS_NIL(cons) && !ANY_SEXP_IS_CONS(cons))
+ return ANY_SEXP_ERROR;
- memcpy(&next, &ANY_SEXP_GET_CDR(cons), sizeof(any_sexp_t));
- memcpy(&ANY_SEXP_GET_CDR(cons), &prev, sizeof(any_sexp_t));
- memcpy(&prev, &cons, sizeof(any_sexp_t));
- memcpy(&cons, &next, sizeof(any_sexp_t));
- }
+ memcpy(&next, &ANY_SEXP_GET_CDR(cons), sizeof(any_sexp_t));
+ memcpy(&ANY_SEXP_GET_CDR(cons), &prev, sizeof(any_sexp_t));
+ memcpy(&prev, &cons, sizeof(any_sexp_t));
+ memcpy(&cons, &next, sizeof(any_sexp_t));
+ }
- return prev;
-}
-
-int any_sexp_stream_print(any_sexp_t sexp, any_sexp_fprintf_t fprintf, void *stream)
-{
- int c = 0;
- switch (ANY_SEXP_GET_TAG(sexp)) {
- case ANY_SEXP_TAG_ERROR:
- return fprintf(stream, "<error>");
-
- case ANY_SEXP_TAG_NIL:
- return fprintf(stream, "()");
-
- case ANY_SEXP_TAG_CONS:
- c += fprintf(stream, "(");
- while (!ANY_SEXP_IS_NIL(sexp) && !ANY_SEXP_IS_ERROR(sexp)) {
- c += any_sexp_stream_print(any_sexp_car(sexp), fprintf, stream);
- sexp = any_sexp_cdr(sexp);
-
- if (!ANY_SEXP_IS_NIL(sexp))
- c += fprintf(stream, " ");
- }
- c += fprintf(stream, ")");
- return c;
-
- case ANY_SEXP_TAG_SYMBOL:
- return fprintf(stream, "%s", ANY_SEXP_GET_SYMBOL(sexp));
-
- case ANY_SEXP_TAG_STRING:
- return fprintf(stream, "\"%s\"", ANY_SEXP_GET_STRING(sexp));
- }
-}
-
-int any_sexp_fprint(any_sexp_t sexp, FILE *file)
-{
- return any_sexp_stream_print(sexp, (any_sexp_fprintf_t)fprintf, file);
-}
-
-int any_sexp_print(any_sexp_t sexp)
-{
- return any_sexp_fprint(sexp, stdout);
+ return prev;
}
void any_sexp_free(any_sexp_t sexp)
{
- switch (ANY_SEXP_GET_TAG(sexp)) {
- case ANY_SEXP_TAG_NIL:
- case ANY_SEXP_TAG_ERROR:
- break;
-
- case ANY_SEXP_TAG_CONS:
- any_sexp_free(any_sexp_car(sexp));
- any_sexp_free(any_sexp_cdr(sexp));
- ANY_SEXP_FREE(ANY_SEXP_GET_CONS(sexp));
- break;
-
- case ANY_SEXP_TAG_SYMBOL:
- case ANY_SEXP_TAG_STRING:
- ANY_SEXP_FREE(ANY_SEXP_GET_SYMBOL(sexp));
- break;
- }
+ switch (ANY_SEXP_GET_TAG(sexp)) {
+ case ANY_SEXP_TAG_NIL:
+ case ANY_SEXP_TAG_ERROR:
+ break;
+
+ case ANY_SEXP_TAG_CONS:
+ any_sexp_free(any_sexp_car(sexp));
+ any_sexp_free(any_sexp_cdr(sexp));
+ ANY_SEXP_FREE(ANY_SEXP_GET_CONS(sexp));
+ break;
+
+ case ANY_SEXP_TAG_SYMBOL:
+ case ANY_SEXP_TAG_STRING:
+ ANY_SEXP_FREE(ANY_SEXP_GET_SYMBOL(sexp));
+ break;
+ }
}
#endif
diff --git a/test/sexp.c b/test/sexp.c
index f6f0b5e..c15b53e 100644
--- a/test/sexp.c
+++ b/test/sexp.c
@@ -7,27 +7,27 @@
int main()
{
- const char *s = "(a b c (sub list) ())\n"
- "(another lispy thingy)\n"
- "() id ciao 20 a1020|x|3a\n"
- ";comm\n3433 ;s\n"
- "'symbol 'another 'a\n"
- "'(a b c) '('a) ''x \"escape \\\"inside the string\"\n"
- "\"string very long sus\" (\"a\" \"b\")\n";
+ const char *s = "(a b c (sub list) ())\n"
+ "(another lispy thingy)\n"
+ "() id ciao 20 a1020|x|3a\n"
+ ";comm\n3433 ;s\n"
+ "'symbol 'another 'a\n"
+ "'(a b c) '('a) ''x \"escape \\\"inside the string\"\n"
+ "\"string very long sus\" (\"a\" \"b\")\n";
- any_sexp_string_stream_t stream;
- any_sexp_parser_t parser;
- any_sexp_parser_init_string(&parser, &stream, s, strlen(s));
+ any_sexp_reader_t reader;
+ any_sexp_reader_string_t string;
+ any_sexp_reader_string_init(&reader, &string, s, strlen(s));
- 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);
- }
+ any_sexp_t sexp = any_sexp_read(&reader);
+ while (!ANY_SEXP_IS_ERROR(sexp)) {
+ any_sexp_print(sexp);
+ putchar('\n');
+ any_sexp_free(sexp);
+ sexp = any_sexp_read(&reader);
+ }
- //printf("%zu\n", sizeof(any_sexp_t));
+ //printf("%zu\n", sizeof(any_sexp_t));
- return 0;
+ return 0;
}