diff --git a/CMakeLists.txt b/CMakeLists.txt index c060257..345bb8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,15 @@ cmake_minimum_required(VERSION 3.5) project(LiteGoCompiler) - -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_BUILD_TYPE Release) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w -O3 -g") - +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w -O2 -g") # library in subdirectory add_subdirectory(antlr) add_subdirectory(src) - -# excutable +# executable add_executable(LiteGoCompiler main.cpp) target_include_directories(LiteGoCompiler @@ -26,3 +23,12 @@ target_link_libraries(LiteGoCompiler icg tcg ) + +# Custom clean target to remove all directories +add_custom_target(clean-all + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_SOURCE_DIR}/* + COMMENT "Removing all directories and files in the current directory" +) + +# Make 'clean' depend on 'clean-all' +set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*") \ No newline at end of file diff --git a/main.cpp b/main.cpp index 33e6767..f41bebe 100644 --- a/main.cpp +++ b/main.cpp @@ -6,131 +6,115 @@ #include "GoParserListener.h" #include "GoParserBaseListener.h" #include "TCG/Translator.h" +#include +#include +#include +#include +#include +#include using namespace std; - 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::SetStderrLogging(google::INFO); - google::InstallFailureSignalHandler(); // 捕捉信号 - FLAGS_log_prefix = true; // 日志前缀 - FLAGS_colorlogtostderr = true; // 颜色 - FLAGS_alsologtostderr = true; // 日志输出到屏幕 - FLAGS_logbufsecs = 0; // 日志缓冲时间 + 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 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::vector 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; + std::string log_file_name; }; +std::optional 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]; - int i = 1; - while (i < argc) { + + for (int i = 1; i < argc; ++i) { std::string argv_i = argv[i]; - if (argv_i[0] == '-') { - // option - if ((argv_i == "-h") || (argv_i == "--help")) { - std::cout << "可选参数如下:" << std::endl; - std::cout << "-h (--help): 帮助" << std::endl; - std::cout << "-o (--output): [default: .] 输出文件路径" << std::endl; - std::cout << "-3 (--3code): [default: 3code.txt] 输出 3code 文件名" << std::endl; - std::cout << "-a (--asm): [default: out] 输出 asm 文件名" << std::endl; - std::cout << "-b (--bin): [default: bin] 输出 bin 文件名" << std::endl; - std::cout << "-l (--log): [default: log] 输出 log 目录" << std::endl; - exit(0); - } + if (argv_i.starts_with('-')) { if (argv_i.length() == 1) { - std::cout << "选项错误" << std::endl; - exit(0); - } else if (i + 1 == argc) { - std::cout << "选项 " << argv_i << " 没有给定值" << std::endl; - exit(0); - } else { - // 解析参数 - if ((argv_i == "-o") || (argv_i == "--output")) { - cmd_param.output = argv[++i]; - } else if ((argv_i == "-3") || (argv_i == "--3code")) { - cmd_param.output_3code = argv[++i]; - } else if ((argv_i == "-a") || (argv_i == "--asm")) { - cmd_param.output_asm = argv[++i]; - } else if ((argv_i == "-b") || (argv_i == "--bin")) { - cmd_param.output_bin == argv[++i]; - } else if ((argv_i == "-l") || (argv_i == "--log")) { - cmd_param.log_path = argv[++i]; + 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::cout << "未知参数 " << argv_i << std::endl; - exit(0); + std::cerr << "Unknown parameter " << argv_i << std::endl; + exit(EXIT_FAILURE); } } } else { - // input cmd_param.input.emplace_back(argv[i]); } - i++; } - if (cmd_param.input.size() == 0) { - std::cout << "没有输入的 .go 文件" << std::endl; - exit(0); + + if (cmd_param.input.empty()) { + std::cerr << "No input .go files provided." << std::endl; + exit(EXIT_FAILURE); } - system(("mkdir -p " + cmd_param.output).c_str()); + + for (const auto& input_file : cmd_param.input) { + std::string base_name = std::filesystem::path(input_file).stem().string(); + if (base_name.ends_with(".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[]){ - std::string cmd0 = "cd ../grammar/java"; - cmd0 += "&& javac *.java"; - cmd0 += "&& cd ../../build"; - // system(cmd0.c_str()); - +int main(int argc, char* argv[]) { 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(); - // string filename = "calculate.go"; - string filename = cmd_param.input[0]; - LOG(WARNING) << "start 翻译文件: " << filename; - + LOG(INFO) << "Starting translation for file: " << filename; antlr4::ANTLRFileStream file; file.loadFromFile(filename); antlr4::ANTLRInputStream inputStream(file.toString()); - LOG(WARNING) << "start 词法分析"; + + LOG(INFO) << "Starting lexical analysis."; GoLexer lexer(&inputStream); antlr4::CommonTokenStream tokens(&lexer); - LOG(WARNING) << "start 语法分析"; + 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); - sleep(1); - LOG(WARNING) << "start 三地址 -> 汇编"; - std::shared_ptr tac_file = std::make_shared(std::move(listener.TACBlocks)); - Translator translator(std::shared_ptr(tac_file), listener.globalScope); + LOG(INFO) << "Translating three-address code to assembly."; + auto tac_file = make_shared(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); - std::string path_bin = cmd_param.output + "/" + cmd_param.output_bin; - std::string cmd; - cmd = "nasm -f elf32 -o " + cmd_param.output + "/out.o " + path_asm; - std::cout << cmd << std::endl; system(cmd.c_str()); - cmd = "nasm -f elf32 -o " + cmd_param.output + "/print.o " + "/usr/local/share/doc/print.asm"; - std::cout << cmd << std::endl; system(cmd.c_str()); - cmd = "ld -m elf_i386 -o " + path_bin + " " + cmd_param.output + "/out.o " + cmd_param.output + "/print.o"; - std::cout << cmd << std::endl; system(cmd.c_str()); + LOG(INFO) << "Translation completed successfully."; return 0; -} +} \ No newline at end of file diff --git a/test/02calculate.go b/test/e/02calculate.go similarity index 100% rename from test/02calculate.go rename to test/e/02calculate.go diff --git a/test/03if.go b/test/e/03if.go similarity index 100% rename from test/03if.go rename to test/e/03if.go diff --git a/test/04for.go b/test/e/04for.go similarity index 100% rename from test/04for.go rename to test/e/04for.go diff --git a/test/05func.go b/test/e/05func.go similarity index 100% rename from test/05func.go rename to test/e/05func.go diff --git a/test/06array.go b/test/e/06array.go similarity index 100% rename from test/06array.go rename to test/e/06array.go diff --git a/test/error01.go b/test/e/07error.go similarity index 100% rename from test/error01.go rename to test/e/07error.go diff --git a/test/simple.go b/test/e/08error.go similarity index 100% rename from test/simple.go rename to test/e/08error.go diff --git a/test/test2.go b/test/e/09test.go similarity index 100% rename from test/test2.go rename to test/e/09test.go diff --git a/test/test3.go b/test/e/10test.go similarity index 100% rename from test/test3.go rename to test/e/10test.go diff --git a/test/test4.go b/test/e/11test.go similarity index 100% rename from test/test4.go rename to test/e/11test.go diff --git a/test/e/print.asm b/test/e/print.asm new file mode 100644 index 0000000..4f725e5 --- /dev/null +++ b/test/e/print.asm @@ -0,0 +1,53 @@ +; print.asm +global myprint ; 设置print为全局可见 + + +myprint: + push ebp + mov ebp, esp + + push eax + push ebx + push ecx + push edx + push esi + + mov edi, 0 + + sub esp, 1 + mov byte [esp], 0 + add edi, 1 + + sub esp, 1 + mov byte [esp], 10 + add edi, 1 + + mov edx, 0 + mov eax, [ebp + 8] + ; mov eax, 98765 + mov ecx, 10 +LOOP_: + div ecx + add edx, 48 + sub esp, 1 + mov byte [esp], dl + add edi, 1 + mov edx, 0 + cmp eax, 0 + jne LOOP_ + + mov eax, 4 ; 发起系统调用 + mov ebx, 1 ; ebx表示stdout + mov ecx, esp ; 表示字符串的地址 + mov edx, edi ; 表示字符的个数 + int 0x80 ; int 0x80表示系统调用 + + add esp, edi + + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret diff --git a/test/e/print.o b/test/e/print.o new file mode 100644 index 0000000..1152900 Binary files /dev/null and b/test/e/print.o differ diff --git a/test/print.o b/test/print.o new file mode 100644 index 0000000..440b919 Binary files /dev/null and b/test/print.o differ diff --git a/test/test.go b/test/test.go deleted file mode 100644 index b2348e9..0000000 --- a/test/test.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import "fmt" - -var g int = ^20 - -func swap(x, y int) (int, int) { - return y, x -} - -func main() { - // if语句 - - - - - - var a,b int = 10,20 - if a < 20 { - fmt.Printf("a 小于 20\n" ); - } else { - fmt.Printf("a 不小于 20\n" ); - } - - // for语句 - var sum int - for i:=0; i <= 10; i++ { - sum += i - } - for sum <= 15 { //10加到15 - sum += sum - } - for {} - - // 函数调用 - var s1,s2 int = "aaa","bbb" - s3, s4 := swap(s1, s2) - - // 全局变量vs局部变量 - var g int = 10 - fmt.Printf ("结果: g = %d\n", g) - - // 指针 - var tmp int= 20 - var p *int - ip = &a - fmt.Printf("*ip 变量的值: %d\n", *ip ) -} diff --git a/test_all.sh b/test_all.sh index 1775055..13c4996 100755 --- a/test_all.sh +++ b/test_all.sh @@ -6,18 +6,24 @@ failure_count=0 failed_files=() successful_files=() -for test_file in ../test/*.go; do +test_folder=../test/e + +for test_file in $test_folder/*.go; do base_name=$(basename "$test_file" .go) echo -e "\n========== 编译 $base_name ==========" - if ! ./LiteGoCompiler ../test/$test_file; then + if ! ./LiteGoCompiler $test_folder/$base_name.go; then echo "编译错误" failure_count=$((failure_count + 1)) failed_files+=("$base_name") continue fi - if ! ld -m elf_i386 -o run.bin out.o print.o; then + nasm -f elf32 -o "$base_name/out.o" "$base_name/out.asm" + nasm -f elf32 -o "$test_folder/print.o" $test_folder/print.asm + + + if ! ld -m elf_i386 -o "$base_name/out.bin" "$base_name/out.o" "$test_folder/print.o"; then echo "链接错误" failure_count=$((failure_count + 1)) failed_files+=("$base_name") @@ -25,7 +31,7 @@ for test_file in ../test/*.go; do fi echo -e "\n========== 运行 $base_name ==========" - if ! ./run.bin; then + if ! $base_name/out.bin; then echo "运行错误" failure_count=$((failure_count + 1)) failed_files+=("$base_name") @@ -38,7 +44,7 @@ done # 输出统计结果 echo -e "\n========== 编译结果统计 ==========" -echo "编译成功的文件数量: $success_count" -echo "编译成功的文件名: ${successful_files[*]}" -echo "编译失败的文件数量: $failure_count" -echo "编译失败的文件名: ${failed_files[*]}" \ No newline at end of file +echo "成功的文件数量: $success_count" +echo "成功的文件名: ${successful_files[*]}" +echo "失败的文件数量: $failure_count" +echo "失败的文件名: ${failed_files[*]}" \ No newline at end of file