Fix: Parsing of mov instructions containing a constant, like "MOV 10, reg1"
This commit is contained in:
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user