Advertisement
Guest User

tinyAssembler

a guest
Aug 25th, 2013
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //TinyAssembler by NasenSpray
  2.  
  3. #include <iostream>
  4. #include <fstream>
  5. #include <unordered_map>
  6. #include <algorithm>
  7. #include <string>
  8. #include <list>
  9. #include <cstdint>
  10. #include <sstream>
  11. #include <regex>
  12. #include <iomanip>
  13.  
  14. namespace tiny
  15. {
  16.     enum OperandType {
  17.         None,
  18.         Memory,
  19.         Literal,
  20.         Label,
  21.     };
  22.  
  23.     enum Mnemonic {
  24.         AND,    OR,     XOR,    NOT,
  25.         MOV,    RANDOM, ADD,    SUB,
  26.         JMP,    JZ,     JEQ,    JLS,
  27.         JGT,    HALT,   APRINT, DPRINT,
  28.     };
  29.  
  30.     enum OperandCombination {
  31.         N = 0,
  32.         M = 0x1,
  33.         L = 0x2,
  34.         MM = 0x11,
  35.         ML = 0x12,
  36.         LM = 0x21,
  37.         LL = 0x22,
  38.         MMM = 0x111,
  39.         LMM = 0x211,
  40.         MML = 0x112,
  41.         LML = 0x212,
  42.     };
  43.  
  44.     enum Instruction {
  45.         AND_MM   = 0x00,
  46.         AND_ML   = 0x01,
  47.         OR_MM    = 0x02,
  48.         OR_ML    = 0x03,
  49.         XOR_MM   = 0x04,
  50.         XOR_ML   = 0x05,
  51.         NOT_M    = 0x06,
  52.         MOV_MM   = 0x07,
  53.         MOV_ML   = 0x08,
  54.         RANDOM_M = 0x09,
  55.         ADD_MM   = 0x0A,
  56.         ADD_ML   = 0x0B,
  57.         SUB_MM   = 0x0C,
  58.         SUB_ML   = 0x0D,
  59.         JMP_M    = 0x0E,
  60.         JMP_L    = 0x0F,
  61.         JZ_MM    = 0x10,
  62.         JZ_ML    = 0x11,
  63.         JZ_LM    = 0x12,
  64.         JZ_LL    = 0x13,
  65.         JEQ_MMM  = 0x14,
  66.         JEQ_LMM  = 0x15,
  67.         JEQ_MML  = 0x16,
  68.         JEQ_LML  = 0x17,
  69.         JLS_MMM  = 0x18,
  70.         JLS_LMM  = 0x19,
  71.         JLS_MML  = 0x1A,
  72.         JLS_LML  = 0x1B,
  73.         JGT_MMM  = 0x1C,
  74.         JGT_LMM  = 0x1D,
  75.         JGT_MML  = 0x1E,
  76.         JGT_LML  = 0x1F,
  77.         HALT_N   = 0xFF,
  78.         APRINT_M = 0x20,
  79.         APRINT_L = 0x21,
  80.         DPRINT_M = 0x22,
  81.         DPRINT_L = 0x23,
  82.     };
  83.  
  84.     struct Operand {
  85.         OperandType type;
  86.         uint8_t     value;
  87.         std::string label;
  88.  
  89.         Operand() : type(OperandType::None) {}
  90.         Operand(OperandType t, uint8_t v) : type(t), value(v) {}
  91.         Operand(OperandType t, std::string label) : type(t), label(label) {}
  92.     };
  93.  
  94.     struct MnemonicInstruction {
  95.         Mnemonic op;
  96.         std::vector<Operand>  operand;
  97.     };
  98.  
  99.     struct TranslatedInstruction {
  100.         Instruction op;
  101.         std::vector<Operand>  operand;
  102.  
  103.         TranslatedInstruction(Instruction op, std::vector<Operand>&& operands) : op(op), operand(operands) {}
  104.         size_t size() const { return operand.size() + 1; }
  105.     };
  106.  
  107.     std::pair<std::string, Mnemonic> MnemonicMapData[] =
  108.     {
  109.         std::make_pair("AND",    Mnemonic::AND),
  110.         std::make_pair("OR",     Mnemonic::OR),
  111.         std::make_pair("XOR",    Mnemonic::XOR),
  112.         std::make_pair("NOT",    Mnemonic::NOT),
  113.         std::make_pair("MOV",    Mnemonic::MOV),
  114.         std::make_pair("RANDOM", Mnemonic::RANDOM),
  115.         std::make_pair("ADD",    Mnemonic::ADD),
  116.         std::make_pair("SUB",    Mnemonic::SUB),
  117.         std::make_pair("JMP",    Mnemonic::JMP),
  118.         std::make_pair("JZ",     Mnemonic::JZ),
  119.         std::make_pair("JEQ",    Mnemonic::JEQ),
  120.         std::make_pair("JLS",    Mnemonic::JLS),
  121.         std::make_pair("JGT",    Mnemonic::JGT),
  122.         std::make_pair("HALT",   Mnemonic::HALT),
  123.         std::make_pair("APRINT", Mnemonic::APRINT),
  124.         std::make_pair("DPRINT", Mnemonic::DPRINT)
  125.     };
  126.  
  127.     std::pair<Mnemonic, std::pair<OperandCombination, Instruction>> InstructionData[] =
  128.     {
  129.         std::make_pair(Mnemonic::AND, std::make_pair(OperandCombination::MM, Instruction::AND_MM)),
  130.         std::make_pair(Mnemonic::AND, std::make_pair(OperandCombination::ML, Instruction::AND_ML)),
  131.         std::make_pair(Mnemonic::OR, std::make_pair(OperandCombination::MM, Instruction::OR_MM)),
  132.         std::make_pair(Mnemonic::OR, std::make_pair(OperandCombination::ML, Instruction::OR_ML)),
  133.         std::make_pair(Mnemonic::XOR, std::make_pair(OperandCombination::MM, Instruction::XOR_MM)),
  134.         std::make_pair(Mnemonic::XOR, std::make_pair(OperandCombination::ML, Instruction::XOR_ML)),
  135.         std::make_pair(Mnemonic::NOT, std::make_pair(OperandCombination::M, Instruction::NOT_M)),
  136.  
  137.         std::make_pair(Mnemonic::MOV, std::make_pair(OperandCombination::MM, Instruction::MOV_MM)),
  138.         std::make_pair(Mnemonic::MOV, std::make_pair(OperandCombination::ML, Instruction::MOV_ML)),
  139.  
  140.         std::make_pair(Mnemonic::RANDOM, std::make_pair(OperandCombination::M, Instruction::RANDOM_M)),
  141.  
  142.         std::make_pair(Mnemonic::ADD, std::make_pair(OperandCombination::MM, Instruction::ADD_MM)),
  143.         std::make_pair(Mnemonic::ADD, std::make_pair(OperandCombination::ML, Instruction::ADD_ML)),
  144.  
  145.         std::make_pair(Mnemonic::SUB, std::make_pair(OperandCombination::MM, Instruction::SUB_MM)),
  146.         std::make_pair(Mnemonic::SUB, std::make_pair(OperandCombination::ML, Instruction::SUB_ML)),
  147.  
  148.         std::make_pair(Mnemonic::JMP, std::make_pair(OperandCombination::M, Instruction::JMP_M)),
  149.         std::make_pair(Mnemonic::JMP, std::make_pair(OperandCombination::L, Instruction::JMP_L)),
  150.  
  151.         std::make_pair(Mnemonic::JZ, std::make_pair(OperandCombination::MM, Instruction::JZ_MM)),
  152.         std::make_pair(Mnemonic::JZ, std::make_pair(OperandCombination::ML, Instruction::JZ_ML)),
  153.         std::make_pair(Mnemonic::JZ, std::make_pair(OperandCombination::LM, Instruction::JZ_LM)),
  154.         std::make_pair(Mnemonic::JZ, std::make_pair(OperandCombination::LL, Instruction::JZ_LL)),
  155.  
  156.         std::make_pair(Mnemonic::JEQ, std::make_pair(OperandCombination::MMM, Instruction::JEQ_MMM)),
  157.         std::make_pair(Mnemonic::JEQ, std::make_pair(OperandCombination::LMM, Instruction::JEQ_LMM)),
  158.         std::make_pair(Mnemonic::JEQ, std::make_pair(OperandCombination::MML, Instruction::JEQ_MML)),
  159.         std::make_pair(Mnemonic::JEQ, std::make_pair(OperandCombination::LML, Instruction::JEQ_LML)),
  160.  
  161.         std::make_pair(Mnemonic::JLS, std::make_pair(OperandCombination::MMM, Instruction::JLS_MMM)),
  162.         std::make_pair(Mnemonic::JLS, std::make_pair(OperandCombination::LMM, Instruction::JLS_LMM)),
  163.         std::make_pair(Mnemonic::JLS, std::make_pair(OperandCombination::MML, Instruction::JLS_MML)),
  164.         std::make_pair(Mnemonic::JLS, std::make_pair(OperandCombination::LML, Instruction::JLS_LML)),
  165.  
  166.         std::make_pair(Mnemonic::JGT, std::make_pair(OperandCombination::MMM, Instruction::JGT_MMM)),
  167.         std::make_pair(Mnemonic::JGT, std::make_pair(OperandCombination::LMM, Instruction::JGT_LMM)),
  168.         std::make_pair(Mnemonic::JGT, std::make_pair(OperandCombination::MML, Instruction::JGT_MML)),
  169.         std::make_pair(Mnemonic::JGT, std::make_pair(OperandCombination::LML, Instruction::JGT_LML)),
  170.  
  171.         std::make_pair(Mnemonic::HALT, std::make_pair(OperandCombination::N, Instruction::HALT_N)),
  172.  
  173.         std::make_pair(Mnemonic::APRINT, std::make_pair(OperandCombination::M, Instruction::APRINT_M)),
  174.         std::make_pair(Mnemonic::APRINT, std::make_pair(OperandCombination::L, Instruction::APRINT_L)),
  175.         std::make_pair(Mnemonic::DPRINT, std::make_pair(OperandCombination::M, Instruction::DPRINT_M)),
  176.         std::make_pair(Mnemonic::DPRINT, std::make_pair(OperandCombination::L, Instruction::DPRINT_L)),
  177.     };
  178.  
  179.     std::unordered_map<std::string, Mnemonic> MnemonicMap(MnemonicMapData, MnemonicMapData + (sizeof(MnemonicMapData) / sizeof(MnemonicMapData[0])));
  180.     std::unordered_multimap<Mnemonic, std::pair<OperandCombination, Instruction>> MnemonicInstructionMap(InstructionData, InstructionData + (sizeof(InstructionData) / sizeof(InstructionData[0])));
  181.  
  182.     struct AssemblerError {
  183.         std::string message;
  184.         AssemblerError(std::string msg) : message(msg) {}
  185.     };
  186.  
  187.     class Assembler
  188.     {
  189.     public:
  190.         Assembler() : offset(0) {}
  191.  
  192.         void push_line(std::string s)
  193.         {
  194.             //matches empty line
  195.             static const std::regex regWhite("^\\s*(//.*)?$");
  196.             //matches labels
  197.             static const std::regex regLabel("^\\s*([a-zA-Z_]+[a-zA-Z_0-9]*)\\s*:\\s*(//.*)?$");
  198.             //matches syntactically valid instruction formats
  199.             static const std::regex regInstruction("^\\s*([[:alpha:]]+)(?:\\s*|((\\s+(?:[0-9]+|[a-zA-Z_]+[a-zA-Z_0-9]*|'.'|\\[\\s*[0-9]+\\s*\\]))+))\\s*(//.*)?$");
  200.  
  201.             std::smatch match;
  202.             if (std::regex_match(s, regWhite)) {
  203.                 return;
  204.             } else if (std::regex_match(s, match, regLabel)) {
  205.                 auto str = match[1].str();
  206.                 str = str.substr(0, str.find_first_of(" \t:"));
  207.                 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
  208.                 if (MnemonicMap.find(str) != MnemonicMap.end())
  209.                     throw AssemblerError("Illegal label name: " + match[1].str());
  210.                 if (labelMap.insert(std::make_pair(match[1].str(), offset)).second == false)
  211.                     throw AssemblerError("Label already defined: " + match[1].str());
  212.             } else if (std::regex_match(s, match, regInstruction)) {
  213.                 auto str = match[1].str();
  214.                 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
  215.                 auto op = MnemonicMap.find(str);
  216.                 if (op == MnemonicMap.end()) {
  217.                     //try to find a possible suggestion
  218.                     for (size_t i = str.length()-1; i > 0; i--) {
  219.                         auto trial = str.substr(0, i);
  220.                         if (MnemonicMap.find(trial) != MnemonicMap.end())
  221.                             throw AssemblerError("Unrecognized instruction: " + str + " (did you mean " + trial + "?)");
  222.                     }
  223.                     throw AssemblerError("Unrecognized instruction: " + str);
  224.                 }
  225.  
  226.                 MnemonicInstruction m;
  227.                 size_t comb = OperandCombination::N;
  228.                 m.op = op->second;
  229.                 std::string args = match[2].str();
  230.                
  231.                 if (!args.empty()) { //we have args to parse :O
  232.                     for(;;) {
  233.                         args.erase(0, args.find_first_not_of(" \t"));
  234.                         if (args.empty() || args.substr(0,2) == "//")
  235.                             break;
  236.  
  237.                         if (m.operand.size() >= 3)
  238.                             throw AssemblerError("Too many operands");
  239.  
  240.                         args.erase(0, args.find_first_not_of(" \t"));
  241.                         if (args[0] == '[') {
  242.                             //memory operand
  243.                             int val = 0xFFFF;
  244.                             try {
  245.                                 val = std::stoi(args.substr(1, args.find_first_of(']')-1));
  246.                             } catch (...) {}
  247.  
  248.                             if (val < 0 || val > 255)
  249.                                 throw AssemblerError("Illegal operand: " + args);
  250.  
  251.                             m.operand.push_back(Operand(OperandType::Memory, (uint8_t)val));
  252.                             comb <<= 4; comb |= 1;
  253.                             args.erase(0, args.find_first_of(']')+1);
  254.                         } else if (args[0] == '\'') {
  255.                             //ASCII literal
  256.                             m.operand.push_back(Operand(OperandType::Literal, args[1]));
  257.                             comb <<= 4; comb |= 2;
  258.                             args.erase(0, 3);
  259.                         } else {
  260.                             //literal
  261.                             auto lit = args.substr(0, args.find_first_of(" \t"));
  262.                             if (lit.find_first_not_of("0123456789") == std::string::npos) {
  263.                                 //numeric
  264.                                 int val = 0xFFFF;
  265.                                 try {
  266.                                     val = std::stoi(lit);
  267.                                 } catch (...) {}
  268.  
  269.                                 if (val < 0 || val > 255)
  270.                                     throw AssemblerError("Illegal operand: " + lit);
  271.  
  272.                                 m.operand.push_back(Operand(OperandType::Literal, (uint8_t)val));
  273.                                 comb <<= 4; comb |= 0x2;
  274.                             } else {
  275.                                 //label
  276.                                 auto labelIt = labelMap.find(lit);
  277.                                 if (labelIt == labelMap.end()) {
  278.                                     auto check = lit;
  279.                                     std::transform(check.begin(), check.end(), check.begin(), ::toupper);
  280.                                     if (MnemonicMap.find(check) != MnemonicMap.end())
  281.                                         throw AssemblerError("Illegal label name: " + lit);
  282.                                     m.operand.push_back(Operand(OperandType::Label, lit));
  283.                                 } else
  284.                                     m.operand.push_back(Operand(OperandType::Literal, labelIt->second));
  285.                                 comb <<= 4; comb |= 2;
  286.                             }
  287.  
  288.                             args.erase(0, lit.size());
  289.                         }
  290.                     }
  291.                 }
  292.  
  293.                 //check for existence of Instruction
  294.                 auto range = MnemonicInstructionMap.equal_range(m.op);
  295.                 for (auto it = range.first; it != range.second; it++) {
  296.                     if (it->second.first == (OperandCombination)comb) {
  297.                         //found it!
  298.                         TranslatedInstruction t(it->second.second, std::move(m.operand));
  299.                         offset += t.size();
  300.                         if (offset > 255)
  301.                             throw AssemblerError("Output to big");
  302.                         instructions.push_back(t);
  303.                         return;
  304.                     }
  305.                 }
  306.                 throw AssemblerError("Unexpected or missing operands");
  307.             } else {
  308.                 throw AssemblerError("Unrecognized input: " + s);
  309.             }
  310.  
  311.             return;
  312.  
  313.         }
  314.  
  315.         template<class F>
  316.         bool emit(F emitter)
  317.         {
  318.             if (!instructions.empty()) {
  319.                 auto inst = instructions.front();
  320.                 emitter(inst.op);
  321.                 for (size_t i = 0; i < inst.operand.size(); ++i)
  322.                     emitter(inst.operand[i].value);
  323.                 instructions.pop_front();
  324.                 return true;
  325.             }
  326.             return false;
  327.         }
  328.  
  329.         void resolve()  
  330.         {
  331.             //resolves labels
  332.             for (auto it = instructions.begin(); it != instructions.end(); it++) {
  333.                 for (auto itO = it->operand.begin(); itO != it->operand.end(); itO++) {
  334.                     if (itO->type == OperandType::Label) {
  335.                         auto itL = labelMap.find(itO->label);
  336.                         if (itL == labelMap.end())
  337.                             throw AssemblerError("Unresolved label: " + itO->label);
  338.  
  339.                         itO->type = OperandType::Literal;
  340.                         itO->value = itL->second;
  341.                     }
  342.                 }
  343.             }
  344.  
  345.         }
  346.  
  347.     private:
  348.         std::list<TranslatedInstruction> instructions;
  349.         std::unordered_map<std::string, size_t> labelMap;
  350.         size_t offset;
  351.     };
  352. }
  353.  
  354. int main(int argc, char *argv[])
  355. {
  356.     using namespace std;
  357.  
  358.     cout << "tinyAssembler v0.1" << endl;
  359.  
  360.     if (argc != 2) {
  361.         cout << "Usage: tiny <input file>" << endl;
  362.         return -1;
  363.     }
  364.  
  365.     ifstream input(argv[1]);
  366.     if (!input.is_open()) {
  367.         cout << "Couldn't open file: " << argv[1] << endl;
  368.         return -1;
  369.     }
  370.    
  371.     tiny::Assembler as;
  372.     size_t lineNr = 0;
  373.     string line;
  374.     try {
  375.         while (getline(input, line)) {
  376.             lineNr++;
  377.             as.push_line(line);
  378.         }
  379.         //resolve missing labels
  380.         as.resolve();
  381.        
  382.         cout << "Output:" << endl;
  383.         size_t offset = 0;
  384.         while (as.emit([&](uint8_t val) { cout << "0x" << hex << setfill('0') << setw(2) <<  (int)val << " "; offset++;}))
  385.             cout << endl;
  386.  
  387.         cout << endl << "Done, emitted " << dec << offset << " bytes" << endl;
  388.     } catch (tiny::AssemblerError err) {
  389.         cout << "Error in line " << dec << lineNr << ": " << line << endl;
  390.         cout << err.message << endl;
  391.     }
  392.     return 0;
  393. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement