factor out a struct HLREngine

This commit is contained in:
Sven M. Hallberg 2013-06-17 19:11:18 +02:00
parent 3e85648844
commit 7eff4b8d94

View file

@ -61,6 +61,16 @@ typedef struct HLREnhGrammar_ {
HArena *arena; HArena *arena;
} HLREnhGrammar; } HLREnhGrammar;
typedef struct HLREngine_ {
const HLRTable *table;
HSlist *left; // left stack; reductions happen here
HSlist *right; // right stack; input appears here
size_t state;
bool running;
HArena *arena; // will hold the results
HArena *tarena; // tmp, deleted after parse
} HLREngine;
// XXX move to internal.h or something // XXX move to internal.h or something
// XXX replace other hashtable iterations with this // XXX replace other hashtable iterations with this
@ -733,24 +743,33 @@ h_lr_lookup(const HLRTable *table, size_t state, const HCFChoice *symbol)
} }
} }
HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream) HLREngine *h_lrengine_new(HArena *arena, HArena *tarena, const HLRTable *table)
{ {
HLRTable *table = parser->backend_data; HLREngine *engine = h_arena_malloc(tarena, sizeof(HLREngine));
if(!table)
return NULL;
HArena *arena = h_new_arena(mm__, 0); // will hold the results engine->table = table;
HArena *tarena = h_new_arena(mm__, 0); // tmp, deleted after parse engine->left = h_slist_new(tarena);
HSlist *left = h_slist_new(tarena); // left stack; reductions happen here engine->right = h_slist_new(tarena);
HSlist *right = h_slist_new(tarena); // right stack; input appears here engine->state = 0;
engine->running = 1;
engine->arena = arena;
engine->tarena = tarena;
return engine;
}
void h_lrengine_step(HLREngine *engine, HInputStream *stream)
{
// short-hand names
HSlist *left = engine->left;
HSlist *right = engine->right;
HArena *arena = engine->arena;
HArena *tarena = engine->tarena;
// stack layout: // stack layout:
// on the left stack, we put pairs: (saved state, semantic value) // on the left stack, we put pairs: (saved state, semantic value)
// on the right stack, we put pairs: (symbol, semantic value) // on the right stack, we put pairs: (symbol, semantic value)
// run while the recognizer finds handles in the input
size_t state = 0;
while(1) {
// make sure there is input on the right stack // make sure there is input on the right stack
if(h_slist_empty(right)) { if(h_slist_empty(right)) {
// XXX use statically-allocated terminal symbols // XXX use statically-allocated terminal symbols
@ -778,15 +797,18 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
HCFChoice *symbol = right->head->elem; HCFChoice *symbol = right->head->elem;
// table lookup // table lookup
const HLRAction *action = h_lr_lookup(table, state, symbol); const HLRAction *action = h_lr_lookup(engine->table, engine->state, symbol);
if(action == NULL) if(action == NULL) {
break; // no handle recognizable in input, terminate parsing // no handle recognizable in input, terminate
engine->running = false;
return;
}
if(action->type == HLR_SHIFT) { if(action->type == HLR_SHIFT) {
h_slist_push(left, (void *)(uintptr_t)state); h_slist_push(left, (void *)(uintptr_t)engine->state);
h_slist_pop(right); // symbol (discard) h_slist_pop(right); // symbol (discard)
h_slist_push(left, h_slist_pop(right)); // semantic value h_slist_push(left, h_slist_pop(right)); // semantic value
state = action->nextstate; engine->state = action->nextstate;
} else { } else {
assert(action->type == HLR_REDUCE); assert(action->type == HLR_REDUCE);
size_t len = action->production.length; size_t len = action->production.length;
@ -801,7 +823,7 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
HParsedToken *v = NULL; HParsedToken *v = NULL;
for(size_t i=0; i<len; i++) { for(size_t i=0; i<len; i++) {
v = h_slist_pop(left); v = h_slist_pop(left);
state = (uintptr_t)h_slist_pop(left); engine->state = (uintptr_t)h_slist_pop(left);
// collect values in result sequence // collect values in result sequence
value->seq->elements[len-1-i] = v; value->seq->elements[len-1-i] = v;
@ -820,8 +842,11 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
value = (HParsedToken *)symbol->reshape(make_result(arena, value)); value = (HParsedToken *)symbol->reshape(make_result(arena, value));
// call validation and semantic action, if present // call validation and semantic action, if present
if(symbol->pred && !symbol->pred(make_result(tarena, value))) if(symbol->pred && !symbol->pred(make_result(tarena, value))) {
break; // validation failed -> no parse // validation failed -> no parse; terminate
engine->running = false;
return;
}
if(symbol->action) if(symbol->action)
value = (HParsedToken *)symbol->action(make_result(arena, value)); value = (HParsedToken *)symbol->action(make_result(arena, value));
@ -829,22 +854,38 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
h_slist_push(right, value); h_slist_push(right, value);
h_slist_push(right, symbol); h_slist_push(right, symbol);
} }
} }
HParseResult *h_lrengine_result(HLREngine *engine)
{
// parsing was successful iff the start symbol is on top of the right stack // parsing was successful iff the start symbol is on top of the right stack
HParseResult *result = NULL; if(h_slist_pop(engine->right) == engine->table->start) {
if(h_slist_pop(right) == table->start) {
// next on the right stack is the start symbol's semantic value // next on the right stack is the start symbol's semantic value
assert(!h_slist_empty(right)); assert(!h_slist_empty(engine->right));
HParsedToken *tok = h_slist_pop(right); HParsedToken *tok = h_slist_pop(engine->right);
result = make_result(arena, tok); return make_result(engine->arena, tok);
} else { } else {
h_delete_arena(arena); return NULL;
result = NULL;
} }
}
HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream)
{
HLRTable *table = parser->backend_data;
if(!table)
return NULL;
HArena *arena = h_new_arena(mm__, 0); // will hold the results
HArena *tarena = h_new_arena(mm__, 0); // tmp, deleted after parse
HLREngine *engine = h_lrengine_new(arena, tarena, table);
// run while the recognizer finds handles in the input
while(engine->running)
h_lrengine_step(engine, stream);
HParseResult *result = h_lrengine_result(engine);
if(!result)
h_delete_arena(arena);
h_delete_arena(tarena); h_delete_arena(tarena);
return result; return result;
} }