컴공 일기229
게시글 주소: https://orbi.kr/00062045045
요새는 운동을 하러 가는 것 이외엔, 공학과 수학에 집중하고 있습니다. 나도 모르게, 몰입이 되고 있다는 느낌을 많이 받고 있어요. 다만, 결과는 과정의 수려함들을 집어삼켜 먹는 습성이 있는 걸 잘 알아서, 큰 욕심은 내지 않고 있습니다.
과정에 주목하는 삶을 살고 있달까요. 뭐, 무엇인가를 크게 이뤄나가는 일상은 아닙니다만, 개인적으론 참 만족스럽습니다.
저번 일기에서 그려보았듯, Assembler를 제작하고 있어요. 재미있는 여정입니다.
Parser 모듈 : 입력 코드에 대한 접근을 캡슐화(Capsulation)합니다. 어셈블리 명령을 읽어 들여 구문을 분석하고, 명령 세부요소(필드/기호)에 편리하게 접근하도록 합니다. 추가적으로 모든 공백과 주석문을 제거합니다.
Parser.h
#pragma once
#ifndef HACK_ASSEMBLER_PARSER_H
#define HACK_ASSEMBLER_PARSER_H
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <map>
using namespace std;
class Parser
{
public:
Parser(string& filename);
//File is closed implicitly.
bool hasMoreCommands();
//Returns true if the file contains commands that still need to be parsed,
//Return flase otherwise.
void advance(unsigned long& lineNr);
char commandType(unsigned long& lineNr);
string symbol();
//Returns the symbol or decimal value of the current command.
//Should only be called if commandType() returns 'A' or 'L'.
string destM();
// Returns the destination mnemonic of the current command.
string compM();
string jumpM();
private:
ifstream fin;
string currentCommand;
map <char, char> commandTable;
};
#endif
-Parser.cpp
#include "Parser.h"
using namespace std;
Parser::Parser(string& fileName)
{
fin.open(fileName);
if (fin.fail())
{
cout << fileName << "not found." << endl;
exit(1);
}
//Populate the command map table.
commandTable['@'] = 'A';
commandTable['A'] = 'C';
commandTable['D'] = 'C';
commandTable['M'] = 'C';
commandTable['0'] = 'C';
commandTable['1'] = 'C';
commandTable['-'] = 'C';
commandTable['!'] = 'C';
commandTable['('] = 'L';
}
bool Parser::hasMoreCommands()
{
return !fin.eof();
}
void Parser::advance(unsigned long& lineNr)
{
string currentLine;
unsigned long commentPos;
bool commandFound;
commandFound = false;
while (!commandFound && getline(fin, currentLine))
{
lineNr++;
//Remove whitespace.
currentLine.erase(remove_if(currentLine.begin(), currentLine.end(), ::isspace), currentLine.end());
//Remove comments.
commentPos = currentLine.find("//");
//if comments were found
if (commentPos != string::npos)
{
currentLine.erase(commentPos, currentLine.length() - commentPos);
}
commandFound = !currentLine.empty();
}
currentCommand = currentLine;
}
char Parser::commandType(unsigned long& lineNr)
{
if (commandTable.find(currentCommand[0]) != commandTable.end())
{
return commandTable[currentCommand[0]];
}
cout << "Invalid syntax at line: " << lineNr << endl;
}
string Parser::symbol()
{
unsigned long openBracketPos, closeBracketPos;
openBracketPos = currentCommand.find('(');
closeBracketPos = currentCommand.find(')');
//A-instruction: return everything after the '@' character
if (currentCommand[0] == '@')
{
return currentCommand.substr(1, currentCommand.length() - 1);
}
else if (openBracketPos != string::npos && closeBracketPos != string::npos) {
return currentCommand.substr(openBracketPos + 1, closeBracketPos - openBracketPos - 1);
}
// If the function was called in error, return a blank string.
return "";
}
string Parser::destM()
{
unsigned long equalSignPos;
//Return everything before the '=' character.
if (equalSignPos != string::npos)
{
return currentCommand.substr(0, equalSignPos);
}
//If no destination was specified, return a blank string.
return "";
}
string Parser::compM()
{
unsigned long equalSignPos, semiColonPos;
equalSignPos = currentCommand.find('=');
semiColonPos = currentCommand.find(';');
// Return the computation mnemonic based on three cases.
if (equalSignPos != string::npos)
{
//Case 1: dest = comp ; jump
if (semiColonPos != string::npos)
{
return currentCommand.substr(equalSignPos + 1, semiColonPos - equalSignPos - 1);
}
//Case 2: dest = comp
return currentCommand.substr(equalSignPos + 1, currentCommand.length() - equalSignPos - 1);
}
else if (semiColonPos != string::npos)
{
//Case 3: comp ; jump
return currentCommand.substr(0, semiColonPos);
}
return "";
}
string Parser::jumpM()
{
unsigned long semiColonPos;
//Return everything after the ';' character.
if (semiColonPos != string::npos)
{
return currentCommand.substr(semiColonPos + 1, currentCommand.length() - semiColonPos - 1);
}
//If a jump was not specified, return a blank string.
}
CodeTranslator 모듈 : 어셈블리 언어의 연상기호를 2진 코드로 변환합니다.
-CodeTranslator.h
#pragma once
#ifndef HACK_ASSEMBLER_CODE_H
#define HACK_ASSEMBLER_CODE_H
#include <iostream>
#include <map>
using namespace std;
class CodeTranslator
{
public:
CodeTranslator();
//Populates the code translation map tables
// with the language specification.
string dest(string destMenmonic, unsigned long& lineNr);
//Returns the binary code of the destination mnemonic
//as a string containing 3 bits.
//Line number is passed for use in an error message.
string comp(string compMnemonic, unsigned long& lineNr);
//Returns the binary code of the computation mnemonic
//as a string containing 3 bits.
//Line number is passed for use in an error message.
string jump(string jumpMnemonic, unsigned long& lineNr);
//Returns the binary code of the jump mnemonic
//as a string containing 3 bits.
//Line number is passed for use in an error meassage.
private:
map<string, string> destTable;
map<string, string> compTable;
map<string, string> jumpTable;
};
#endif
-CodeTranslator.cpp
#include "CodeTranslator.h" | |
using namespace std; | |
CodeTranslator::CodeTranslator() { | |
// Populate the translation map tables. | |
destTable[""] = "000"; | |
destTable["M"] = "001"; | |
destTable["D"] = "010"; | |
destTable["MD"] = "011"; | |
destTable["A"] = "100"; | |
destTable["AM"] = "101"; | |
destTable["AD"] = "110"; | |
destTable["AMD"] = "111"; | |
compTable["0"] = "0101010"; | |
compTable["1"] = "0111111"; | |
compTable["-1"] = "0111010"; | |
compTable["D"] = "0001100"; | |
compTable["A"] = "0110000"; | |
compTable["!D"] = "0001101"; | |
compTable["!A"] = "0110001"; | |
compTable["-D"] = "0001111"; | |
compTable["-A"] = "0110011"; | |
compTable["D+1"] = "0011111"; | |
compTable["A+1"] = "0110111"; | |
compTable["D-1"] = "0001110"; | |
compTable["A-1"] = "0110010"; | |
compTable["D+A"] = "0000010"; | |
compTable["D-A"] = "0010011"; | |
compTable["A-D"] = "0000111"; | |
compTable["D&A"] = "0000000"; | |
compTable["D|A"] = "0010101"; | |
compTable["M"] = "1110000"; | |
compTable["!M"] = "1110001"; | |
compTable["-M"] = "1110011"; | |
compTable["M+1"] = "1110111"; | |
compTable["M-1"] = "1110010"; | |
compTable["D+M"] = "1000010"; | |
compTable["D-M"] = "1010011"; | |
compTable["M-D"] = "1000111"; | |
compTable["D&M"] = "1000000"; | |
compTable["D|M"] = "1010101"; | |
jumpTable[""] = "000"; | |
jumpTable["JGT"] = "001"; | |
jumpTable["JEQ"] = "010"; | |
jumpTable["JGE"] = "011"; | |
jumpTable["JLT"] = "100"; | |
jumpTable["JNE"] = "101"; | |
jumpTable["JLE"] = "110"; | |
jumpTable["JMP"] = "111"; | |
} | |
string CodeTranslator::dest(string destMnemonic, unsigned long& lineNr) { | |
if (destTable.find(destMnemonic) != destTable.end()) { | |
return destTable[destMnemonic]; | |
} | |
// If none of the mnemonics are found, output an error message, | |
// and provide the line number in the original source where the error occurred. | |
cout << "Invalid syntax in destination statement at line: " << lineNr << endl; | |
exit(1); | |
} | |
string CodeTranslator::comp(string compMnemonic, unsigned long& lineNr) { | |
if (compTable.find(compMnemonic) != compTable.end()) { | |
return compTable[compMnemonic]; | |
} | |
// If none of the mnemonics are found, output an error message, | |
// and provide the line number in the original source where the error occurred. | |
cout << "Invalid syntax in computation statement at line: " << lineNr << endl; | |
exit(1); | |
} | |
string CodeTranslator::jump(string jumpMnemonic, unsigned long& lineNr) { | |
if (jumpTable.find(jumpMnemonic) != jumpTable.end()) { | |
return jumpTable[jumpMnemonic]; | |
} | |
// If none of the mnemonics are found, output an error message, | |
// and provide the line number in the original source where the error occurred. | |
cout << "Invalid syntax in jump statement at line: " << lineNr << endl; | |
exit(1); | |
} |
0 XDK (+0)
유익한 글을 읽었다면 작성자에게 XDK를 선물하세요.
저 컴공인데 엄청 어려워 보이네요...
어.. 어셈블러를 직접 구현하는 과정이 컴공에 없기는 하죠 ㅠㅠ 개인적으로 그게 아쉬워서 방학을 기회로 해보고 있답니다!
와...컴공 가고 싶었는데 뭔가 엄청 어려워보인다
원리를 알면 생각보다 간단한 코드예요. 번역을 하려면, 문장을 단어별로 세세히 쪼갤 필요가 있고, 그 단어의 의미를 하나하나 파악하잖아요?
그런 원리예요 ㅎㅎ 그걸 코드로 표현한다면 복잡해보이지만, 어느정도 공부를 하고 나면 한 눈에 보이는 정도입니다.
ㅠㅠ 컴공 지망생이긴 한데 혹시 가서 고등학고 때 배웠던 과목 중 쓰이는 과목이 있나요..?
수능 국어요! 코딩도 결국 글쓰기예요. 그러니까, '글'을 읽는 원리라든가, 쓰는 원리에 익숙하면 굉장히 유리한 점을 지니고 있습니다. 수학도 많이 쓰이고요. 근데, 고등학교 수학에서 배웠던 것들이 '기반'이 되기는 하는데, 그것이 '중심'이 되는 것은 물론 아닙니다.