├── .gitignore ├── Makefile ├── README ├── character_list.h ├── characters.c ├── characters.h ├── class_builtin_class.c ├── class_character.c ├── class_character.h ├── class_class.h ├── class_cons.h ├── class_integer.c ├── class_integer.h ├── class_string.h ├── class_symbol.h ├── header.h ├── integer_list.h ├── integers.c ├── integers.h ├── main.c ├── strings.c ├── strings.h ├── symbols.c └── symbols.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | bocl 3 | .*.swp 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -W -Wall 2 | 3 | OBJECT=integers.o characters.o main.o strings.o class_integer.o symbols.o class_character.o class_builtin_class.o 4 | 5 | all: $(OBJECT) 6 | gcc -o bocl $(OBJECT) 7 | 8 | clean: 9 | rm -f bocl $(OBJECT) 10 | 11 | strings.o: class_string.h class_symbol.h integers.h symbols.h characters.h strings.h 12 | class_integer.o: class_class.h 13 | symbols.o: symbols.h 14 | class_builtin_class.o: header.h class_symbol.h symbols.h 15 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Welcome to Bootstrap Common Lisp, or BOCL for short. 2 | 3 | BOCL is (meant to one day be) a fully conforming Common Lisp 4 | implementation with a twist. It is meant only for bootstrapping other 5 | Common Lisp implementations on platforms where, for some reason, no 6 | Common Lisp implementation is already available. It is not meant for 7 | writing end-user applications. 8 | 9 | This main purpose of BOCL has some consequences to the way it is 10 | implemented. In particular, there is no attempt to make it fast. 11 | Instead, the emphasis is on simplicity, maintainability, and 12 | correctness. Specifically: 13 | 14 | * We use the Boehm-Weiser conservative garbage collector. 15 | 16 | * We take advantage of all situations in which the Common Lisp 17 | standard states that some behavior is undefined or implementation 18 | defined, in that we then do whatever is the easiest solution for 19 | the situation. 20 | 21 | * The type FIXNUM does not have a corresponding class. All integers 22 | are represented the same way. 23 | 24 | * All objects have the same basic representation as a header 25 | containing a pointer to the class of the object and a pointer to a 26 | vector (not a Common Lisp vector) with the objects-specific 27 | contents. 28 | 29 | * The only specialized arrays are those mandated by the Common Lisp 30 | standard, and even those arrays do not use any special 31 | representation. Thus an array of single bits will still have a 32 | full BOCL object for each element, but that object is either the 33 | integer 0 or the integer 1. 34 | 35 | * More generally, we make no attempt to save space. 36 | 37 | * Hash tables are internally implemented as lists for simplicity. 38 | 39 | * There is no attempt to handle tail-call merging. 40 | 41 | * All functions are called with three arguments: the static 42 | environment, the dynamic environment, and a Common Lisp list of 43 | arguments. 44 | 45 | Currently, several free (or, more generally, FLOSS) implementations of 46 | Common Lisp are built from sources in some other language. That 47 | language is typically C, but sometimes something else, like C++. 48 | There are probably several reasons for these implementations to be 49 | written this way, including historical (there was no widespread 50 | existing Common Lisp implementation when they were written), limited 51 | knowledge (the author did not know how to write a Common Lisp 52 | implementation in Common Lisp), and more. 53 | 54 | The process of building a Common Lisp system from sources written in 55 | some other language is a painful one, especially if one of the main 56 | objectives is for it to be fast, safe, and helpful to the programmer. 57 | Large parts of the system must be written in a language that is not 58 | very well adapted to expressing the semantics of Common Lisp. Even 59 | though large parts of the system can be written in Common Lisp, 60 | because of the way the system is built, many system modules must be 61 | written in a subset of Common Lisp, making also that part painful to 62 | write. For instance, it is common that CLOS not be available until 63 | very late in the bootstrapping process. 64 | 65 | The existence of BOCL will relieve most of the pain of maintainers of 66 | Common Lisp systems by concentrating that pain into BOCL. These 67 | maintainers can now migrate their code from the existing 68 | implementation language to Common Lisp, relying on BOCL to exist. At 69 | the same time, there is considerably less pain because of the 70 | simplifications to BOCL listed above. 71 | 72 | BOCL is (or rather, will be) implemented in ISO C. We (will) do our 73 | utmost to avoid using constructs with undefined semantics, as the C 74 | standard indicates. Only readily available shell tools are used in 75 | order to maximize portability. 76 | 77 | As an exception to the goal of simplicity, BOCL will contain a full 78 | implementation of the CLOS meta-object protocol (MOP) so as to allow 79 | implementers of other Common Lisp systems to take advantage of the MOP 80 | in their own implementations. 81 | 82 | In addition to being a bootstrapping tool for Common Lisp 83 | implementers, we think that BOCL will be an excellent illustration of 84 | the semantics of Common Lisp. To make it easier for people interested 85 | in that topic, we think it is important that the BOCL code be highly 86 | idiomatic, uniform, and well documented. 87 | 88 | BOCL will not happen unless it is contributed to by others, so if you 89 | have knowledge of how to implement Common Lisp in C or interest in 90 | learning how to do it, please consider contributing. 91 | -------------------------------------------------------------------------------- /character_list.h: -------------------------------------------------------------------------------- 1 | /* We define all ASCII characters at compile time, because characters 2 | are used to build string that we also need at compile time. 3 | */ 4 | 5 | X(NUL, 0); 6 | X(SOH, 1); 7 | X(STX, 2); 8 | X(ETX, 3); 9 | X(EOT, 4); 10 | X(ENQ, 5); 11 | X(ACK, 6); 12 | X(BEL, 7); 13 | X(BS, 8); 14 | X(TAB, 9); 15 | X(LF, 10); 16 | X(VT, 11); 17 | X(FF, 12); 18 | X(CR, 13); 19 | X(SO, 14); 20 | X(SI, 15); 21 | X(DLE, 16); 22 | X(DC1, 17); 23 | X(DC2, 18); 24 | X(DC3, 19); 25 | X(DC4, 20); 26 | X(NAK, 21); 27 | X(SYN, 22); 28 | X(ETB, 23); 29 | X(CAN, 24); 30 | X(EM, 25); 31 | X(SUB, 26); 32 | X(ESC, 27); 33 | X(FS, 28); 34 | X(GS, 29); 35 | X(RS, 30); 36 | X(US, 31); 37 | 38 | X(space, 32); 39 | X(exclamation_mark, 33); 40 | X(double_quote, 34); 41 | X(hash_sign, 35); 42 | X(dollar_sign, 36); 43 | X(percent_sign, 37); 44 | X(ampersand, 38); 45 | X(single_quote, 39); 46 | X(left_parenthesis, 40); 47 | X(right_parenthesis, 41); 48 | X(asterisk, 42); 49 | X(plus_sign, 43); 50 | X(comma, 44); 51 | X(minus_sign, 45); 52 | X(dot, 46); 53 | X(slash, 47); 54 | X(0, 48); 55 | X(1, 49); 56 | X(2, 50); 57 | X(3, 51); 58 | X(4, 52); 59 | X(5, 53); 60 | X(6, 54); 61 | X(7, 55); 62 | X(8, 56); 63 | X(9, 57); 64 | X(colon, 58); 65 | X(semicolon, 59); 66 | X(less_than_sign, 60); 67 | X(equal_sign, 61); 68 | X(greater_than_sign, 62); 69 | X(question_mark, 63); 70 | 71 | X(at_sign, 64); 72 | X(A, 65); 73 | X(B, 66); 74 | X(C, 67); 75 | X(D, 68); 76 | X(E, 69); 77 | X(F, 70); 78 | X(G, 71); 79 | X(H, 72); 80 | X(I, 73); 81 | X(J, 74); 82 | X(K, 75); 83 | X(L, 76); 84 | X(M, 77); 85 | X(N, 78); 86 | X(O, 79); 87 | X(P, 80); 88 | X(Q, 81); 89 | X(R, 82); 90 | X(S, 83); 91 | X(T, 84); 92 | X(U, 85); 93 | X(V, 86); 94 | X(W, 87); 95 | X(X, 88); 96 | X(Y, 89); 97 | X(Z, 90); 98 | X(left_bracket, 91); 99 | X(backslash, 92); 100 | X(right_bracket, 93); 101 | X(circumflex, 94); 102 | X(underscore, 95); 103 | 104 | X(backquote, 96); 105 | X(a, 97); 106 | X(b, 98); 107 | X(c, 99); 108 | X(d, 100); 109 | X(e, 101); 110 | X(f, 102); 111 | X(g, 103); 112 | X(h, 104); 113 | X(i, 105); 114 | X(j, 106); 115 | X(k, 107); 116 | X(l, 108); 117 | X(m, 109); 118 | X(n, 110); 119 | X(o, 111); 120 | X(p, 112); 121 | X(q, 113); 122 | X(r, 114); 123 | X(s, 115); 124 | X(t, 116); 125 | X(u, 117); 126 | X(v, 118); 127 | X(w, 119); 128 | X(x, 120); 129 | X(y, 121); 130 | X(z, 122); 131 | X(left_brace, 123); 132 | X(vertical_bar, 124); 133 | X(right_brace, 125); 134 | X(tilde, 126); 135 | X(DEL, 127); 136 | -------------------------------------------------------------------------------- /characters.c: -------------------------------------------------------------------------------- 1 | #include "class_character.h" 2 | #include "class_symbol.h" 3 | #include "class_class.h" 4 | #include "integers.h" 5 | #include "symbols.h" 6 | 7 | /* We define all ASCII characters at compile time, because characters 8 | are used to build string that we also need at compile time. 9 | */ 10 | 11 | #define X(name, value) \ 12 | static void *character_ ## name ## _rack[] = { \ 13 | reference_symbol(NIL), \ 14 | (void *) &integer_1_header, \ 15 | (void *) value, \ 16 | }; \ 17 | \ 18 | struct header_struct character_ ## name ## _header = { \ 19 | &class_character_header, \ 20 | character_ ## name ## _rack, \ 21 | } 22 | #include "character_list.h" 23 | #undef X 24 | -------------------------------------------------------------------------------- /characters.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | #include "class_character.h" 4 | 5 | #define X(name, value) extern struct header_struct character_ ## name ## _header 6 | #include "character_list.h" 7 | #undef X 8 | -------------------------------------------------------------------------------- /class_builtin_class.c: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "class_symbol.h" 3 | #include "symbols.h" 4 | 5 | /* This definition is obviously wrong. It is to be considered a 6 | temporary solution so that we can create an executable, which 7 | requires all external references to be resolved. */ 8 | 9 | struct header_struct class_built_in_class_header = 10 | { 11 | reference_symbol(NIL), 12 | reference_symbol(NIL), 13 | }; 14 | 15 | 16 | -------------------------------------------------------------------------------- /class_character.c: -------------------------------------------------------------------------------- 1 | #include "class_class.h" 2 | 3 | void * 4 | class_character_rack[] = 5 | { 6 | reference_symbol(NIL), 7 | }; 8 | 9 | struct header_struct class_character_header = 10 | { 11 | &class_built_in_class_header, 12 | class_character_rack, 13 | }; 14 | -------------------------------------------------------------------------------- /class_character.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "integers.h" 3 | 4 | extern struct header_struct class_character_header; 5 | 6 | #define reference_character(name) \ 7 | (void *) &character_ ## name ## _header 8 | -------------------------------------------------------------------------------- /class_class.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "symbols.h" 3 | 4 | extern struct header_struct class_built_in_class_header; 5 | 6 | #define declare_class(name) \ 7 | extern struct header_struct class_ ## name ## _header; 8 | 9 | #define reference_class(name) \ 10 | (void *) &class_ ## name ## _header 11 | -------------------------------------------------------------------------------- /class_cons.h: -------------------------------------------------------------------------------- 1 | #ifndef CLASS_CONS_H 2 | #define CLASS_CONS_H 3 | 4 | #include "header.h" 5 | 6 | extern struct header_struct class_cons_header; 7 | 8 | #define define_cons(name, car, cdr) \ 9 | \ 10 | void * \ 11 | cons_ ## name ## _rack[] = \ 12 | { \ 13 | reference_symbol(NIL), \ 14 | car, \ 15 | cdr, \ 16 | }; \ 17 | \ 18 | struct header_struct cons_ ## name ## _header = \ 19 | { \ 20 | &class_cons_header, \ 21 | cons_ ## name ## _rack, \ 22 | } 23 | 24 | #define reference_cons(name) \ 25 | (void *) &cons_ ## name ## _header 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /class_integer.c: -------------------------------------------------------------------------------- 1 | #include "class_class.h" 2 | 3 | void * 4 | class_integer_rack[] = 5 | { 6 | reference_symbol(NIL), 7 | }; 8 | 9 | struct header_struct class_integer_header = 10 | { 11 | &class_built_in_class_header, 12 | class_integer_rack, 13 | }; 14 | -------------------------------------------------------------------------------- /class_integer.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | extern struct header_struct class_integer_header; 4 | 5 | #define define_integer(value) \ 6 | \ 7 | void * \ 8 | integer_ ## value ## _rack[] = \ 9 | { \ 10 | reference_symbol(NIL), \ 11 | (void *) &integer_1_header, \ 12 | (void *) value, \ 13 | }; \ 14 | \ 15 | struct header_struct integer_ ## value ## _header = \ 16 | { \ 17 | &class_integer_header, \ 18 | integer_ ## value ## _rack, \ 19 | } 20 | 21 | #define reference_integer(value) \ 22 | (void *) &integer_ ## value ## _header 23 | -------------------------------------------------------------------------------- /class_string.h: -------------------------------------------------------------------------------- 1 | #ifndef CLASS_STRING_H 2 | #define CLASS_STRING_H 3 | 4 | extern struct header_struct class_string_header; 5 | 6 | #define reference_string(name) \ 7 | (void *) &string_ ## name ## _header 8 | 9 | #define declare_string(name) \ 10 | extern struct header_struct string_ ## name ## _header; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /class_symbol.h: -------------------------------------------------------------------------------- 1 | #ifndef CLASS_SYMBOL_H 2 | #define CLASS_SYMBOL_H 3 | 4 | #include "class_string.h" 5 | 6 | extern struct header_struct class_symbol_header; 7 | 8 | #define define_symbol(name, package) \ 9 | \ 10 | void * \ 11 | symbol_ ## name ## _rack[] = \ 12 | { \ 13 | reference_symbol(NIL), \ 14 | reference_string(name), \ 15 | reference_symbol(NIL), \ 16 | }; \ 17 | \ 18 | struct header_struct symbol_ ## name ## _header = \ 19 | { \ 20 | reference_symbol(NIL), \ 21 | symbol_ ## name ## _rack, \ 22 | }; 23 | 24 | #define declare_symbol(name) \ 25 | extern struct header_struct symbol_ ## name ## _header; 26 | 27 | #define reference_symbol(name) \ 28 | (void *) &symbol_ ## name ## _header 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /header.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_H 2 | #define HEADER_H 3 | 4 | struct header_struct 5 | { 6 | struct header_struct *class; 7 | void **rack; 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /integer_list.h: -------------------------------------------------------------------------------- 1 | X(0); 2 | X(2); 3 | X(3); 4 | X(4); 5 | X(5); 6 | X(6); 7 | X(7); 8 | X(8); 9 | X(9); 10 | X(10); 11 | X(11); 12 | X(12); 13 | X(13); 14 | X(14); 15 | X(15); 16 | X(16); 17 | X(17); 18 | X(18); 19 | X(19); 20 | X(20); 21 | X(21); 22 | X(22); 23 | X(23); 24 | X(24); 25 | X(25); 26 | X(26); 27 | X(27); 28 | X(28); 29 | X(29); 30 | X(30); 31 | X(31); 32 | X(32); 33 | X(33); 34 | X(34); 35 | X(35); 36 | X(36); 37 | X(37); 38 | X(38); 39 | X(39); 40 | X(40); 41 | X(41); 42 | X(42); 43 | X(43); 44 | X(44); 45 | X(45); 46 | X(46); 47 | X(47); 48 | X(48); 49 | X(49); 50 | X(50); 51 | X(51); 52 | X(52); 53 | X(53); 54 | X(54); 55 | X(55); 56 | X(56); 57 | X(57); 58 | X(58); 59 | X(59); 60 | X(60); 61 | X(61); 62 | X(62); 63 | X(63); 64 | X(64); 65 | X(65); 66 | X(66); 67 | X(67); 68 | X(68); 69 | X(69); 70 | X(70); 71 | X(71); 72 | X(72); 73 | X(73); 74 | X(74); 75 | X(75); 76 | X(76); 77 | X(77); 78 | X(78); 79 | X(79); 80 | X(80); 81 | X(81); 82 | X(82); 83 | X(83); 84 | X(84); 85 | X(85); 86 | X(86); 87 | X(87); 88 | X(88); 89 | X(89); 90 | X(90); 91 | X(91); 92 | X(92); 93 | X(93); 94 | X(94); 95 | X(95); 96 | X(96); 97 | X(97); 98 | X(98); 99 | X(99); 100 | X(100); 101 | -------------------------------------------------------------------------------- /integers.c: -------------------------------------------------------------------------------- 1 | #include "class_integer.h" 2 | #include "class_symbol.h" 3 | #include "class_class.h" 4 | #include "integers.h" 5 | #include "symbols.h" 6 | 7 | void * 8 | integer_1_rack[] = 9 | { 10 | reference_symbol(NIL), 11 | reference_integer(1), 12 | (void *) 1, 13 | }; 14 | 15 | struct header_struct integer_1_header = 16 | { 17 | reference_class(integer), 18 | integer_1_rack, 19 | }; 20 | 21 | /* We define some integers at compile time, because integers are used 22 | in the rack of most objects to indicate the number of words the 23 | object contains. And, since we want to generate some of these 24 | other objects at compile time as well, we need these integers for 25 | that purpose. 26 | */ 27 | 28 | #define X(value) \ 29 | static void *integer_ ## value ## _rack[] = { \ 30 | reference_symbol(NIL), \ 31 | (void *) &integer_1_header, \ 32 | (void *) value, \ 33 | }; \ 34 | \ 35 | struct header_struct integer_ ## value ## _header = { \ 36 | &class_integer_header, \ 37 | integer_ ## value ## _rack, \ 38 | } 39 | #include "integer_list.h" 40 | #undef X 41 | -------------------------------------------------------------------------------- /integers.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | #define X(value) extern struct header_struct integer_ ## value ## _header 4 | X(1); 5 | #include "integer_list.h" 6 | #undef X 7 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | int 2 | main(void) 3 | { 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /strings.c: -------------------------------------------------------------------------------- 1 | #include "class_string.h" 2 | #include "class_symbol.h" 3 | #include "integers.h" 4 | #include "symbols.h" 5 | #include "characters.h" 6 | #include "strings.h" 7 | 8 | void * 9 | string_NIL_rack[] = 10 | { 11 | reference_symbol(NIL), 12 | &integer_3_header, 13 | &character_N_header, 14 | &character_I_header, 15 | &character_L_header, 16 | }; 17 | 18 | struct header_struct string_NIL_header = 19 | { 20 | reference_symbol(NIL), 21 | string_NIL_rack, 22 | }; 23 | 24 | void * 25 | string_T_rack[] = 26 | { 27 | reference_symbol(NIL), 28 | &integer_1_header, 29 | &character_T_header, 30 | }; 31 | 32 | struct header_struct string_T_header = 33 | { 34 | reference_symbol(NIL), 35 | string_T_rack, 36 | }; 37 | -------------------------------------------------------------------------------- /strings.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | 3 | declare_string(NIL); 4 | -------------------------------------------------------------------------------- /symbols.c: -------------------------------------------------------------------------------- 1 | #include "symbols.h" 2 | #include "strings.h" 3 | 4 | define_symbol(NIL, 0); 5 | -------------------------------------------------------------------------------- /symbols.h: -------------------------------------------------------------------------------- 1 | #include "header.h" 2 | #include "class_symbol.h" 3 | 4 | declare_symbol(NIL); 5 | --------------------------------------------------------------------------------