main.cpp 3.24 KB
Newer Older
lxq's avatar
lxq committed
1
#include "Module.hpp"
lyz's avatar
lyz committed
2
#include "ast.hpp"
lxq's avatar
lxq committed
3
#include "cminusf_builder.hpp"
jhe's avatar
lab3  
jhe committed
4
#include "CodeGen.hpp"
lyz's avatar
lyz committed
5 6

#include <filesystem>
lxq's avatar
lxq committed
7
#include <fstream>
lyz's avatar
lyz committed
8 9 10 11 12 13
#include <iostream>
#include <string>

using std::string;
using std::operator""s;

lxq's avatar
lxq committed
14
struct Config {
lyz's avatar
lyz committed
15 16 17 18 19
    string exe_name; // compiler exe name
    std::filesystem::path input_file;
    std::filesystem::path output_file;

    bool emitast{false};
jhe's avatar
lab3  
jhe committed
20
    bool emitasm{false};
lxq's avatar
lxq committed
21
    bool emitllvm{false};
lyz's avatar
lyz committed
22

lxq's avatar
lxq committed
23
    Config(int argc, char **argv) : argc(argc), argv(argv) {
lyz's avatar
lyz committed
24 25 26 27
        parse_cmd_line();
        check();
    }

lxq's avatar
lxq committed
28
  private:
lyz's avatar
lyz committed
29 30 31 32 33 34 35 36 37 38
    int argc{-1};
    char **argv{nullptr};

    void parse_cmd_line();
    void check();
    // print helper infomation and exit
    void print_help() const;
    void print_err(const string &msg) const;
};

lxq's avatar
lxq committed
39
int main(int argc, char **argv) {
lyz's avatar
lyz committed
40
    Config config(argc, argv);
lxq's avatar
lxq committed
41

lyz's avatar
lyz committed
42 43
    auto syntax_tree = parse(config.input_file.c_str());
    auto ast = AST(syntax_tree);
lxq's avatar
lxq committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

    if (config.emitast) { // if emit ast (lab1), print ast and return
        ASTPrinter printer;
        ast.run_visitor(printer);
    } else {
        std::unique_ptr<Module> m;
        CminusfBuilder builder;
        ast.run_visitor(builder);
        m = builder.getModule();

        std::ofstream output_stream(config.output_file);
        if (config.emitllvm) {
            auto abs_path = std::filesystem::canonical(config.input_file);
            output_stream << "; ModuleID = 'cminus'\n";
            output_stream << "source_filename = " << abs_path << "\n\n";
            output_stream << m->print();
jhe's avatar
lab3  
jhe committed
60 61 62 63
        } else if (config.emitasm) {
            CodeGen codegen(m.get());
            codegen.run();
            output_stream << codegen.print();
lxq's avatar
lxq committed
64 65
        }

jhe's avatar
lab3  
jhe committed
66
        // TODO: lab4 (IR optimization or codegen)
lxq's avatar
lxq committed
67
    }
lyz's avatar
lyz committed
68 69 70 71

    return 0;
}

lxq's avatar
lxq committed
72
void Config::parse_cmd_line() {
lyz's avatar
lyz committed
73
    exe_name = argv[0];
lxq's avatar
lxq committed
74 75
    for (int i = 1; i < argc; ++i) {
        if (argv[i] == "-h"s || argv[i] == "--help"s) {
lyz's avatar
lyz committed
76
            print_help();
lxq's avatar
lxq committed
77 78
        } else if (argv[i] == "-o"s) {
            if (output_file.empty() && i + 1 < argc) {
lyz's avatar
lyz committed
79 80
                output_file = argv[i + 1];
                i += 1;
lxq's avatar
lxq committed
81
            } else {
lyz's avatar
lyz committed
82 83
                print_err("bad output file");
            }
lxq's avatar
lxq committed
84
        } else if (argv[i] == "-emit-ast"s) {
lyz's avatar
lyz committed
85
            emitast = true;
jhe's avatar
lab3  
jhe committed
86 87
        } else if (argv[i] == "-S"s) {
            emitasm = true;
lxq's avatar
lxq committed
88 89 90 91
        } else if (argv[i] == "-emit-llvm"s) {
            emitllvm = true;
        } else {
            if (input_file.empty()) {
lyz's avatar
lyz committed
92
                input_file = argv[i];
lxq's avatar
lxq committed
93
            } else {
lyz's avatar
lyz committed
94 95 96 97 98 99 100 101
                string err =
                    "unrecognized command-line option \'"s + argv[i] + "\'"s;
                print_err(err);
            }
        }
    }
}

lxq's avatar
lxq committed
102 103
void Config::check() {
    if (input_file.empty()) {
lyz's avatar
lyz committed
104 105
        print_err("no input file");
    }
lxq's avatar
lxq committed
106
    if (input_file.extension() != ".cminus") {
lyz's avatar
lyz committed
107 108
        print_err("file format not recognized");
    }
lxq's avatar
lxq committed
109
    if (output_file.empty()) {
lyz's avatar
lyz committed
110 111 112 113
        output_file = input_file.stem();
    }
}

lxq's avatar
lxq committed
114
void Config::print_help() const {
lyz's avatar
lyz committed
115
    std::cout << "Usage: " << exe_name
jhe's avatar
lab3  
jhe committed
116
              << " [-h|--help] [-o <target-file>] [-emit-ast] [-emit-llvm] [-S] "
lyz's avatar
lyz committed
117 118 119 120 121
                 "<input-file>"
              << std::endl;
    exit(0);
}

lxq's avatar
lxq committed
122
void Config::print_err(const string &msg) const {
lyz's avatar
lyz committed
123 124 125
    std::cout << exe_name << ": " << msg << std::endl;
    exit(-1);
}