This commit is contained in:
Jonas Maier 2022-12-16 12:45:06 +01:00
parent c4809a1393
commit acff699d2c
10 changed files with 470 additions and 61 deletions

View File

@ -4,6 +4,7 @@
#include <stdlib.h>
#include <execinfo.h>
int *FOO = NULL;
void __print_backtrace__(void)
{
void *funs[100] = {0};
@ -19,5 +20,7 @@ void __print_backtrace__(void)
printf(" %s\n", names[i]);
}
++*FOO;
exit(-1);
}

View File

@ -269,6 +269,7 @@ static ptr panic(ptr i)
printf("error: ");
println(get_head(i));
failwith("explicit panic");
return 0;
}
static ptr concat_sym(ptr i)
@ -276,7 +277,8 @@ static ptr concat_sym(ptr i)
i = eval_elems(i);
int len = 0;
ptr cursor = i;
while (kind(cursor) == T_CON) {
while (kind(cursor) == T_CON)
{
len += strlen(get_symbol_str(get_symbol(get_head(cursor))));
cursor = get_tail(cursor);
}
@ -285,7 +287,8 @@ static ptr concat_sym(ptr i)
char buf[SYM_SIZE] = {0};
cursor = i;
while (kind(cursor) == T_CON) {
while (kind(cursor) == T_CON)
{
strcat(buf, get_symbol_str(get_symbol(get_head(cursor))));
cursor = get_tail(cursor);
}
@ -297,13 +300,45 @@ static ptr progn(ptr i)
{
i = eval_elems(i);
ptr result = new_nil();
while (kind(i) == T_CON) {
while (kind(i) == T_CON)
{
result = get_head(i);
i = get_tail(i);
}
return result;
}
static ptr read(ptr i)
{
i = eval_elems(i);
i = get_head(i);
ptr cursor = i;
i64 size = 0;
while (kind(cursor) == T_CON)
{
size++;
cursor = get_tail(cursor);
}
printf("%d\n\n", size);
char buf[size+1];
cursor = i;
i64 k = 0;
while (kind(cursor) == T_CON)
{
buf[k++] = (char) get_int(get_head(cursor));
cursor = get_tail(cursor);
}
buf[k] = 0;
char *buf_ptr = &(buf[0]);
return parse(&buf_ptr);
}
void register_builtins(void)
{
new_builtin(&eq, "=");
@ -325,6 +360,7 @@ void register_builtins(void)
new_builtin(&is_pair, "pair?");
new_builtin(&is_list, "list?");
new_builtin(&read, "read");
new_builtin(&eval_quote, "quote");
new_builtin(&eval_quasiquote, "quasiquote");

View File

@ -2,7 +2,7 @@
#define __CONST_H__
// number of "values" that can be stored in the interpreter
#define MEM_LEN 100000
#define MEM_LEN 10000000
// maximal usage in percent:
// this is to avoid repeatedly running the garbage collector to free

45
eval.c
View File

@ -3,6 +3,7 @@
static ptr (*builtins[MAX_BUILTINS])(ptr) = {0};
static int builtins_len = 1;
static int debug = 0;
void new_builtin(ptr (*fun)(ptr), char *sym)
{
@ -94,6 +95,10 @@ static ptr beta_reduce(ptr code, ptr formal_arg, ptr arg, int inside_quote)
ptr eval(ptr i)
{
if (debug) {
printf("[DEBUG] ");
println(i);
}
switch (kind(i))
{
case T_NAT:
@ -135,7 +140,14 @@ ptr eval(ptr i)
return builtins[-fun](args);
}
if (kind(fun) != T_CON) {
if (is_pragma(fun))
{
debug = 1;
return new_nil();
}
if (kind(fun) != T_CON)
{
printf("unexpected form of function application: (");
print(fun);
@ -145,7 +157,11 @@ ptr eval(ptr i)
ptr fun_head = elem(0, fun);
assert(is_functionlike(fun_head));
if (!is_functionlike(fun_head))
{
println(fun_head);
assert(is_functionlike(fun_head));
}
if (is_lambda(fun_head))
{
@ -156,17 +172,40 @@ ptr eval(ptr i)
ptr formal_args = elem(1, fun);
ptr fun_body = elem(2, fun);
// TODO Partial app
int partial_args_len = 0;
ptr partial_args[10];
while (kind(formal_args) != T_NIL)
{
ptr f_arg = get_head(formal_args);
ptr c_arg = get_head(args);
fun_body = beta_reduce(fun_body, f_arg, c_arg, false);
if (is_partial_app(c_arg))
{
partial_args[partial_args_len++] = f_arg;
assert(partial_args_len < 10);
}
else
{
fun_body = beta_reduce(fun_body, f_arg, c_arg, false);
}
formal_args = get_tail(formal_args);
args = get_tail(args);
}
// in this case we just return a different lambda
if (partial_args_len > 0)
{
ptr new_formal_args = new_nil();
while (partial_args_len)
{
new_formal_args = new_cons(partial_args[--partial_args_len], new_formal_args);
}
return new_cons(fun_head, new_cons(new_formal_args, new_cons(fun_body, new_nil())));
}
if (is_macro(fun_head))
{
// macro expansion

61
input.txt Normal file
View File

@ -0,0 +1,61 @@
Valve WT has flow rate=0; tunnels lead to valves BD, FQ
Valve UG has flow rate=0; tunnels lead to valves FQ, YB
Valve FN has flow rate=0; tunnels lead to valves TV, GA
Valve RU has flow rate=11; tunnels lead to valves YZ, QS, BL, BT, WJ
Valve RH has flow rate=0; tunnels lead to valves AS, II
Valve FL has flow rate=0; tunnels lead to valves HR, PQ
Valve KQ has flow rate=18; tunnels lead to valves FR, BN
Valve PM has flow rate=25; tunnels lead to valves YZ, FR
Valve RQ has flow rate=0; tunnels lead to valves FQ, MW
Valve BL has flow rate=0; tunnels lead to valves RU, IR
Valve FF has flow rate=0; tunnels lead to valves QS, ED
Valve KP has flow rate=0; tunnels lead to valves QM, MA
Valve YB has flow rate=0; tunnels lead to valves UG, HR
Valve TV has flow rate=17; tunnels lead to valves BD, MT, FN
Valve HY has flow rate=0; tunnels lead to valves DW, IU
Valve KF has flow rate=0; tunnels lead to valves AA, HR
Valve YC has flow rate=0; tunnels lead to valves II, MA
Valve EE has flow rate=0; tunnels lead to valves AA, CD
Valve ED has flow rate=9; tunnels lead to valves HG, FF
Valve SA has flow rate=0; tunnels lead to valves MW, LS
Valve II has flow rate=20; tunnels lead to valves YC, CY, QP, RH
Valve BN has flow rate=0; tunnels lead to valves BT, KQ
Valve MO has flow rate=0; tunnels lead to valves XO, VI
Valve YZ has flow rate=0; tunnels lead to valves RU, PM
Valve WJ has flow rate=0; tunnels lead to valves RU, QP
Valve AW has flow rate=0; tunnels lead to valves HR, DW
Valve MJ has flow rate=0; tunnels lead to valves BP, AA
Valve DW has flow rate=4; tunnels lead to valves AU, CB, HY, GL, AW
Valve QM has flow rate=0; tunnels lead to valves KP, FQ
Valve LF has flow rate=5; tunnels lead to valves LS, QN, AU, BP, ZY
Valve QS has flow rate=0; tunnels lead to valves FF, RU
Valve BT has flow rate=0; tunnels lead to valves BN, RU
Valve VI has flow rate=22; tunnel leads to valve MO
Valve LS has flow rate=0; tunnels lead to valves LF, SA
Valve QD has flow rate=0; tunnels lead to valves HR, ZY
Valve HG has flow rate=0; tunnels lead to valves AS, ED
Valve BD has flow rate=0; tunnels lead to valves WT, TV
Valve CD has flow rate=0; tunnels lead to valves EE, MW
Valve QP has flow rate=0; tunnels lead to valves II, WJ
Valve MW has flow rate=7; tunnels lead to valves PQ, SA, CB, CD, RQ
Valve AU has flow rate=0; tunnels lead to valves DW, LF
Valve RR has flow rate=0; tunnels lead to valves AS, MA
Valve GA has flow rate=0; tunnels lead to valves FN, MA
Valve MT has flow rate=0; tunnels lead to valves CY, TV
Valve HR has flow rate=14; tunnels lead to valves KF, YB, QD, AW, FL
Valve AS has flow rate=16; tunnels lead to valves RR, RH, HG, IR
Valve CY has flow rate=0; tunnels lead to valves MT, II
Valve AA has flow rate=0; tunnels lead to valves OX, KF, GL, MJ, EE
Valve IU has flow rate=0; tunnels lead to valves XO, HY
Valve XO has flow rate=23; tunnels lead to valves IU, MO
Valve FR has flow rate=0; tunnels lead to valves KQ, PM
Valve CB has flow rate=0; tunnels lead to valves MW, DW
Valve ZY has flow rate=0; tunnels lead to valves QD, LF
Valve BP has flow rate=0; tunnels lead to valves LF, MJ
Valve QN has flow rate=0; tunnels lead to valves LF, FQ
Valve IR has flow rate=0; tunnels lead to valves AS, BL
Valve PQ has flow rate=0; tunnels lead to valves FL, MW
Valve GL has flow rate=0; tunnels lead to valves AA, DW
Valve OX has flow rate=0; tunnels lead to valves MA, AA
Valve MA has flow rate=10; tunnels lead to valves RR, YC, GA, OX, KP
Valve FQ has flow rate=12; tunnels lead to valves QN, WT, UG, RQ, QM

288
lisp
View File

@ -10,8 +10,6 @@
)
))
(if (= 0 0) 1 2)
(def fold (.\ (init fun list)
(if (pair? list)
(fold (fun init (hd list)) fun (tl list))
@ -66,6 +64,8 @@
`(def #name (.\ #args #body))
)
(defun /= (x y) (nil? (= x y)))
(defun square(x) (* x x))
(square 9)
@ -301,44 +301,274 @@ Point
(symcat 'he 'he 'ho)
(def input nil)
(typedfun max ((list? values))
(fold 0 (.\ (x y) (cond ((< x y) y) (else x))) values)
)
(defun split.aux (split_val values)
(cond
((nil? values) nil)
((= split_val (hd values)) (cons nil (split.aux split_val (tl values))))
(else (let split' (split.aux split_val (tl values))
(cond
((nil? split') (list (list (hd values))))
(else (cons
(cons (hd values) (hd split'))
(tl split')
))
)
))
)
(typedfun min ((list? values))
(fold 1000000000 (.\ (x y) (cond ((< x y) x) (else y))) values)
)
(typedfun split ((any? split_val) (list? values))
(let result (split.aux split_val values)
(cond
((nil? result) nil)
((nil? (fst result)) (tl result))
(else result)
(defun split.aux(delimiter array)
(cond
((nil? array)
(list nil nil))
(else
(let res (split.aux delimiter (tl array))
(cond
((/= delimiter (fst array))
(list (cons (fst array) (fst res)) (snd res)))
(else
(list nil (cons (fst res) (snd res))))
))
)
)
)
(max input)
(defun split (delimiter array)
(snd (split.aux delimiter (cons delimiter array)))
)
(split 5 '(1 2 3 5 4))
(split 5 '(1 2 3 5 4 5))
(split 5 '(5 1 2 5 3 5 4 5))
(typedfun sum((list? x)) (fold 0 + x))
(defun succ(x) (+ 1 x))
(typedfun len((list? x)) (fold 0 succ x))
(defun pow(a b)
(cond
((= 0 b) 1)
(else (* a (pow a (- b 1))))
)
)
(split (hd ",") "hello, world!")
(typedfun string->int ((list? str))
(let digit (- (hd str) (hd "0"))
(let res (tl str)
(cond
((nil? res) digit)
(else (+
(string->int res)
(* digit
(pow 10 (len res))
)
))
)
)))
(defun take(n xs)
(cond
((= n 0)
nil)
((nil? xs)
nil)
(else
(cons (hd xs) (take (- n 1) (tl xs))))
)
)
(defun drop(n xs)
(cond
((= n 0)
xs)
(else
(drop (- n 1) (tl xs)))
)
)
(defun contains(x xs)
(cond
((nil? xs) nil)
((= x (hd xs)) true)
(else (contains x (tl xs)))
)
)
(defun mod(x y)
(- x (* y (/ x y)))
)
(defun chunk.aux(size xs)
(cond
((nil? xs)
(list nil nil))
(else
(let rest (chunk.aux size (tl xs))
(cond
((= size (len (fst rest)))
(list (list (hd xs)) (cons (fst rest) (snd rest))))
(else
(list (cons (hd xs) (fst rest)) (snd rest)))
))
)
)
)
(typedfun chunk((int? size) (list? xs))
(let sol (chunk.aux size xs)
(filter id (cons (fst sol) (snd sol))))
)
(defun flatten(xss)
(fold (hd xss) concat (tl xss))
)
(defun half(xs)
(let half_len (/ (len xs) 2)
(list
(take half_len xs)
(drop half_len xs)
))
)
(defun find_same(yss)
(let xs (hd yss)
(let ys (tl yss)
(fst
(filter
(.\ (x)
(all (.\ (y) (contains x y)) ys))
xs)
))))
)
(defun and(a b)
(cond (a (cond (b true))))
)
(defun range(begin end)
(iter (- end begin) succ begin)
)
(def in
(map (.\ (l) (drop 6 l))
(filter id
(split 10
input)))
)
(defun remove_space(string)
(filter (.\ (char) (/= (hd " ") char)) string)
)
(defun parse_valve(line)
(let name (take 2 line)
(let flow
(string->int
(fst
(split (hd ";")
(snd
(split (hd "=")
line)))))
(let conns
(map remove_space
(split (hd ",")
(drop 24
(snd
(split (hd ";")
line)))))
`(#name #flow #conns))))
)
(def valves
(map parse_valve in)
)
(def name fst)
(def flow snd)
(def conn trd)
(defun maybe_head(list)
(cond
((nil? list) nil)
(else (hd list))
)
)
(defun or (x y)
(cond
(x x)
(1 y)
)
)
(defun map.new() nil)
(defun map.get_or(m key default)
(or (map.get m key) default)
)
(defun map.get_all(m key)
(map snd
(filter (.\ (entry) (= key (fst entry)))
m))
)
(defun map.get(map key)
(maybe_head (map.get_all map key))
)
(defun map.update(m key fun)
(map.ins m key (maybe_head (map fun (map.get_all m key))))
)
(defun map.update_or(map key default fun)
(map.ins map key (fun (map.get_or map key default)))
)
(defun map.rem(map key)
(filter (.\ (entry) (/= key (fst entry))) map)
)
(defun map.ins(map key val)
(cons
`(#key #val)
(map.rem map key)
)
)
(defun map.keys(m)
(map fst m)
)
(def infty 10000000)
(def key fst)
(def val snd)
'valves
valves
(def names (map name valves))
'names
names
(defun repeat(amt list)
(cond
((= 0 amt) nil)
(else (concat list (repeat (- amt 1) list)))
)
)
(defun make2(x) `(#x #x))
(def edges (flatten (map (.\ (vertex) (map (.\ (neighbor) (list (name vertex) neighbor)) (conn vertex))) valves)))
(def dist0 (fold (map.new) (map.ins .. .. 0) (map make2 names)))
(defun smoler(a b)
(cond
((< a b) a)
(else b)
)
)
dist0
(fold
dist0
(.\ (dist edge)
(fold
dist
(.\ (d entry)
(let from (fst edge)
(let to (snd (key entry))
(let len (+ 1 (val entry))
(let e `(#from #to)
(map.update_or d e infty (smoler .. len))
)))))
(filter (.\ (entry) (= (snd edge) (fst (key entry)))) dist)
)
)
(repeat 30 edges)
)
(= edges (repeat 1 edges))
'(end of program)

2
lisp.c
View File

@ -38,7 +38,7 @@ int main(void)
lisp[fsize] = 0;
init();
dump();
//dump();
char *lisp_ptr = &lisp[0];
char **cursor = &lisp_ptr;

2
lisp.h
View File

@ -97,6 +97,8 @@ int is_lambda(ptr i);
int is_macro(ptr i);
int is_functionlike(ptr i);
int is_definition(ptr i);
int is_partial_app(ptr i);
int is_pragma(ptr i);
void print(ptr i);
void println(ptr i);

84
mem.c
View File

@ -17,17 +17,19 @@ should never be GC'ed
static ptr builtin_use;
#define make(name) \
static ptr sym_ ## name = 0; \
int is_ ## name(ptr i) \
{ \
return i == sym_ ## name; \
}
make(quote)
make(unquote)
make(quasiquote)
make(lambda)
make(macro)
make(definition)
static ptr sym_##name = 0; \
int is_##name(ptr i) \
{ \
return i == sym_##name; \
}
make(quote);
make(unquote);
make(quasiquote);
make(lambda);
make(macro);
make(definition);
make(partial_app);
make(pragma);
#undef make
int is_functionlike(ptr i)
@ -57,9 +59,40 @@ static void init_builtin_symbols(void)
make_sym(sym_quote, "quote");
make_sym(sym_unquote, "unquote");
make_sym(sym_quasiquote, "quasiquote");
make_sym(sym_partial_app, "..");
make_sym(sym_pragma, "pragma");
#undef make_sym
}
/*
reads the input file
*/
void read_input(void)
{
FILE *f = fopen("input.txt", "rb");
assert(f);
fseek(f, 0, SEEK_END);
size_t fsize = (size_t)ftell(f);
fseek(f, 0, SEEK_SET);
char *buf = malloc(fsize + 1);
assert(buf);
fread(buf, fsize, 1, f);
fclose(f);
buf[fsize] = 0;
ptr input = new_nil();
for (char *cursor = buf + fsize - 1; cursor >= buf; cursor--)
{
input = new_cons(new_int(*cursor), input);
}
new_binding(new_symbol("input"), input);
free(buf);
}
/*
initializes the interpreter
do NOT call twice
@ -67,12 +100,12 @@ do NOT call twice
void init(void)
{
static int initialized = 0;
if (initialized) {
if (initialized)
{
failwith("already initialized");
}
initialized = 1;
mem[0].kind = T_NIL;
mem[1].kind = T_INT;
@ -97,6 +130,7 @@ void init(void)
init_builtin_symbols();
register_builtins();
builtin_use = empty;
read_input();
}
/* GC run count */
@ -120,16 +154,17 @@ static void mark_globals(void)
ptr *walker;
/*
searches the entire C stack for references to LISP values
/*
searches the entire C stack for references to LISP values
if it finds any, it marks those values as 'in use'
*/
void stack_search_impl(void)
{
ptr dummy = 0;
walker = &dummy;
while (++walker != stack_top) {
if (*walker < MEM_LEN && *walker > 0)
while (++walker != stack_top)
{
if (*walker<MEM_LEN && * walker> 0)
{
mem[*walker].gc = gen;
}
@ -144,7 +179,8 @@ if it is a freshly marked value, it will also mark the child values
*/
static void maybe_mark(ptr i)
{
if (i < 0) return;
if (i < 0)
return;
if (mem[i].gc != gen)
{
mem[i].gc = gen;
@ -175,7 +211,7 @@ static void mark_all_reachable(void)
}
}
/*
/*
marks all unreachable nodes as 'empty' and make them available to be reused
*/
static void reconstruct_empty_list(void)
@ -204,14 +240,15 @@ static void reconstruct_empty_list(void)
empty = prev_empty;
int usage = 100 - 100 * free_memory / MEM_LEN;
//printf("GC go brrrr... (%d%%)\n", usage);
if (usage > MAX_MEMORY_USAGE || usage > 99) {
// printf("GC go brrrr... (%d%%)\n", usage);
if (usage > MAX_MEMORY_USAGE || usage > 99)
{
printf("Out of memory.\n");
exit(-1);
}
}
/*
/*
garbage collector to free up nodes
does not return if out of memory, instead will stop program
*/
@ -242,7 +279,8 @@ static ptr alloc(void)
return new;
}
static void check(ptr i) {
static void check(ptr i)
{
if (i >= 0 && i < MEM_LEN)
{
if (mem[i].gc == ~0 && mem[i].kind == T_EMT)

2
run.sh
View File

@ -1,6 +1,6 @@
#! /bin/sh
gcc -O3 *.c *.s \
gcc -g -Oz *.c *.s \
-o lisp.bin \
-std=c17 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wstrict-prototypes -Wmissing-prototypes