factor out a struct HLREngine
This commit is contained in:
parent
3e85648844
commit
7eff4b8d94
1 changed files with 141 additions and 100 deletions
|
|
@ -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));
|
||||||
|
|
||||||
|
|
@ -831,20 +856,36 @@ HParseResult *h_lr_parse(HAllocator* mm__, const HParser* parser, HInputStream*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue