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 {
|
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",
|
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))
|
return std::find(mnemonics.begin(), mnemonics.end(), static_cast<std::string_view>(token))
|
||||||
!= mnemonics.end();
|
!= mnemonics.end();
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
#include "../ast/nodes/MovNode.h"
|
#include "../ast/nodes/MovNode.h"
|
||||||
#include "../ast/nodes/ConstNode.h"
|
#include "../ast/nodes/ConstNode.h"
|
||||||
#include "../ast/nodes/AluNode.h"
|
#include "../ast/nodes/AluNode.h"
|
||||||
#include <map>
|
#include "../ast/nodes/JumpNode.h"
|
||||||
|
|
||||||
// ! Helper Functions
|
// ! Helper Functions
|
||||||
|
|
||||||
// ! Public 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> {
|
auto Parser::parse() -> std::unique_ptr<Node> {
|
||||||
while (peek().getType() != Token::END) {
|
while (peek().getType() != Token::END) {
|
||||||
@ -20,16 +20,7 @@ auto Parser::parse() -> std::unique_ptr<Node> {
|
|||||||
throw "Parser Error: Expected Mnemonic!";
|
throw "Parser Error: Expected Mnemonic!";
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Put these functions in a map, mapped to the mnemonic name string
|
eaters[static_cast<std::string>(peek())](*this);
|
||||||
if (static_cast<std::string_view>(peek()) == "MOV") {
|
|
||||||
mov();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<std::string_view>(peek()) == "ADD") {
|
|
||||||
alu();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::move(ast);
|
return std::move(ast);
|
||||||
@ -54,19 +45,17 @@ void Parser::mov() {
|
|||||||
uint8_t source = 0; // Load from reg0
|
uint8_t source = 0; // Load from reg0
|
||||||
if (peek().getType() == Token::NUMBER) {
|
if (peek().getType() == Token::NUMBER) {
|
||||||
ast->addChild(std::move(std::make_unique<ConstNode>(static_cast<uint8_t>(peek())))); // Load constant to reg0
|
ast->addChild(std::move(std::make_unique<ConstNode>(static_cast<uint8_t>(peek())))); // Load constant to reg0
|
||||||
} else if (peek().getType() == Token::IDENTIFIER) {
|
} else if (peek().getType() == Token::IDENTIFIER && static_cast<std::string_view>(peek().subtoken(0, 3)) == "reg") {
|
||||||
source = static_cast<uint8_t>(peek());
|
source = static_cast<uint8_t>(peek().subtoken(3, 1));
|
||||||
} else {
|
} else {
|
||||||
throw "Parser Error: Expected Constant or Register!";
|
throw "Parser Error: Expected Constant or Register!";
|
||||||
}
|
}
|
||||||
get(); // Eat source
|
get(); // Eat source
|
||||||
|
|
||||||
const Token identifier = peek().subtoken(0, 3);
|
if (peek().getType() != Token::IDENTIFIER || static_cast<std::string_view>(peek().subtoken(0, 3)) != "reg") {
|
||||||
const Token reg = peek().subtoken(3, 1); // Get reg number
|
|
||||||
if (peek().getType() != Token::IDENTIFIER || static_cast<std::string_view>(identifier) != "reg") {
|
|
||||||
throw "Parser Error: Expected Register!";
|
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
|
get(); // Eat target
|
||||||
|
|
||||||
ast->addChild(std::move(std::make_unique<MovNode>(source, 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
|
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 <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
#include "../lexer/Token.h"
|
#include "../lexer/Token.h"
|
||||||
#include "../ast/Node.h"
|
#include "../ast/Node.h"
|
||||||
#include "../ast/nodes/RootNode.h"
|
#include "../ast/nodes/RootNode.h"
|
||||||
@ -28,10 +30,25 @@ private:
|
|||||||
|
|
||||||
void alu();
|
void alu();
|
||||||
|
|
||||||
|
void jmp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<Token> &tokens;
|
|
||||||
std::vector<Token>::const_iterator position;
|
std::vector<Token>::const_iterator position;
|
||||||
std::unique_ptr<Node> ast = std::make_unique<RootNode>();
|
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
|
#endif //LOGISIMASSEMBLER_PARSER_H
|
||||||
|
Reference in New Issue
Block a user