71 llvm::Value *val = llvm::Constant::getNullValue(type);
72 if (vds.
expr !=
nullptr) {
75 if (val->getType() != type) {
78 llvm::Value *var =
nullptr;
80 var =
new llvm::GlobalVariable(*
module, type, vds.
type.
is_const, llvm::GlobalValue::ExternalLinkage, llvm::dyn_cast<llvm::Constant>(val), vds.
name);
83 var =
builder.CreateAlloca(type,
nullptr, vds.
name +
".alloca");
90 llvm::Value *var_inst =
nullptr;
92 while (!vars.empty()) {
93 auto vars_it = vars.top().find(vas.
name);
94 if (vars_it != vars.top().end()) {
95 var_inst = vars_it->second;
99 if (var_inst ==
nullptr) {
100 std::stringstream ss;
101 ss <<
"Variable \033[0m'" << vas.
name <<
"'\033[31m does not exists";
109 std::vector<llvm::Type*> args;
111 size_t args_count = fds.
args.size();
112 for (
size_t i = 0; i < args_count; i++) {
114 switch (fds.
args[i].type.type) {
116 func_name +=
".bool";
119 func_name +=
".char";
122 func_name +=
".short";
128 func_name +=
".long";
131 func_name +=
".float";
134 func_name +=
".double";
137 func_name +=
".T_" + fds.
args[i].type.name;
140 func_name +=
".C_" + fds.
args[i].type.name;
143 if (fds.
args[i].type.is_const) {
144 func_name +=
"_const";
146 if (fds.
args[i].type.is_ptr) {
150 llvm::FunctionType *func_type = llvm::FunctionType::get(ret_type, args,
false);
151 llvm::Function *func = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage, func_name, *
module);
153 llvm::BasicBlock *entry = llvm::BasicBlock::Create(
context,
"entry", func);
165 for (llvm::Argument& arg : func->args()) {
166 arg.setName(fds.
args[index].name);
167 llvm::AllocaInst *arg_alloca =
builder.CreateAlloca(arg.getType(),
nullptr, fds.
args[index].name);
168 builder.CreateStore(&arg, arg_alloca);
172 bool have_ret_in_global =
false;
173 for (
auto& stmt : fds.
block) {
175 if (have_ret_in_global) {
178 have_ret_in_global =
true;
182 if (!have_ret_in_global) {
199 std::vector<llvm::Value*> args;
200 for (
auto& arg : fcs.
args) {
204 size_t last_score = SIZE_MAX;
205 size_t best_candidate_index = 0;
206 size_t candidate_index = 0;
207 for (
auto& candidate : function_candidates) {
208 auto candidate_args_it = candidate->args();
211 for (
auto& arg : candidate_args_it) {
212 llvm::Type *candidate_arg_type = arg.getType();
215 if (candidate_arg_type != calling_arg_type) {
216 if (candidate_arg_type->isIntegerTy() && calling_arg_type->isIntegerTy()) {
219 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isFloatingPointTy()) {
222 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isIntegerTy()) {
233 if (score <= last_score) {
234 best_candidate_index = candidate_index;
241 builder.CreateCall(function_candidates[best_candidate_index], args, function_candidates[best_candidate_index]->getName() +
".call");
245 if (rs.
expr !=
nullptr) {
258 llvm::Function *parent =
builder.GetInsertBlock()->getParent();
260 llvm::BasicBlock *then_bb = llvm::BasicBlock::Create(
context,
"if.then", parent);
261 llvm::BasicBlock *else_bb = llvm::BasicBlock::Create(
context,
"if.else", parent);
262 llvm::BasicBlock *merge_bb = llvm::BasicBlock::Create(
context,
"if.merge", parent);
264 builder.CreateCondBr(cond_val, then_bb, else_bb ? else_bb : merge_bb);
266 builder.SetInsertPoint(then_bb);
273 if (
builder.GetInsertBlock()->getTerminator() ==
nullptr) {
277 builder.SetInsertPoint(else_bb);
284 if (
builder.GetInsertBlock()->getTerminator() ==
nullptr) {
287 builder.SetInsertPoint(merge_bb);
291 llvm::Function *parent =
builder.GetInsertBlock()->getParent();
292 llvm::BasicBlock *cond_bb = llvm::BasicBlock::Create(
context,
"while.cond", parent);
293 llvm::BasicBlock *body_bb = llvm::BasicBlock::Create(
context,
"while.body", parent);
294 llvm::BasicBlock *exit_bb = llvm::BasicBlock::Create(
context,
"while.exit", parent);
297 builder.SetInsertPoint(cond_bb);
300 builder.CreateCondBr(cond_value, body_bb, exit_bb);
301 builder.SetInsertPoint(body_bb);
304 for (
auto& stmt : wcs.
block) {
311 builder.SetInsertPoint(exit_bb);
315 llvm::Function *parent =
builder.GetInsertBlock()->getParent();
316 llvm::BasicBlock *cond_bb = llvm::BasicBlock::Create(
context,
"do.while.cond", parent);
317 llvm::BasicBlock *body_bb = llvm::BasicBlock::Create(
context,
"do.while.body", parent);
318 llvm::BasicBlock *exit_bb = llvm::BasicBlock::Create(
context,
"do.while.exit", parent);
321 builder.SetInsertPoint(body_bb);
324 for (
auto& stmt : dwcs.
block) {
331 builder.SetInsertPoint(cond_bb);
333 builder.CreateCondBr(cond_value, body_bb, exit_bb);
335 builder.SetInsertPoint(exit_bb);
339 llvm::Function *parent =
builder.GetInsertBlock()->getParent();
340 llvm::BasicBlock *indexator_bb = llvm::BasicBlock::Create(
context,
"for.indexator", parent);
341 llvm::BasicBlock *cond_bb = llvm::BasicBlock::Create(
context,
"for.cond", parent);
342 llvm::BasicBlock *iteration_bb = llvm::BasicBlock::Create(
context,
"for.iteration", parent);
343 llvm::BasicBlock *body_bb = llvm::BasicBlock::Create(
context,
"for.body", parent);
344 llvm::BasicBlock *exit_bb = llvm::BasicBlock::Create(
context,
"for.exit", parent);
346 builder.CreateBr(indexator_bb);
347 builder.SetInsertPoint(indexator_bb);
351 builder.SetInsertPoint(cond_bb);
354 builder.CreateCondBr(condition_value, body_bb, exit_bb);
355 builder.SetInsertPoint(body_bb);
358 for (
auto& stmt : fcs.
block) {
364 builder.CreateBr(iteration_bb);
365 builder.SetInsertPoint(iteration_bb);
369 builder.SetInsertPoint(exit_bb);
383 for (
auto& stmt : ms.
block) {
391 std::string all_name;
392 for (
size_t i = 0; i < ums.
path.size(); i++) {
393 all_name += ums.
path[i];
394 if (i != ums.
path.size() - 1) {
398 std::filesystem::path path_to_mod_without_ext;
399 for (
size_t i = 0; i < ums.
path.size(); i++) {
400 path_to_mod_without_ext +=
"/" + ums.
path[i];
402 std::filesystem::path path_to_mod_without_ext_in_libs =
libs_path + path_to_mod_without_ext.string();
403 std::string path_to_mod_without_ext_in_libs_as_str = path_to_mod_without_ext_in_libs.string();
405 if (std::filesystem::is_directory(path_to_mod_without_ext_in_libs_as_str)) {
406 if (std::filesystem::exists(path_to_mod_without_ext_in_libs_as_str +
"/main.tp")) {
407 file = std::ifstream(path_to_mod_without_ext_in_libs_as_str +
"/main.tp");
408 std::ostringstream content;
409 content << file.rdbuf();
411 Lexer lex(content.str(), path_to_mod_without_ext_in_libs_as_str +
"/main.tp",
is_debug);
412 std::vector<Token> tokens = lex.
tokenize();
414 std::vector<AST::StmtPtr>
stmts = parser.
parse();
417 std::map<std::string, SemanticAnalyzer::ModuleInfo*> modules = semantic.
get_modules();
419 for (
auto&
module : modules) {
423 for (
auto& func :
module.second->functions) {
425 for (
auto& candidate : candidates_at_functions) {
427 std::move(candidate->args), candidate->ret_type, std::move(candidate->block), -1));
431 for (
size_t i =
current_path.size() - current_path_size; i > 0; i--) {
437 std::string path_to_file;
438 for (
const auto& entry : std::filesystem::recursive_directory_iterator(
libs_path)) {
439 if (entry.path().filename() == ums.
path.back() +
".tp" && !std::filesystem::is_directory(entry.path())) {
440 path_to_file = entry.path();
441 file = std::ifstream(path_to_file);
445 if (!file.is_open()) {
446 std::stringstream ss;
447 ss <<
"Module \033[0m'" << all_name <<
"'\033[31m does not exists";
450 std::ostringstream content;
451 content << file.rdbuf();
453 Lexer lex(content.str(), path_to_mod_without_ext_in_libs_as_str +
".tp",
is_debug);
454 std::vector<Token> tokens = lex.
tokenize();
456 std::vector<AST::StmtPtr>
stmts = parser.
parse();
459 std::map<std::string, SemanticAnalyzer::ModuleInfo*> modules = semantic.
get_modules();
461 for (
auto&
module : modules) {
465 for (
auto& func :
module.second->functions) {
467 for (
auto& candidate : candidates_at_functions) {
469 std::move(candidate->args), candidate->ret_type, std::move(candidate->block), -1));
473 for (
size_t i =
current_path.size() - current_path_size; i > 0; i--) {
480 for (
auto& stmt : es.
block) {
482 std::vector<llvm::Type*> args_types;
483 for (
auto& arg : func->args) {
486 llvm::FunctionType *func_type = llvm::FunctionType::get(
type_to_llvm(func->ret_type), args_types,
false);
487 llvm::Function *function = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage,
get_mangled_name(func->name), *
module);
507 else if (
auto ve =
dynamic_cast<AST::VarExpr*
>(&expr)) {
526 return llvm::ConstantInt::get(
type_to_llvm(lit.
type), llvm::APInt(8, std::get<char8_t>(value)));
528 return llvm::ConstantInt::get(
type_to_llvm(lit.
type), llvm::APInt(16, std::get<int16_t>(value)));
530 return llvm::ConstantInt::get(
type_to_llvm(lit.
type), llvm::APInt(32, std::get<int32_t>(value)));
532 return llvm::ConstantInt::get(
type_to_llvm(lit.
type), llvm::APInt(64, std::get<int64_t>(value)));
534 return llvm::ConstantFP::get(
type_to_llvm(lit.
type), llvm::APFloat(std::get<float_t>(value)));
536 return llvm::ConstantFP::get(
type_to_llvm(lit.
type), llvm::APFloat(std::get<double_t>(value)));
538 return llvm::ConstantInt::get(
type_to_llvm(lit.
type), llvm::APInt(1, std::get<bool>(value)));
540 llvm::Constant *str_const = llvm::ConstantDataArray::getString(
context, std::get<std::string>(value),
true);
541 llvm::GlobalVariable *str_var =
new llvm::GlobalVariable(*
module, str_const->getType(),
true, llvm::GlobalValue::PrivateLinkage, str_const,
"string.lit");
551 llvm::Type *left_type = left->getType();
553 llvm::Type *right_type = right->getType();
556 if (left_type != common_type) {
558 left_type = left->getType();
560 else if (right_type != common_type) {
562 right_type = right->getType();
566 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
567 return builder.CreateFAdd(left, right,
"fadd.tmp");
569 return builder.CreateAdd(left, right,
"add.tmp");
571 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
572 return builder.CreateFSub(left, right,
"fsub.tmp");
574 return builder.CreateSub(left, right,
"sub.tmp");
576 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
577 return builder.CreateFMul(left, right,
"fmul.tmp");
579 return builder.CreateMul(left, right,
"mul.tmp");
581 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
582 return builder.CreateFDiv(left, right,
"fdiv.tmp");
584 return builder.CreateSDiv(left, right,
"div.tmp");
586 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
587 return builder.CreateFRem(left, right,
"frem.tmp");
589 return builder.CreateSRem(left, right,
"rem.tmp");
591 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
592 return builder.CreateFCmpUEQ(left, right,
"feq.tmp");
594 return builder.CreateICmpEQ(left, right,
"eq.tmp");
596 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
597 return builder.CreateNeg(
builder.CreateFCmpUEQ(left, right,
"feq.tmp"),
"fnoteq.tmp");
599 return builder.CreateNeg(
builder.CreateICmpEQ(left, right,
"eq.tmp"),
"noteq.tmp");
601 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
602 return builder.CreateFCmpUGT(left, right,
"fgt.tmp");
604 return builder.CreateICmpSGT(left, right,
"gt.tmp");
606 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
607 return builder.CreateFCmpUGE(left, right,
"fge.tmp");
609 return builder.CreateICmpSGE(left, right,
"ge.tmp");
611 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
612 return builder.CreateFCmpULT(left, right,
"flt.tmp");
614 return builder.CreateICmpSLT(left, right,
"lt.tmp");
616 if (left_type->isFloatingPointTy() || right_type->isFloatingPointTy()) {
617 return builder.CreateFCmpULE(left, right,
"fle.tmp");
619 return builder.CreateICmpSLE(left, right,
"le.tmp");
621 return builder.CreateLogicalAnd(left, right,
"land.tmp");
623 return builder.CreateLogicalAnd(left, right,
"lor.tmp");
630 llvm::Value *raw_value =
nullptr;
633 while (!vars.empty()) {
634 auto vars_it = vars.top().find(ve->name);
635 if (vars_it != vars.top().end()) {
636 raw_value = vars_it->second;
646 if (value->getType()->isFloatingPointTy()) {
647 return builder.CreateFNeg(value,
"neg.tmp");
649 return builder.CreateNeg(value,
"neg.tmp");
651 if (value->getType()->isFloatingPointTy()) {
652 return builder.CreateFCmpOEQ(value,
builder.getInt32(0),
"lnot.tmp");
654 return builder.CreateICmpEQ(value,
builder.getInt32(0),
"lnot.tmp");
656 return builder.CreateLoad(value->getType(), value);
667 while (!vars.empty()) {
668 auto vars_it = vars.top().find(ve.
name);
669 if (vars_it != vars.top().end()) {
670 llvm::Type *type =
nullptr;
671 if (
auto global = llvm::dyn_cast<llvm::GlobalVariable>(vars_it->second)) {
672 type = global->getValueType();
674 return global->getInitializer();
677 else if (
auto local = llvm::dyn_cast<llvm::AllocaInst>(vars_it->second)) {
678 type = local->getAllocatedType();
680 return builder.CreateLoad(type, vars_it->second, ve.
name +
".load");
684 std::stringstream ss;
685 ss <<
"Variable \033[0m'" << ve.
name <<
"'\033[31m does not exists";
691 std::vector<llvm::Value*> args;
692 for (
auto& arg : fce.
args) {
696 size_t last_score = SIZE_MAX;
697 size_t best_candidate_index = 0;
698 size_t candidate_index = 0;
699 for (
auto& candidate : function_candidates) {
700 auto candidate_args_it = candidate->args();
703 for (
auto& arg : candidate_args_it) {
704 llvm::Type *candidate_arg_type = arg.getType();
707 if (candidate_arg_type != calling_arg_type) {
708 if (candidate_arg_type->isIntegerTy() && calling_arg_type->isIntegerTy()) {
711 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isFloatingPointTy()) {
714 else if (candidate_arg_type->isFloatingPointTy() && calling_arg_type->isIntegerTy()) {
725 if (score <= last_score) {
726 best_candidate_index = candidate_index;
733 return builder.CreateCall(function_candidates[best_candidate_index], args, function_candidates[best_candidate_index]->getName() +
".call");
737 llvm::Value *value =
nullptr;
739 for (
size_t i = 0; i < co.
chain.size(); i++) {
747 for (
size_t i =
current_path.size() - current_path_size; i > 0; i--) {
754 llvm::Type *base_type =
nullptr;
757 base_type = llvm::Type::getInt8Ty(
context);
760 base_type = llvm::Type::getInt16Ty(
context);
763 base_type = llvm::Type::getInt32Ty(
context);
766 base_type = llvm::Type::getInt64Ty(
context);
769 base_type = llvm::Type::getFloatTy(
context);
772 base_type = llvm::Type::getDoubleTy(
context);
775 base_type = llvm::Type::getInt1Ty(
context);
778 base_type = llvm::Type::getVoidTy(
context);
784 return llvm::PointerType::get(
context, 0);
793 else if (left->isIntegerTy() || right->isIntegerTy()) {
794 if (left->isIntegerTy() && right->isIntegerTy()) {
795 unsigned left_width = left->getIntegerBitWidth();
796 unsigned right_width = right->getIntegerBitWidth();
798 return left_width > right_width ? left : right;
800 else if (left->isFloatingPointTy() || right->isFloatingPointTy()) {
801 return left->isFloatingPointTy() ? left : right;
804 else if (left->isFloatingPointTy() && right->isFloatingPointTy()) {
805 return left->isDoubleTy() && right->isFloatTy() ? left : right;
807 else if (left->isDoubleTy() || right->isDoubleTy()) {
808 return llvm::Type::getDoubleTy(
context);
814 llvm::Type *val_type = val->getType();
815 if (val_type == expected_type) {
818 else if (val_type->isIntegerTy() && expected_type->isIntegerTy()) {
819 unsigned long value_width = val_type->getIntegerBitWidth();
820 unsigned long expected_width = expected_type->getIntegerBitWidth();
822 if (value_width > expected_width) {
823 return builder.CreateTrunc(val, expected_type,
"trunc.tmp");
826 return builder.CreateSExt(val, expected_type,
"sext.tmp");
829 else if (val_type->isFloatingPointTy() && expected_type->isFloatingPointTy()) {
830 if (val_type->isFloatTy() && expected_type->isDoubleTy()) {
831 return builder.CreateFPExt(val, expected_type,
"fpext.tmp");
834 return builder.CreateFPTrunc(val, expected_type,
"fptrunc.tmp");
837 else if (val_type->isIntegerTy() && expected_type->isFloatingPointTy()) {
838 return builder.CreateSIToFP(val, expected_type,
"sitofp.tmp");
840 else if (val_type->isPointerTy()) {
841 return builder.CreatePointerCast(val, expected_type,
"ptrcast.tmp");
849 while (!path.empty()) {
852 res = part.
name +
"-" + res;
855 res = part.
name +
"#" + res;
859 return res + base_name;
863 std::vector<PathPart> res;
865 for (
const char c : mangled_name) {
Binary expression container.
Chain of objects expression container.
std::vector< ExprPtr > chain
Statement of do-while cycle.
std::vector< StmtPtr > block
Base class of expression.
Statement of extern calls.
std::vector< StmtPtr > block
std::vector< StmtPtr > block
Function calling expression container.
std::vector< ExprPtr > args
Statement of functions calling.
std::vector< ExprPtr > args
Statement of functions declaration.
std::vector< StmtPtr > block
std::vector< Argument > args
Statement of control flow operator.
std::vector< StmtPtr > else_block
std::vector< StmtPtr > then_block
Statement of module definition.
std::vector< StmtPtr > block
Unary expression container.
Statement of import the module.
std::vector< std::string > path
Statement of assignment of variable.
Statement of variable declaration.
Variable expression container.
Statement of while cycle.
std::vector< StmtPtr > block
void generate_while_cycle_stmt(AST::WhileCycleStmt &wcs)
Method for generating LLVM IR code for while cycle.
void generate_module_stmt(AST::ModuleStmt &ms)
Method for generating LLVM IR code for module definition.
void generate_do_while_cycle_stmt(AST::DoWhileCycleStmt &dwcs)
Method for generating LLVM IR code for do-while cycle.
void generate_var_asgn_stmt(AST::VarAsgnStmt &vas)
Method for generating LLVM IR code for variable assignment.
llvm::Value * generate_var_expr(AST::VarExpr &ve)
Method for generating LLVM IR code for variable expressions.
void generate_extern_stmt(AST::ExternStmt &es)
Method for generating LLVM IR code for extern calls.
llvm::LLVMContext context
llvm::Type * get_common_type(llvm::Type *left, llvm::Type *right)
Method for getting comon type between two types.
std::string get_mangled_name(std::string base_name)
Method for getting mangled name.
llvm::Value * generate_func_call_expr(AST::FuncCallExpr &fce)
Method for generating LLVM IR code for function calling expressions.
void generate_func_call_stmt(AST::FuncCallStmt &fcs)
Method for generating LLVM IR code for function calling.
void generate_continue_stmt(AST::ContinueStmt &cs)
Method for generating LLVM IR code for continue statement.
void generate_use_module_stmt(AST::UseModuleStmt &ums)
Method for generating LLVM IR code for import the module.
void generate_break_stmt(AST::BreakStmt &bs)
Method for generating LLVM IR code for break statement.
std::vector< PathPart > get_resolved_name(std::string mangled_name)
Method for getting resolved name by mangled name.
void generate_var_decl_stmt(AST::VarDeclStmt &vds)
Method for generating LLVM IR code for variable definition.
void generate_if_else_stmt(AST::IfElseStmt &ies)
Method for generating LLVM IR code for control flow operators.
void generate_return_stmt(AST::ReturnStmt &rs)
Method for generating LLVM IR code for 'return'.
std::stack< std::map< std::string, llvm::Value * > > variables
llvm::Value * generate_literal_expr(AST::Literal &lit)
Method for generating LLVM IR code for literals.
void generate_for_cycle_stmt(AST::ForCycleStmt &fcs)
Method for generating LLVM IR code for for cycle.
std::vector< AST::StmtPtr > & stmts
std::map< std::string, std::vector< llvm::Function * > > functions
llvm::Value * generate_obj_chain_expr(AST::ChainObjects &co)
Method for generating LLVM IR code for chain of objects expression.
std::unique_ptr< llvm::Module > module
std::stack< std::pair< llvm::BasicBlock *, llvm::BasicBlock * > > loop_blocks
llvm::Value * generate_binary_expr(AST::BinaryExpr &be)
Method for generating LLVM IR code for binary expressions.
llvm::Value * generate_expr(AST::Expr &expr)
Method for generating LLVM IR code for expressions.
void generate_stmt(AST::Stmt &stmt)
Method for generating LLVM IR code for passing statement.
llvm::Value * generate_unary_expr(AST::UnaryExpr &ue)
Method for generating LLVM IR code for unary expressions.
llvm::Value * implicitly_cast(llvm::Value *val, llvm::Type *expected_type)
Method for implicitly cast value to expected type.
std::stack< llvm::Type * > functions_ret_types
llvm::Type * type_to_llvm(AST::Type type)
Method for converting AST::Type to llvm::Type.
void generate_func_decl_stmt(AST::FuncDeclStmt &fds)
Method for generating LLVM IR code for function definition.
std::stack< PathPart > current_path
void generate()
Method for generating LLVM IR code.
std::vector< Token > tokenize()
Method for tokenizing source code.
std::vector< AST::StmtPtr > parse()
Method for parsing tokens into AST tree.
void analyze()
Method for analyze all statements.
std::map< std::string, ModuleInfo * > get_modules() const
Method for getting modules from semantic.
std::map< std::string, std::vector< std::shared_ptr< FunctionInfo > > > get_functions() const
Method for getting functions from semantic.
Header file for defining compiler code generator.
void throw_exception(SubsystemType type, std::string msg, uint32_t line, std::string file_name, bool is_debug)
Function for throwing exception.
Header file for defining thrown exceptions by the compiler.
Header file for defining the lexer.
std::unique_ptr< Stmt > StmtPtr
Header file for defining parser.
Header file for defining semantic analyzer.
Structure for describing the type.
std::variant< bool, char8_t, int16_t, int32_t, int64_t, float_t, double_t, std::string > value
Structure of part of path to object.
enum CodeGenerator::PathPart::Object object