← index
cplusplus2x.Examples/C++20/MasterX/src/apps/ats/translate.cpp
Source: cplusplus2x.Examples/C++20/MasterX/src/apps/ats/translate.cpp
#include "translate.hpp"
#include "function.hpp"

namespace translate {

    bool confirm_mode(const icode::opc code, unsigned int mode, unsigned char &op_byte) {
        for (unsigned int i = 0; interp::m_code[i].p_code != icode::opc::NOTINC; ++i) {
            if (interp::m_code[i].p_code == code && interp::m_code[i].address_mode == mode) {
                op_byte = interp::m_code[i].op_code;
                return true;
            }
        }
        op_byte = 0;
        return false;
    }

    bool check_labels() {
        for (unsigned int ix = 0; ix < code.instruct.size(); ++ix) {
            icode::Instruction &i = code.instruct[ix];
            if (i.op1.op_t == icode::op_type::OP_LABELTEXT) {
                auto valid = interp::label_table.find(i.op1.label_text);
                if (valid == interp::label_table.end()) {
                    stream << "Error could not find label: " << i.op1.label_text << "\r\n";
                    return false;
                }
                i.op1.label_index = valid->second;
            }
            if (i.op1.op_t == icode::op_type::OP_LABEL) {
                auto valid = interp::label_line_table.find(i.op1.op);
                if (valid == interp::label_line_table.end()) {
                    stream << "Error line number: " << i.op1.op << " does not exisit.\r\n";
                    return false;
                }
                i.op1.label_index = valid->second;
            }
        }
        return true;
    }

    bool build_code() {
        try {
            if (interp::lines.size() == 0) {
                stream << "Error: No code to build...\r\n";
                return false;
            }

            if (!interp::label_table.empty())
                interp::label_table.erase(interp::label_table.begin(), interp::label_table.end());
            if (!interp::label_line_table.empty())
                interp::label_line_table.erase(interp::label_line_table.begin(), interp::label_line_table.end());

            for (unsigned int i = 0; i < interp::lines.size(); ++i) {
                if (build_line(i) == false) {
                    stream << "Error on line: " << interp::lines[i].index << "\r\n";
                    return false;
                }
            }

            if (check_labels() == false)
                return false;

            return true;
        } catch (const cExcep &e) {
            stream << e.err;
        }
        return false;
    }

