static int _clone_fs_action(BMapAction *action_set, Reference *ref, int key, Action *action) { int result = REF_RESULT_SOLVED; //TODO: Make type for clone a parameter, do not override by // default. // When a symbol is present, assume nonterminal invocation int clone_type; if(ref->type == REF_TYPE_DEFAULT) { // It could happen when merging loops in final states // that action->type == ACTION_REDUCE clone_type = action->type; } else if(ref->type == REF_TYPE_SHIFT) { if (action->type == ACTION_REDUCE) { // This could happen when the start state of a // nonterminal is also an end state. trace_op( "skip", ref->state, action, key, "reduction on first-set", 0 ); goto end; } clone_type = ACTION_SHIFT; } else if(ref->type == REF_TYPE_START) { if (action->type == ACTION_REDUCE || action->type == ACTION_ACCEPT) { trace_op( "skip", ref->state, action, key, "reduction on first-set", 0 ); goto end; } clone_type = ACTION_START; } //TODO: Detect collision for ranges (only testing `key` for now) Action *col = state_get_transition(ref->state, key); // TODO: Unify collision detection, skipping and merging with the ones // used in the state functions. if(col && ref->strategy == REF_STRATEGY_MERGE) { if(!action_compare(*action, *col)) { trace_op( "collision", ref->state, action, key, "skip duplicate", 0 ); goto end; } if(col->state == NULL || action->state == NULL) { trace_op( "collision", ref->state, action, key, "unhandled", 0 ); goto end; } //Collision: redefine actions in order to disambiguate. trace_op( "collision", ref->state, col, key, "deambiguate state", 0 ); //TODO: should only merge if actions are identical //TODO: Make this work with ranges. State *merge = malloc(sizeof(State)); state_init(merge); //Merge first set for the actions continuations. state_add_reference(merge, REF_TYPE_DEFAULT, REF_STRATEGY_MERGE, NULL, col->state); state_add_reference(merge, REF_TYPE_DEFAULT, REF_STRATEGY_MERGE, NULL, action->state); //Create unified action pointing to merged state. action_init(col, clone_type, col->reduction, merge, col->flags, col->end_symbol); result = REF_RESULT_CHANGED; } else { //No collision detected, clone the action an add it. Action clone; action_init(&clone, clone_type, action->reduction, action->state, action->flags, action->end_symbol); trace_op( "add", ref->state, &clone, key, "first-set", 0 ); bmap_action_m_append(action_set, key, clone); } end: return result; }
static void _clone_rs_action(Reference *ref, BMapAction *action_set, Nonterminal *nt, int key, Action *action) { Symbol *sb = ref->symbol; // Empty transitions should not be cloned. // They should be followed recursively to get the whole follow set, // otherwise me might loose reductions. // Always reduce? int clone_type = ACTION_REDUCE; Action *col = state_get_transition(nt->end, key); // TODO: Unify collision detection, skipping and merging with the ones // used in the state functions. if(col) { if(!action_compare(*action, *col)) { trace_op( "collision", nt->end, action, key, "skip duplicate", 0 ); goto end; } //Collision: redefine actions in order to disambiguate. trace_op( "collision", nt->end, col, key, "unhandled return set collision", 0 ); // TODO: sentinel? } else { //No collision detected, clone the action an add it. Action clone; action_init(&clone, clone_type, sb->id, NULL, action->flags, action->end_symbol); // TODO: Empty transitions should not be cloned. // They should be followed recursively to get the whole // follow set. // This happens when: // * A nonterminal is invoked at the end of a repetition and // the repetition is within a group. An empty transition // will be created between the repetition and the group, // when the nonterminal is solved the empty transition will // be found in the follow-set. trace_op( "add", nt->end, &clone, key, "return-set", 0 ); bmap_action_m_append(action_set, key, clone); } end: return; }
opcode_t * runops_slow_core(struct Parrot_Interp *interpreter, opcode_t *pc) { #ifdef USE_TRACE_INTERP Interp * trace_i; struct Parrot_Context *trace_ctx; #endif opcode_t *opc, *ostart, *oend; static size_t dod, gc; #ifdef code_start # undef code_start #endif #ifdef code_end # undef code_end #endif #define code_start interpreter->code->byte_code #define code_end (interpreter->code->byte_code + \ interpreter->code->cur_cs->base.size) #ifdef USE_TRACE_INTERP if (Interp_flags_TEST(interpreter, PARROT_TRACE_FLAG)) { trace_i = make_interpreter(interpreter, NO_FLAGS); Parrot_init(trace_i); /* remeber old context */ trace_ctx = mem_sys_allocate(sizeof(struct Parrot_Context)); mem_sys_memcopy(trace_ctx, &trace_i->ctx, sizeof(struct Parrot_Context)); /* copy in current */ mem_sys_memcopy(&trace_i->ctx, &interpreter->ctx, sizeof(struct Parrot_Context)); trace_i->code = interpreter->code; Interp_flags_SET(trace_i, PARROT_EXTERN_CODE_FLAG); } #endif dod = interpreter->dod_runs; gc = interpreter->collect_runs; while (pc) {/* && pc >= code_start && pc < code_end) {*/ interpreter->cur_pc = pc; opc = pc; ostart = code_start; oend = code_end; DO_OP(pc, interpreter); if (Interp_flags_TEST(interpreter, PARROT_TRACE_FLAG)) { #ifdef USE_TRACE_INTERP mem_sys_memcopy(&trace_i->ctx, &interpreter->ctx, sizeof(struct Parrot_Context)); trace_op(trace_i, ostart, oend, opc); #else trace_op(interpreter, ostart, oend, opc); #endif if (dod != interpreter->dod_runs) { dod = interpreter->dod_runs; PIO_printf(interpreter, " DOD\n"); } if (gc != interpreter->collect_runs) { gc = interpreter->collect_runs; PIO_printf(interpreter, " GC\n"); } } } #ifdef USE_TRACE_INTERP if (Interp_flags_TEST(interpreter, PARROT_TRACE_FLAG)) { /* restore trace context */ mem_sys_memcopy(&trace_i->ctx, trace_ctx, sizeof(struct Parrot_Context)); mem_sys_free(trace_ctx); } #endif /* if (pc && (pc < code_start || pc >= code_end)) { internal_exception(INTERP_ERROR, "Error: Control left bounds of byte-code block (now at location %d)!\n", (int)(pc - code_start)); }*/ #undef code_start #undef code_end return pc; }