diff --git a/CHANGELOG.org b/CHANGELOG.org
index 91184ab..3bea072 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -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
diff --git a/cc_core.c b/cc_core.c
index c04c368..0d77f8d 100644
--- a/cc_core.c
+++ b/cc_core.c
@@ -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;
diff --git a/test/test.answers b/test/test.answers
index 14e69a5..bbf2dbb 100644
--- a/test/test.answers
+++ b/test/test.answers
@@ -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
diff --git a/test/test100/proof.answer b/test/test100/proof.answer
index 3046896..ed47876 100644
--- a/test/test100/proof.answer
+++ b/test/test100/proof.answer
@@ -1 +1 @@
-b882976ea4fb2ede866851a57fd3be0653ac1918b87e183e4c1cd6cb5c60d2b4 test/test100/proof
+b39435961127c9f5096e07a54c1aff13b02444d0ca07c61477558c1b1ff999a1 test/test100/proof
diff --git a/test/test26/.gitignore b/test/test26/.gitignore
new file mode 100644
index 0000000..5b7810f
--- /dev/null
+++ b/test/test26/.gitignore
@@ -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 .
+
+# Ignore the files created by script
+*.M1
+*.hex2
+proof
+
+# A place to put a good run for comparison
+actual.M1
diff --git a/test/test26/cleanup.sh b/test/test26/cleanup.sh
new file mode 100755
index 0000000..b60c815
--- /dev/null
+++ b/test/test26/cleanup.sh
@@ -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 .
+
+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
diff --git a/test/test26/gcc_req.h b/test/test26/gcc_req.h
new file mode 100644
index 0000000..4d499f8
--- /dev/null
+++ b/test/test26/gcc_req.h
@@ -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 .
+ */
+
+#include
+#include
+
+typedef struct cell* (FUNCTION)(struct cell *);
diff --git a/test/test26/hello.sh b/test/test26/hello.sh
new file mode 100755
index 0000000..128132f
--- /dev/null
+++ b/test/test26/hello.sh
@@ -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 .
+
+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
diff --git a/test/test26/lisp.c b/test/test26/lisp.c
new file mode 100644
index 0000000..833aa45
--- /dev/null
+++ b/test/test26/lisp.c
@@ -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 .
+ */
+
+#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;
+}
diff --git a/test/test26/lisp.h b/test/test26/lisp.h
new file mode 100644
index 0000000..b2dd5bf
--- /dev/null
+++ b/test/test26/lisp.h
@@ -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 .
+ */
+
+#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;
diff --git a/test/test26/lisp_cell.c b/test/test26/lisp_cell.c
new file mode 100644
index 0000000..6260ec5
--- /dev/null
+++ b/test/test26/lisp_cell.c
@@ -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 .
+ */
+
+#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;
+}
diff --git a/test/test26/lisp_eval.c b/test/test26/lisp_eval.c
new file mode 100644
index 0000000..bb9b7de
--- /dev/null
+++ b/test/test26/lisp_eval.c
@@ -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 .
+ */
+
+#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));
+}
diff --git a/test/test26/lisp_print.c b/test/test26/lisp_print.c
new file mode 100644
index 0000000..7db570c
--- /dev/null
+++ b/test/test26/lisp_print.c
@@ -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 .
+ */
+
+#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("#", output_file);
+ }
+ else if(PROC == op->type)
+ {
+ file_print("#", 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);
+ }
+}
diff --git a/test/test26/lisp_read.c b/test/test26/lisp_read.c
new file mode 100644
index 0000000..be13950
--- /dev/null
+++ b/test/test26/lisp_read.c
@@ -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 .
+ */
+
+#include "lisp.h"
+#include
+#include
+
+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;
+}