Skip to content

Commit

Permalink
#76 add functions to AsmLex and reimplement Assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
c71n93 committed Dec 19, 2023
1 parent ee0e232 commit bdd9b21
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 62 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ $ build/chai <app.chai>
### Chai bytecode currently is just a Sequence of instructions.
For instance, there is disassembler of simple app.chai
```
fn main 8 0:
fn main 8 0 {
Ldia 6
Star r2
Ldia 8
Expand All @@ -21,6 +21,7 @@ fn main 8 0:
Printc acc
Mov 0 r0
Ret
}
```
Where Ret returns exit code `r0`. "main" is name of the starting function, `8` is number of registers in it, `0` is number of arguments passing into the function.
This script compiled to chai-bytecode should print "0", because '0' == 48.
Expand Down
5 changes: 4 additions & 1 deletion include/ChaiVM/utils/file-format/chai-file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ class ChaiFile {
chai::interpreter::Immidiate addConst(std::unique_ptr<Constant> &&constant);

void addWithConst(chai::interpreter::Operation op, int64_t data);

void addWithConst(chai::interpreter::Operation op, double data);

chai::bytecode_t getWithConst(chai::interpreter::Operation op,
int64_t data);
chai::bytecode_t getWithConst(chai::interpreter::Operation op, double data);

/**
* A more or less convenient way to add a function to the file
* @param access_flags
Expand Down
43 changes: 37 additions & 6 deletions include/frontend/assembler/asmlex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ namespace front::assembler {

class AsmLex final : public yyFlexLexer {
public:
enum LexemType { INTEGER, FLOAT, IDENTIFIER, COMMA, UNKNOWN };
enum LexemType {
INTEGER,
FLOAT,
IDENTIFIER,
FUNC,
OP_CURLY_BRACKET,
CL_CURLY_BRACKET,
COMMA,
UNKNOWN
};

class Lexem {
public:
Expand All @@ -38,6 +47,21 @@ class AsmLex final : public yyFlexLexer {
std::string value;
~Identifier() override {}
};
class Func final : public Lexem {
public:
Func(LexemType t) : Lexem(t) {}
~Func() override {}
};
class OpCurlyBracket final : public Lexem {
public:
OpCurlyBracket(LexemType t) : Lexem(t) {}
~OpCurlyBracket() override {}
};
class ClCurlyBracket final : public Lexem {
public:
ClCurlyBracket(LexemType t) : Lexem(t) {}
~ClCurlyBracket() override {}
};
class Coma final : public Lexem {
public:
Coma(LexemType t) : Lexem(t) {}
Expand All @@ -63,29 +87,36 @@ class AsmLex final : public yyFlexLexer {
int processInt() {
currentLexem_ =
std::make_unique<Int>(LexemType::INTEGER, std::atol(yytext));
std::string a = yytext;
return 0;
}
int processFloat() {
currentLexem_ =
std::make_unique<Float>(LexemType::FLOAT, std::atof(yytext));
std::string a = yytext;
return 0;
}
int processIdentifier() {
currentLexem_ =
std::make_unique<Identifier>(LexemType::IDENTIFIER, yytext);
std::string a = yytext;
return 0;
}
int processFunc() {
currentLexem_ = std::make_unique<Coma>(LexemType::FUNC);
return 0;
}
int processOpCurlyBracket() {
currentLexem_ = std::make_unique<Coma>(LexemType::OP_CURLY_BRACKET);
return 0;
}
int processClCurlyBracket() {
currentLexem_ = std::make_unique<Coma>(LexemType::CL_CURLY_BRACKET);
return 0;
}
int processComma() {
currentLexem_ = std::make_unique<Coma>(LexemType::COMMA);
std::string a = yytext;
return 0;
}
int processUnknown() {
currentLexem_ = std::make_unique<Unknown>(LexemType::UNKNOWN);
std::string a = yytext;
return 1;
}
};
Expand Down
69 changes: 24 additions & 45 deletions include/frontend/assembler/assembler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ class Assembler final {
checkError();
while (lex_.currentLexem()->type == AsmLex::IDENTIFIER) {
checkError();
processInstruction();
chaiFile_.addInstr(processInstruction());
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::IDENTIFIER &&
OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value) == chai::interpreter::Ret) {
processInstruction();
chaiFile_.addInstr(processInstruction());
break;
}
}
}
void processInstruction() {
chai::bytecode_t processInstruction() {
chai::interpreter::Operation op = OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
Expand All @@ -68,84 +68,63 @@ class Assembler final {
}
switch (opToFormat(op)) {
case chai::interpreter::N:
processN();
break;
return processN(op);
case chai::interpreter::R:
processR();
break;
return processR(op);
case chai::interpreter::RR:
processRR();
break;
return processRR(op);
case chai::interpreter::I:
processI();
break;
return processI(op);
case chai::interpreter::RI:
processRI();
break;
return processRI(op);
case chai::interpreter::Unknown:
default:
throw AssembleError("Unknown instruction type", lex_.lineno());
break;
}
}
void processN() {
chai::interpreter::Operation op = OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
chaiFile_.addInstr(chai::utils::instr2Raw(op, 0, 0));
chai::bytecode_t processN(chai::interpreter::Operation op) {
return chai::utils::instr2Raw(op, 0, 0);
}
void processR() {
chai::interpreter::Operation op = OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
chai::bytecode_t processR(chai::interpreter::Operation op) {
chai::interpreter::RegisterId regId = processReg();
chaiFile_.addInstr(chai::utils::instr2Raw(op, regId, 0));
return chai::utils::instr2Raw(op, regId, 0);
}
void processRR() {
chai::interpreter::Operation op = OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
chai::bytecode_t processRR(chai::interpreter::Operation op) {
chai::interpreter::RegisterId reg1Id = processReg();
expectComma();
chai::interpreter::RegisterId reg2Id = processReg();
chaiFile_.addInstr(chai::utils::instr2Raw(op, reg1Id, reg2Id));
return chai::utils::instr2Raw(op, reg1Id, reg2Id);
}
void processI() {
chai::interpreter::Operation op = OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
chai::bytecode_t processI(chai::interpreter::Operation op) {
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::INTEGER) {
chaiFile_.addWithConst(
return chaiFile_.getWithConst(
op, static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())
->value));
} else if (lex_.currentLexem()->type == AsmLex::FLOAT) {
chaiFile_.addWithConst(
return chaiFile_.getWithConst(
op, (static_cast<AsmLex::Float *>(lex_.currentLexem().get())
->value));
} else {
throw AssembleError("Unknown instruction type", lex_.lineno());
}
}
void processRI() {
chai::interpreter::Operation op = OpString(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
chai::bytecode_t processRI(chai::interpreter::Operation op) {
chai::interpreter::RegisterId regId = processReg();
expectComma();
lex_.nextLexem();
if (lex_.currentLexem()->type == AsmLex::INTEGER) {
chaiFile_.addInstr(chai::utils::inst2RawRI(
return chai::utils::inst2RawRI(
op, regId,
static_cast<int64_t>(
static_cast<AsmLex::Int *>(lex_.currentLexem().get())
->value)));
->value));
} else if (lex_.currentLexem()->type == AsmLex::FLOAT) {
chaiFile_.addInstr(chai::utils::inst2RawRI(
return chai::utils::inst2RawRI(
op, regId,
static_cast<AsmLex::Float *>(lex_.currentLexem().get())
->value));
static_cast<AsmLex::Float *>(lex_.currentLexem().get())->value);
} else {
throw AssembleError("Unknown instruction type", lex_.lineno());
}
Expand All @@ -156,7 +135,7 @@ class Assembler final {
if (lex_.currentLexem()->type != AsmLex::IDENTIFIER) {
throw AssembleError("Expected register", lex_.lineno());
}
return RegNameToRegId(
return regNameToRegId(
static_cast<AsmLex::Identifier *>(lex_.currentLexem().get())
->value);
}
Expand All @@ -180,7 +159,7 @@ class Assembler final {
opToFormat(chai::interpreter::Operation op) {
return chai::interpreter::OP_TO_FORMAT[op];
}
chai::interpreter::RegisterId RegNameToRegId(std::string regName) {
chai::interpreter::RegisterId regNameToRegId(std::string regName) {
chai::interpreter::RegisterId regId;
if (regName.length() > 1 && regName[0] == 'r') {
std::string digits = regName.substr(1);
Expand Down
12 changes: 12 additions & 0 deletions src/ChaiVM/utils/file-format/chai-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ void ChaiFile::addWithConst(chai::interpreter::Operation op, double data) {
addInstr(chai::utils::instr2Raw(op, id));
}

chai::bytecode_t ChaiFile::getWithConst(chai::interpreter::Operation op,
int64_t data) {
chai::chsize_t id = addConst(std::make_unique<ConstI64>(data));
return chai::utils::instr2Raw(op, id);
}

chai::bytecode_t ChaiFile::getWithConst(chai::interpreter::Operation op,
double data) {
chai::chsize_t id = addConst(std::make_unique<ConstF64>(data));
return chai::utils::instr2Raw(op, id);
}

chai::interpreter::Immidiate
ChaiFile::addFunction(chai::interpreter::Immidiate access_flags,
const std::string &name, const std::string &descriptor,
Expand Down
4 changes: 4 additions & 0 deletions src/frontend/assembler/asmlex.l
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ COMMENT #.*
INT [+-]?[1-9][0-9]*
FLOAT [+-]?([1-9][0-9]*\.?[0-9]*|0\.[0-9]*|0)
IDENTIFIER [a-zA-Z_][a-zA-Z0-9_.]*
FUNC "fn"
COMMA ,

%%
Expand All @@ -22,6 +23,9 @@ COMMA ,
{INT} return processInt();
{FLOAT} return processFloat();
{IDENTIFIER} return processIdentifier();
"fn" return processFunc();
"{" return processOpCurlyBracket();
"}" return processClCurlyBracket();
{COMMA} return processComma();
. return processUnknown();

Expand Down
18 changes: 9 additions & 9 deletions test/frontend/assembler/assembler-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ class AssemblerTest : public ::testing::Test {
chai::interpreter::CodeManager codeManager_;
chai::memory::LinearBuffer buffer_ = chai::memory::LinearBuffer(1024 * 256);
chai::interpreter::Executor exec_{&codeManager_, buffer_};
std::filesystem::path input_ = "./run.chai";
std::filesystem::path input_ = "./asm.chai";
std::ofstream write_input_{input_, std::ios::out};
std::filesystem::path output_ = "./bytecode.ch";
};

TEST_F(AssemblerTest, run) {
std::ofstream write_input{input_, std::ios::out};
write_input << "Ldia 6\n"
<< "Star r2\n"
<< "Ldia 8\n"
<< "Star r3\n"
<< "Ldra r3\n"
<< "Mul r2\n"
<< "Ret" << std::endl;
write_input_ << "Ldia 6\n"
<< "Star r2\n"
<< "Ldia 8\n"
<< "Star r3\n"
<< "Ldra r3\n"
<< "Mul r2\n"
<< "Ret" << std::endl;
Assembler asM{input_, output_};
asM.assemble();
codeManager_.load(output_);
Expand Down

0 comments on commit bdd9b21

Please sign in to comment.