Beispiel #1
0
void do_run(void)
{
    state.halted = 0;
    lc3_run(state);
    memory->Update();
    registers->Update();
}
Beispiel #2
0
void do_step(unsigned int times)
{
    state.halted = 0;
    lc3_run(state, times);
    memory->Update();
    registers->Update();
}
Beispiel #3
0
/** Entry
  *
  *
  */
void* LC3RunThread::Entry()
{
    ///TODO consider writing this without rewriting next_line/prev_line.
    int depth = 0;
    lc3_instr instr;
    bool interrupt_begin = false;

    state.halted = 0;

    switch(run_mode)
    {
    case RUNMODE_RUN:
        while(!state.halted)
        {
            lc3_step(state);
            if (TestDestroy()) break;
            Yield();
        }
        break;
    case RUNMODE_RUNFOR:
        if (runtime > 0)
            lc3_run(state, runtime);
        else
            lc3_rewind(state, -runtime);
        break;
    case RUNMODE_STEP:
        lc3_step(state);
        break;
    case RUNMODE_BACK:
        lc3_back(state);
        break;
    case RUNMODE_FINISH:
        depth = 1;
    case RUNMODE_NEXTLINE:
        // Subroutine depth
        do
        {
            // Get Next Instruction.
            instr = lc3_decode(state, state.mem[state.pc]);
            // So if we get a JSR/JSRR or if we get a TRAP and true traps are enabled
            if (instr.data.opcode == JSR_INSTR || (instr.data.opcode == TRAP_INSTR && state.true_traps))
                depth++;

            // If we get a RET instruction JMP R7
            if (instr.data.opcode == JMP_INSTR && instr.jmp.base_r == 7)
                depth--;

            // If we get an RTI instruction
            if (instr.data.opcode == RTI_INSTR)
                depth--;

            // Execute
            lc3_step(state);

            // If we got interrupted
            if (state.interrupt_enabled && state.undo_stack.back().changes == LC3_INTERRUPT_BEGIN)
                depth++;

            if (TestDestroy()) break;
            Yield();
        }
        while (depth != 0 && !state.halted);
        break;
    case RUNMODE_PREVLINE:
        // Subroutine depth
        depth = 0;

        do
        {
            if (!state.undo_stack.empty())
            {
                lc3_state_change& last = state.undo_stack.back();
                // Can't backstep through interrupt
                if (last.changes == LC3_INTERRUPT_BEGIN)
                    break;

                // Get rid of all processed interrupts.
                while (last.changes == LC3_INTERRUPT && !state.undo_stack.empty())
                {
                    lc3_back(state);
                    last = state.undo_stack.back();
                    if (TestDestroy()) break;
                    Yield();
                }
            }

            // Execute (Have to do this first you can't assume mem[pc - 1] was the last
            // instruction due to jumps.
            lc3_back(state);
            // Get the instruction that got you where you are.
            lc3_instr instr = lc3_decode(state, state.mem[state.pc]);
            // If we get a RET instruction JMP R7
            if (instr.data.opcode == JMP_INSTR && instr.jmp.base_r == 7)
                depth++;
            // So if we get a JSR/JSRR or if we get a TRAP and true traps are enabled
            if (instr.data.opcode == JSR_INSTR || (instr.data.opcode == TRAP_INSTR && state.true_traps))
                depth--;
            if (TestDestroy()) break;
            Yield();
            // Don't have to handle interrupts here...
        }
        while (depth != 0 && !state.halted && !state.undo_stack.empty());
        break;
    case RUNMODE_REWIND:
        // Do this until no more changes.
        while (!state.undo_stack.empty() && !interrupt_begin)
        {
            lc3_state_change& last = state.undo_stack.back();
            interrupt_begin = (last.changes == LC3_INTERRUPT_BEGIN);
            // Backstep
            lc3_back(state);

            if (TestDestroy()) break;
            Yield();
        }
        break;
    }

    wxQueueEvent(frame, new wxThreadEvent(wxEVT_COMMAND_RUNTHREAD_COMPLETED));

    return NULL;
}
Beispiel #4
0
void lc3_run_test_case(lc3_test& test, const std::string& filename, int seed)
{
    lc3_state state;

    // Preliminary stuff
    if (seed != -1) srand(seed);
    lc3_init(state, test.randomize, test.randomize);
    if (test.true_traps) lc3_set_true_traps(state, 1);
    if (test.interrupt_enabled) state.interrupt_enabled = 1;
    bool disable_plugins = test.disable_plugins;
    state.max_stack_size = 0;
    state.max_call_stack_size = -1;
    state.in_lc3test = true;

    try
    {
        LC3AssembleOptions options;
        options.multiple_errors = false;
        options.warnings_as_errors = false;
        options.process_debug_comments = false;
        options.enable_warnings = false;
        options.disable_plugins = disable_plugins;
        lc3_assemble(state, filename, options);
    }
    catch (LC3AssembleException e)
    {
        throw e.what();
    }


    std::stringstream* newinput = new std::stringstream();

    // Set up test environment
    for (unsigned int i = 0; i < test.input.size(); i++)
    {
        lc3_test_input& input = test.input[i];
        int value_calc;
        int address_calc = 0;
        unsigned short effective_address;

        ///TODO flip the condition here so that if new types are added you don't have to check for it here...
        if (input.type != TEST_IO && input.type != TEST_REGISTER && input.type != TEST_PC && input.type != TEST_SUBROUTINE &&
            lc3_calculate(state, input.address, address_calc) == -1)
            throw "An address expression " + input.address + " was not formed correctly.";
        else if (input.type == TEST_REGISTER)
        {
            if (input.address.size() != 2)
                throw "Register format is RX where x is between 0-7 found: " + input.address;

            address_calc = input.address[1] - '0';
            if (address_calc > 7 || address_calc < 0)
                throw "Invalid register " + input.address;
        }
        else
            lc3_calculate(state, input.address, address_calc);

        effective_address = (unsigned short) address_calc;

        switch (input.type)
        {
            case TEST_VALUE:
                if (lc3_calculate(state, input.value, value_calc))
                    throw "<in test-value> A value expression " + input.value + " was malformed.";
                state.mem[effective_address] = (short) value_calc;
                break;
            case TEST_REGISTER:
                if (lc3_calculate(state, input.registerval, value_calc))
                    throw "<in test-register> A value expression " + input.registerval + " was malformed.";
                state.regs[effective_address] = (short) value_calc;
                break;
            case TEST_PC:
                if (lc3_calculate(state, input.pcval, value_calc))
                    throw "<in test-pc> A value expression " + input.pcval + " was malformed.";
                state.pc = (unsigned short) value_calc;
                break;
            case TEST_POINTER:
                if (lc3_calculate(state, input.pointer, value_calc))
                    throw "<in test-pointer> An expression was " + input.pointer + " malformed.";
                state.mem[(unsigned short) state.mem[effective_address]] = (short) value_calc;
                break;
            case TEST_STRING:
                for (unsigned int j = 0; j < input.text.size(); j++)
                    state.mem[state.mem[effective_address] + j] = input.text[j];
                state.mem[(unsigned short) (state.mem[effective_address] + input.text.size())] = 0;
                break;
            case TEST_ARRAY:
                for (unsigned int j = 0; j < input.array.size(); j++)
                {
                    if (lc3_calculate(state, input.array[j], value_calc))
                        throw "<in test-array> An expression was " + input.array[j] + " malformed.";
                    state.mem[(unsigned short) (state.mem[effective_address] + j)] = (short) value_calc;
                }
                break;
            case TEST_IO:
                newinput->str(input.io);
                break;
            case TEST_SUBROUTINE:
                break;
            default:
                throw "Unknown test type";
        }

        if (input.type == TEST_SUBROUTINE)
        {
            lc3_subr_input& subr = input.subroutine;
            int pc;
            int r7;
            int r6;
            int r5;
            if (lc3_calculate(state, subr.name, pc) == -1)
                throw "<in test-subr> invalid subroutine name given " + subr.name;
            if (lc3_calculate(state, subr.stack, r6) == -1)
                throw "<in test-subr> stack expression was malformed " + subr.stack;
            if (lc3_calculate(state, subr.r7, r7) == -1)
                throw "<in test-subr> r7 expression was malformed " + subr.r7;
            if (lc3_calculate(state, subr.r5, r5) == -1)
                throw "<in test-subr> r5 expression was malformed " + subr.r5;

            state.pc = (unsigned short) pc;
            state.regs[6] = (unsigned short)(r6 - subr.params.size());
            state.regs[7] = (unsigned short) r7;
            state.regs[5] = (unsigned short) r5;
            state.mem[state.regs[7]] = 0xF025;

            for (unsigned int j = 0; j < subr.params.size(); j++)
            {
                if (lc3_calculate(state, subr.params[j], value_calc))
                    throw "<in test-subr> param expression " + subr.params[j] + " was malformed.";
                state.mem[(unsigned short)state.regs[6] + j] = (short) value_calc;
            }

            // This fixes the issue in which a subroutine is being tested, but it makes calls to other subroutines who takes a
            // different number of parameters than the subroutine under test.
            // If the file uses subroutine annotations then overwrite it.
            for (const auto& info : subr.subroutines)
            {
                int address = 0;
                if (lc3_calculate(state, info.name, address) == -1)
                    throw "<in test-subr> invalid subroutine name given " + info.name;

                lc3_subroutine_info test_info = info;
                test_info.address = (unsigned short) address;
                state.subroutines[(unsigned short)address] = test_info;
            }
        }
    }

    state.input = newinput;
    // Setup output capture device
    std::stringstream* newoutput = new std::stringstream();
    state.output = newoutput;
    std::stringstream* newwarning = new std::stringstream();
    state.warning = newwarning;

    if (test.has_max_executions)
    {
        unsigned long i = 0;
        // Do this num times or until halted.
        while (i < test.max_executions && !state.halted)
        {
            //printf("%04x: %s (%x)\n", state.pc, lc3_disassemble(state, state.mem[state.pc]).c_str(), (unsigned short)state.mem[state.pc]);
                /*printf("R0 %6d|x%04x\tR1 %6d|x%04x\tR2 %6d|x%04x\tR3 %6d|x%04x\nR4 %6d|x%04x\tR5 %6d|x%04x\tR6 %6d|x%04x\tR7 %6d|x%04x\nCC: %s\tPC: %04x\n\n",
                       state.regs[0], (unsigned short)state.regs[0], state.regs[1], (unsigned short)state.regs[1], state.regs[2], (unsigned short)state.regs[2],
                       state.regs[3], (unsigned short)state.regs[3], state.regs[4], (unsigned short)state.regs[4], state.regs[5], (unsigned short)state.regs[5],
                       state.regs[6], (unsigned short)state.regs[6], state.regs[7], (unsigned short)state.regs[7], (state.n ? "N" : (state.z ? "Z" : "P")),
                       (unsigned short) state.pc);*/
            // Step one instruction
            lc3_step(state);
            // Increment instruction count
            i++;
        }
        //lc3_run(state, test.max_executions);
    }
    else
        lc3_run(state);

    // Fill in the output values
    test.has_halted = state.halted;
    test.executions = state.executions;
    test.warnings = state.warnings;
    test.warning = newwarning->str();

    bool test_passed = true;
    unsigned int test_points = 0;
    unsigned int test_max_points = 0;
    // Check test environment
    for (unsigned int i = 0; i < test.output.size(); i++)
    {
        std::stringstream expected;
        std::stringstream actual;

        lc3_test_output& output = test.output[i];
        int value_calc;
        short short_cmp;
        int address_calc = 0;
        unsigned short effective_address;
        std::string str;
        std::vector<short> arrayexpected;
        std::vector<short> arrayactual;

        if (output.type != TEST_IO && output.type != TEST_REGISTER && output.type != TEST_PC && lc3_calculate(state, output.address, address_calc) == -1)
            throw "An address expression " + output.address + " was not formed correctly.";
        else if (output.type == TEST_REGISTER)
        {
            address_calc = output.address[1] - '0';
            if (address_calc > 7)
                throw "Invalid register " + output.address;
        }
        effective_address = (unsigned short) address_calc;

        output.passed = true;
        output.earned = 0;
        switch (output.type)
        {
            case TEST_VALUE:
                if (lc3_calculate(state, output.value, value_calc))
                    throw "<in test-value> An expression " + output.value + " was malformed.";

                short_cmp = (short) value_calc;
                output.passed = lc3_test_check(output, &state.mem[effective_address], &short_cmp);

                actual << state.mem[effective_address];
                expected << short_cmp;
                break;
            case TEST_REGISTER:
                if (lc3_calculate(state, output.registerval, value_calc))
                    throw "<in test-register> An expression " + output.registerval + " was malformed.";

                short_cmp = (short) value_calc;
                output.passed = lc3_test_check(output, &state.regs[effective_address], &short_cmp);

                actual << state.regs[effective_address];
                expected << short_cmp;
                break;
            case TEST_PC:
                if (lc3_calculate(state, output.pcval, value_calc))
                    throw "<in test-pc> An expression " + output.pcval + " was malformed.";

                short_cmp = (short) value_calc;
                output.passed = lc3_test_check(output, &state.pc, &short_cmp);

                actual << state.pc;
                expected << short_cmp;

                break;
            case TEST_POINTER:
                if (lc3_calculate(state, output.pointer, value_calc))
                    throw "<in test-pointer> An expression " + output.pointer + " was malformed.";

                short_cmp = (short) value_calc;
                output.passed = lc3_test_check(output, &state.mem[(unsigned short)state.mem[effective_address]], &short_cmp);

                actual << state.mem[(unsigned short)state.mem[effective_address]];
                expected << short_cmp;

                break;
            case TEST_STRING:
                value_calc = (unsigned short)state.mem[effective_address];
                short_cmp = state.mem[(unsigned short)value_calc];

                while(short_cmp > 0 && short_cmp <= 255)
                {
                    actual.put((char) short_cmp);
                    value_calc++;
                    short_cmp = state.mem[(unsigned short)value_calc];
                }

                str = actual.str();
                output.passed = lc3_test_check(output, &str, &output.text);
                expected << output.text;
                break;
            case TEST_ARRAY:
                for (unsigned int j = 0; j < output.array.size(); j++)
                {
                    if (lc3_calculate(state, output.array[j], value_calc))
                        throw "<in test-array> An expression " + output.array[j] + " was malformed.";

                    arrayexpected.push_back(state.mem[(unsigned short)(state.mem[effective_address] + j)]);
                    arrayactual.push_back((short)value_calc);

                    actual << state.mem[(unsigned short)(state.mem[effective_address] + j)] << " ";
                    expected << (short)value_calc << " ";
                }

                output.passed = lc3_test_check(output, &arrayactual, &arrayexpected);
                break;
            case TEST_IO:
                str = newoutput->str();
                output.passed = lc3_test_check(output, &str, &output.io);
                actual << str;
                expected << output.io;
                break;
            case TEST_SUBROUTINE:
                break;
            default:
                throw "Unknown test type";
        }

        if (output.type != TEST_SUBROUTINE)
        {
            if (output.passed)
                output.earned = output.points;
        }

        if (output.type == TEST_SUBROUTINE)
        {
            std::stringstream extra;
            lc3_subr_output& subr = output.subroutine;

            std::vector<short> expected_stack;
            std::vector<short> actual_stack;

            std::vector<short> locals;
            std::vector<short> params;
            for (int j = (int)subr.locals.size() - 1; j >= 0; j--)
            {
                if (lc3_calculate(state, subr.locals[j], value_calc))
                    throw "<in test-subr> A local variable expression " + subr.locals[i] + "was malformed.";

                expected_stack.push_back((short)value_calc);
                locals.push_back((short) value_calc);
            }

            int r7;
            int r6;
            int r5;
            int answer;
            if (lc3_calculate(state, subr.stack, r6) == -1)
                throw "<in test-subr> stack expression " + subr.stack + " was malformed";
            if (lc3_calculate(state, subr.r7, r7) == -1)
                throw "<in test-subr> r7 expression " + subr.r7 + " was malformed";
            if (lc3_calculate(state, subr.r5, r5) == -1)
                throw "<in test-subr> r5 expression " + subr.r5 + " was malformed";
            if (lc3_calculate(state, subr.answer, answer) == -1)
                throw "<in test-subr> answer expression " + subr.answer + " was malformed";

            expected_stack.push_back((short)r5);
            expected_stack.push_back((short)r7);
            expected_stack.push_back((short)answer);

            for (unsigned int j = 0; j < subr.params.size(); j++)
            {
                if (lc3_calculate(state, subr.params[j], value_calc))
                    throw "<in test-subr> A param expression " + subr.params[j] + " was malformed.";
                expected_stack.push_back((short)value_calc);
                params.push_back((short) value_calc);
            }

            // Code to get the students stack frame
            unsigned short actual_r6 = (unsigned short) r6;
            if (state.first_level_calls.size() >= 1)
            {
                const auto& call_info = state.first_level_calls[0];
                unsigned short subr_location = call_info.address;
                if (state.subroutines.find(subr_location) == state.subroutines.end())
                {
                    extra << "      [WARNING] Could not determine number of parameters for subroutine " <<
                        lc3_sym_rev_lookup(state, subr_location) << " at address " <<
                        std::hex << "0x" << subr_location << "\n";
                }
                unsigned short start = call_info.r6 + call_info.params.size();
                // Screams...
                if (start >= actual_r6)
                    extra << "      [WARNING] Could not get students stack frame.\n"
                             "      Is the student managing the stack correctly?\n";
                else
                    actual_stack.assign(state.mem + start, state.mem + actual_r6);
            }
            else if (state.first_level_calls.empty())
            {
                int num_params = subr.params.size();
                // Get at least the parameters student could probably not save anything...
                actual_stack.assign(state.mem + (actual_r6 - num_params), state.mem + actual_r6);
                // Get additional addresses modified
                unsigned short start = actual_r6 - num_params - 1;
                while (state.memory_ops.find(start) != state.memory_ops.end())
                {
                    if (!state.memory_ops[start].writes) break;
                    actual_stack.insert(actual_stack.begin(), state.mem[start]);
                    start--;
                }
            }

            for (unsigned int j = 0; j < expected_stack.size(); j++)
                expected << std::hex << "0x" << expected_stack[j] << " ";
            expected << " r5: " << std::hex << "0x" << (short)r5 <<
                        " r6: " << std::hex << "0x" << (actual_r6 - subr.params.size() - 1) <<
                        " r7: " << std::hex << "0x" << (short)(r7 + 1);


            for (unsigned int j = 0; j < actual_stack.size(); j++)
                actual << std::hex << "0x" << actual_stack[j] << " ";
            actual << " r5: " << std::hex << "0x" << state.regs[5] <<
                      " r6: " << std::hex << "0x" << state.regs[6] <<
                      " r7: " << std::hex << "0x" << state.regs[7];

            // now that I have all information available time for some checks.
            std::map<short, int> actual_stack_map;
            for (unsigned int j = 0; j < actual_stack.size(); j++)
                actual_stack_map[actual_stack[j]] += 1;

            int points = 0;
            // If they get something wrong then it will also be wrong in edit distance
            // so cut some slack if you get a value wrong.
            int ed_forgiveness = 0;

            if (actual_stack_map[(short)answer] > 0)
            {
                actual_stack_map[(short)answer] -= 1;
                points += subr.points_answer;
                extra << CHECK << ANSWER_FOUND << " +" << subr.points_answer << ".\n";
            }
            else
            {
                ed_forgiveness++;
                extra << MISS << ANSWER_FOUND << " -" << subr.points_answer << ".\n";
            }

            if (state.regs[6] == (short)(actual_r6 - subr.params.size() - 1))
            {
                points += subr.points_r6;
                extra << CHECK << R6_FOUND << " +" << subr.points_r6 << ".\n";
            }
            else
            {
                extra << MISS << R6_FOUND << " -" << subr.points_r6 << ".\n";
            }

            if (actual_stack_map[(short)r7] > 0 && state.regs[7] == (short)(r7+1))
            {
                actual_stack_map[(short)r7] -= 1;
                points += subr.points_r7;
                extra << CHECK << R7_FOUND << " +" << subr.points_r7 << ".\n";
            }
            else
            {
                // Don't count if just r7 was clobbered
                if (actual_stack_map[(short)r7] <= 0)
                    ed_forgiveness++;
                extra << MISS << R7_FOUND << " -" << subr.points_r7 << ".\n";
            }

            if (actual_stack_map[(short)r5] > 0 && state.regs[5] == (short)r5)
            {
                actual_stack_map[(short)r5] -= 1;
                points += subr.points_r5;
                extra << CHECK << R5_FOUND << " +" << subr.points_r5 << ".\n";
            }
            else
            {
                if (actual_stack_map[(short)r5] <= 0)
                    ed_forgiveness++;
                extra << MISS << R5_FOUND << " -" << subr.points_r5 << ".\n";
            }

            for (unsigned int j = 0; j < params.size(); j++)
            {
                if (actual_stack_map[params[j]] > 0)
                {
                    actual_stack_map[params[j]] -= 1;
                    points += subr.points_params;
                    extra << CHECK << params[j] << " " << PARAM_FOUND << " +" << subr.points_params << ".\n";
                }
                else
                {
                    ed_forgiveness++;
                    extra << MISS << params[j] << " " << PARAM_FOUND << " -" << subr.points_params << ".\n";
                }
            }

            bool all_locals_wrong = true;
            for (unsigned int j = 0; j < locals.size(); j++)
            {
                if (actual_stack_map[locals[j]] > 0)
                {
                    actual_stack_map[locals[j]] -= 1;
                    points += subr.points_locals;
                    all_locals_wrong = false;
                    extra << CHECK << locals[j] << " " << LOCAL_FOUND << " +" << subr.points_locals << ".\n";
                }
                else
                {
                    ed_forgiveness++;
                    extra << MISS << locals[j] << " " << LOCAL_FOUND << " -" << subr.points_locals << ".\n";
                }
            }

            // Subroutine calls check.
            std::set<lc3_subroutine_call_info, lc3_subroutine_call_info_cmp> actual_calls(state.first_level_calls.begin(), state.first_level_calls.end());
            std::set<lc3_subroutine_call_info, lc3_subroutine_call_info_cmp> expected_calls;
            for (const auto& expected_call : subr.calls)
            {
                lc3_subroutine_call_info info;
                int addr = lc3_sym_lookup(state, expected_call.name);
                if (addr == -1)
                    throw "Invalid subroutine name given in <call> " + expected_call.name;
                for (unsigned int i = 0; i < expected_call.params.size(); i++)
                {
                    int param;
                    if (lc3_calculate(state, expected_call.params[i], param) == -1)
                        throw "<in test-subr/call> param expression " + expected_call.params[i] + " was malformed";
                    info.params.push_back(param);
                }
                info.address = addr;
                info.r6 = 0;
                expected_calls.insert(info);
            }

            for (const auto& call : expected_calls)
            {
                std::stringstream call_name;
                call_name << lc3_sym_rev_lookup(state, call.address) << "(";
                if (state.subroutines.find(call.address) == state.subroutines.end())
                    call_name << "?";
                for (unsigned int i = 0; i < call.params.size(); i++)
                {

                    call_name << std::hex << "0x" << call.params[i];
                    if (i != call.params.size() - 1)
                        call_name << ",";
                }
                call_name << ")";

                if (actual_calls.find(call) != actual_calls.end())
                {
                    extra << CHECK << "Call " << call_name.str() << " made correctly.\n";
                    points += subr.points_calls;
                }
                else
                {
                    extra << MISS << "Call " << call_name.str() << " was not made.\n";
                }
            }
            for (const auto& call : actual_calls)
            {
                std::stringstream call_name;

                std::string name = lc3_sym_rev_lookup(state, call.address);
                if (name.empty())
                    call_name << "0x" << std::hex << call.address << "(";
                else
                    call_name << name << "(";
                if (state.subroutines.find(call.address) == state.subroutines.end())
                    call_name << "?";
                for (unsigned int i = 0; i < call.params.size(); i++)
                {

                    call_name << std::hex << "0x" << call.params[i];
                    if (i != call.params.size() - 1)
                        call_name << ",";
                }
                call_name << ")";

                if (expected_calls.find(call) == expected_calls.end())
                {
                    extra << MISS << "Unexpected Call " << call_name.str() << " made.\n";
                }
            }

            // Read answer check sigh...
            if (subr.points_read_answer > 0)
            {
                for (const auto& call : actual_calls)
                {
                    if (expected_calls.find(call) != expected_calls.end() && !call.params.empty())
                    {
                        if (state.memory_ops[call.r6 - 1].reads > 0)
                        {
                            extra << CHECK << "Read answer from stack.\n";
                            points += subr.points_read_answer;
                        }
                        else
                            extra << MISS << "Did not read answer from stack.\n";
                    }
                }
            }

            // If all local variables are wrong then it can be argued that they was saving registers
            // And forgot to save locals...
            if (all_locals_wrong)
            {
                // Bro do you even calling convention
                if (actual_stack.size() > subr.params.size() + 3)
                    // Truncate stack to last num_params + 3 elements the stuff we care about (don't do expected since ed forgiveness handles it).
                    actual_stack.erase(actual_stack.begin(), actual_stack.begin() + (actual_stack.size() - subr.params.size() - 3));
                if (!subr.locals.empty())
                    extra << "      All locals were not found, so locals aren't included in structure check.\n";
            }
            else
            {
                if (actual_stack.size() > expected_stack.size())
                    expected_stack.insert(expected_stack.begin(), actual_stack.begin(), actual_stack.begin() + (actual_stack.size() - expected_stack.size()));
            }

            int ed_grade = edit_distance(actual_stack, expected_stack);
            points -= (ed_grade - ed_forgiveness) * subr.deductions_edist;
            int mistakes = ed_grade - ed_forgiveness;


            if (mistakes == 0)
                extra << "      Found no structural mistakes in the stack.  No changes needed.\n";
            else
                extra << "      Found " << mistakes << " structural mistakes in stack -" << subr.deductions_edist * mistakes << ".\n";

            output.passed = (ed_grade == 0) && (ed_forgiveness == 0);
            output.extra_output += extra.str();
            output.earned = points;
        }

        test_passed = test_passed && output.passed;
        test_points += output.earned;
        test_max_points += output.points;

        output.expected = expected.str();
        output.actual = actual.str();
    }

    // Tear down
    delete state.input;
    delete state.output;
    delete state.warning;

    test.passed = test_passed;
    test.points = test_points;
    test.max_points = test_max_points;
}
Beispiel #5
0
/** cmd_runprompt
 *
 * Determine what the user input is and run 
 *
 * @param mach A pointer to the lc3 simulator
 * @param prompt A pointer to the string the user provided
 * @param lastCommand The last command index to be run
 */
