Add basic assembler without symbols support
This commit is contained in:
10
README.md
10
README.md
@@ -1,3 +1,13 @@
|
|||||||
# hack-assembler
|
# hack-assembler
|
||||||
|
|
||||||
An implementation of a hack assembler in C++.
|
An implementation of a hack assembler in C++.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
g++ -o hack-assembler main.cpp
|
||||||
|
cat <input_file.asm> | ./hack-assembler > <output_file.hack>
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
This project is under the WTFPL License. See [LICENSE](LICENSE) for details.
|
||||||
|
|||||||
145
main.cpp
Normal file
145
main.cpp
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <bitset>
|
||||||
|
#include <string>
|
||||||
|
#include <cctype>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
// Comp map
|
||||||
|
const std::map<std::string, std::string> 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<std::string, std::string> 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<std::string, std::string> 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<unsigned char>(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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user