Add argument variable binding
diff --git a/src/lisp/Jmk b/src/lisp/Jmk
index aa75bf6..4d0825f 100644
--- a/src/lisp/Jmk
+++ b/src/lisp/Jmk
@@ -17,7 +17,8 @@
lisp.o \
compiler.o \
lib/std.o \
- plat/linux.o
+ plat/linux.o \
+ istream.o
LUA = vendor/luajit/src/host/minilua
@@ -33,7 +34,7 @@
run: lisp
status_log(RUN, ./lisp)
- @./lisp "$$(cat test.lisp)"
+ @./lisp ./test.lisp
format:
status_log(FORMAT, *)
diff --git a/src/lisp/compiler.dasc b/src/lisp/compiler.dasc
index 2ac21f3..3040e45 100644
--- a/src/lisp/compiler.dasc
+++ b/src/lisp/compiler.dasc
@@ -7,6 +7,9 @@
#include <dasm_proto.h>
#include <dasm_x86.h>
+#include <stdlib.h>
+#include <string.h>
+
#define value_size sizeof(value_t)
|.arch x86;
@@ -73,6 +76,7 @@
dasm_growpc(&d, local.npc);
// Generate code
+ // TODO: first pass, extract bound and free variables
| setup 0;
@@ -84,6 +88,17 @@
if ((name & HEAP_MASK) != SYMBOL_TAG)
err("function name must be a symbol");
+ value_t a = arglist;
+ for (int i = 0; !nilp(a); a = cdr(a), i++)
+ {
+ if (!symbolp(car(a)))
+ {
+ err("defun argument must be a symbol");
+ }
+
+ add_variable(&local, V_ARGUMENT, (char *)(car(a) ^ SYMBOL_TAG), i);
+ }
+
for (; !nilp(body); body = cdr(body))
{
compile_expression(env, &local, car(body), Dst);
@@ -131,7 +146,11 @@
{
| mov eax, (nil);
}
- else if (integerp(val) || stringp(val) || symbolp(val))
+ else if (symstreq(val, "t"))
+ {
+ | mov eax, (t);
+ }
+ else if (integerp(val) || stringp(val))
{
| mov eax, val;
}
@@ -161,7 +180,7 @@
compile_expression(env, local, elt(args, 1), Dst);
| jmp =>after_label;
- |=>false_label:
+ |=>false_label:;
if (nargs == 3)
compile_expression(env, local, elt(args, 2), Dst);
|=>after_label:
@@ -171,6 +190,9 @@
struct function *func =
find_function(env, (char *)(fsym ^ SYMBOL_TAG));
+ if (func == NULL)
+ err("Function undefined");
+
if (nargs != func->nargs)
err("wrong number of args");
@@ -182,10 +204,27 @@
| mov ebx, (func->code_addr);
| call ebx;
- | add esp, (nargs * 4);
+ | add esp, (nargs * value_size);
// result in eax
}
}
+ else if (symbolp(val))
+ {
+ // For now ignore global variables, only search locally
+ struct variable *v = find_variable(local, (char *)(val ^ SYMBOL_TAG));
+
+ if (!v)
+ err("Variable unbound");
+
+ switch (v->type)
+ {
+ case V_ARGUMENT:
+ | mov eax, dword [ebp + value_size * (v->number + 2)];
+ break;
+ default:
+ err("Sorry, can only access V_ARGUMENT variables for now :(");
+ }
+ }
}
void compile_expr_to_func(struct environment *env, char *name, value_t val,
@@ -200,3 +239,37 @@
add_function(env, name, link(Dst), 0);
}
+
+struct variable *add_variable(struct local *local, enum var_type type,
+ char *name, int number)
+{
+ struct variable *var = malloc(sizeof(struct variable));
+ var->prev = local->first;
+ var->type = type;
+ var->name = name;
+ var->number = number;
+
+ local->first = var;
+
+ return var;
+}
+
+void destroy_local(struct local *local)
+{
+ for (struct variable *v = local->first; v;)
+ {
+ struct variable *t = v;
+ v = v->prev;
+ free(t);
+ }
+}
+
+struct variable *find_variable(struct local *local, char *name)
+{
+ struct variable *v = local->first;
+
+ for (; v && strcmp(v->name, name) != 0; v = v->prev)
+ {}
+
+ return v;
+}
diff --git a/src/lisp/compiler.h b/src/lisp/compiler.h
index ae66001..4d8ffba 100644
--- a/src/lisp/compiler.h
+++ b/src/lisp/compiler.h
@@ -27,10 +27,19 @@
struct function *first;
};
+enum var_type
+{
+ V_BOUND, // Bound local variable
+ V_ARGUMENT, // Bound function argument
+ V_GLOBAL, // Global variable
+ V_FREE // Free (lexical) variable
+};
+
struct variable
{
char *name;
- int number;
+ uintptr_t number;
+ enum var_type type;
struct variable *prev;
};
@@ -52,3 +61,8 @@
void compile_tl(value_t val, struct environment *env);
struct environment compile_all(struct istream *is);
struct function *find_function(struct environment *env, char *name);
+struct variable *add_variable(struct local *local, enum var_type type,
+ char *name, int number);
+// Might return null
+struct variable *find_variable(struct local *local, char *name);
+void destroy_local(struct local *local);
diff --git a/src/lisp/istream.c b/src/lisp/istream.c
new file mode 100644
index 0000000..9351adf
--- /dev/null
+++ b/src/lisp/istream.c
@@ -0,0 +1,208 @@
+#include "istream.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct stristream_private
+{
+ char *val;
+ int i;
+ int length;
+ int line;
+ int fromleft;
+ int linestart;
+};
+
+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)
+ {
+ char c = p->val[p->i++];
+
+ p->fromleft++;
+
+ if (c == '\n')
+ {
+ p->fromleft = 1;
+ p->line++;
+ p->linestart = p->i;
+ }
+
+ return c;
+ }
+ 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;
+}
+
+void stristream_showpos(struct istream *s, FILE *out)
+{
+ struct stristream_private *p = s->data;
+
+ fprintf(out, "line: %d, char %d\n", p->line, p->fromleft);
+
+ int end = p->length;
+
+ for (int i = p->linestart; i < p->length; i++)
+ {
+ if (p->val[i] == '\n')
+ {
+ end = i;
+ break;
+ }
+ }
+
+ fprintf(out, " | %.*s\n", end - p->linestart, p->val + p->linestart);
+ fprintf(out, " | ");
+ for (int i = 0; i < p->fromleft - 1; i++)
+ fprintf(out, " ");
+
+ fprintf(out, "\033[31m^\033[0m\n");
+}
+
+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;
+ p->line = 1;
+ p->fromleft = 1;
+ p->linestart = 0;
+
+ is->data = p;
+ is->get = stristream_get;
+ is->peek = stristream_peek;
+ is->read = stristream_read;
+ is->showpos = stristream_showpos;
+
+ 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));
+}
+
+struct fistream_private
+{
+ FILE *file;
+ int next;
+ bool has_next;
+};
+
+int fistream_peek(struct istream *is)
+{
+ struct fistream_private *p = is->data;
+
+ if (p->has_next)
+ return p->next;
+
+ p->next = fgetc(p->file);
+ p->has_next = true;
+ return p->next;
+}
+
+int fistream_get(struct istream *is)
+{
+ struct fistream_private *p = is->data;
+
+ if (p->has_next)
+ {
+ p->has_next = false;
+ return p->next;
+ }
+
+ return fgetc(p->file);
+}
+
+int fistream_read(struct istream *is, char *buffer, int size)
+{
+ struct fistream_private *p = is->data;
+
+ int offset = 0;
+
+ if (p->has_next)
+ {
+ *buffer = p->next;
+ p->has_next = false;
+ buffer++;
+ size--;
+ offset = 1;
+ }
+
+ return (int)fread(buffer, 1, size, p->file) + offset;
+}
+
+void fistream_showpos(struct istream *s, FILE *out)
+{
+ // TODO: implement
+}
+
+struct istream *new_fistream(char *path, bool binary)
+{
+ struct istream *is = malloc(sizeof(struct istream));
+
+ FILE *fp = fopen(path, binary ? "rb" : "r");
+
+ if (fp == NULL)
+ {
+ free(is);
+ return NULL;
+ }
+
+ struct fistream_private *p = is->data =
+ malloc(sizeof(struct fistream_private));
+
+ p->has_next = false;
+ p->file = fp;
+
+ is->data = p;
+ is->get = fistream_get;
+ is->peek = fistream_peek;
+ is->read = fistream_read;
+ is->showpos = fistream_showpos;
+
+ return is;
+}
+
+void del_fistream(struct istream *is)
+{
+ struct fistream_private *p = is->data;
+
+ fclose(p->file);
+
+ free(is->data);
+ free(is);
+}
diff --git a/src/lisp/istream.h b/src/lisp/istream.h
new file mode 100644
index 0000000..aceada8
--- /dev/null
+++ b/src/lisp/istream.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#define MIN(a, b) (a) > (b) ? (b) : (a)
+
+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);
+
+ void (*showpos)(struct istream *s, FILE *out);
+};
+
+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);
+
+struct istream *new_fistream(char *path, bool binary);
+void del_fistream(struct istream *fistream);
\ No newline at end of file
diff --git a/src/lisp/lisp.c b/src/lisp/lisp.c
index 7a7d6cb..58e58e7 100644
--- a/src/lisp/lisp.c
+++ b/src/lisp/lisp.c
@@ -7,11 +7,10 @@
#include <stdlib.h>
#include <string.h>
-#define MIN(a, b) (a) > (b) ? (b) : (a)
-
struct alloc_list *first_a = NULL, *last_a = NULL;
value_t nil = 0b00101111; // magic ;)
+value_t t = 1 << 3;
void err(const char *msg)
{
@@ -282,117 +281,6 @@
return first;
}
-struct stristream_private
-{
- char *val;
- int i;
- int length;
- int line;
- int fromleft;
- int linestart;
-};
-
-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)
- {
- char c = p->val[p->i++];
-
- p->fromleft++;
-
- if (c == '\n')
- {
- p->fromleft = 1;
- p->line++;
- p->linestart = p->i;
- }
-
- return c;
- }
- 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;
-}
-
-void stristream_showpos(struct istream *s, FILE *out)
-{
- struct stristream_private *p = s->data;
-
- fprintf(out, "line: %d, char %d\n", p->line, p->fromleft);
-
- int end = p->length;
-
- for (int i = p->linestart; i < p->length; i++)
- {
- if (p->val[i] == '\n')
- {
- end = i;
- break;
- }
- }
-
- fprintf(out, " | %.*s\n", end - p->linestart, p->val + p->linestart);
- fprintf(out, " | ");
- for (int i = 0; i < p->fromleft - 1; i++)
- fprintf(out, " ");
-
- fprintf(out, "\033[31m^\033[0m\n");
-}
-
-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;
- p->line = 1;
- p->fromleft = 1;
- p->linestart = 0;
-
- is->data = p;
- is->get = stristream_get;
- is->peek = stristream_peek;
- is->read = stristream_read;
- is->showpos = stristream_showpos;
-
- 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, char *pattern)
{
char *check = strdup(pattern);
diff --git a/src/lisp/lisp.h b/src/lisp/lisp.h
index d3a0a29..48de7d4 100644
--- a/src/lisp/lisp.h
+++ b/src/lisp/lisp.h
@@ -1,5 +1,6 @@
#pragma once
+#include "istream.h"
#include <stdbool.h>
#include <stdio.h>
@@ -52,19 +53,6 @@
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);
-
- void (*showpos)(struct istream *s, FILE *out);
-};
-
bool startswith(struct istream *s, char *pattern);
bool readsym(struct istream *is, value_t *val);
@@ -95,13 +83,9 @@
void printval(value_t 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);
-
void err(const char *msg);
bool symstreq(value_t sym, char *str);
extern value_t nil;
+extern value_t t;
diff --git a/src/lisp/main.c b/src/lisp/main.c
index 5679572..b2c7590 100644
--- a/src/lisp/main.c
+++ b/src/lisp/main.c
@@ -9,11 +9,17 @@
return 1;
}
- struct istream *is = new_stristream_nt(argv[1]);
+ struct istream *is = new_fistream(argv[1], false);
+
+ if (is == NULL)
+ {
+ fprintf(stderr, "Could not open %s\n", argv[1]);
+ return 1;
+ }
struct environment env = compile_all(is);
value_t (*lisp_main)() = find_function(&env, "main")->def0;
lisp_main();
- // del_stristream (is);
+ del_fistream(is);
}
diff --git a/src/lisp/test.lisp b/src/lisp/test.lisp
index 6f4abb8..08b96ba 100644
--- a/src/lisp/test.lisp
+++ b/src/lisp/test.lisp
@@ -1,12 +1,7 @@
-(defun two-plus-two ()
- (+ 2 2))
-
-(defun hmm-main ()
- (print "64 / (2 + 2) =")
- (print (/ 64 (two-plus-two)))
- (print nil))
+(defun add-two (a)
+ (+ a 2))
(defun main ()
(if t
- (print 1)
- (print 2)))
+ (print (add-two (* 4 3)))
+ (print (- 3 6))))