    bool build_line(unsigned int line) {
        std::vector<lex::Token> tokens;
        unsigned int line_value = interp::lines[line].index;
        interp::label_line_table[line_value] = line;
        tokenize_line(interp::lines[line].text, tokens);
        icode::Instruction inst;
        inst.text = interp::lines[line].text;
        inst.line_num = line_value;
        match(tokens[0], lex::TOKEN_CHAR);
        icode::opc op;
        inst.instruction_text = interp::lines[line].text;
        op = icode::strtoInc(tokens[0].getToken());
        if (op == icode::opc::NOTINC) {
            inst.label = true;
            inst.label_text = tokens[0].getToken();
            inst.label_index = line;
            interp::label_table[inst.label_text] = line;
            match(tokens[1], lex::TOKEN_CHAR);
            icode::opc op_code;
            op_code = icode::strtoInc(tokens[1].getToken());
            if (op_code == icode::opc::NOTINC) {
                std::ostringstream stream;
                stream << "Error: Line: " << line_value << "Expected instruction instead found: " << tokens[1].getToken() << "\r\n";
                throw cExcep(stream.str());

            } else {
                inst.opcode = op_code;
            }
        } else {
            inst.opcode = op;
        }

        if (inst.label == true) {
            tokens.erase(tokens.begin());
        }

        unsigned int tok_size = tokens.size() - 1;

        switch (tok_size) {
        case 0: {
            if (confirm_mode(inst.opcode, interp::IMPLIED, inst.op_byte) == false) {
                std::ostringstream stream;
                stream << "Error on Line: " << line_value << " instruction " << icode::op_array[static_cast<unsigned int>(inst.opcode)] << " not valid in implied address mode.\r\n";
                throw cExcep(stream.str());
            }
            inst.mode = interp::IMPLIED;
        } break;
        case 1:
            switch (tokens[1].getTokenType()) {
            case lex::TOKEN_DIGIT: {

                if (confirm_mode(inst.opcode, interp::RELATIVE, inst.op_byte) == false) {
                    if (confirm_mode(inst.opcode, interp::ABSOULTE, inst.op_byte) == true) {
                        inst.mode = interp::ABSOULTE;
                    } else {
                        std::ostringstream stream;
                        stream << "Error on Line: " << line_value << " instruction " << inst.opcode << " not supported in relative addressing mode.\r\n";
                        throw cExcep(stream.str());
                    }
                } else
                    inst.mode = interp::RELATIVE;
                unsigned int label_value = atoi(tokens[1].getToken().c_str());
                inst.op1 = icode::Operand(label_value, icode::op_type::OP_LABEL);
            } break;
            case lex::TOKEN_HEX: {
                if (confirm_mode(inst.opcode, interp::ABSOULTE, inst.op_byte) == false) {
                    std::ostringstream stream;
                    stream << "Error on Line: " << line_value << " " << inst.opcode << " not supported in absoulte addressing mode.\r\n";
                    throw cExcep(stream.str());
                }
                unsigned int hex_address = icode::toHex(tokens[1].getToken());
                if (hex_address <= 255) {
                    inst.op1 = icode::Operand(hex_address, icode::op_type::OP_MEMORY);
                    inst.mode = interp::ZEROPAGE;

                } else {
                    inst.op1 = icode::Operand(hex_address, icode::op_type::OP_MEMORY);
                    inst.mode = interp::ABSOULTE;
                }
            } break;
            case lex::TOKEN_CHAR:
                // check if label exisits
                if (tokens[1].getToken() == "A" && confirm_mode(inst.opcode, interp::ACCUMULATOR, inst.op_byte) == true) {
                    inst.op1 = icode::Operand(0, icode::op_type::OP_REGISTER_A);
                    inst.mode = interp::ACCUMULATOR;
                    break;
                } else if (confirm_mode(inst.opcode, interp::ABSOULTE, inst.op_byte) == false) {

                    if (confirm_mode(inst.opcode, interp::RELATIVE, inst.op_byte) == true) {
                        inst.mode = interp::RELATIVE;
                    } else {

                        std::ostringstream stream;
                        stream << "Error on Line: " << line_value << " instruction " << inst.opcode << " does not support addressing mode.\r\n";
                    }
                } else {
                    inst.mode = interp::ABSOULTE;
                }
                inst.op1 = icode::Operand(0, icode::op_type::OP_LABELTEXT);
                inst.op1.label_text = tokens[1].getToken();
                break;
            default:
                break;
            }

            break;
        case 2:

            switch (tokens[1].getTokenType()) {
            case lex::TOKEN_OPERATOR: {
                if (tokens[1].getToken() == "#") {

                    unsigned int numeric_value = 0;

                    if (tokens[2].getTokenType() == lex::TOKEN_DIGIT) {
                        numeric_value = atoi(tokens[2].getToken().c_str());

                    } else if (tokens[2].getTokenType() == lex::TOKEN_HEX) {
                        numeric_value = icode::toHex(tokens[2].getToken());
                    } else {
                        std::ostringstream stream;
                        stream << "Error on Line: " << line_value << " Deicmal or Hex value expected..\r\n";
                        throw cExcep(stream.str());
                    }

                    if (confirm_mode(inst.opcode, interp::IMMEDIATE, inst.op_byte) == false) {
                        std::ostringstream stream;
                        stream << "Error on Line: " << line_value << " instruction " << inst.opcode << " not supported in immediate addressing mode.\r\n";
                        throw cExcep(stream.str());
                    }

                    if (numeric_value > 255) {
                        std::ostringstream stream;
                        stream << "Error on Line: " << line_value << " operand is a single byte (no greater than 255).\r\n";
                        throw cExcep(stream.str());
                    }

                    inst.op1 = icode::Operand(numeric_value, icode::op_type::OP_DECIMAL);
                    inst.mode = interp::IMMEDIATE;

                } else {
                    std::ostringstream stream;
                    stream << "Error on Line: " << line_value << " Expected # operator..\r\n";
                    throw cExcep(stream.str());
                }
            } break;
            default:
                break;
            }
            break;
        case 3: {
            std::string reg = icode::lcase(tokens[3].getToken());
            switch (tokens[1].getTokenType()) {
            case lex::TOKEN_HEX: {

                unsigned int hex_value = icode::toHex(tokens[1].getToken());
                match(tokens[2], lex::TOKEN_OPERATOR);
                match(tokens[2], ",");

                if (tokens[2].getToken() == "," && reg == "x") {

                    if (confirm_mode(inst.opcode, interp::ABSOULTE_X, inst.op_byte) == false) {
                        if (confirm_mode(inst.opcode, interp::ZEROPAGE_X, inst.op_byte)) {
                            inst.mode = interp::ZEROPAGE_X;
                        } else {
                            std::ostringstream stream;
                            stream << "Error on Line: " << line_value << " instruction " << inst.opcode << " has X register but not supported in absoulte X address mode.\r\n";
                            throw cExcep(stream.str());
                        }
                    }

                    if (hex_value > 0xFF)
                        inst.mode = interp::ABSOULTE_X;
                    else
                        inst.mode = interp::ZEROPAGE_X;
                }
                if (tokens[2].getToken() == "," && reg == "y") {
                    if (confirm_mode(inst.opcode, interp::ABSOULTE_Y, inst.op_byte) == false) {
                        if (confirm_mode(inst.opcode, interp::ZEROPAGE_Y, inst.op_byte)) {
                            inst.mode = interp::ZEROPAGE_Y;
                        } else {
                            std::ostringstream stream;
                            stream << "Error on Line: " << line_value << " instruction " << inst.opcode << " has Y register but not supported in absoulte y address mode.\r\n";
                            throw cExcep(stream.str());
                        }
                    }

                    if (hex_value <= 255)
                        inst.mode = interp::ZEROPAGE_Y;
                    else
                        inst.mode = interp::ABSOULTE_Y;
                }
                inst.op1 = icode::Operand(hex_value, icode::op_type::OP_MEMORY);
            } break;
            default: {

                std::ostringstream stream;
                stream << "Error on Line: " << line_value << " instruction " << inst.opcode << " requires address value.\r\n";
                throw cExcep(stream.str());

            } break;
            }

        } break;
        case 4:
            stream << "4: " << tokens[4] << "\r\n";
            break;
        default:
            stream << "Default: " << tok_size << "\r\n";
            break;
        }

        code.instruct.push_back(inst);
        return true;
    }

    void tokenize_line(const std::string &text, std::vector<lex::Token> &tokens) {
        std::istringstream stream(text);
        lex::Scanner scan(stream);
        while (scan.valid()) {
            lex::Token token;
            scan >> token;
            if (token.getTokenType() != lex::TOKEN_EOF)
                tokens.push_back(token);
        }
    }

    void match(const lex::Token &token, const lex::Token_type &type) {
        if (token.getTokenType() != type) {
            std::ostringstream stream;
            stream << "Expected Type: " << type << "\r\n";
            throw cExcep(stream.str());
        }
    }

    void match(const lex::Token &token, const std::string &text) {
        if (token.getToken() != text) {
            std::ostringstream stream;
            stream << "Expected: " << text << " found: " << token.getToken() << "\r\n";
            throw cExcep(stream.str());
        }
    }
} // namespace translate