Slow_Lisp prototype update

This commit is contained in:
Jeremiah Orians 2018-11-10 09:55:09 -05:00
parent f05b23ef34
commit 6f6dc7b48d
No known key found for this signature in database
GPG Key ID: 7457821534D2ACCD
14 changed files with 1652 additions and 2 deletions

View File

@ -19,6 +19,8 @@
Added support for \f, \v and \e
Added refresh to bootstrap.sh to build seed from cc_x86.s
Added missing license headers
Added support for ~expressions
Added prototype for Slow_Lisp build test
** Changed
Converted M2-Planet to use GNU style error message

View File

@ -575,6 +575,11 @@ void primary_expr()
common_recursion(postfix_expr);
emit_out("XOR_ebx_eax_into_eax\n");
}
else if('~' == global_token->s[0])
{
common_recursion(postfix_expr);
emit_out("NOT_eax\n");
}
else if(global_token->s[0] == '(')
{
global_token = global_token->next;

View File

@ -9,7 +9,7 @@ a9a3e332d13ded5f80d7431f8717f26527b3722b33ea57760a9a5723dffc099c test/results/t
f1c01feb865c4d552033186d9ce50dd39468a7e8aebf762886c13ad3e03b5011 test/results/test08-binary
3b39e72f3de90ed690adfaf6145af46157cef2ec5e72867ac577fa27a0229894 test/results/test09-binary
020e86020819cc4963e6185b22e534fcf8306b6cb116f12643f254a24688ff0a test/results/test10-binary
a9708d6e40a4c00d7afe1163a9d149d46525071e9b8a0f283d82f76b443da182 test/results/test100-binary
0c5850abb4ea2c4ba62005d6783b7b076baf86e2b960a806e10ee25dfc30b620 test/results/test100-binary
3fd11bad4a426ce1ff8fd9c6d7d2b943effae9f3f5740b7376e426e9b0555851 test/results/test11-binary
f98ab8e4bb35580e0dde96126d7a56aff66bda208d02c8d89390b40d6cff591c test/results/test12-binary
5051ffca2615144419f8ec1a5d4999486ae81e7781428f59e47e866af97cef92 test/results/test13-binary

View File

@ -1 +1 @@
b882976ea4fb2ede866851a57fd3be0653ac1918b87e183e4c1cd6cb5c60d2b4 test/test100/proof
b39435961127c9f5096e07a54c1aff13b02444d0ca07c61477558c1b1ff999a1 test/test100/proof

23
test/test26/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
## Copyright (C) 2017 Jeremiah Orians
## This file is part of M2-Planet.
##
## M2-Planet is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## M2-Planet is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with M2-Planet. If not, see <http://www.gnu.org/licenses/>.
# Ignore the files created by script
*.M1
*.hex2
proof
# A place to put a good run for comparison
actual.M1

22
test/test26/cleanup.sh Executable file
View File

@ -0,0 +1,22 @@
#! /bin/sh
## Copyright (C) 2017 Jeremiah Orians
## This file is part of M2-Planet.
##
## M2-Planet is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## M2-Planet is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with M2-Planet. If not, see <http://www.gnu.org/licenses/>.
rm -f test/test26/lisp.M1
rm -f test/test26/lisp-footer.M1
rm -f test/test26/lisp.hex2
rm -f test/test26/proof
exit 0

21
test/test26/gcc_req.h Normal file
View File

@ -0,0 +1,21 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
typedef struct cell* (FUNCTION)(struct cell *);

58
test/test26/hello.sh Executable file
View File

@ -0,0 +1,58 @@
#! /bin/sh
## Copyright (C) 2017 Jeremiah Orians
## This file is part of M2-Planet.
##
## M2-Planet is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## M2-Planet is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with M2-Planet. If not, see <http://www.gnu.org/licenses/>.
set -x
# Build the test
./bin/M2-Planet -f test/test26/lisp.h \
-f functions/malloc.c \
-f functions/calloc.c \
-f functions/numerate_number.c \
-f functions/match.c \
-f functions/file.c \
-f functions/file_print.c \
-f functions/exit.c \
-f test/test26/lisp.c \
-f test/test26/lisp_cell.c \
-f test/test26/lisp_eval.c \
-f test/test26/lisp_print.c \
-f test/test26/lisp_read.c \
--debug \
-o test/test26/lisp.M1 || exit 1
# Build debug footer
blood-elf -f test/test26/lisp.M1 \
-o test/test26/lisp-footer.M1 || exit 2
# Macro assemble with libc written in M1-Macro
M1 -f test/common_x86/x86_defs.M1 \
-f functions/libc-core.M1 \
-f test/test26/lisp.M1 \
-f test/test26/lisp-footer.M1 \
--LittleEndian \
--Architecture 1 \
-o test/test26/lisp.hex2 || exit 3
# Resolve all linkages
hex2 -f test/common_x86/ELF-i386-debug.hex2 \
-f test/test26/lisp.hex2 \
--LittleEndian \
--Architecture 1 \
--BaseAddress 0x8048000 \
-o test/results/test26-binary \
--exec_enable || exit 4
exit 0

161
test/test26/lisp.c Normal file
View File

@ -0,0 +1,161 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lisp.h"
struct file_list
{
struct file_list* next;
FILE* file;
};
/* Prototypes */
struct cell* eval(struct cell* exp, struct cell* env);
void init_sl3();
int Readline(FILE* source_file, char* temp);
struct cell* parse(char* program, int size);
void writeobj(FILE *ofp, struct cell* op);
void garbage_init(int number_of_cells);
void garbage_collect();
/* Read Eval Print Loop*/
int REPL(FILE* in, FILE *out)
{
int read;
input = in;
char* message = calloc(MAX_STRING + 2, sizeof(char));
read = Readline(in, message);
if(0 == read)
{
return TRUE;
}
struct cell* temp = parse(message, read);
current = temp;
temp = eval(temp, top_env);
writeobj(out, temp);
current = nil;
if(echo) fputc('\n', out);
return FALSE;
}
void recursively_evaluate(struct file_list* a)
{
if(NULL == a) return;
recursively_evaluate(a->next);
int Reached_EOF = FALSE;
while(!Reached_EOF)
{
garbage_collect();
Reached_EOF = REPL(a->file, console_output);
}
}
/*** Main Driver ***/
int main(int argc, char **argv)
{
int number_of_cells = 1000000;
file_output = fopen("/dev/null", "w");
console_output = stdout;
struct file_list* essential = NULL;
int i = 1;
while(i <= argc)
{
if(NULL == argv[i])
{
i = i + 1;
}
else if(match(argv[i], "-c") || match(argv[i], "--console"))
{
console_output = fopen(argv[i + 1], "w");
if(NULL == console_output)
{
file_print("The file: ", stderr);
file_print(argv[i + 1], stderr);
file_print(" does not appear writable\n", stderr);
exit(EXIT_FAILURE);
}
i = i + 2;
}
else if(match(argv[i], "-f") || match(argv[i], "--file"))
{
struct file_list* new = calloc(1, sizeof(struct file_list));
new->file = fopen(argv[i + 1], "r");
if(NULL == new->file)
{
file_print("The file: ", stderr);
file_print(argv[i + 1], stderr);
file_print(" does not appear readable\n", stderr);
exit(EXIT_FAILURE);
}
new->next = essential;
essential = new;
i = i + 2;
}
else if(match(argv[i], "-h") || match(argv[i], "--help"))
{
file_print("Usage: ", stdout);
file_print(argv[0], stdout);
file_print(" -f FILENAME1 {-f FILENAME2}\n", stdout);
exit(EXIT_SUCCESS);
}
else if(match(argv[i], "-m") || match(argv[i], "--memory"))
{
number_of_cells = numerate_string(argv[i + 1]);
i = i + 2;
}
else if(match(argv[i], "-o") || match(argv[i], "--output"))
{
file_output = fopen(argv[i + 1], "w");
if(NULL == file_output)
{
file_print("The file: ", stderr);
file_print(argv[i + 1], stderr);
file_print(" does not appear writable\n", stderr);
exit(EXIT_FAILURE);
}
i = i + 2;
}
else if(match(argv[i], "-v") || match(argv[i], "--version"))
{
file_print("Slow_Lisp 0.1\n", stdout);
exit(EXIT_SUCCESS);
}
else
{
file_print("Unknown option\n", stderr);
exit(EXIT_FAILURE);
}
}
/* Our most important initializations */
garbage_init(number_of_cells);
init_sl3();
int Reached_EOF;
echo = TRUE;
recursively_evaluate(essential);
Reached_EOF = FALSE;
while(!Reached_EOF)
{
garbage_collect();
Reached_EOF = REPL(stdin, stdout);
}
fclose(file_output);
return 0;
}

87
test/test26/lisp.h Normal file
View File

@ -0,0 +1,87 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gcc_req.h"
//CONSTANT FREE 1
#define FREE 1
//CONSTANT MARKED 2
#define MARKED 2
//CONSTANT INT 4
#define INT 4
//CONSTANT SYM 8
#define SYM 8
//CONSTANT CONS 16
#define CONS 16
//CONSTANT PROC 32
#define PROC 32
//CONSTANT PRIMOP 64
#define PRIMOP 64
//CONSTANT CHAR 128
#define CHAR 128
//CONSTANT STRING 256
#define STRING 256
// CONSTANT FALSE 0
#define FALSE 0
// CONSTANT TRUE 1
#define TRUE 1
struct cell
{
int type;
union
{
struct cell* car;
int value;
char* string;
FUNCTION* function;
};
struct cell* cdr;
struct cell* env;
};
// CONSTANT MAX_STRING 4096
#define MAX_STRING 4096
/* Common functions */
struct cell* make_cons(struct cell* a, struct cell* b);
int numerate_string(char *a);
char* numerate_number(int a);
int match(char* a, char* b);
void file_print(char* s, FILE* f);
/* Global objects */
struct cell *all_symbols;
struct cell *top_env;
struct cell *nil;
struct cell *tee;
struct cell *quote;
struct cell *s_if;
struct cell *s_lambda;
struct cell *s_define;
struct cell *s_setb;
struct cell *s_cond;
struct cell *s_begin;
struct cell *s_let;
struct cell *s_while;
struct cell *current;
FILE* input;
FILE* file_output;
FILE* console_output;
int echo;
int left_to_take;

261
test/test26/lisp_cell.c Normal file
View File

@ -0,0 +1,261 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lisp.h"
/* Deal with the fact GCC converts the 1 to the size of the structs being iterated over */
#define CELL_SIZE 1
//CONSTANT CELL_SIZE 16
struct cell *free_cells;
struct cell *gc_block_start;
struct cell *top_allocated;
void update_remaining()
{
int count = 0;
struct cell* i = free_cells;
while(NULL != i)
{
count = count + 1;
i = i->cdr;
}
left_to_take = count;
}
struct cell* insert_ordered(struct cell* i, struct cell* list)
{
if(NULL == list)
{
return i;
}
if(i < list)
{
i->cdr = list;
return i;
}
list->cdr = insert_ordered(i, list->cdr);
return list;
}
void reclaim_marked()
{
struct cell* i;
for(i= top_allocated; i >= gc_block_start ; i = i - CELL_SIZE)
{
if(i->type & MARKED)
{
i->type = FREE;
i->car = NULL;
i->cdr = NULL;
i->env = NULL;
free_cells = insert_ordered(i, free_cells);
}
}
}
void relocate_cell(struct cell* current, struct cell* target, struct cell* list)
{
for(; NULL != list; list = list->cdr)
{
if(list->car == current)
{
list->car = target;
}
if(list->cdr == current)
{
list->cdr = target;
}
if(list->env == current)
{
list->env = target;
}
if((list->type & CONS)|| list->type & PROC )
{
relocate_cell(current, target, list->car);
}
}
}
struct cell* pop_cons();
void compact(struct cell* list)
{
for(; NULL != list; list = list->cdr)
{
if((FREE != list->type) && (list > free_cells ))
{
struct cell* temp = pop_cons();
temp->type = list->type;
temp->car = list->car;
temp->cdr = list->cdr;
temp->env = list->env;
relocate_cell(list, temp, all_symbols);
relocate_cell(list, temp, top_env);
}
if((list->type & CONS)|| list->type & PROC )
{
compact(list->car);
}
}
}
void mark_all_cells()
{
struct cell* i;
for(i= gc_block_start; i < top_allocated; i = i + CELL_SIZE)
{
/* if not in the free list */
if(!(i->type & FREE))
{
/* Mark it */
i->type = i->type | MARKED;
}
}
}
void unmark_cells(struct cell* list, struct cell* stop, int count)
{
if(count > 1) return;
for(; NULL != list; list = list->cdr)
{
if(list == stop) count = count + 1;
list->type = list->type & ~MARKED;
if(list->type & PROC)
{
unmark_cells(list->car, stop, count);
if(NULL != list->env)
{
unmark_cells(list->env, stop, count);
}
}
if(list->type & CONS)
{
unmark_cells(list->car, stop, count);
}
}
}
void garbage_collect()
{
mark_all_cells();
unmark_cells(current, current, 0);
unmark_cells(all_symbols, all_symbols, 0);
unmark_cells(top_env, top_env, 0);
reclaim_marked();
update_remaining();
compact(all_symbols);
compact(top_env);
top_allocated = NULL;
}
void garbage_init(int number_of_cells)
{
gc_block_start = calloc(number_of_cells + 1, sizeof(struct cell));
top_allocated = gc_block_start + number_of_cells;
free_cells = NULL;
garbage_collect();
top_allocated = NULL;
}
struct cell* pop_cons()
{
if(NULL == free_cells)
{
file_print("OOOPS we ran out of cells", stderr);
exit(EXIT_FAILURE);
}
struct cell* i;
i = free_cells;
free_cells = i->cdr;
i->cdr = NULL;
if(i > top_allocated)
{
top_allocated = i;
}
left_to_take = left_to_take - 1;
return i;
}
struct cell* make_cell(int type, struct cell* a, struct cell* b, struct cell* env)
{
struct cell* c = pop_cons();
c->type = type;
c->car = a;
c->cdr = b;
c->env = env;
return c;
}
struct cell* make_int(int a)
{
struct cell* c = pop_cons();
c->type = INT;
c->value = a;
return c;
}
struct cell* make_char(int a)
{
struct cell* c = pop_cons();
c->type = CHAR;
c->value = a;
return c;
}
struct cell* make_string(char* a)
{
struct cell* c = pop_cons();
c->type = STRING;
c->string = a;
return c;
}
struct cell* make_sym(char* name)
{
struct cell* c = pop_cons();
c->type = SYM;
c->string = name;
return c;
}
struct cell* make_cons(struct cell* a, struct cell* b)
{
return make_cell(CONS, a, b, nil);
}
struct cell* make_proc(struct cell* a, struct cell* b, struct cell* env)
{
return make_cell(PROC, a, b, env);
}
struct cell* make_prim(void* fun)
{
struct cell* c = pop_cons();
c->type = PRIMOP;
c->function = fun;
return c;
}

643
test/test26/lisp_eval.c Normal file
View File

@ -0,0 +1,643 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lisp.h"
/* Support functions */
struct cell* findsym(char *name)
{
struct cell* symlist;
for(symlist = all_symbols; nil != symlist; symlist = symlist->cdr)
{
if(match(name, symlist->car->string))
{
return symlist;
}
}
return nil;
}
struct cell* make_sym(char* name);
struct cell* intern(char *name)
{
struct cell* op = findsym(name);
if(nil != op) return op->car;
op = make_sym(name);
all_symbols = make_cons(op, all_symbols);
return op;
}
/*** Environment ***/
struct cell* extend(struct cell* env, struct cell* symbol, struct cell* value)
{
return make_cons(make_cons(symbol, value), env);
}
struct cell* multiple_extend(struct cell* env, struct cell* syms, struct cell* vals)
{
if(nil == syms)
{
return env;
}
return multiple_extend(extend(env, syms->car, vals->car), syms->cdr, vals->cdr);
}
struct cell* extend_env(struct cell* sym, struct cell* val, struct cell* env)
{
env->cdr = make_cons(env->car, env->cdr);
env->car = make_cons(sym, val);
return val;
}
struct cell* assoc(struct cell* key, struct cell* alist)
{
if(nil == alist) return nil;
for(; nil != alist; alist = alist->cdr)
{
if(alist->car->car->string == key->string) return alist->car;
}
return nil;
}
/*** Evaluator (Eval/Apply) ***/
struct cell* eval(struct cell* exp, struct cell* env);
struct cell* make_proc(struct cell* a, struct cell* b, struct cell* env);
struct cell* evlis(struct cell* exps, struct cell* env)
{
if(exps == nil) return nil;
return make_cons(eval(exps->car, env), evlis(exps->cdr, env));
}
struct cell* progn(struct cell* exps, struct cell* env)
{
if(exps == nil) return nil;
struct cell* result;
progn_reset:
result = eval(exps->car, env);
if(exps->cdr == nil) return result;
exps = exps->cdr;
goto progn_reset;
}
struct cell* exec_func(FUNCTION * func, struct cell* vals)
{
return func(vals);
}
struct cell* apply(struct cell* proc, struct cell* vals)
{
struct cell* temp = nil;
if(proc->type == PRIMOP)
{
temp = exec_func(proc->function, vals);
}
else if(proc->type == PROC)
{
struct cell* env = make_cons(proc->env->car, proc->env->cdr);
temp = progn(proc->cdr, multiple_extend(env, proc->car, vals));
}
else
{
file_print("Bad argument to apply\n", stderr);
exit(EXIT_FAILURE);
}
return temp;
}
struct cell* evcond(struct cell* exp, struct cell* env)
{
/* Return nil but the result is technically undefined per the standard */
if(nil == exp)
{
return nil;
}
if(tee == eval(exp->car->car, env))
{
return eval(exp->car->cdr->car, env);
}
return evcond(exp->cdr, env);
}
void garbage_collect();
struct cell* evwhile(struct cell* exp, struct cell* env)
{
if(nil == exp) return nil;
struct cell* conditional = eval(exp->cdr->car, env);
while(tee == conditional)
{
eval(exp->cdr->cdr->car, env);
conditional = eval(exp->cdr->car, env);
if((tee == exp->cdr->car) && (left_to_take < 1000)) garbage_collect();
}
return conditional;
}
struct cell* process_sym(struct cell* exp, struct cell* env);
struct cell* process_cons(struct cell* exp, struct cell* env);
struct cell* eval(struct cell* exp, struct cell* env)
{
if(exp == nil) return nil;
if(SYM == exp->type) return process_sym(exp, env);
if(CONS == exp->type) return process_cons(exp, env);
return exp;
}
struct cell* process_sym(struct cell* exp, struct cell* env)
{
struct cell* tmp = assoc(exp, env);
if(tmp == nil)
{
file_print("Unbound symbol:", stderr);
file_print(exp->string, stderr);
fputc('\n', stderr);
exit(EXIT_FAILURE);
}
return tmp->cdr;
}
struct cell* process_if(struct cell* exp, struct cell* env)
{
if(eval(exp->cdr->car, env) != nil)
{
return eval(exp->cdr->cdr->car, env);
}
return eval(exp->cdr->cdr->cdr->car, env);
}
struct cell* process_setb(struct cell* exp, struct cell* env)
{
struct cell* newval = eval(exp->cdr->cdr->car, env);
struct cell* pair = assoc(exp->cdr->car, env);
pair->cdr = newval;
return newval;
}
struct cell* process_let(struct cell* exp, struct cell* env)
{
struct cell* lets;
for(lets = exp->cdr->car; lets != nil; lets = lets->cdr)
{
env = make_cons(make_cons(lets->car->car, eval(lets->car->cdr->car, env)), env);
}
return progn(exp->cdr->cdr, env);
}
struct cell* process_cons(struct cell* exp, struct cell* env)
{
if(exp->car == s_if) return process_if(exp, env);
if(exp->car == s_cond) return evcond(exp->cdr, env);
if(exp->car == s_begin) return progn(exp->cdr, env);
if(exp->car == s_lambda) return make_proc(exp->cdr->car, exp->cdr->cdr, env);
if(exp->car == quote) return exp->cdr->car;
if(exp->car == s_define) return(extend_env(exp->cdr->car, eval(exp->cdr->cdr->car, env), env));
if(exp->car == s_setb) return process_setb(exp, env);
if(exp->car == s_let) return process_let(exp, env);
if(exp->car == s_while) return evwhile(exp, env);
return apply(eval(exp->car, env), evlis(exp->cdr, env));
}
/*** Primitives ***/
struct cell* prim_apply(struct cell* args)
{
return apply(args->car, args->cdr->car);
}
struct cell* nullp(struct cell* args)
{
if(nil == args->car) return tee;
return nil;
}
struct cell* make_int(int a);
struct cell* prim_sum(struct cell* args)
{
if(nil == args) return nil;
int sum;
for(sum = 0; nil != args; args = args->cdr)
{
sum = sum + args->car->value;
}
return make_int(sum);
}
struct cell* prim_sub(struct cell* args)
{
if(nil == args) return nil;
int sum = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
sum = sum - args->car->value;
}
return make_int(sum);
}
struct cell* prim_prod(struct cell* args)
{
if(nil == args) return nil;
int prod;
for(prod = 1; nil != args; args = args->cdr)
{
prod = prod * args->car->value;
}
return make_int(prod);
}
struct cell* prim_div(struct cell* args)
{
if(nil == args) return make_int(1);
int div = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
div = div / args->car->value;
}
return make_int(div);
}
struct cell* prim_mod(struct cell* args)
{
if(nil == args) return nil;
int mod = args->car->value % args->cdr->car->value;
if(nil != args->cdr->cdr)
{
file_print("wrong number of arguments to mod\n", stderr);
exit(EXIT_FAILURE);
}
return make_int(mod);
}
struct cell* prim_and(struct cell* args)
{
if(nil == args) return nil;
for(; nil != args; args = args->cdr)
{
if(tee != args->car) return nil;
}
return tee;
}
struct cell* prim_or(struct cell* args)
{
if(nil == args) return nil;
for(; nil != args; args = args->cdr)
{
if(tee == args->car) return tee;
}
return nil;
}
struct cell* prim_not(struct cell* args)
{
if(nil == args) return nil;
if(tee != args->car) return tee;
return nil;
}
struct cell* prim_numgt(struct cell* args)
{
if(nil == args) return nil;
int temp = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
if(temp <= args->car->value)
{
return nil;
}
temp = args->car->value;
}
return tee;
}
struct cell* prim_numge(struct cell* args)
{
if(nil == args) return nil;
int temp = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
if(temp < args->car->value)
{
return nil;
}
temp = args->car->value;
}
return tee;
}
struct cell* prim_numeq(struct cell* args)
{
if(nil == args) return nil;
int temp = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
if(temp != args->car->value)
{
return nil;
}
}
return tee;
}
struct cell* prim_numle(struct cell* args)
{
if(nil == args) return nil;
int temp = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
if(temp > args->car->value)
{
return nil;
}
temp = args->car->value;
}
return tee;
}
struct cell* prim_numlt(struct cell* args)
{
if(nil == args) return nil;
int temp = args->car->value;
for(args = args->cdr; nil != args; args = args->cdr)
{
if(temp >= args->car->value)
{
return nil;
}
temp = args->car->value;
}
return tee;
}
struct cell* prim_listp(struct cell* args)
{
if(nil == args) return nil;
if(CONS == args->car->type)
{
return tee;
}
return nil;
}
struct cell* prim_get_type(struct cell* args)
{
if(nil == args) return nil;
return make_int(args->car->type);
}
struct cell* make_cell(int type, struct cell* a, struct cell* b, struct cell* env);
struct cell* prim_set_type(struct cell* args)
{
if(nil == args) return nil;
return make_cell(args->cdr->car->value, args->car->car, args->car->cdr, args->car->env);
}
struct cell* prim_output(struct cell* args, FILE* out)
{
for(; nil != args; args = args->cdr)
{
if(INT == args->car->type)
{
file_print(numerate_number(args->car->value), out);
}
else if(CHAR == args->car->type)
{
fputc(args->car->value, out);
}
else if(CONS == args->car->type)
{
prim_output(args->car, out);
}
else
{
file_print(args->car->string, out);
}
}
return tee;
}
struct cell* prim_stringeq(struct cell* args)
{
if(nil == args) return nil;
char* temp = args->car->string;
for(args = args->cdr; nil != args; args = args->cdr)
{
if(!match(temp, args->car->string))
{
return nil;
}
}
return tee;
}
struct cell* prim_display(struct cell* args)
{
return prim_output(args, console_output);
}
struct cell* prim_write(struct cell* args)
{
return prim_output(args, file_output);
}
struct cell* prim_freecell(struct cell* args)
{
if(nil == args)
{
file_print("Remaining Cells: ", stdout);
file_print(numerate_number(left_to_take), stdout);
return nil;
}
return make_int(left_to_take);
}
struct cell* make_char(int a);
struct cell* string_to_list(char* string)
{
if(NULL == string) return nil;
if(0 == string[0]) return nil;
struct cell* result = make_char(string[0]);
struct cell* tail = string_to_list(string + 1);
return make_cons(result, tail);
}
struct cell* prim_string_to_list(struct cell* args)
{
if(nil == args) return nil;
if(STRING == args->car->type)
{
return string_to_list(args->car->string);
}
return nil;
}
struct cell* make_string(char* a);
int list_to_string(int index, char* string, struct cell* args)
{
struct cell* i;
for(i = args; nil != i; i = i->cdr)
{
if(CHAR == i->car->type)
{
string[index] = i->car->value;
index = index + 1;
}
if(CONS == i->car->type)
{
index = list_to_string(index, string, i->car);
}
}
return index;
}
struct cell* prim_list_to_string(struct cell* args)
{
if(nil == args) return nil;
char* string = calloc(MAX_STRING + 2, sizeof(char));
list_to_string(0, string, args);
return make_string(string);
}
struct cell* prim_echo(struct cell* args)
{
if(nil == args) return nil;
if(nil == args->car) echo = FALSE;
if(tee == args->car)
{
echo = TRUE;
return make_string("");
}
return args->car;
}
struct cell* prim_read_byte(struct cell* args)
{
if(nil == args) return make_char(fgetc(input));
return nil;
}
struct cell* prim_halt(struct cell* args)
{
/* Cleanup */
free(args);
fclose(file_output);
/* Actual important part */
exit(EXIT_SUCCESS);
}
struct cell* prim_list(struct cell* args) {return args;}
struct cell* prim_cons(struct cell* args) { return make_cons(args->car, args->cdr->car); }
struct cell* prim_car(struct cell* args) { return args->car->car; }
struct cell* prim_cdr(struct cell* args) { return args->car->cdr; }
void spinup(struct cell* sym, struct cell* prim)
{
all_symbols = make_cons(sym, all_symbols);
top_env = extend(top_env, sym, prim);
}
/*** Initialization ***/
struct cell* intern(char *name);
struct cell* make_prim(void* fun);
struct cell* make_sym(char* name);
void init_sl3()
{
/* Special symbols */
nil = make_sym("nil");
tee = make_sym("#t");
quote = make_sym("quote");
s_if = make_sym("if");
s_cond = make_sym("cond");
s_lambda = make_sym("lambda");
s_define = make_sym("define");
s_setb = make_sym("set!");
s_begin = make_sym("begin");
s_let = make_sym("let");
s_while = make_sym("while");
/* Globals of interest */
all_symbols = make_cons(nil, nil);
top_env = extend(nil, nil, nil);
/* Add Eval Specials */
spinup(tee, tee);
spinup(quote, quote);
spinup(s_if, s_if);
spinup(s_cond, s_cond);
spinup(s_lambda, s_lambda);
spinup(s_define, s_define);
spinup(s_setb, s_setb);
spinup(s_begin, s_begin);
spinup(s_let, s_let);
spinup(s_while, s_while);
/* Add Primitive Specials */
spinup(make_sym("apply"), make_prim(prim_apply));
spinup(make_sym("null?"), make_prim(nullp));
spinup(make_sym("+"), make_prim(prim_sum));
spinup(make_sym("-"), make_prim(prim_sub));
spinup(make_sym("*"), make_prim(prim_prod));
spinup(make_sym("/"), make_prim(prim_div));
spinup(make_sym("mod"), make_prim(prim_mod));
spinup(make_sym("and"), make_prim(prim_and));
spinup(make_sym("or"), make_prim(prim_or));
spinup(make_sym("not"), make_prim(prim_not));
spinup(make_sym(">"), make_prim(prim_numgt));
spinup(make_sym(">="), make_prim(prim_numge));
spinup(make_sym("="), make_prim(prim_numeq));
spinup(make_sym("<="), make_prim(prim_numle));
spinup(make_sym("<"), make_prim(prim_numlt));
spinup(make_sym("display"), make_prim(prim_display));
spinup(make_sym("write"), make_prim(prim_write));
spinup(make_sym("free_mem"), make_prim(prim_freecell));
spinup(make_sym("get-type"), make_prim(prim_get_type));
spinup(make_sym("set-type!"), make_prim(prim_set_type));
spinup(make_sym("list?"), make_prim(prim_listp));
spinup(make_sym("list"), make_prim(prim_list));
spinup(make_sym("list->string"), make_prim(prim_list_to_string));
spinup(make_sym("string->list"), make_prim(prim_string_to_list));
spinup(make_sym("string=?"), make_prim(prim_stringeq));
spinup(make_sym("cons"), make_prim(prim_cons));
spinup(make_sym("car"), make_prim(prim_car));
spinup(make_sym("cdr"), make_prim(prim_cdr));
spinup(make_sym("echo"), make_prim(prim_echo));
spinup(make_sym("read-byte"), make_prim(prim_read_byte));
spinup(make_sym("HALT"), make_prim(prim_halt));
}

