Skip to content

Commit

Permalink
Merge branch '76-asm-functions' into 87-implementing-funcs-in-assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
c71n93 committed Jun 8, 2024
2 parents 9619217 + 39a4bb9 commit 61f28ac
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 54 deletions.
6 changes: 3 additions & 3 deletions include/ChaiVM/utils/instr2Raw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ chai::bytecode_t instr2Raw(interpreter::Operation op,

chai::bytecode_t instr2Raw(interpreter::Operation op);

chai::bytecode_t inst2RawRI(interpreter::Operation op,
interpreter::RegisterId r1,
interpreter::Immidiate imm);
chai::bytecode_t instr2RawRI(interpreter::Operation op,
interpreter::RegisterId r1,
interpreter::Immidiate imm);

} // namespace chai::utils
10 changes: 10 additions & 0 deletions include/frontend/assembler/asmlex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class AsmLex final : public yyFlexLexer {
OP_CURLY_BRACKET,
CL_CURLY_BRACKET,
COMMA,
EOF_,
UNKNOWN
};

Expand Down Expand Up @@ -77,6 +78,11 @@ class AsmLex final : public yyFlexLexer {
Comma() : Lexem(LexemType::COMMA) {}
~Comma() override {}
};
class Eof final : public Lexem {
public:
Eof(LexemType t) : Lexem(t) {}
~Eof() override {}
};
class Unknown final : public Lexem {
public:
Unknown() : Lexem(LexemType::UNKNOWN) {}
Expand Down Expand Up @@ -131,6 +137,10 @@ class AsmLex final : public yyFlexLexer {
LexemType::STRING, withQuotes.substr(1, withQuotes.size() - 2));
return 0;
}
int processEOF() {
currentLexem_ = std::make_unique<Eof>(LexemType::EOF_);
return 0;
}
int processUnknown() {
currentLexem_ = std::make_unique<Unknown>();
return 1;
Expand Down
108 changes: 71 additions & 37 deletions include/frontend/assembler/assembler.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <sstream>
#include <utility>

#include "ChaiVM/interpreter/autogen/operations.hpp"
#include "ChaiVM/utils/file-format/chai-file.hpp"
Expand Down Expand Up @@ -30,6 +31,10 @@ class Assembler final {
*/
void assemble() {
processMain();
while (lex_.currentLexem()->type != AsmLex::EOF_) {
processFunction();
lex_.nextLexem();
}
chaiFile_.toFile(outPath_);
}

Expand All @@ -50,22 +55,42 @@ class Assembler final {
checkError();
chaiFile_.addInstr(processInstruction());
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::IDENTIFIER &&
SmartOperation(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value) == chai::interpreter::Ret) {
chaiFile_.addInstr(processInstruction());
break;
}
}
}
/*
* @todo #76:90min Add function description to assembler
*/
/*
* @todo #76:90min Add function to constant pool before parsing instructions (for recursion)
*/
void processFunction() {
expectCurrentLexem(AsmLex::FUNC, "Expected function declaration");
expectNextLexem(AsmLex::IDENTIFIER, "Expected function name");
std::string func_name = static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())->value;
expectNextLexem(AsmLex::INTEGER, "Expected number of registers in function frame");
auto num_regs = static_cast<uint8_t>(static_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
expectNextLexem(AsmLex::INTEGER, "Expected number of function arguments");
auto num_args = static_cast<uint8_t>(static_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
expectNextLexem(AsmLex::OP_CURLY_BRACKET, "Expected opening curly bracket");
std::vector<chai::bytecode_t> instrs;
lex_.nextLexem();
while (lex_.currentLexem()->type != AsmLex::CL_CURLY_BRACKET) {
instrs.push_back(processInstruction());
lex_.nextLexem();
}
expectCurrentLexem(AsmLex::CL_CURLY_BRACKET, "Expected closing curly bracket");
chaiFile_.addFunction(UINT16_MAX, func_name, "V(V)", instrs, num_args, num_regs);
}
chai::bytecode_t processInstruction() {
SmartOperation op = SmartOperation(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
if (op == chai::interpreter::Inv) {
throw AssembleError("Invalid instruction", lex_.lineno());
}
if (op == chai::interpreter::Call) {
return processCall(op);
}
switch (op.format()) {
case chai::interpreter::N:
return processN(op);
Expand All @@ -85,6 +110,12 @@ class Assembler final {
break;
}
}
chai::bytecode_t processCall(chai::interpreter::Operation op) {
auto val = static_cast<uint64_t>(
static_cast<AsmLex::Int *>(lex_.nextLexem().get())->value);
std::cout << "[Call]: val = " << val << std::endl;
return chai::utils::instr2RawRI(op, val, val);
}
chai::bytecode_t processN(chai::interpreter::Operation op) {
return chai::utils::instr2Raw(op, 0, 0);
}
Expand All @@ -94,67 +125,65 @@ class Assembler final {
}
chai::bytecode_t processRR(chai::interpreter::Operation op) {
chai::interpreter::RegisterId reg1Id = processReg();
expectComma();
expectNextLexem(AsmLex::COMMA, "Expected coma");
chai::interpreter::RegisterId reg2Id = processReg();
return chai::utils::instr2Raw(op, reg1Id, reg2Id);
}
chai::bytecode_t processI(chai::interpreter::Operation op) {
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::INTEGER) {
return chaiFile_.getWithConst(
op, static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())
->value));
auto val = static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2Raw(op, imm);
} else if (lex_.currentLexem()->type == AsmLex::FLOAT) {
return chaiFile_.getWithConst(
op, (static_cast<AsmLex::Float *>(lex_.currentLexem().get())
->value));
auto val =
static_cast<AsmLex::Float *>(lex_.currentLexem().get())->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2Raw(op, imm);
} else if (lex_.currentLexem()->type == AsmLex::STRING) {
std::string str =
static_cast<AsmLex::String *>(lex_.currentLexem().get())->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstRawStr>(str));
auto bytecode = chai::utils::instr2Raw(op, imm);
chaiFile_.addInstr(bytecode);
return bytecode;
return chai::utils::instr2Raw(op, imm);
} else {
throw AssembleError("Unknown instruction type in ProcessI",
lex_.lineno());
}
}
chai::bytecode_t processRI(chai::interpreter::Operation op) {
chai::interpreter::RegisterId regId = processReg();
expectComma();
expectNextLexem(AsmLex::COMMA, "Expected coma");
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::INTEGER) {
return chai::utils::inst2RawRI(
op, regId,
static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())
->value));
auto val = static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())->value);
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2RawRI(op, regId, imm);
} else if (lex_.currentLexem()->type == AsmLex::FLOAT) {
return chai::utils::inst2RawRI(
op, regId,
static_cast<AsmLex::Float *>(lex_.currentLexem().get())->value);
auto val =
static_cast<AsmLex::Float *>(lex_.currentLexem().get())->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstI64>(val));
return chai::utils::instr2RawRI(op, regId, imm);
} else if (lex_.currentLexem()->type == AsmLex::STRING) {
std::string str =
static_cast<AsmLex::String *>(lex_.currentLexem().get())->value;
auto imm = chaiFile_.addConst(
std::make_unique<chai::utils::fileformat::ConstRawStr>(str));
auto bytecode = chai::utils::inst2RawRI(op, regId, imm);
chaiFile_.addInstr(bytecode);
return bytecode;
return chai::utils::instr2RawRI(op, regId, imm);
} else {
throw AssembleError("Unknown instruction type in processRI",
lex_.lineno());
}
}

