Add main entry point, fix some bugs, continue AST compilation
Some checks failed
Build-StoryEditor / build_linux (push) Has been cancelled
Build-StoryEditor / build_win32 (push) Has been cancelled
Deploy-Documentation / deploy (push) Has been cancelled

This commit is contained in:
anthony@rabine.fr 2025-04-06 22:43:34 +02:00
parent af859d7085
commit b9a946eab4
15 changed files with 598 additions and 90 deletions

28
.vscode/launch.json vendored
View file

@ -95,6 +95,34 @@
}
]
},
{
"name": "Debug Compiler AST Tests",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/core/story-manager/tests/build/compiler_test", // Remplacez par le chemin de votre exécutable
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}/core/story-manager/tests/build",
"environment": [],
"externalConsole": false,
"linux": {
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb"
},
"osx": {
"MIMode": "lldb",
"miDebuggerPath": "/Users/user936511/.vscode/extensions/ms-vscode.cpptools-1.18.5-darwin-arm64/debugAdapters/lldb-mi/bin/lldb-mi"
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
{
"name": "Black Magic Probe",

View file

@ -119,6 +119,19 @@ public:
Error GetLastError() { return m_lastError; }
bool GetMain(Instr &instr) const {
// Find the main label
bool success = m_labels.count(".main") == 1;
if (success)
{
instr = m_labels.at(".main");
}
return success;
}
private:
bool CompileMnemonicArguments(Instr &instr);

View file

@ -0,0 +1,137 @@
#pragma once
#include <iostream>
#include <thread>
#include <stdarg.h>
#include <string.h>
#include "chip32_assembler.h"
#include "chip32_macros.h"
namespace Chip32
{
class Machine
{
public:
bool parseResult{false};
bool buildResult{false};
chip32_result_t runResult{VM_OK};
static int get_from_memory(chip32_ctx_t *ctx, uint32_t addr, char *text)
{
int valid = 0;
// Test if address is valid
bool isRam = addr & 0x80000000;
addr &= 0xFFFF; // mask the RAM/ROM bit, ensure 16-bit addressing
if (isRam) {
strcpy(&text[0], (const char *)&ctx->ram.mem[addr]);
} else {
strcpy(&text[0], (const char *)&ctx->rom.mem[addr]);
}
return valid;
}
static uint8_t story_player_syscall(chip32_ctx_t *ctx, uint8_t code)
{
uint8_t retCode = SYSCALL_RET_OK;
char working_buf[100] = {0};
// Printf
if (code == 4)
{
// In R0: string with escaped characters
// R1: Number of arguments
// R2, R3 ... arguments
// Integers: stored in registers by values
// Strings: first character address in register
get_from_memory(ctx, ctx->registers[R0], working_buf);
int arg_count = ctx->registers[R1];
switch(arg_count){
case 0:
puts(working_buf);
break;
case 1:
printf(working_buf, ctx->registers[R2]);
puts("");
break;
case 2:
printf(working_buf, ctx->registers[R2], ctx->registers[R3]);
puts("");
break;
case 3:
printf(working_buf, ctx->registers[R2], ctx->registers[R3], ctx->registers[R4]);
puts("");
break;
default:
break;
}
}
// WAIT (sleep)
else if (code == 5)
{
std::this_thread::sleep_for(std::chrono::milliseconds(ctx->registers[R0]));
}
return retCode;
}
void QuickExecute(const std::string &assemblyCode)
{
std::vector<uint8_t> program;
Chip32::Assembler assembler;
Chip32::Result result;
uint8_t data[8*1024];
parseResult = assembler.Parse(assemblyCode);
std::cout << assembler.GetLastError().ToString() << std::endl;
buildResult = assembler.BuildBinary(program, result);
result.Print();
chip32_ctx_t chip32_ctx;
chip32_ctx.stack_size = 512;
chip32_ctx.rom.mem = program.data();
chip32_ctx.rom.addr = 0;
chip32_ctx.rom.size = program.size();
chip32_ctx.ram.mem = data;
chip32_ctx.ram.addr = 40 *1024;
chip32_ctx.ram.size = sizeof(data);
chip32_ctx.syscall = story_player_syscall;
chip32_initialize(&chip32_ctx);
Instr mainLine;
if (assembler.GetMain(mainLine))
{
// set pointer counter to the main line
chip32_ctx.registers[PC] = mainLine.addr;
}
runResult = chip32_run(&chip32_ctx);
}
};
} // namespace Chip32

View file

@ -22,6 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <iostream>
#include <sstream>
#include <stack>

View file

@ -17,6 +17,45 @@ BaseNode::~BaseNode()
std::cout << "Deleted base node" << std::endl;
}
std::string BaseNode::GenerateRandomString(size_t length, uint32_t flags)
{
std::string charset = "";
if (flags & CHARSET_ALPHABET_LOWER)
{
charset += "abcdefghijklmnopqrstuvwxyz";
}
if (flags & CHARSET_ALPHABET_UPPER)
{
charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
if (flags & CHARSET_NUMBERS)
{
charset += "0123456789";
}
if (flags & CHARSET_SIGNS)
{
charset += "!@#$%^&*()_+-=[]{}|;:,.<>?";
}
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<> distribution(0, charset.size() - 1);
std::string result;
result.reserve(length);
for (size_t i = 0; i < length; ++i) {
result += charset[distribution(generator)];
}
return result;
}
std::string BaseNode::GetEntryLabel(const std::string &id)
{
std::stringstream ss;

View file

@ -19,6 +19,24 @@ public:
float y;
};
/*
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"!@#$%^&*()_+-=[]{}|;:,.<>?";
*/
enum RandomFlags
{
CHARSET_ALPHABET_LOWER = 0x1,
CHARSET_ALPHABET_UPPER = 0x2,
CHARSET_NUMBERS = 0x4,
CHARSET_SIGNS = 0x8,
ALL_CHARSETS = CHARSET_ALPHABET_LOWER | CHARSET_ALPHABET_UPPER |CHARSET_NUMBERS | CHARSET_SIGNS
};
BaseNode(const std::string &type, const std::string &typeName);
virtual ~BaseNode();
@ -28,12 +46,19 @@ public:
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) = 0;
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) = 0;
virtual std::string GenerateConstants() const { return ""; }
virtual std::string GenerateAssembly() const = 0;
void SetPosition(float x, float y);
// make this virtual so that graphical node override the behavior
virtual float GetX() const;
virtual float GetY() const;
std::string GetMyEntryLabel() const {
return GetEntryLabel(m_uuid);
}
// Coded type, internal use
std::string GetType() const
{
@ -59,6 +84,7 @@ public:
void SetInternalData(const nlohmann::json &j);
nlohmann::json GetInternalData() const;
static std::string GenerateRandomString(size_t length, uint32_t flags = RandomFlags::ALL_CHARSETS);
private:
std::string m_title{"Default title"};

View file

@ -56,11 +56,11 @@ public:
for (auto& node : nodes) {
auto astNode = std::make_shared<AstNode>();
astNode->position = {0, 0};
x += 10; // Espacement horizontal
if (x > 50) { // Nouvelle ligne
astNode->position = {x, y};
x += 1; // Espacement horizontal
if (x > 20) { // Nouvelle ligne
x = 0;
y += 5; // Espacement vertical
y += 1; // Espacement vertical
}
astNode->node = node;
@ -75,74 +75,173 @@ public:
}
// Gestion des conditions et des corps de boucles/branches
/*
for(auto& node : nodes) {
if (node.type == Node::Type::LOOP || node.type == Node::Type::BRANCH){
for (auto& node : nodes) {
std::string nodeType = node->GetTypeName();
if (nodeType == "LOOP" || nodeType == "BRANCH") {
for (auto& connection : connections) {
if (connection.inNodeId == node.id && connection.inPortIndex == 0) { // Condition
node.condition = nodeMap[connection.outNodeId];
}
if (connection.inNodeId == node.id && connection.inPortIndex == 1) { // Body
node.body.push_back(nodeMap[connection.outNodeId]);
}
if (node.type == Node::Type::BRANCH && connection.inNodeId == node.id && connection.inPortIndex == 2) { // ElseBody
if(node.elseBody == nullptr) {
node.elseBody = new Node(Node::Type::VARIABLE, "dummy"); // Créer un noeud dummy juste pour l'elsebody.
node.elseBody->body.push_back(nodeMap[connection.outNodeId]);
} else {
node.elseBody->body.push_back(nodeMap[connection.outNodeId]);
if (connection->inNodeId == node->GetId()) {
if (connection->inPortIndex == 0) { // Condition
m_ast.nodeMap[node->GetId()]->condition = m_ast.nodeMap[connection->outNodeId];
} else if (connection->inPortIndex == 1) { // Body
m_ast.nodeMap[node->GetId()]->body.push_back(m_ast.nodeMap[connection->outNodeId]);
} else if (nodeType == "BRANCH" && connection->inPortIndex == 2) { // ElseBody
// if (m_ast.nodeMap[node->GetId()]->elseBody == nullptr) {
// auto dummyNode = std::make_shared<BaseNode>("DummyNode");
// auto dummyAstNode = std::make_shared<AstNode>();
// dummyAstNode->node = dummyNode;
// m_ast.nodeMap[node->GetId()]->elseBody = dummyAstNode;
// }
m_ast.nodeMap[node->GetId()]->elseBody->body.push_back(m_ast.nodeMap[connection->outNodeId]);
}
}
}
}
}
*/
}
// Fonction pour afficher le schéma des nœuds
void displayNodeSchema() {
// Définir une taille fixe pour la grille
const int gridWidth = 20; // 20 cases de large
int gridHeight = 0;
// Afficher les nœuds
for (auto& astNode : m_ast.nodeMap) {
// Calculer la hauteur nécessaire pour la grille
for (const auto& astNode : m_ast.nodeMap) {
gridHeight = std::max(gridHeight, astNode.second->position.second + 1);
}
// Créer une grille pour la console
std::vector<std::vector<std::string>> grid(gridHeight, std::vector<std::string>(gridWidth, " "));
// Placer les nœuds dans la grille
for (const auto& astNode : m_ast.nodeMap) {
auto pos = astNode.second->position;
std::cout << "\033[" << pos.second + 1 << ";" << pos.first + 1 << "H"; // Déplacer le curseur
std::cout << "[" << astNode.second->node->GetTypeName() << "]";
}
/*
// Afficher les connexions
for (auto& connection : connections) {
auto outPos = nodePositions[connection.outNodeId];
auto inPos = nodePositions[connection.inNodeId];
std::string nodeName = astNode.second->node->GetTypeName();
// Dessiner une ligne entre les nœuds (simplifié)
int startX = outPos.first + 10;
int startY = outPos.second + 1;
// Tronquer le nom du nœud à 3 caractères
if (nodeName.length() > 3) {
nodeName = nodeName.substr(0, 3);
} else {
// Ajouter des espaces pour centrer le nom dans la case
nodeName.insert(nodeName.end(), 3 - nodeName.length(), ' ');
}
// Placer le nom du nœud dans la grille
grid[pos.second][pos.first] = nodeName;
}
// Dessiner les connexions
for (const auto& astNode : m_ast.nodeMap) {
for (const auto& input : astNode.second->inputs) {
auto outPos = input->position;
auto inPos = astNode.second->position;
// Dessiner une ligne entre les nœuds
int startX = outPos.first + 1; // Commencer après le nom du nœud
int startY = outPos.second;
int endX = inPos.first;
int endY = inPos.second + 1;
int endY = inPos.second;
if (startY == endY) { // Ligne horizontale
for (int i = startX; i < endX; ++i) {
std::cout << "\033[" << startY << ";" << i + 1 << "H-";
// Ligne horizontale
for (int i = startX; i <= endX; ++i) {
if (i < gridWidth) {
grid[startY][i][0] = '-'; // Dessiner la ligne dans la première position de la case
}
} else { // Ligne verticale + horizontale
for (int i = startX; i < startX + (endX - startX) / 2; ++i) {
std::cout << "\033[" << startY << ";" << i + 1 << "H-";
}
for (int i = std::min(startY, endY); i < std::max(startY, endY); ++i) {
std::cout << "\033[" << i + 1 << ";" << startX + (endX - startX) / 2 + 1 << "H|";
}
for (int i = startX + (endX - startX) / 2 + 1; i < endX; ++i) {
std::cout << "\033[" << endY << ";" << i + 1 << "H-";
}
}
std::cout << "\033[" << endY << ";" << endX << "H>";
}
std::cout << "\033[" << 100 << ";" << 1 << "H"; // Déplacer le curseur en bas
// Ligne verticale
for (int i = std::min(startY, endY); i <= std::max(startY, endY); ++i) {
if (i < gridHeight) {
grid[i][endX][0] = '|'; // Dessiner la ligne dans la première position de la case
}
}
}
}
*/
// Afficher la grille avec des séparateurs verticaux
for (const auto& row : grid) {
for (size_t i = 0; i < row.size(); ++i) {
std::cout << row[i];
if (i < row.size() - 1) {
std::cout << "|"; // Séparateur vertical
}
}
std::cout << std::endl;
}
}
void generateAssembly() {
std::string assemblyCode;
std::map<std::string, std::string> labels;
// Generate all constants
for (const auto& astNode : m_ast.nodeMap) {
assemblyCode += astNode.second->node->GenerateConstants();
}
// After the constants, the main entry point:
assemblyCode += ".main:\n";
// Générer des labels uniques pour les nœuds
for (const auto& nodePair : m_ast.nodeMap) {
std::string label = m_ast.generateLabel(m_ast);
labels[nodePair.first] = label;
// Générer du code pour chaque type de nœud
std::string nodeType = nodePair.second->node->GetTypeName();
if (nodeType == "LOOP") {
// Générer du code pour une boucle
assemblyCode += " ; Loop start\n";
// Ajouter des instructions pour la condition de la boucle
if (nodePair.second->condition) {
assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n";
assemblyCode += " skipz r0\n";
assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n";
}
// Ajouter des instructions pour le corps de la boucle
for (const auto& bodyNode : nodePair.second->body) {
assemblyCode += " ; Loop body\n";
// Ajouter des instructions pour chaque nœud du corps
}
assemblyCode += " jump " + label + "\n"; // Retour au début de la boucle
} else if (nodeType == "BRANCH") {
// Générer du code pour un branchement
assemblyCode += " ; Branch start\n";
// Ajouter des instructions pour la condition du branchement
if (nodePair.second->condition) {
assemblyCode += " cmp_eq r0, " + labels[nodePair.second->condition->node->GetId()] + ", 0\n";
assemblyCode += " skipnz r0\n";
assemblyCode += " jump " + labels[nodePair.second->body.front()->node->GetId()] + "\n";
}
// Ajouter des instructions pour le corps du branchement
for (const auto& bodyNode : nodePair.second->body) {
assemblyCode += " ; Branch body\n";
// Ajouter des instructions pour chaque nœud du corps
}
// Ajouter des instructions pour le corps du else
if (nodePair.second->elseBody) {
assemblyCode += " ; Else body\n";
// Ajouter des instructions pour chaque nœud du corps du else
}
} else {
// Générer du code pour d'autres types de nœuds
assemblyCode += " ; Other node type: " + nodeType + "\n";
assemblyCode += nodePair.second->node->GenerateAssembly();
// Ajouter des instructions spécifiques au type de nœud
}
}
// Ajouter le code assembleur généré à l'AST
m_ast.assemblyCode = assemblyCode;
}
std::string GetCode() const {
return m_ast.assemblyCode;
}
private:

View file

@ -0,0 +1,36 @@
#pragma once
#include "base_node.h"
class ExecutionNode : public BaseNode
{
public:
ExecutionNode(const std::string &type, const std::string &typeName)
: BaseNode(type, typeName) {}
void Initialize() override {
// Initialisation spécifique pour ExecutionNode
}
std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override {
return GetMyEntryLabel() + ":\n";
}
std::string GenerateAssembly() const override {
return GetMyEntryLabel() + ":\n";
}
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
// Génération des constantes pour ExecutionNode
return "ExecutionNode Constants";
}
// Ajoutez des méthodes spécifiques pour gérer les entrées et sorties d'exécution
void AddExecutionInput() {
// Logique pour ajouter une entrée d'exécution
}
void AddExecutionOutput() {
// Logique pour ajouter une sortie d'exécution
}
};

View file

@ -0,0 +1,31 @@
#pragma once
#include "execution_node.h"
class FunctionEntryNode : public ExecutionNode
{
public:
FunctionEntryNode(const std::string &type, const std::string &typeName)
: ExecutionNode(type, typeName) {}
void Initialize() override {
// Initialisation spécifique pour FunctionEntryNode
// Par exemple, préparer les entrées nécessaires pour la fonction
}
std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override {
// Logique de construction pour FunctionEntryNode
return GetMyEntryLabel() + ":\n";
}
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
// Génération des constantes pour FunctionEntryNode
return "FunctionEntryNode Constants";
}
// Ajoutez des méthodes spécifiques pour gérer l'entrée de la fonction
void PrepareFunctionEntry() {
// Logique pour préparer l'entrée de la fonction
}
};

