// This is an internal header; it provides macros to make desugaring cleaner. #include #include "../internal.h" #ifndef HAMMER_CONTEXTFREE__H #define HAMMER_CONTEXTFREE__H // HCFStack struct HCFStack_ { HCFChoice **stack; int count; int cap; HCFChoice *last_completed; // Last completed choice. // XXX is last_completed still needed? HCFChoice *prealloc; // If not NULL, will be used for the outermost choice. }; #ifndef UNUSED #define UNUSED __attribute__((unused)) #endif static inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *stk__) UNUSED; static inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) UNUSED; static HCFStack* h_cfstack_new(HAllocator *mm__) UNUSED; static HCFStack* h_cfstack_new(HAllocator *mm__) { HCFStack *stack = h_new(HCFStack, 1); stack->count = 0; stack->cap = 4; stack->stack = h_new(HCFChoice*, stack->cap); stack->prealloc = NULL; return stack; } static void h_cfstack_free(HAllocator *mm__, HCFStack *stk__) UNUSED; static void h_cfstack_free(HAllocator *mm__, HCFStack *stk__) { h_free(stk__->prealloc); h_free(stk__->stack); h_free(stk__); } static inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFChoice *item) UNUSED; static inline void h_cfstack_add_to_seq(HAllocator *mm__, HCFStack *stk__, HCFChoice *item) { HCFChoice *cur_top = stk__->stack[stk__->count-1]; assert(cur_top->type == HCF_CHOICE); assert(cur_top->seq[0] != NULL); // There must be at least one sequence... stk__->last_completed = item; for (int i = 0;; i++) { if (cur_top->seq[i+1] == NULL) { assert(cur_top->seq[i]->items != NULL); for (int j = 0;; j++) { if (cur_top->seq[i]->items[j] == NULL) { cur_top->seq[i]->items = mm__->realloc(mm__, cur_top->seq[i]->items, sizeof(HCFChoice*) * (j+2)); cur_top->seq[i]->items[j] = item; cur_top->seq[i]->items[j+1] = NULL; return; } } } } } static inline HCFChoice* h_cfstack_new_choice_raw(HAllocator *mm__, HCFStack *stk__) { HCFChoice *ret = stk__->prealloc? stk__->prealloc : h_new(HCFChoice, 1); stk__->prealloc = NULL; ret->reshape = NULL; ret->action = NULL; ret->pred = NULL; ret->type = ~0; // invalid type // Add it to the current sequence... if (stk__->count > 0) { h_cfstack_add_to_seq(mm__, stk__, ret); } return ret; } static inline void h_cfstack_add_charset(HAllocator *mm__, HCFStack *stk__, HCharset charset) { HCFChoice *ni = h_cfstack_new_choice_raw(mm__, stk__); ni->type = HCF_CHARSET; ni->charset = charset; stk__->last_completed = ni; } static inline void h_cfstack_add_char(HAllocator *mm__, HCFStack *stk__, uint8_t chr) { HCFChoice *ni = h_cfstack_new_choice_raw(mm__, stk__); ni->type = HCF_CHAR; ni->chr = chr; stk__->last_completed = ni; } static inline void h_cfstack_add_end(HAllocator *mm__, HCFStack *stk__) { HCFChoice *ni = h_cfstack_new_choice_raw(mm__, stk__); ni->type = HCF_END; stk__->last_completed = ni; } static inline void h_cfstack_begin_choice(HAllocator *mm__, HCFStack *stk__) { HCFChoice *choice = h_cfstack_new_choice_raw(mm__, stk__); choice->type = HCF_CHOICE; choice->seq = h_new(HCFSequence*, 1); choice->seq[0] = NULL; if (stk__->count + 1 > stk__->cap) { assert(stk__->cap > 0); stk__->cap *= 2; stk__->stack = mm__->realloc(mm__, stk__->stack, stk__->cap * sizeof(HCFChoice*)); } assert(stk__->cap >= 1); stk__->stack[stk__->count++] = choice; } static inline void h_cfstack_begin_seq(HAllocator *mm__, HCFStack *stk__) { HCFChoice *top = stk__->stack[stk__->count-1]; for (int i = 0;; i++) { if (top->seq[i] == NULL) { top->seq = mm__->realloc(mm__, top->seq, sizeof(HCFSequence*) * (i+2)); HCFSequence *seq = top->seq[i] = h_new(HCFSequence, 1); top->seq[i+1] = NULL; seq->items = h_new(HCFChoice*, 1); seq->items[0] = NULL; return; } } } static inline void h_cfstack_end_seq(HAllocator *mm__, HCFStack *stk__) UNUSED; static inline void h_cfstack_end_seq(HAllocator *mm__, HCFStack *stk__) { // do nothing. You should call this anyway. } static inline void h_cfstack_end_choice(HAllocator *mm__, HCFStack *stk__) UNUSED; static inline void h_cfstack_end_choice(HAllocator *mm__, HCFStack *stk__) { assert(stk__->count > 0); stk__->last_completed = stk__->stack[stk__->count-1]; stk__->count--; } #define HCFS_APPEND(choice) h_cfstack_add_to_seq(mm__, stk__, (choice)) #define HCFS_DESUGAR(parser) h_desugar(mm__, stk__, parser) #define HCFS_ADD_CHARSET(charset) h_cfstack_add_charset(mm__, stk__, (charset)) #define HCFS_ADD_CHAR(chr) h_cfstack_add_char(mm__, stk__, (chr)) #define HCFS_ADD_END() h_cfstack_add_end(mm__, stk__) // The semicolons on BEGIN macros are intentional; pretend that they // are control structures. #define HCFS_BEGIN_CHOICE() h_cfstack_begin_choice(mm__, stk__); #define HCFS_BEGIN_SEQ() h_cfstack_begin_seq(mm__, stk__); #define HCFS_END_CHOICE() h_cfstack_end_choice(mm__, stk__) #define HCFS_END_SEQ() h_cfstack_end_seq(mm__, stk__) #define HCFS_THIS_CHOICE (stk__->stack[stk__->count-1]) #endif