diff --git a/include/picrin/read.h b/include/picrin/read.h index 31bdbf6c..8b977d58 100644 --- a/include/picrin/read.h +++ b/include/picrin/read.h @@ -14,11 +14,24 @@ enum pic_typecase { PIC_CASE_FOLD, }; +struct pic_trie { + struct pic_trie *table[256]; + struct pic_proc *proc; +}; + struct pic_reader { short typecase; xhash labels; + struct pic_trie *trie; }; +void pic_init_reader(pic_state *); + +void pic_define_reader(pic_state *, const char *, pic_func_t); + +struct pic_trie *pic_trie_new(pic_state *); +void pic_trie_delete(pic_state *, struct pic_trie *); + #if defined(__cplusplus) } #endif diff --git a/src/gc.c b/src/gc.c index 9fc02c7d..9a947837 100644 --- a/src/gc.c +++ b/src/gc.c @@ -21,6 +21,7 @@ #include "picrin/data.h" #include "picrin/dict.h" #include "picrin/record.h" +#include "picrin/read.h" #if GC_DEBUG # include @@ -550,6 +551,21 @@ gc_mark(pic_state *pic, pic_value v) gc_mark_object(pic, obj); } +static void +gc_mark_trie(pic_state *pic, struct pic_trie *trie) +{ + size_t i; + + for (i = 0; i < sizeof trie->table / sizeof(struct pic_trie *); ++i) { + if (trie->table[i] != NULL) { + gc_mark_trie(pic, trie->table[i]); + } + } + if (trie->proc != NULL) { + gc_mark_object(pic, (struct pic_object *)trie->proc); + } +} + static void gc_mark_phase(pic_state *pic) { @@ -604,6 +620,9 @@ gc_mark_phase(pic_state *pic) } } + /* readers */ + gc_mark_trie(pic, pic->reader->trie); + /* library table */ gc_mark(pic, pic->libs); } diff --git a/src/init.c b/src/init.c index 48601882..0d345a01 100644 --- a/src/init.c +++ b/src/init.c @@ -6,6 +6,7 @@ #include "picrin.h" #include "picrin/pair.h" +#include "picrin/read.h" #include "picrin/lib.h" #include "picrin/macro.h" #include "picrin/error.h" @@ -73,6 +74,8 @@ pic_init_core(pic_state *pic) { size_t ai = pic_gc_arena_preserve(pic); + pic_init_reader(pic); + pic_deflibrary (pic, "(picrin base core)") { pic_define_syntactic_keyword(pic, pic->lib->env, pic->sDEFINE, pic->rDEFINE); pic_define_syntactic_keyword(pic, pic->lib->env, pic->sSETBANG, pic->rSETBANG); diff --git a/src/read.c b/src/read.c index a7ebdfd7..5b6ab58b 100644 --- a/src/read.c +++ b/src/read.c @@ -13,6 +13,7 @@ #include "picrin/vector.h" #include "picrin/blob.h" #include "picrin/port.h" +#include "picrin/proc.h" static pic_value read(pic_state *pic, struct pic_port *port, int c); static pic_value read_nullable(pic_state *pic, struct pic_port *port, int c); @@ -665,74 +666,28 @@ read_unmatch(pic_state *pic, struct pic_port *port, int c) read_error(pic, "unmatched parenthesis"); } -static pic_value -read_dispatch(pic_state *pic, struct pic_port *port, int c) -{ - c = next(port); - - switch (c) { - case '!': - return read_directive(pic, port, c); - case '|': - return read_block_comment(pic, port, c); - case ';': - return read_datum_comment(pic, port, c); - case 't': case 'f': - return read_boolean(pic, port, c); - case '\\': - return read_char(pic, port, c); - case '(': - return read_vector(pic, port, c); - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return read_label(pic, port, c); - case 'u': - return read_unsigned_blob(pic, port, c); - case '.': - return read_eval(pic, port, c); - default: - read_error(pic, "unexpected dispatch character"); - } -} - static pic_value read_nullable(pic_state *pic, struct pic_port *port, int c) { + struct pic_trie *trie = pic->reader->trie; + c = skip(port, c); if (c == EOF) { read_error(pic, "unexpected EOF"); } - switch (c) { - case ')': - return read_unmatch(pic, port, c); - case ';': - return read_comment(pic, port, c); - case '#': - return read_dispatch(pic, port, c); - case '\'': - return read_quote(pic, port, c); - case '`': - return read_quasiquote(pic, port, c); - case ',': - return read_comma(pic, port, c); - case '"': - return read_string(pic, port, c); - case '|': - return read_pipe(pic, port, c); - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return read_number(pic, port, c); - case '+': - return read_plus(pic, port, c); - case '-': - return read_minus(pic, port, c); - case '(': case '[': - return read_pair(pic, port, c); - default: - return read_symbol(pic, port, c); + if (trie->table[c] == NULL) { + read_error(pic, "invalid character at the seeker head"); } + for (trie = trie->table[c]; trie->table[peek(port)] != NULL; trie = trie->table[c]) { + c = next(port); + } + + if (trie->proc == NULL) { + read_error(pic, "no reader registered for current string"); + } + return pic_apply2(pic, trie->proc, pic_obj_value(port), pic_char_value(c)); } static pic_value @@ -751,6 +706,134 @@ read(pic_state *pic, struct pic_port *port, int c) return val; } +struct pic_trie * +pic_trie_new(pic_state *pic) +{ + struct pic_trie *trie; + + trie = pic_alloc(pic, sizeof(struct pic_trie)); + trie->proc = NULL; + memset(trie->table, 0, sizeof trie->table); + + return trie; +} + +void +pic_trie_delete(pic_state *pic, struct pic_trie *trie) +{ + size_t i; + + for (i = 0; i < sizeof trie->table / sizeof(struct pic_trie *); ++i) { + if (trie->table[i] != NULL) { + pic_trie_delete(pic, trie->table[i]); + } + } + + pic_free(pic, trie); +} + +void +pic_define_reader(pic_state *pic, const char *str, pic_func_t reader) +{ + struct pic_trie *trie = pic->reader->trie; + int c; + + while ((c = *str++)) { + if (trie->table[c] == NULL) { + trie->table[c] = pic_trie_new(pic); + } + trie = trie->table[c]; + } + trie->proc = pic_proc_new(pic, reader, "reader"); +} + +#define DEFINE_READER(name) \ + static pic_value \ + pic_##name(pic_state *pic) \ + { \ + struct pic_port *port; \ + char c; \ + \ + pic_get_args(pic, "pc", &port, &c); \ + \ + return name(pic, port, c); \ + } + +DEFINE_READER(read_unmatch) +DEFINE_READER(read_comment) +DEFINE_READER(read_quote) +DEFINE_READER(read_quasiquote) +DEFINE_READER(read_comma) +DEFINE_READER(read_string) +DEFINE_READER(read_pipe) +DEFINE_READER(read_plus) +DEFINE_READER(read_minus) +DEFINE_READER(read_pair) +DEFINE_READER(read_directive) +DEFINE_READER(read_block_comment) +DEFINE_READER(read_datum_comment) +DEFINE_READER(read_boolean) +DEFINE_READER(read_char) +DEFINE_READER(read_vector) +DEFINE_READER(read_unsigned_blob) +DEFINE_READER(read_eval) +DEFINE_READER(read_symbol) +DEFINE_READER(read_number) +DEFINE_READER(read_label) + +void +pic_init_reader(pic_state *pic) +{ + static const char INIT[] = "!$%&*./:<=>?@^_~"; + char buf[3] = { 0 }; + size_t i; + + pic_define_reader(pic, ")", pic_read_unmatch); + pic_define_reader(pic, ";", pic_read_comment); + pic_define_reader(pic, "'", pic_read_quote); + pic_define_reader(pic, "`", pic_read_quasiquote); + pic_define_reader(pic, ",", pic_read_comma); + pic_define_reader(pic, "\"", pic_read_string); + pic_define_reader(pic, "|", pic_read_pipe); + pic_define_reader(pic, "+", pic_read_plus); + pic_define_reader(pic, "-", pic_read_minus); + pic_define_reader(pic, "(", pic_read_pair); + pic_define_reader(pic, "[", pic_read_pair); + + pic_define_reader(pic, "#!", pic_read_directive); + pic_define_reader(pic, "#|", pic_read_block_comment); + pic_define_reader(pic, "#;", pic_read_datum_comment); + pic_define_reader(pic, "#t", pic_read_boolean); + pic_define_reader(pic, "#f", pic_read_boolean); + pic_define_reader(pic, "#\\", pic_read_char); + pic_define_reader(pic, "#(", pic_read_vector); + pic_define_reader(pic, "#u", pic_read_unsigned_blob); + pic_define_reader(pic, "#.", pic_read_eval); + + /* read number */ + for (buf[0] = '0'; buf[0] <= '9'; ++buf[0]) { + pic_define_reader(pic, buf, pic_read_number); + } + + /* read symbol */ + for (buf[0] = 'a'; buf[0] <= 'z'; ++buf[0]) { + pic_define_reader(pic, buf, pic_read_symbol); + } + for (buf[0] = 'A'; buf[0] <= 'Z'; ++buf[0]) { + pic_define_reader(pic, buf, pic_read_symbol); + } + for (i = 0; i < sizeof INIT; ++i) { + buf[0] = INIT[i]; + pic_define_reader(pic, buf, pic_read_symbol); + } + + /* read label */ + buf[0] = '#'; + for (buf[1] = '0'; buf[1] <= '9'; ++buf[1]) { + pic_define_reader(pic, buf, pic_read_label); + } +} + pic_value pic_read(pic_state *pic, struct pic_port *port) { diff --git a/src/state.c b/src/state.c index 7b32566c..d9427f3d 100644 --- a/src/state.c +++ b/src/state.c @@ -62,6 +62,7 @@ pic_open(int argc, char *argv[], char **envp) /* reader */ pic->reader = malloc(sizeof(struct pic_reader)); pic->reader->typecase = PIC_CASE_DEFAULT; + pic->reader->trie = pic_trie_new(pic); xh_init_int(&pic->reader->labels, sizeof(pic_value)); /* error handling */ @@ -181,6 +182,7 @@ pic_close(pic_state *pic) /* free reader struct */ xh_destroy(&pic->reader->labels); + pic_trie_delete(pic, pic->reader->trie); free(pic->reader); /* free global stacks */