View file

@ -0,0 +1,30 @@
#pragma once
#include "execution_node.h"
class FunctionExitNode : public ExecutionNode
{
public:
FunctionExitNode(const std::string &type, const std::string &typeName)
: ExecutionNode(type, typeName) {}
void Initialize() override {
// Initialisation spécifique pour FunctionExitNode
// Par exemple, préparer les sorties nécessaires pour la fonction
}
std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override {
// Logique de construction pour FunctionExitNode
return "FunctionExitNode Build";
}
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
// Génération des constantes pour FunctionExitNode
return "FunctionExitNode Constants";
}
// Ajoutez des méthodes spécifiques pour gérer la sortie de la fonction
void FinalizeFunctionExit() {
// Logique pour finaliser la sortie de la fonction
}
};

View file

@ -0,0 +1,31 @@
#pragma once
#include "base_node.h"
class OperatorNode : public BaseNode
{
public:
OperatorNode(const std::string &type, const std::string &typeName)
: BaseNode(type, typeName) {}
void Initialize() override {
// Initialisation spécifique pour DataNode
}
std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override {
// Logique de construction pour DataNode
return "DataNode Build";
}
std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override {
// Génération des constantes pour DataNode
return "DataNode Constants";
}
// Ajoutez des méthodes spécifiques pour gérer les données directement
void ProcessData() {
// Logique pour traiter les données directement
}
};

View file

@ -6,9 +6,9 @@
PrintNode::PrintNode(const std::string &type)
: BaseNode(type, "Print Node")
: ExecutionNode(type, "Print Node")
{
m_label = GenerateRandomString(10, BaseNode::CHARSET_ALPHABET_LOWER | BaseNode::CHARSET_ALPHABET_UPPER );// Should be enough to avoid collision?
}
@ -19,35 +19,39 @@ void PrintNode::Initialize()
std::string PrintNode::GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns)
{
std::string s;
return s;
std::stringstream ss;
ss << "$" << m_label << " DC8, " << m_text << "\n";
return ss.str();
}
std::string PrintNode::Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns)
{
return "";
}
std::string PrintNode::GenerateConstants() const
{
std::stringstream ss;
std::list<std::shared_ptr<Connection>> conns;
page.GetNodeConnections(conns, GetId());
int i = 0;
std::list<std::shared_ptr<Connection>>::iterator c = conns.begin();
if (conns.size() == 2)
{
ss << R"(; ---------------------------- )"
<< GetTitle()
<< " Type: Branch"
<< "\n";
ss << "eq r0, r0, r1\n"
<< "skipz r0\n"
<< "jump " << BaseNode::GetEntryLabel((*c)->inNodeId);
++c;
ss << "jump " << BaseNode::GetEntryLabel((*c)->inNodeId);
}
ss << "$" << m_label << " DC8, \"" << m_text << "\"\n";
return ss.str();
}
std::string PrintNode::GenerateAssembly() const
{
std::stringstream ss;
ss << ExecutionNode::GenerateAssembly()
<< " push r0\n"
<< " push r1\n"
<< " lcons r0, $" << m_label << "\n"
<< " lcons r1, 0 ; number of arguments\n" // FIXME: handle arguments
<< " syscall 4\n"
<< " pop r1\n"
<< " pop r0\n";
// << ""mov r2, %2 // arguments are in r2, r3, r4 etc.
return ss.str();
}

