Beginning of Lisp parser
diff --git a/src/lisp/.clang-format b/src/lisp/.clang-format
new file mode 100644
index 0000000..bfc16c1
--- /dev/null
+++ b/src/lisp/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Microsoft
+
+AlignAfterOpenBracket: Align
+SpacesInSquareBrackets: true
+SpaceInEmptyBlock: true
+SpacesInConditionalStatement: true
+SpaceBeforeParens: Always
+UseTab: ForIndentation
+TabWidth: 4
+ColumnLimit: 80
diff --git a/src/lisp/Jmk b/src/lisp/Jmk
new file mode 100644
index 0000000..5fc5fc4
--- /dev/null
+++ b/src/lisp/Jmk
@@ -0,0 +1,18 @@
+init(lisp, lisp)
+
+preset(optimize)
+preset(32)
+preset(debug)
+preset(warn)
+
+archetype(c)
+
+OBJECTS = main.o lisp.o
+
+type(executable)
+
+run: lisp
+ status_log(RUN, ./lisp)
+ @./lisp
+
+finish
diff --git a/src/lisp/lisp b/src/lisp/lisp
new file mode 100755
index 0000000..5f8e81b
--- /dev/null
+++ b/src/lisp/lisp
Binary files differ
diff --git a/src/lisp/lisp.c b/src/lisp/lisp.c
new file mode 100644
index 0000000..be75adf
--- /dev/null
+++ b/src/lisp/lisp.c
@@ -0,0 +1,257 @@
+#include "lisp.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define MIN(a, b) (a)>(b)?(b):(a)
+
+struct alloc_list *first_a = NULL, *last_a = NULL;
+
+struct value cons (struct value car, struct value cdr)
+{
+ struct cons *c = malloc (sizeof (struct cons));
+
+ struct alloc_list *item = malloc (sizeof (struct alloc_list));
+ item->type = T_CONS;
+ item->data.cons_val = c;
+
+ if ( last_a )
+ {
+ item->prev = last_a;
+ last_a->next = item;
+ item->next = NULL;
+ }
+ else
+ {
+ item->prev = item->next = NULL;
+ first_a = last_a = item;
+ }
+
+ struct value v;
+ v.tag.type = T_CONS;
+ v.value.cons_val = c;
+
+ return v;
+}
+
+void skipws (struct istream *is)
+{
+ while ( isspace (is->peek (is)) )
+ is->get (is);
+}
+
+bool isallowedchar (char c)
+{
+ return (c >= '#' && c <= '\'') ||
+ (c >= '*' && c <= '/') ||
+ (c >= '>' && c <= '@');
+}
+
+bool issymstart (char c)
+{
+ return isalpha (c) || isallowedchar (c);
+}
+
+bool issym (char c)
+{
+ return isalpha (c) || isallowedchar (c) || isdigit (c);
+}
+
+bool readsym (struct istream *is, struct value *val)
+{
+ skipws (is);
+
+ if ( !issymstart (is->peek (is)) )
+ return false;
+
+ int size = 8;
+ char *s = malloc (size);
+
+ s[0] = is->get (is);
+
+ for ( int i = 1; ; i++ )
+ {
+ if ( issym (is->peek (is)) )
+ {
+ if ( i >= size )
+ {
+ size *= 2;
+ s = realloc (s, size);
+ }
+
+ s[i] = is->get (is);
+ }
+ else
+ {
+ s[i] = 0;
+ val->tag.type = T_SYMBOL;
+ val->tag.length = i - 1;
+ val->value.symbol_val = s;
+
+ return true;
+ }
+ }
+}
+
+bool readstr (struct istream *is, struct value *val)
+{
+ skipws (is);
+
+ if ( is->peek (is) != '"' )
+ return false;
+
+ bool escape = false;
+ int size = 8;
+ char *s = malloc (size);
+
+ (void) is->get (is);
+
+ for ( int i = 0; ; i++ )
+ {
+ if ( is->peek (is) != '"' )
+ {
+ if ( i >= size )
+ {
+ i *= 2;
+ s = realloc (s, i);
+ }
+
+ char c = is->get (is);
+
+ if ( escape && c == 'n' )
+ c = '\n';
+ else if ( escape && c == '\\' )
+ c = '\\';
+
+ if ( c == '\\' && !escape )
+ {
+ escape = true;
+ i--; // will be incremented again, UGLY.
+ }
+ else
+ {
+ escape = false;
+ s[i] = c;
+ }
+ }
+ else
+ {
+ is->get (is);
+
+ val->tag.type = T_STRING;
+ val->tag.length = i;
+ val->value.string_val = s;
+
+ return true;
+ }
+ }
+}
+
+void printval (struct value v, int depth)
+{
+ for ( int i = 0; i < depth; i++ )
+ printf(" ");
+
+ switch (v.tag.type)
+ {
+ case T_SYMBOL:
+ printf ("'%s\n", v.value.symbol_val);
+ return;
+ case T_STRING:
+ printf ("\"%s\"\n", v.value.string_val);
+ return;
+ default:
+ printf ("<unknown %d>\n", v.tag.type);
+ }
+}
+
+bool read1 (struct istream *is, struct value *val)
+{
+ if ( readsym (is, val) )
+ return true;
+
+ if ( readstr (is, val) )
+ return true;
+
+ return false;
+}
+
+struct stristream_private
+{
+ char *val;
+ int i;
+ int length;
+};
+
+int stristream_peek (struct istream *is)
+{
+ struct stristream_private *p = is->data;
+
+ if ( p->i < p->length )
+ return p->val[ p->i ];
+ else
+ return -1;
+}
+
+int stristream_get (struct istream *is)
+{
+ struct stristream_private *p = is->data;
+
+ if ( p->i < p->length )
+ return p->val[ p->i++ ];
+ else
+ return -1;
+
+}
+
+int stristream_read (struct istream *s, char *buffer, int size)
+{
+ struct stristream_private *p = s->data;
+
+ int len = MIN (size, p->length - p->i);
+ memcpy (buffer, p->val, len);
+ return len;
+}
+
+struct istream *new_stristream (char *str, int length)
+{
+ struct istream *is = malloc (sizeof (struct istream));
+ struct stristream_private *p = malloc (sizeof (struct stristream_private));
+
+ p->val = strndup (str, length);
+ p->i = 0;
+ p->length = length;
+
+ is->data = p;
+ is->get = stristream_get;
+ is->peek = stristream_peek;
+ is->read = stristream_read;
+
+ return is;
+}
+
+void del_stristream(struct istream *stristream)
+{
+ struct stristream_private *p = stristream->data;
+ free (p->val);
+ free (p);
+ free (stristream);
+}
+
+struct istream *new_stristream_nt (char *str)
+{
+ return new_stristream(str, strlen(str));
+}
+
+bool startswith (struct istream *s, const char *pattern)
+{
+ const char *check = strdup (pattern);
+ s->read (s, check, strlen (pattern));
+
+ bool res = strcmp (check, pattern) == 0;
+ free (check);
+
+ return res;
+}
diff --git a/src/lisp/lisp.h b/src/lisp/lisp.h
new file mode 100644
index 0000000..016f8e5
--- /dev/null
+++ b/src/lisp/lisp.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <stdbool.h>
+
+extern unsigned int cons_magic;
+
+enum type
+{
+ T_INT = 0,
+ T_FLOAT,
+ T_NIL,
+ T_SYMBOL,
+ T_STRING,
+ T_VECTOR,
+ T_CLASS,
+ T_CONS,
+};
+
+struct tag
+{
+ unsigned int type : 3;
+ unsigned int length : 29;
+} __attribute__ ((packed));
+
+struct cons;
+
+union value_type {
+ int int_val;
+ float float_val;
+ struct cons *cons_val;
+ char *symbol_val; // interned
+ char *string_val;
+};
+
+struct value
+{
+ struct tag tag;
+ union value_type value;
+} __attribute__ ((packed));
+
+struct cons
+{
+ int magic;
+ int marked; // must be reserved
+ struct value car, cdr;
+};
+
+struct alloc_list
+{
+ int type;
+ union value_type data;
+ struct alloc_list *next, *prev;
+};
+
+struct istream
+{
+ void *data;
+
+ // These two return -1 on error
+ int (*peek) (struct istream *s);
+ int (*get) (struct istream *s);
+
+ int (*read) (struct istream *s, char *buffer, int size);
+};
+
+bool startswith (struct istream *s, const char *pattern);
+
+bool readsym (struct istream *is, struct value *val);
+bool readstr (struct istream *is, struct value *val);
+
+struct value cons (struct value car, struct value cdr);
+bool read1 (struct istream *is, struct value *val);
+struct value read (struct istream);
+struct value readn (struct istream);
+
+void printval (struct value v, int depth);
+
+struct istream *new_stristream (char *str, int length);
+// same as above but null terminated
+struct istream *new_stristream_nt (char *str);
+void del_stristream(struct istream *stristream);
diff --git a/src/lisp/main.c b/src/lisp/main.c
new file mode 100644
index 0000000..7c8224e
--- /dev/null
+++ b/src/lisp/main.c
@@ -0,0 +1,14 @@
+#include "lisp.h"
+
+int main (int argc, char **argv)
+{
+ struct istream *is = new_stristream_nt ("abcde \"asdf dsf sdf\"");
+ struct value val;
+
+ while ( read1 (is, &val) )
+ {
+ printval (val, 0);
+ }
+
+ del_stristream (is);
+}