diff --git a/src/Makefile b/src/Makefile index 128de05..47e136d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -45,6 +45,7 @@ TESTS := t_benchmark.o \ t_bitreader.o \ t_bitwriter.o \ t_parser.o \ + t_misc.o \ test_suite.o OUTPUTS := libhammer.a \ diff --git a/src/backends/packrat.c b/src/backends/packrat.c index d05129d..cc2a9db 100644 --- a/src/backends/packrat.c +++ b/src/backends/packrat.c @@ -77,14 +77,18 @@ HParserCacheValue* recall(HParserCacheKey *k, HParseState *state) { void setupLR(const HParser *p, HParseState *state, HLeftRec *rec_detect) { if (!rec_detect->head) { HRecursionHead *some = a_new(HRecursionHead, 1); - some->head_parser = p; some->involved_set = NULL; some->eval_set = NULL; + some->head_parser = p; + some->involved_set = h_slist_new(state->arena); + some->eval_set = NULL; rec_detect->head = some; } assert(state->lr_stack->head != NULL); - HLeftRec *lr = state->lr_stack->head->elem; - while (lr && lr->rule != p) { + HSlistNode *head = state->lr_stack->head; + HLeftRec *lr; + while (head && (lr = head->elem)->rule != p) { lr->head = rec_detect->head; h_slist_push(lr->head->involved_set, (void*)lr->rule); + head = head->next; } } @@ -101,7 +105,7 @@ HParseResult* grow(HParserCacheKey *k, HParseState *state, HRecursionHead *head) HParseResult *old_res = old_cached->right->result; // reset the eval_set of the head of the recursion at each beginning of growth - head->eval_set = head->involved_set; + head->eval_set = h_slist_copy(head->involved_set); HParseResult *tmp_res = perform_lowlevel_parse(state, k->parser); if (tmp_res) { diff --git a/src/datastructures.c b/src/datastructures.c index b1e4f75..3d94804 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -41,6 +41,26 @@ HSlist* h_slist_new(HArena *arena) { return ret; } +HSlist* h_slist_copy(HSlist *slist) { + HSlist *ret = h_slist_new(slist->arena); + HSlistNode *head = slist->head; + HSlistNode *tail; + if (head != NULL) { + h_slist_push(ret, head->elem); + tail = ret->head; + head = head->next; + } + while (head != NULL) { + // append head item to tail in a new node + HSlistNode *node = h_arena_malloc(slist->arena, sizeof(HSlistNode)); + node->elem = head->elem; + node->next = NULL; + tail = tail->next = node; + head = head->next; + } + return ret; +} + void* h_slist_pop(HSlist *slist) { HSlistNode *head = slist->head; if (!head) diff --git a/src/hammer.h b/src/hammer.h index 0791769..5a0c625 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -43,9 +43,8 @@ typedef enum HTokenType_ { TT_SINT, TT_UINT, TT_SEQUENCE, - TT_USER = 64, TT_ERR, - TT_MAX + TT_USER = 64 } HTokenType; typedef struct HCountedArray_ { diff --git a/src/internal.h b/src/internal.h index 67ecb22..0dcf857 100644 --- a/src/internal.h +++ b/src/internal.h @@ -209,6 +209,7 @@ HCountedArray *h_carray_new(HArena * arena); void h_carray_append(HCountedArray *array, void* item); HSlist* h_slist_new(HArena *arena); +HSlist* h_slist_copy(HSlist *slist); void* h_slist_pop(HSlist *slist); void h_slist_push(HSlist *slist, void* item); bool h_slist_find(HSlist *slist, const void* item); diff --git a/src/t_misc.c b/src/t_misc.c new file mode 100644 index 0000000..5c08a2e --- /dev/null +++ b/src/t_misc.c @@ -0,0 +1,16 @@ +#include +#include "test_suite.h" +#include "hammer.h" + +static void test_tt_user(void) { + g_check_cmpint(TT_USER, >, TT_NONE); + g_check_cmpint(TT_USER, >, TT_BYTES); + g_check_cmpint(TT_USER, >, TT_SINT); + g_check_cmpint(TT_USER, >, TT_UINT); + g_check_cmpint(TT_USER, >, TT_SEQUENCE); + g_check_cmpint(TT_USER, >, TT_ERR); +} + +void register_misc_tests(void) { + g_test_add_func("/core/misc/tt_user", test_tt_user); +} diff --git a/src/t_parser.c b/src/t_parser.c index b1f9b63..daca1a3 100644 --- a/src/t_parser.c +++ b/src/t_parser.c @@ -365,6 +365,17 @@ static void test_not(void) { g_check_parse_ok(not_2, "a++b", 4, "(u0x61 <2b.2b> u0x62)"); } +static void test_leftrec(void) { + const HParser *a_ = h_ch('a'); + + HParser *lr_ = h_indirect(); + h_bind_indirect(lr_, h_choice(h_sequence(lr_, a_, NULL), a_, NULL)); + + g_check_parse_ok(lr_, "a", 1, "u0x61"); + g_check_parse_ok(lr_, "aa", 2, "(u0x61 u0x61)"); + g_check_parse_ok(lr_, "aaa", 3, "((u0x61 u0x61) u0x61)"); +} + void register_parser_tests(void) { g_test_add_func("/core/parser/token", test_token); g_test_add_func("/core/parser/ch", test_ch); @@ -406,4 +417,5 @@ void register_parser_tests(void) { g_test_add_func("/core/parser/and", test_and); g_test_add_func("/core/parser/not", test_not); g_test_add_func("/core/parser/ignore", test_ignore); + g_test_add_func("/core/parser/leftrec", test_leftrec); } diff --git a/src/test_suite.c b/src/test_suite.c index 8d2913a..e01d020 100644 --- a/src/test_suite.c +++ b/src/test_suite.c @@ -22,6 +22,7 @@ extern void register_bitreader_tests(); extern void register_bitwriter_tests(); extern void register_parser_tests(); +extern void register_misc_tests(); extern void register_benchmark_tests(); int main(int argc, char** argv) { @@ -31,6 +32,7 @@ int main(int argc, char** argv) { register_bitreader_tests(); register_bitwriter_tests(); register_parser_tests(); + register_misc_tests(); register_benchmark_tests(); g_test_run();