chai::interpreter::RegisterId processReg() {
lex_.nextLexem();
if (lex_.currentLexem()->type != AsmLex::IDENTIFIER) {
throw AssembleError("Expected register", lex_.lineno());
}
expectNextLexem(AsmLex::IDENTIFIER, "Expected register name");
return regNameToRegId(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
Expand All @@ -165,10 +194,15 @@ class Assembler final {
throw AssembleError("Unknown lexem", lex_.lineno());
}
}
void expectComma() {
void expectNextLexem(AsmLex::LexemType type, std::string msg) {
lex_.nextLexem();
if (lex_.currentLexem()->type != AsmLex::COMMA) {
throw AssembleError("Expected comma", lex_.lineno());
if (lex_.currentLexem()->type != type) {
throw AssembleError(std::move(msg), lex_.lineno());
}
}
void expectCurrentLexem(AsmLex::LexemType type, std::string msg) {
if (lex_.currentLexem()->type != type) {
throw AssembleError(std::move(msg), lex_.lineno());
}
}
chai::interpreter::RegisterId regNameToRegId(std::string regName) {
Expand Down
2 changes: 1 addition & 1 deletion src/ChaiVM/utils/instr2Raw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ chai::bytecode_t instr2Raw(Operation op, Immidiate imm) {

chai::bytecode_t instr2Raw(Operation op) { return (operation2opcode(op)); }

chai::bytecode_t inst2RawRI(Operation op, RegisterId r1, Immidiate imm) {
chai::bytecode_t instr2RawRI(Operation op, RegisterId r1, Immidiate imm) {
return (operation2opcode(op)) | (static_cast<chai::bytecode_t>(imm) << 16) |
(r1 << 8);
}
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/assembler/asmlex.l
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ COMMA ,
{COMMENT} /* skip */
{INT} return processInt();
{FLOAT} return processFloat();
{IDENTIFIER} return processIdentifier();
"fn" return processFunc();
"{" return processOpCurlyBracket();
"}" return processClCurlyBracket();
{COMMA} return processComma();
{IDENTIFIER} return processIdentifier();
{STRING} return processString();
<<EOF>> return processEOF();
. return processUnknown();

%%
Expand Down
2 changes: 1 addition & 1 deletion test/ChaiVM/interpreter/executor-test-fixture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Immidiate ExecutorTest::loadRR(chai::interpreter::Operation op,
Immidiate ExecutorTest::loadRI(chai::interpreter::Operation op,
chai::interpreter::RegisterId reg1,
chai::interpreter::Immidiate imm) {
return chaiFile_.addInstr(chai::utils::inst2RawRI(op, reg1, imm));
return chaiFile_.addInstr(chai::utils::instr2RawRI(op, reg1, imm));
}

Immidiate ExecutorTest::loadI(chai::interpreter::Operation op,
Expand Down
1 change: 0 additions & 1 deletion test/ChaiVM/interpreter/executor_test.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "executor-test-fixture.hpp"

using chai::bytecode_t;
using chai::utils::inst2RawRI;
using chai::utils::instr2Raw;
using namespace chai::interpreter;
using namespace chai::utils::fileformat;
Expand Down
6 changes: 3 additions & 3 deletions test/ChaiVM/interpreter/simple-programs-executor-test.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "executor-test-fixture.hpp"

using chai::bytecode_t;
using chai::utils::inst2RawRI;
using chai::utils::instr2Raw;
using chai::utils::instr2RawRI;
using namespace chai::interpreter;
using namespace chai::utils::fileformat;

Expand Down Expand Up @@ -82,8 +82,8 @@ TEST_F(ExecutorTest, Factorial) {
UINT16_MAX, "factorial", "(I)I",
std::vector<bytecode_t>{
instr2Raw(Ldra, 7, 0), // val2
inst2RawRI(If_icmpne, one,
static_cast<Immidiate>(3 * sizeof(bytecode_t))),
instr2RawRI(If_icmpne, one,
static_cast<Immidiate>(3 * sizeof(bytecode_t))),
instr2Raw(Ldia, one), instr2Raw(Ret), instr2Raw(Star, 2, 0),
instr2Raw(Subi, one), instr2Raw(Star, 7, 0),
instr2Raw(Call, func_ref), instr2Raw(Mul, 2, 0),
Expand Down
16 changes: 16 additions & 0 deletions test/frontend/assembler/assembler-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,19 @@ TEST_F(AssemblerTest, runWithStrings) {
exec_.run();
EXPECT_EQ(codeManager_.getCnstString(exec_.acc()), "Hello world");
}

TEST_F(AssemblerTest, runWithFunctions) {
write_input_ << "Ldia 271\n"
<< "Call 8\n"
<< "Ret\n"
<< "fn aboba_func 50 2 {\n"
<< "Ldia 125\n"
<< "Ret\n"
<< "}\n" << std::endl;
Assembler asM{input_, output_};
asM.assemble();
codeManager_.load(output_);
exec_.run();
EXPECT_EQ(static_cast<int64_t>(exec_.acc()), 125);
EXPECT_EQ(exec_.getCurrentFrame(), nullptr);
}
7 changes: 0 additions & 7 deletions test/frontend/assembler/run.chai

This file was deleted.

0 comments on commit 61f28ac

Please sign in to comment.