View file

@ -2,20 +2,29 @@
#include <string>
#include "i_story_manager.h"
#include "base_node.h"
#include "execution_node.h"
#include "i_script_node.h"
#include "i_story_project.h"
class PrintNode : public BaseNode
class PrintNode : public ExecutionNode
{
public:
PrintNode(const std::string &type);
PrintNode(const std::string &type);
virtual void Initialize() override;
virtual std::string Build(IStoryPage &page, const StoryOptions &options, int nb_out_conns) override;
virtual std::string GenerateConstants(IStoryPage &page, IStoryProject &project, int nb_out_conns) override;
virtual std::string GenerateConstants() const override;
std::string GenerateAssembly() const override;
void SetText(const std::string &text) {
m_text = text;
}
private:
std::string m_label;
std::string m_text; // Text to print
uint32_t m_arguments{0}; // number of arguments
};

View file

@ -8,9 +8,20 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME}
main.cpp
test_ast.cpp
../src/base_node.cpp
../src/branch_node.cpp
../src/print_node.cpp
../src/variable_node.cpp
../src/connection.cpp
../../chip32/chip32_assembler.cpp
../../chip32/chip32_vm.c
)
target_include_directories(${PROJECT_NAME} PRIVATE ../../chip32)
target_include_directories(${PROJECT_NAME} PRIVATE
../../chip32
../src
../interfaces
../lib
../../../shared
)