void cmd_runprompt(lc3machine* mach, char * prompt) 
{
    // copy prompt
    char promptCopy[30];
    strcpy(promptCopy, prompt);
    
    // break appart command by spaces
    char * command;
    command = strtok(promptCopy, " ");
    
    // check if command is a quit
    if (strcmp(command, "quit") == 0 || strcmp(command, "q") == 0)
        exit(0);
    
    // check if command is to step
    else if (strcmp(command, "step") == 0 || strcmp(command, "s") == 0) {
        
        // get number of lines to step
        command = strtok(NULL, " ");
        int lines = command == NULL ? 1 : atoi(command);
        lc3_run(mach, lines);
    }
    
    // check if command is continue
    else if (strcmp(command, "continue") == 0 || strcmp(command, "c") == 0 || strcmp(command, "run") == 0) {
        lc3_run(mach, -1);
    }
    
    // check if want the registers
    else if (strcmp(command, "registers") == 0 || strcmp(command, "r") == 0) {
        cmd_registers(mach);
    }
    
    // check if command is to dump memory
    else if (strcmp(command, "dump") == 0) {
        
        // check if the command is valid
        if ((command = strtok(NULL, " ")) == NULL) {
            printf("ERR: Input invalid: Starting memory index required\n");
            return;
        }
        
        // get starting location
        char * pEnd;
        int dumpStart = (int) strtol(command, &pEnd, 16);
        
        // get ending locaiton
        command = strtok(NULL, " ");
        int dumpEnd = command == NULL ? dumpStart : ((int) strtol(command, &pEnd, 16));
        
        // dump the core
        cmd_dump(mach, dumpStart, dumpEnd);
    }
    
    // check if command is to set memory
    else if (strcmp(command, "setaddr") == 0) {
        
        // check if the command is valid
        if ((command = strtok(NULL, " ")) == NULL) {
            printf("ERR: Input invalid: Memory address required\n");
            return;
        }
        
        // get address
        char * pEnd;
        int address = (int) strtol(command, &pEnd, 16);
        
        // check if the command is valid
        if ((command = strtok(NULL, " ")) == NULL) {
            printf("ERR: Input invalid: Memory value required\n");
            return;
        }
        
        // set value
        cmd_setaddr(mach, address, atoi(command));
    }
    
    // check if command is to set memory
    else if (strcmp(command, "setreg") == 0) {
        
        // check if the command is valid
        if ((command = strtok(NULL, " ")) == NULL) {
            printf("ERR: Input invalid: Register number required\n");
            return;
        }
        
        // get register
        int reg = atoi(command + 1);
        
        // check if the command is valid
        if ((command = strtok(NULL, " ")) == NULL) {
            printf("ERR: Input invalid: Register value required\n");
            return;
        }
        
        // set value
        cmd_setreg(mach, reg, atoi(command));
    }
    
    // check if command is for help
    else if (strcmp(command, "help") == 0) {
        printf("step [n]\n\tExecutes n instructions (n defaults to 1)\nquit\n\tQuits the simulator\ncontinue\n\tRuns until the program halts\nregisters\n\tPrints all registers, pc, and cc values\ndump start [end]\n\tDumps the contents of memory from the starting address to the end (if not provided will just print one value)\nsetaddr addr value\n\tSets the value at the provided address\nsetreg Rn value\n\tSets register n with the provided value\nhelp\n\tDisplays this menu\n");
    }
    
    // command not found
    else
        printf("ERR: Input invalid. Type 'help' for a list of instructions\n");
}