compiler-go/main.cpp

137 lines
4.4 KiB
C++

#include <antlr4-runtime.h>
#include "Common/Common.h"
#include "ICG/myGoListener.h"
#include "GoParser.h"
#include "GoLexer.h"
#include "GoParserListener.h"
#include "GoParserBaseListener.h"
#include "TCG/Translator.h"
#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
#include <optional>
#include <memory>
using namespace std;
bool ends_with(const std::string& str, const std::string& suffix) {
if (str.length() < suffix.length()) {
return false;
}
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
}
void init_log(const std::string& log_file_name, const std::string& log_path) {
system(("mkdir -p " + log_path).c_str());
google::InitGoogleLogging(log_file_name.c_str());
google::SetLogDestination(google::GLOG_INFO, (log_path + "/").c_str());
google::InstallFailureSignalHandler(); // Capture signals
FLAGS_log_prefix = true; // Log prefixes
FLAGS_colorlogtostderr = true; // Color logs in stderr
FLAGS_alsologtostderr = true; // Log to console
FLAGS_logbufsecs = 0; // Disable log buffering
}
struct CmdParam {
std::vector<std::string> input;
std::string output;
std::string output_3code = "3code.txt";
std::string output_asm = "out.asm";
std::string output_bin = "out.bin";
std::string log_path = "./log";
std::string log_file_name;
};
std::optional<std::string> parse_option(const std::string& option, int& i, int argc, char* argv[]) {
if (i + 1 < argc) {
return argv[++i];
}
std::cerr << "Option " << option << " requires a value." << std::endl;
exit(EXIT_FAILURE);
}
CmdParam read_cmd_param(int argc, char* argv[]) {
CmdParam cmd_param;
cmd_param.log_file_name = argv[0];
for (int i = 1; i < argc; ++i) {
std::string argv_i = argv[i];
if (argv_i[0] == '-') {
if (argv_i.length() == 1) {
std::cerr << "Invalid option." << std::endl;
exit(EXIT_FAILURE);
}
if (auto value = parse_option(argv_i, i, argc, argv)) {
if (argv_i == "-o" || argv_i == "--output") {
cmd_param.output = *value;
} else if (argv_i == "-l" || argv_i == "--log") {
cmd_param.log_path = *value;
} else {
std::cerr << "Unknown parameter " << argv_i << std::endl;
exit(EXIT_FAILURE);
}
}
} else {
cmd_param.input.emplace_back(argv[i]);
}
}
if (cmd_param.input.empty()) {
std::cerr << "No input .go files provided." << std::endl;
exit(EXIT_FAILURE);
}
for (const auto& input_file : cmd_param.input) {
std::string base_name = std::filesystem::path(input_file).stem().string();
if (ends_with(base_name, ".go")) {
base_name = base_name.substr(0, base_name.length() - 3);
}
cmd_param.output = base_name;
std::filesystem::create_directories(cmd_param.output);
}
return cmd_param;
}
int main(int argc, char* argv[]) {
try
{
CmdParam cmd_param = read_cmd_param(argc, argv);
init_log(cmd_param.log_file_name, cmd_param.log_path);
const string& filename = cmd_param.input.front();
LOG(INFO) << "Starting translation for file: " << filename;
antlr4::ANTLRFileStream file;
file.loadFromFile(filename);
antlr4::ANTLRInputStream inputStream(file.toString());
LOG(INFO) << "Starting lexical analysis.";
GoLexer lexer(&inputStream);
antlr4::CommonTokenStream tokens(&lexer);
LOG(INFO) << "Starting syntax analysis.";
GoParser parser(&tokens);
myGoListener listener;
antlr4::tree::ParseTreeWalker::DEFAULT.walk(&listener, parser.sourceFile());
std::string path_3code = cmd_param.output + "/" + cmd_param.output_3code;
listener.Go23file_(path_3code);
LOG(INFO) << "Translating three-address code to assembly.";
auto tac_file = make_shared<TACFile>(std::move(listener.TACBlocks));
Translator translator(tac_file, listener.globalScope);
translator.Translate();
std::string path_asm = cmd_param.output + "/" + cmd_param.output_asm;
translator.OutputFile(path_asm);
LOG(INFO) << "Translation completed successfully.";
return 0;
}
catch(...)
{
LOG(ERROR) << "Translation completed unsuccessfully.";
return -1;
}
}