Implement JMP instructions and fix a parsing bug, when MOV is called with a register as source
This commit is contained in:
11
src/ast/nodes/JumpNode.cpp
Normal file
11
src/ast/nodes/JumpNode.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by christoph on 21.03.23.
|
||||
//
|
||||
|
||||
#include "JumpNode.h"
|
||||
|
||||
JumpNode::JumpNode(JumpNode::JumpOperation operation) : operation(operation) {}
|
||||
|
||||
uint8_t JumpNode::compile() const {
|
||||
return (CONDITION & 0b11) << 6 | (operation & 0b111);
|
||||
}
|
34
src/ast/nodes/JumpNode.h
Normal file
34
src/ast/nodes/JumpNode.h
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by christoph on 21.03.23.
|
||||
//
|
||||
|
||||
#ifndef LOGISIMASSEMBLER_JUMPNODE_H
|
||||
#define LOGISIMASSEMBLER_JUMPNODE_H
|
||||
|
||||
#include "../Node.h"
|
||||
|
||||
class JumpNode : public Node {
|
||||
public:
|
||||
enum JumpOperation : uint8_t {
|
||||
NEVER,
|
||||
EQUAL_ZERO,
|
||||
LESS_ZERO,
|
||||
LESS_EQUAL_ZERO,
|
||||
ALWAYS,
|
||||
NOT_ZERO,
|
||||
GREATER_ZERO,
|
||||
GREATER_EQUAL_ZERO
|
||||
};
|
||||
|
||||
public:
|
||||
JumpNode(JumpOperation operation);
|
||||
|
||||
~JumpNode() override = default;
|
||||
|
||||
[[nodiscard]] auto compile() const -> uint8_t override;
|
||||
|
||||
private:
|
||||
JumpOperation operation;
|
||||
};
|
||||
|
||||
#endif //LOGISIMASSEMBLER_JUMPNODE_H
|
@ -45,9 +45,10 @@ auto is_alphabetical(const char character) -> bool {
|
||||
}
|
||||
|
||||
auto is_mnemonic(const Token &token) -> bool {
|
||||
// TODO: Add other mnemonics
|
||||
// TODO: Move this to a separate header
|
||||
const std::vector<std::string> mnemonics = {"MOV",
|
||||
"ADD"};
|
||||
"AND", "OR", "NAND", "NOR", "ADD", "SUB",
|
||||
"JEQ", "JLE", "JLEQ", "JNEQ", "JGR", "JGEQ"};
|
||||
|
||||
return std::find(mnemonics.begin(), mnemonics.end(), static_cast<std::string_view>(token))
|
||||
!= mnemonics.end();
|
||||
|
@ -6,13 +6,13 @@
|
||||
#include "../ast/nodes/MovNode.h"
|
||||
#include "../ast/nodes/ConstNode.h"
|
||||
#include "../ast/nodes/AluNode.h"
|
||||
#include <map>
|
||||
#include "../ast/nodes/JumpNode.h"
|
||||
|
||||
// ! Helper Functions
|
||||
|
||||
// ! Public Functions
|
||||
|
||||
Parser::Parser(const std::vector<Token> &tokens) : tokens(tokens), position(tokens.begin()) {}
|
||||
Parser::Parser(const std::vector<Token> &tokens) : position(tokens.begin()) {}
|
||||
|
||||
auto Parser::parse() -> std::unique_ptr<Node> {
|
||||
while (peek().getType() != Token::END) {
|
||||
@ -20,16 +20,7 @@ auto Parser::parse() -> std::unique_ptr<Node> {
|
||||
throw "Parser Error: Expected Mnemonic!";
|
||||
}
|
||||
|
||||
// TODO: Put these functions in a map, mapped to the mnemonic name string
|
||||
if (static_cast<std::string_view>(peek()) == "MOV") {
|
||||
mov();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (static_cast<std::string_view>(peek()) == "ADD") {
|
||||
alu();
|
||||
continue;
|
||||
}
|
||||
eaters[static_cast<std::string>(peek())](*this);
|
||||
}
|
||||
|
||||
return std::move(ast);
|
||||
@ -54,19 +45,17 @@ void Parser::mov() {
|
||||
uint8_t source = 0; // Load from reg0
|
||||
if (peek().getType() == Token::NUMBER) {
|
||||
ast->addChild(std::move(std::make_unique<ConstNode>(static_cast<uint8_t>(peek())))); // Load constant to reg0
|
||||
} else if (peek().getType() == Token::IDENTIFIER) {
|
||||
source = static_cast<uint8_t>(peek());
|
||||
} else if (peek().getType() == Token::IDENTIFIER && static_cast<std::string_view>(peek().subtoken(0, 3)) == "reg") {
|
||||
source = static_cast<uint8_t>(peek().subtoken(3, 1));
|
||||
} else {
|
||||
throw "Parser Error: Expected Constant or Register!";
|
||||
}
|
||||
get(); // Eat source
|
||||
|
||||
const Token identifier = peek().subtoken(0, 3);
|
||||
const Token reg = peek().subtoken(3, 1); // Get reg number
|
||||
if (peek().getType() != Token::IDENTIFIER || static_cast<std::string_view>(identifier) != "reg") {
|
||||
if (peek().getType() != Token::IDENTIFIER || static_cast<std::string_view>(peek().subtoken(0, 3)) != "reg") {
|
||||
throw "Parser Error: Expected Register!";
|
||||
}
|
||||
auto target = static_cast<uint8_t>(reg);
|
||||
auto target = static_cast<uint8_t>(peek().subtoken(3, 1));
|
||||
get(); // Eat target
|
||||
|
||||
ast->addChild(std::move(std::make_unique<MovNode>(source, target)));
|
||||
@ -89,3 +78,21 @@ void Parser::alu() {
|
||||
|
||||
ast->addChild(std::move(std::make_unique<AluNode>(aluMap[static_cast<std::string>(get())]))); // Eat alu
|
||||
}
|
||||
|
||||
void Parser::jmp() {
|
||||
std::map<std::string, JumpNode::JumpOperation> jmpMap = {{"JEQ", JumpNode::EQUAL_ZERO},
|
||||
{"JLE", JumpNode::LESS_ZERO},
|
||||
{"JLEQ", JumpNode::LESS_EQUAL_ZERO},
|
||||
{"JNEQ", JumpNode::NOT_ZERO},
|
||||
{"JGR", JumpNode::GREATER_ZERO},
|
||||
{"JGEQ", JumpNode::GREATER_EQUAL_ZERO}};
|
||||
|
||||
if (peek().getType() != Token::MNEMONIC) {
|
||||
throw "Parser Error: Expected Mnemonic!";
|
||||
}
|
||||
if (!jmpMap.contains(static_cast<std::string>(peek()))) {
|
||||
throw "Parser Error: Invalid JMP operation!";
|
||||
}
|
||||
|
||||
ast->addChild(std::move(std::make_unique<JumpNode>(jmpMap[static_cast<std::string>(get())]))); // Eat jmp
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include "../lexer/Token.h"
|
||||
#include "../ast/Node.h"
|
||||
#include "../ast/nodes/RootNode.h"
|
||||
@ -28,10 +30,25 @@ private:
|
||||
|
||||
void alu();
|
||||
|
||||
void jmp();
|
||||
|
||||
private:
|
||||
const std::vector<Token> &tokens;
|
||||
std::vector<Token>::const_iterator position;
|
||||
std::unique_ptr<Node> ast = std::make_unique<RootNode>();
|
||||
|
||||
std::map<std::string, std::function<void(Parser &)>> eaters = {{"MOV", &Parser::mov},
|
||||
{"AND", &Parser::alu},
|
||||
{"OR", &Parser::alu},
|
||||
{"NAND", &Parser::alu},
|
||||
{"NOR", &Parser::alu},
|
||||
{"ADD", &Parser::alu},
|
||||
{"SUB", &Parser::alu},
|
||||
{"JEQ", &Parser::jmp},
|
||||
{"JLE", &Parser::jmp},
|
||||
{"JLEQ", &Parser::jmp},
|
||||
{"JNEQ", &Parser::jmp},
|
||||
{"JGR", &Parser::jmp},
|
||||
{"JGEQ", &Parser::jmp}};
|
||||
};
|
||||
|
||||
#endif //LOGISIMASSEMBLER_PARSER_H
|
||||
|
Reference in New Issue
Block a user