1 #include <uvm/syscalls.h>
12 #define HEAP_SIZE 1024
15 u32 free = 1; // cell 0 is reserved so that 0 can be the empty list.
16 #define TYPE_OF(pointer) (pointer >> 30)
17 #define VALUE_OF(pointer) (pointer & 0x3fffffff)
18 #define JOY_VALUE(type, value) ((type & 3) << 30) | (value & 0x3fffffff)
25 cons(u32 head, u32 tail)
27 if (free >= HEAP_SIZE)
31 u32 cell = JOY_VALUE(joyList, free);
35 u32 head(u32 list) { return heads[VALUE_OF(list)]; }
36 u32 tail(u32 list) { return tails[VALUE_OF(list)]; }
39 /*u32 cons(u32 head, u32 tail) { return tail; }*/
47 // And now for a hash table.
48 // https://benhoyt.com/writings/hash-table-in-c/#hash-tables
49 // https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
50 #define FNV_OFFSET 0xcbf29ce484222325
51 #define FNV_PRIME 0x100000001b3
55 u64 hash = FNV_OFFSET;
56 for (char* p = key; *p; ++p) {
57 hash = hash ^ (u64)(unsigned char)(*p);
58 hash = hash * FNV_PRIME;
62 // Capacity is a power of two (10 for now.)
65 #define HASH_MASK 1023
66 char* hash_table[CAPACITY];
68 ht_insert(char *symbol)
70 u64 hash = hash_key(symbol);
71 u32 index = hash % CAPACITY;
73 char *candidate = hash_table[index];
75 //print_str("interning ");print_str(symbol);print_endl();
76 hash_table[index] = symbol;
77 return JOY_VALUE(joySymbol, VALUE_OF(hash));
80 // https://en.wikipedia.org/wiki/Double_hashing
81 // Rather than use another hash function I'm going to try
82 // using the extra bits of the same hash.
83 u32 increment = ((VALUE_OF(hash) >> EXPONENT) | 1) % CAPACITY;
84 // If I understand correctly, making the increment odd
85 // means it will traverse the whole (even-sized) table.
87 // Compare pointers then hashes (since we already have
88 // one hash I'm guessing that that's cheaper or at least
89 // no more expensive than string comparision.)
90 if (candidate == symbol || hash == hash_key(candidate))
92 index = (index + increment) % CAPACITY;
93 candidate = hash_table[index];
96 //print_str("interning ");print_str(symbol);print_endl();
97 hash_table[index] = symbol;
99 return JOY_VALUE(joySymbol, VALUE_OF(hash));
104 // Note that hash will be truncated to N (N=30 as it happens) bits
106 u32 index = hash % CAPACITY;
107 char *candidate = hash_table[index];
108 u32 increment = ((hash >> EXPONENT) | 1) % CAPACITY;
110 if (hash == VALUE_OF(hash_key(candidate)))
112 index = (index + increment) % CAPACITY;
113 candidate = hash_table[index];
115 /*error = UNKNOWN_WORD_ERROR;*/
126 // Simple string storage heap.
128 #define STRING_HEAP_SIZE 100000
129 char string_heap[STRING_HEAP_SIZE];
130 u32 string_heap_top = 0;
132 allocate_string(char *buffer, u32 offset, u32 length)
134 u64 end = string_heap_top + length + 1;
135 if (end >= STRING_HEAP_SIZE)
137 memcpy(string_heap + string_heap_top, buffer + offset, length);
138 string_heap[end] = '\0';
139 u32 new_string = string_heap_top;
140 string_heap_top = (u32)end + 1;
141 //print_str("allocating ");print_str(string_heap + new_string);print_endl();
142 return string_heap + new_string;
148 push_symbol(char *symbol, u32 stack)
150 return cons(JOY_VALUE(joySymbol, ht_insert(symbol)), stack);
155 char* LEFT_BRACKET_symbol = "[";
156 char* RIGHT_BRACKET_symbol = "]";
161 is_integer(char *str, u32 index, u32 length)
163 for (;length; --length) {
164 char ch = *(str + index + length - 1);
183 convert_integer(char *str, u32 index, u32 length)
186 length = length + index;
187 for (; index < length; ++index) {
188 char ch = *(str + index);
189 u8 digit = (u8)ch - (u8)'0';
190 result = result * 10 + digit;
192 //print_str("converted integer ");print_i64(result);print_endl();
193 return JOY_VALUE(joyInt, result);
199 tokenate(char *str, u32 index, u32 length)
202 && *(str + index) == 't'
203 && *(str + index + 1) == 'r'
204 && *(str + index + 2) == 'u'
205 && *(str + index + 3) == 'e'
207 //print_str("tokenate true");print_endl();
208 return JOY_VALUE(joyBool, 1);
211 && *(str + index) == 'f'
212 && *(str + index + 1) == 'a'
213 && *(str + index + 2) == 'l'
214 && *(str + index + 3) == 's'
215 && *(str + index + 4) == 'e'
217 //print_str("tokenate false");print_endl();
218 return JOY_VALUE(joyBool, 0);
220 if (is_integer(str, index, length)) {
221 //print_str("tokenate integer");print_endl();
222 return convert_integer(str, index, length);
224 // TODO: Convert bools and ints here?
225 // Use ht_insert to avoid multiple allocations of the same string!
226 char *token = allocate_string(str, index, length);
229 return JOY_VALUE(joySymbol, ht_insert(token));
234 tokenize0(char *str, u32 str_length, u32 index, u32 acc)
236 if (index >= str_length) {
237 //print_i64(index);print_str(" : ");print_str("END tokenize");print_endl();
238 //print_i64(acc);print_str("<");print_endl();
241 //print_i64(index);print_str(" : ");print_str(str + index);print_endl();
242 char ch = str[index];
244 acc = cons(LEFT_BRACKET, tokenize0(str, str_length, index + 1, acc));
245 //print_i64(acc);print_str("<[");print_endl();
249 acc = cons(RIGHT_BRACKET, tokenize0(str, str_length, index + 1, acc));
250 //print_i64(acc);print_str("<]");print_endl();
254 return tokenize0(str, str_length, index + 1, acc);
257 for (; i < str_length; ++i) {
258 if (str[i] == '[' || str[i] == ']' || str[i] == ' ') {
262 // i == str_length OR str[i] is a delimiter char.
263 return cons(tokenate(str, index, i - index), tokenize0(str, str_length, i, acc));
271 return tokenize0(str, strlen(str), 0, empty_list);
286 reverse_list_in_place(u32 el)
288 if (!el) { // Empty list.
292 if (!t) { // Length-one list.
295 // Re-write tails[el] to point to null
296 tails[el] = empty_list;
297 // reverse the tail of this list and prepend it to [el].
305 text_to_expression(char *str)
307 u32 frame = empty_list;
308 u32 tokens = tokenize(str);
309 //print_str("tokens: "); print_joy_list(tokens); print_endl();
312 u32 tok = head(tokens);
313 tokens = tail(tokens);
314 if (LEFT_BRACKET == tok) {
315 //print_str("left bracket");print_endl();
316 stack[stack_top] = frame;
321 if (RIGHT_BRACKET == tok) {
322 //print_str("right bracket");print_endl();
323 tok = reverse_list_in_place(frame);
324 //print_str("new list: "); print_joy_list(tok); print_endl();
325 --stack_top; // This first! THEN get the old frame! D'oh!
326 frame = stack[stack_top];
328 frame = cons(tok, frame);
329 //print_str("t2e frame: "); print_joy_list(frame); print_endl();
331 return reverse_list_in_place(frame);
336 print_joy_value(u32 jv)
338 u8 type = TYPE_OF(jv);
339 if (type == joyInt) {
340 print_i64(VALUE_OF(jv));
341 } else if (type == joyBool) {
342 print_str(VALUE_OF(jv) ? "true" : "false");
343 } else if (type == joyList) {
347 } else if (type == joySymbol) {
348 char *str = ht_lookup(VALUE_OF(jv));
349 /*if (error != NO_ERROR)*/
356 print_joy_list(u32 list)
359 print_joy_value(head(list));
370 memset(string_heap, 0, sizeof(string_heap));
371 LEFT_BRACKET = JOY_VALUE(joySymbol, ht_insert(LEFT_BRACKET_symbol));
372 RIGHT_BRACKET = JOY_VALUE(joySymbol, ht_insert(RIGHT_BRACKET_symbol));
374 //char *buffer = " 1[2[ 3 cats ]4] cats dogs bunnies";
375 char *buffer = " 1[2]3 bunnies";
376 /*print_str(allocate_string(buffer, 4, 4)); print_endl();*/
377 /*print_str(allocate_string(buffer, 2, 4)); print_endl();*/
378 /*print_str(allocate_string(buffer, 7, 5)); print_endl();*/
379 u32 jv = text_to_expression(" 1[2[true 3][[]]bob]false[]bob 3[4]5");
380 //jv = reverse_list_in_place(jv);
381 if (LEFT_BRACKET == jv) {
384 //jv = JOY_VALUE(joyList, jv);