Program Listing for File code_generator.h¶
↰ Return to documentation for file (src/code_generator.h)
//
// Created by Zayd Hammoudeh on 11/15/18.
//
#ifndef TYPE_CHECKER_CODE_GENERATOR_H
#define TYPE_CHECKER_CODE_GENERATOR_H
#include <string>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <stack>
#include "quack_program.h"
#include "quack_class.h"
#include "quack_param.h"
#include "compiler_utils.h"
#include "ASTNode.h"
namespace CodeGen {
class Gen {
public:
Gen(Quack::Program * prog, const std::string &quack_filename) : prog_(prog) {
#ifdef _WIN32
char file_sep = '\\';
#else
char file_sep = '/';
#endif
std::size_t per_loc = quack_filename.rfind('.');
std::size_t slash_loc = quack_filename.rfind(file_sep);
// Preserve path and filename for the generated code
if (per_loc==std::string::npos || (slash_loc != std::string::npos && per_loc < slash_loc)) {
output_file_path_ = quack_filename;
} else if (per_loc == 0 || (slash_loc != std::string::npos && per_loc == slash_loc + 1)) {
throw std::runtime_error("It appears you have only file extension and no file name");
} else {
output_file_path_ = quack_filename.substr(0, per_loc);
}
output_file_path_ += ".c";
fout_.open(output_file_path_);
}
~Gen() {
fout_.close();
}
void run() {
export_includes();
std::vector<Quack::Class*> user_classes = topologically_sort_classes();
CodeGen::Settings settings(fout_);
for (auto q_class : user_classes)
q_class->generate_code(settings);
export_main(settings);
std::cout << "Code generation completed successfully." << std::endl;
}
private:
static std::vector<Quack::Class*> topologically_sort_classes() {
std::vector<Quack::Class*> user_classes;
for (auto & class_pair : *Quack::Class::Container::singleton()) {
std::stack<Quack::Class*> stack;
Quack::Class* q_class = class_pair.second;
if (!q_class->is_user_class())
continue;
do {
bool found = false;
for (auto * temp_class : user_classes) {
if (temp_class->name_ == q_class->name_) {
found = true;
break;
}
}
if (found)
break;
stack.push(q_class);
q_class = q_class->super_;
} while(q_class && q_class->is_user_class());
// Add all new classes with super classes first
while(!stack.empty()) {
user_classes.emplace_back(stack.top());
stack.pop();
}
}
return user_classes;
}
void export_includes() {
std::pair<std::string, bool> libs[] = {{"stdlib", false},
{"stdio", false},
{"stdbool", false},
{"builtins", true}};
for (auto &lib_pair : libs) {
fout_ << "#include " << (lib_pair.second ? "\"" : "<")
<< lib_pair.first << ".h" << (lib_pair.second ? "\"" : ">") << "\n";
}
fout_ << std::endl;
}
void generate_main(CodeGen::Settings settings, const std::string &main_subfunc_name) {
Quack::Class * nothing_class = Quack::Class::Container::Nothing();
fout_ << "\n"
<< nothing_class->generated_object_type_name() << " " << main_subfunc_name << "() {\n";
settings.return_type_ = Quack::Class::Container::Nothing();
settings.st_ = prog_->main_->symbol_table_;
Quack::Class::generate_symbol_table(settings, 1, prog_->main_);
AST::ASTNode::generate_one_line_comment(settings, 1, "main Method Body");
prog_->main_->block_->generate_code(settings, 0);
fout_ << AST::ASTNode::indent_str(1) << "return none;\n"
<< "}" << std::endl;
settings.return_type_ = nullptr;
settings.st_ = nullptr;
}
void export_main(CodeGen::Settings settings) {
generate_main(settings, METHOD_MAIN);
fout_ << "\n" << "int main() {"
<< "\n" << AST::ASTNode::indent_str(1) << METHOD_MAIN << "();\n"
<< "}" << std::endl;
}
std::string output_file_path_;
std::ofstream fout_;
const Quack::Program * prog_;
};
}
#endif //TYPE_CHECKER_CODE_GENERATOR_H