handle suspend on lookahead at the very end of the chunk

This commit is contained in:
Sven M. Hallberg 2015-09-04 21:05:56 +02:00
parent 010a1a36ff
commit 1276004250
3 changed files with 27 additions and 14 deletions

View file

@ -296,7 +296,7 @@ static HLLkState *llk_parse_start_(HAllocator* mm__, const HParser* parser)
return s; return s;
} }
// returns partial result or NULL // returns partial result or NULL (no parse)
static HCountedArray *llk_parse_chunk_(HLLkState *s, const HParser* parser, static HCountedArray *llk_parse_chunk_(HLLkState *s, const HParser* parser,
HInputStream* stream) HInputStream* stream)
{ {
@ -316,6 +316,8 @@ static HCountedArray *llk_parse_chunk_(HLLkState *s, const HParser* parser,
// when we empty the stack, the parse is complete. // when we empty the stack, the parse is complete.
while(!h_slist_empty(stack)) { while(!h_slist_empty(stack)) {
tok = NULL;
// pop top of stack for inspection // pop top of stack for inspection
x = h_slist_pop(stack); x = h_slist_pop(stack);
assert(x != NULL); assert(x != NULL);
@ -323,6 +325,16 @@ static HCountedArray *llk_parse_chunk_(HLLkState *s, const HParser* parser,
if(x != MARK && x->type == HCF_CHOICE) { if(x != MARK && x->type == HCF_CHOICE) {
// x is a nonterminal; apply the appropriate production and continue // x is a nonterminal; apply the appropriate production and continue
// look up applicable production in parse table
const HCFSequence *p = h_llk_lookup(table, x, stream);
if(p == NULL)
goto no_parse;
if(p == H_NEED_INPUT)
goto need_input;
// an infinite loop case that shouldn't happen
assert(!p->items[0] || p->items[0] != x);
// push stack frame // push stack frame
h_slist_push(stack, seq); // save current partial value h_slist_push(stack, seq); // save current partial value
h_slist_push(stack, x); // save the nonterminal h_slist_push(stack, x); // save the nonterminal
@ -331,14 +343,6 @@ static HCountedArray *llk_parse_chunk_(HLLkState *s, const HParser* parser,
// open a fresh result sequence // open a fresh result sequence
seq = h_carray_new(arena); seq = h_carray_new(arena);
// look up applicable production in parse table
const HCFSequence *p = h_llk_lookup(table, x, stream);
if(p == NULL)
goto no_parse;
// an infinite loop case that shouldn't happen
assert(!p->items[0] || p->items[0] != x);
// push production's rhs onto the stack (in reverse order) // push production's rhs onto the stack (in reverse order)
HCFChoice **s; HCFChoice **s;
for(s = p->items; *s; s++); for(s = p->items; *s; s++);
@ -433,8 +437,9 @@ static HCountedArray *llk_parse_chunk_(HLLkState *s, const HParser* parser,
need_input: need_input:
if(stream->last_chunk) if(stream->last_chunk)
goto no_parse; goto no_parse;
h_arena_free(arena, tok); // no result, yet if(tok)
h_slist_push(stack, x); // try this symbol again next time h_arena_free(arena, tok); // no result, yet
h_slist_push(stack, x); // try this symbol again next time
return seq; return seq;
} }

View file

@ -349,6 +349,7 @@ void *h_stringmap_get(const HStringMap *m, const uint8_t *str, size_t n, bool en
return m->epsilon_branch; return m->epsilon_branch;
} }
// A NULL result means no parse. H_NEED_INPUT means lookahead is too short.
void *h_stringmap_get_lookahead(const HStringMap *m, HInputStream lookahead) void *h_stringmap_get_lookahead(const HStringMap *m, HInputStream lookahead)
{ {
while(m) { while(m) {
@ -362,9 +363,13 @@ void *h_stringmap_get_lookahead(const HStringMap *m, HInputStream lookahead)
// reading bits from it does not consume them from the real input. // reading bits from it does not consume them from the real input.
uint8_t c = h_read_bits(&lookahead, 8, false); uint8_t c = h_read_bits(&lookahead, 8, false);
if (lookahead.overrun) { // end of input if (lookahead.overrun) { // end of chunk
// XXX assumption of byte-wise grammar and input if (lookahead.last_chunk) { // end of input
return m->end_branch; // XXX assumption of byte-wise grammar and input
return m->end_branch;
} else {
return H_NEED_INPUT;
}
} }
// no match yet, descend // no match yet, descend

View file

@ -56,6 +56,9 @@ bool h_stringmap_empty(const HStringMap *m);
static inline HStringMap *h_stringmap_get_char(const HStringMap *m, const uint8_t c) static inline HStringMap *h_stringmap_get_char(const HStringMap *m, const uint8_t c)
{ return h_hashtable_get(m->char_branches, (void *)char_key(c)); } { return h_hashtable_get(m->char_branches, (void *)char_key(c)); }
// dummy return value used by h_stringmap_get_lookahead when out of input
#define H_NEED_INPUT ((void *)&h_stringmap_get_lookahead)
/* Convert 'parser' into CFG representation by desugaring and compiling the set /* Convert 'parser' into CFG representation by desugaring and compiling the set
* of nonterminals. * of nonterminals.