1

Fix: Parsing of mov instructions containing a constant, like "MOV 10, reg1"

This commit is contained in:
2023-03-21 15:49:29 +01:00
parent e92e7d2183
commit 2e2e5d8ed3
8 changed files with 35 additions and 37 deletions

View File

@ -25,6 +25,10 @@ public:
void addChild(std::unique_ptr<Node> child); void addChild(std::unique_ptr<Node> child);
// TODO: For more complex instructions, compile needs to return a vector<uint8_t>
// TODO: In this case, the Observer may not traverse all nodes...
// The Observer is the wrong choice for compilation.
// I can just call compile on the root, and the root compiles its children.
[[nodiscard]] virtual auto compile() const -> uint8_t = 0; [[nodiscard]] virtual auto compile() const -> uint8_t = 0;
[[nodiscard]] auto getChildren() const -> const std::vector<std::unique_ptr<Node>> &; [[nodiscard]] auto getChildren() const -> const std::vector<std::unique_ptr<Node>> &;
@ -38,6 +42,7 @@ protected:
}; };
protected: protected:
// TODO: Currently the AST degrades to a list, but someday we'll need a real tree
std::vector<std::unique_ptr<Node>> children; std::vector<std::unique_ptr<Node>> children;
}; };

View File

@ -4,19 +4,8 @@
#include "MovNode.h" #include "MovNode.h"
MovNode::MovNode(std::unique_ptr<Node> source, std::unique_ptr<Node> target) { MovNode::MovNode(uint8_t source, uint8_t target) : source(source), target(target) {}
children.push_back(std::move(source));
children.push_back(std::move(target));
}
auto MovNode::source() const -> Node & {
return *children[0];
}
auto MovNode::target() const -> Node & {
return *children[1];
}
auto MovNode::compile() const -> uint8_t { auto MovNode::compile() const -> uint8_t {
return (COPY & 0b11) << 6 | (source().compile() & 0b111) << 3 | (target().compile() & 0b111); return (COPY & 0b11) << 6 | (source & 0b111) << 3 | (target & 0b111);
} }

View File

@ -6,18 +6,19 @@
#define LOGISIMASSEMBLER_MOVNODE_H #define LOGISIMASSEMBLER_MOVNODE_H
#include "../Node.h" #include "../Node.h"
#include "RegNode.h"
class MovNode : public Node { class MovNode : public Node {
public: public:
MovNode(std::unique_ptr<Node> source, std::unique_ptr<Node> target); MovNode(uint8_t source, uint8_t target);
~MovNode() override = default; ~MovNode() override = default;
auto source() const -> Node &;
auto target() const -> Node &;
[[nodiscard]] auto compile() const -> uint8_t override; [[nodiscard]] auto compile() const -> uint8_t override;
private:
uint8_t source;
uint8_t target;
}; };
#endif //LOGISIMASSEMBLER_MOVNODE_H #endif //LOGISIMASSEMBLER_MOVNODE_H

View File

@ -11,5 +11,9 @@ auto RegNode::compile() const -> uint8_t {
throw "Compile Error: Invalid Register!"; throw "Compile Error: Invalid Register!";
} }
return -1;
}
auto RegNode::getRegister() const -> uint8_t {
return reg; return reg;
} }

View File

@ -15,6 +15,8 @@ public:
[[nodiscard]] auto compile() const -> uint8_t override; [[nodiscard]] auto compile() const -> uint8_t override;
[[nodiscard]] auto getRegister() const -> uint8_t;
private: private:
uint8_t reg; uint8_t reg;
}; };

View File

@ -5,5 +5,5 @@
#include "RootNode.h" #include "RootNode.h"
auto RootNode::compile() const -> uint8_t { auto RootNode::compile() const -> uint8_t {
return 0; return -1;
} }

View File