View file

@ -32,6 +32,7 @@ THE SOFTWARE.
#include "branch_node.h"
#include "print_node.h"
#include "variable_node.h"
#include "chip32_machine.h"
#include <stdarg.h>
#include <string.h>
@ -41,19 +42,22 @@ TEST_CASE( "Check various indentations and typos" ) {
Compiler compiler;
auto printNode = std::make_shared<PrintNode>();
auto branchNode = std::make_shared<BranchNode>();
auto printNode = std::make_shared<PrintNode>("print-node");
printNode->SetText("Hello from OST");
// auto branchNode = std::make_shared<BranchNode>("branch-node");
std::vector<std::shared_ptr<BaseNode>> nodes;
nodes.push_back(printNode);
nodes.push_back(branchNode);
// nodes.push_back(branchNode);
std::vector<std::shared_ptr<Connection>> connections;
auto cn1 = std::make_shared<Connection>();
cn1->
// // Création des nœuds
// std::vector<Node> nodes = {
@ -74,10 +78,18 @@ TEST_CASE( "Check various indentations and typos" ) {
// Construction de l'AST
AST ast = buildAST(nodes, connections);
compiler.buildAST(nodes, connections);
compiler.displayNodeSchema();
compiler.generateAssembly();
std::cout << compiler.GetCode() << std::endl;
Chip32::Machine machine;
REQUIRE( parseResult == true );
machine.QuickExecute(compiler.GetCode());
// REQUIRE( parseResult == true );
}