diff --git a/README.md b/README.md index 462de64..cfc48e3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ # hack-assembler -An implementation of a hack assembler in C++. \ No newline at end of file +An implementation of a hack assembler in C++. + +## Usage + +```bash +g++ -o hack-assembler main.cpp +cat | ./hack-assembler > +``` + +## License +This project is under the WTFPL License. See [LICENSE](LICENSE) for details. diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..5071d7e --- /dev/null +++ b/main.cpp @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include + +// Comp map +const std::map compMap = { + {"0", "0101010"}, + {"1", "0111111"}, + {"-1", "0111010"}, + {"D", "0001100"}, + {"A", "0110000"}, + {"!D", "0001101"}, + {"!A", "0110001"}, + {"-D", "0001111"}, + {"-A", "0110011"}, + {"D+1", "0011111"}, + {"A+1", "0110111"}, + {"D-1", "0001110"}, + {"A-1", "0110010"}, + {"D+A", "0000010"}, + {"A+D", "0000010"}, + {"D-A", "0010011"}, + {"A-D", "0000111"}, + {"D&A", "0000000"}, + {"A&D", "0000000"}, + {"D|A", "0010101"}, + {"A|D", "0010101"}, + {"M", "1110000"}, + {"!M", "1110001"}, + {"-M", "1110011"}, + {"M+1", "1110111"}, + {"M-1", "1110010"}, + {"D+M", "1000010"}, + {"D+M", "1000010"}, + {"D-M", "1010011"}, + {"M-D", "1000111"}, + {"D&M", "1000000"}, + {"M&D", "1000000"}, + {"D|M", "1010101"}, + {"M|D", "1010101"} +}; + +// dest Map +const std::map destMap = { + {"null", "000"}, + {"M", "001"}, + {"D", "010"}, + {"MD", "011"}, + {"DM", "011"}, + {"A", "100"}, + {"AM", "101"}, + {"MA", "101"}, + {"AD", "110"}, + {"DA", "110"}, + {"ADM", "111"}, + {"AMD", "111"}, + {"DAM", "111"}, + {"DMA", "111"}, + {"MDA", "111"}, + {"MAD", "111"} +}; + + +// jump Map +const std::map jumpMap = { + {"null", "000"}, + {"JGT", "001"}, + {"JEQ", "010"}, + {"JGE", "011"}, + {"JLT", "100"}, + {"JNE", "101"}, + {"JLE", "110"}, + {"JMP", "111"} +}; + +static inline std::string trim(const std::string &s) { + size_t a = s.find_first_not_of(" \t\n\r"); + if (a == std::string::npos) return ""; + size_t b = s.find_last_not_of(" \t\n\r"); + return s.substr(a, b - a + 1); +} + +static inline std::string strip(const std::string &s) { + std::string result; + for (char c : s) { + if (!std::isspace(static_cast(c))) { + result += c; + } + } + return result; +} + +int main() { + std::string line; + while (std::getline(std::cin, line)) { + line = trim(line); + if (line.empty()) continue; + + // skip comments + if (line[0] == '#' || (line.size() > 1 && line[0] == '/' && line[1] == '/')) continue; + + // A-instruction + if (line[0] == '@') { + std::string value = line.substr(1); + if (value.empty()) continue; + try { + int intValue = std::stoi(value); + std::bitset<16> binaryValue(intValue); + std::cout << binaryValue.to_string() << '\n'; + } catch (...) { continue; } + } else { // C-instruction + std::string instruction = "111"; + size_t eqPos = line.find('='); + size_t scPos = line.find(';'); + // comp + std::string comp; + if (eqPos != std::string::npos) { + comp = line.substr(eqPos + 1, scPos - eqPos - 1); + } else if (scPos != std::string::npos) { + comp = line.substr(0, scPos); + } else { + comp = line; + } + comp = strip(comp); + auto compIt = compMap.find(comp); + if (compIt == compMap.end()) continue; + instruction += compIt->second; + // dest use use destMap "null" key if not found + std::string dest = (eqPos != std::string::npos) ? line.substr(0, eqPos) : "null"; + dest = strip(dest); + auto destIt = destMap.find(dest); + instruction += (destIt != destMap.end()) ? destIt->second : destMap.at("null"); + // jump + std::string jump = (scPos != std::string::npos) ? line.substr(scPos + 1) : "null"; + jump = strip(jump); + auto jumpIt = jumpMap.find(jump); + instruction += (jumpIt != jumpMap.end()) ? jumpIt->second : jumpMap.at("null"); + std::cout << instruction << '\n'; + } + } + return 0; +} +