77
test/test26/lisp_print.c Normal file
View File

@ -0,0 +1,77 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lisp.h"
void writeobj(FILE *output_file, struct cell* op)
{
if(!echo) return;
if(INT == op->type)
{
file_print(numerate_number(op->value), output_file);
}
else if(CONS == op->type)
{
fputc('(', output_file);
do
{
writeobj(output_file, op->car);
if(nil == op->cdr)
{
fputc(')', output_file);
break;
}
op = op->cdr;
if(op->type != CONS)
{
file_print(" . ", output_file);
writeobj(output_file, op);
fputc(')', output_file);
break;
}
fputc(' ', output_file);
} while(TRUE);
}
else if(SYM == op->type)
{
file_print(op->string, output_file);
}
else if(PRIMOP == op->type)
{
file_print("#<PRIMOP>", output_file);
}
else if(PROC == op->type)
{
file_print("#<PROC>", output_file);
}
else if(CHAR == op->type)
{
fputc(op->value, output_file);
}
else if(STRING == op->type)
{
file_print(op->string, output_file);
}
else
{
file_print("Type ", stderr);
file_print(numerate_number(op->type), stderr);
file_print(" is unknown\nPrint aborting hard\n", stderr);
exit(EXIT_FAILURE);
}
}

290
test/test26/lisp_read.c Normal file
View File

@ -0,0 +1,290 @@
/* Copyright (C) 2016 Jeremiah Orians
* This file is part of stage0.
*
* stage0 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* stage0 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with stage0. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lisp.h"
#include <stdint.h>
#include <string.h>
FILE* source_file;
int Reached_EOF;
struct cell* token_stack;
struct cell* make_sym(char* name);
struct cell* intern(char *name);
struct cell* findsym(char *name);
/****************************************************************
* "Convert a string into a list of tokens." *
****************************************************************/
struct cell* tokenize(struct cell* head, char* fullstring, int size)
{
int i = 0;
int done = FALSE;
if((0 >= size) || (0 == fullstring[0]))
{
return head;
}
char *store = calloc(MAX_STRING + 1, sizeof(char));
do
{
int c = fullstring[i];
if((i > size) || (MAX_STRING <= i))
{
done = TRUE;
}
else if(34 == c)
{
store[i] = c;
i = i + 1;
while(34 != fullstring[i])
{
store[i] = fullstring[i];
i = i + 1;
}
i = i + 1;
done = TRUE;
}
else
{
if((' ' == c) || ('\t' == c) || ('\n' == c) | ('\r' == c))
{
i = i + 1;
done = TRUE;
}
else
{
store[i] = c;
i = i + 1;
}
}
} while(!done);
if(i > 1)
{
struct cell* temp = make_sym(store);
temp->cdr = head;
head = temp;
}
else
{
free(store);
}
head = tokenize(head, (fullstring+i), (size - i));
return head;
}
int is_integer(char* a)
{
if(('0' <= a[0]) && ('9' >= a[0]))
{
return TRUE;
}
if('-' == a[0])
{
if(('0' <= a[1]) && ('9' >= a[1]))
{
return TRUE;
}
}
return FALSE;
}
/********************************************************************
* Numbers become numbers *
* Strings become strings *
* Functions become functions *
* quoted things become quoted *
* Everything is treated like a symbol *
********************************************************************/
struct cell* atom(struct cell* a)
{
/* Check for quotes */
if('\'' == a->string[0])
{
a->string = a->string + 1;
return make_cons(quote, make_cons(a, nil));
}
/* Check for strings */
if(34 == a->string[0])
{
a->type = STRING;
a->string = a->string + 1;
return a;
}
/* Check for integer */
if(is_integer(a->string))
{
a->type = INT;
a->value = numerate_string(a->string);
return a;
}
/* Check for functions */
struct cell* op = findsym(a->string);
if(nil != op)
{
return op->car;
}
/* Assume new symbol */
all_symbols = make_cons(a, all_symbols);
return a;
}
/****************************************************************
* "Read an expression from a sequence of tokens." *
****************************************************************/
struct cell* readlist();
struct cell* readobj()
{
struct cell* head = token_stack;
token_stack = head->cdr;
head->cdr = NULL;
if (match("(", head->string))
{
return readlist();
}
return atom(head);
}
struct cell* readlist()
{
struct cell* head = token_stack;
if (match(")", head->string))
{
token_stack = head->cdr;
return nil;
}
struct cell* tmp = readobj();
/* token_stack = head->cdr; */
return make_cons(tmp,readlist());
}
/****************************************************
* Put list of tokens in correct order *
****************************************************/
struct cell* reverse_list(struct cell* head)
{
struct cell* root = NULL;
while(NULL != head)
{
struct cell* next = head->cdr;
head->cdr = root;
root = head;
head = next;
}
return root;
}
/****************************************************
* "Read a Scheme expression from a string." *
****************************************************/
struct cell* parse(char* program, int size)
{
token_stack = tokenize(NULL, program, size);
if(NULL == token_stack)
{
return nil;
}
token_stack = reverse_list(token_stack);
return readobj();
}
/****************************************************
* Do the heavy lifting of reading an s-expreesion *
****************************************************/
unsigned Readline(FILE* source_file, char* temp)
{
int c;
unsigned i;
unsigned depth = 0;
for(i = 0; i < MAX_STRING; i = i + 1)
{
restart_comment:
c = fgetc(source_file);
if((-1 == c) || (4 == c))
{
return i;
}
else if(';' == c)
{
/* drop everything until we hit newline */
while('\n' != c)
{
c = fgetc(source_file);
}
goto restart_comment;
}
else if('"' == c)
{ /* Deal with strings */
temp[i] = c;
i = i + 1;
c = fgetc(source_file);
while('"' != c)
{
temp[i] = c;
i = i + 1;
c = fgetc(source_file);
}
temp[i] = c;
}
else if((0 == depth) && (('\n' == c) || ('\r' == c) || (' ' == c) || ('\t' == c)))
{
goto Line_complete;
}
else if(('(' == c) || (')' == c))
{
if('(' == c)
{
depth = depth + 1;
}
if(')' == c)
{
depth = depth - 1;
}
temp[i] = ' ';
temp[i+1] = c;
temp[i+2] = ' ';
i = i + 2;
}
else
{
temp[i] = c;
}
}
Line_complete:
if(1 > i)
{
return Readline(source_file, temp);
}
return i;
}