@ -3,10 +3,8 @@
// //
#include "Parser.h" #include "Parser.h"
#include "../ast/nodes/RootNode.h"
#include "../ast/nodes/MovNode.h" #include "../ast/nodes/MovNode.h"
#include "../ast/nodes/ConstNode.h" #include "../ast/nodes/ConstNode.h"
#include "../ast/nodes/RegNode.h"
#include "../ast/nodes/AluNode.h" #include "../ast/nodes/AluNode.h"
#include <map> #include <map>
@ -17,8 +15,6 @@
Parser::Parser(const std::vector<Token> &tokens) : tokens(tokens), position(tokens.begin()) {} Parser::Parser(const std::vector<Token> &tokens) : tokens(tokens), position(tokens.begin()) {}
auto Parser::parse() -> std::unique_ptr<Node> { auto Parser::parse() -> std::unique_ptr<Node> {
auto root = std::make_unique<RootNode>();
while (peek().getType() != Token::END) { while (peek().getType() != Token::END) {
if (peek().getType() != Token::MNEMONIC) { if (peek().getType() != Token::MNEMONIC) {
throw "Parser Error: Expected Mnemonic!"; throw "Parser Error: Expected Mnemonic!";
@ -26,17 +22,17 @@ auto Parser::parse() -> std::unique_ptr<Node> {
// TODO: Put these functions in a map, mapped to the mnemonic name string // TODO: Put these functions in a map, mapped to the mnemonic name string
if (static_cast<std::string_view>(peek()) == "MOV") { if (static_cast<std::string_view>(peek()) == "MOV") {
root->addChild(std::move(mov())); mov();
continue; continue;
} }
if (static_cast<std::string_view>(peek()) == "ADD") { if (static_cast<std::string_view>(peek()) == "ADD") {
root->addChild(std::move(alu())); alu();
continue; continue;
} }
} }
return std::move(root); return std::move(ast);
} }
// ! Private Functions // ! Private Functions
@ -49,17 +45,17 @@ auto Parser::get() -> const Token & {
return *(position++); return *(position++);
} }
auto Parser::mov() -> std::unique_ptr<Node> { void Parser::mov() {
if (peek().getType() != Token::MNEMONIC || static_cast<std::string_view>(peek()) != "MOV") { if (peek().getType() != Token::MNEMONIC || static_cast<std::string_view>(peek()) != "MOV") {
throw "Parser Error: Expected 'MOV'!"; throw "Parser Error: Expected 'MOV'!";
} }
get(); // Eat 'MOV' get(); // Eat 'MOV'
std::unique_ptr<Node> sourceNode; uint8_t source = 0; // Load from reg0
if (peek().getType() == Token::NUMBER) { if (peek().getType() == Token::NUMBER) {
sourceNode = std::make_unique<ConstNode>(static_cast<uint8_t>(peek())); 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) {
sourceNode = std::make_unique<RegNode>(static_cast<uint8_t>(peek())); source = static_cast<uint8_t>(peek());
} else { } else {
throw "Parser Error: Expected Constant or Register!"; throw "Parser Error: Expected Constant or Register!";
} }
@ -70,13 +66,13 @@ auto Parser::mov() -> std::unique_ptr<Node> {
if (peek().getType() != Token::IDENTIFIER || static_cast<std::string_view>(identifier) != "reg") { if (peek().getType() != Token::IDENTIFIER || static_cast<std::string_view>(identifier) != "reg") {
throw "Parser Error: Expected Register!"; throw "Parser Error: Expected Register!";
} }
std::unique_ptr<Node> targetNode = std::make_unique<RegNode>(static_cast<uint8_t>(reg)); auto target = static_cast<uint8_t>(reg);
get(); // Eat target get(); // Eat target
return std::move(std::make_unique<MovNode>(std::move(sourceNode), std::move(targetNode))); ast->addChild(std::move(std::make_unique<MovNode>(source, target)));
} }
auto Parser::alu() -> std::unique_ptr<Node> { void Parser::alu() {
std::map<std::string, AluNode::AluOperation> aluMap = {{"AND", AluNode::AND}, std::map<std::string, AluNode::AluOperation> aluMap = {{"AND", AluNode::AND},
{"OR", AluNode::OR}, {"OR", AluNode::OR},
{"NAND", AluNode::NAND}, {"NAND", AluNode::NAND},
@ -91,5 +87,5 @@ auto Parser::alu() -> std::unique_ptr<Node> {
throw "Parser Error: Invalid ALU operation!"; throw "Parser Error: Invalid ALU operation!";
} }
return 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
} }

View File

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "../lexer/Token.h" #include "../lexer/Token.h"
#include "../ast/Node.h" #include "../ast/Node.h"
#include "../ast/nodes/RootNode.h"
class Parser { class Parser {
public: public:
@ -23,14 +24,14 @@ private:
auto get() -> const Token &; auto get() -> const Token &;
auto mov() -> std::unique_ptr<Node>; void mov();
auto alu() -> std::unique_ptr<Node>; void alu();
private: private:
const std::vector<Token> &tokens; 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>();
}; };
#endif //LOGISIMASSEMBLER_PARSER_H #endif //LOGISIMASSEMBLER_PARSER_H