aboutsummaryrefslogtreecommitdiff
path: root/compiler/main.cup
blob: 7a4ae0c52421d32ab69ee284f1616d8e5f75140b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import "std/file.cup"
// FIXME: The order of the following lines is important.
//        Perhaps have multiple passes?
import "compiler/builtins.cup"
import "compiler/parser.cup"
import "compiler/codegen.cup"

fn print_usage_and_exit(name: char*, status: int) {
    puts("Usage: "); puts(name); putsln(" [options] <file>");
    putsln("Options:");
    putsln("  -c <code>  Code to compile");
    putsln("  -h         Show this help");
    putsln("  -o <file>  Output file");
    putsln("  -d         Dump AST to stdout");
    putsln("Output file will be named 'build/host.nasm' by default");
    exit(status);
}

// FIXME: Allow variables functions to be static to a file?
//        we can avoid the prefixes then.
const MAX_STDIN_SOURCE_LEN = 4096;
let m_filename: char*;
let m_outut_filename = "build/host.nasm";
let m_source: char*;
let m_source_len = 0;
let m_dump_ast = false;

fn parse_cli_args(argc: int, argv: char**) {
    for (let i = 1; i < argc; ++i) {
        if (streq(argv[i], "-c")) {
            m_source_len = strlen(argv[i+1]);
            m_source = argv[i+1];
            ++i;
            m_filename = "CLI";
        } else if (streq(argv[i], "-h")) {
            print_usage_and_exit(argv[0], 0);
        } else if (streq(argv[i], "-d")) {
            m_dump_ast = true;
        } else if (streq(argv[i], "-o")) {
            ++i;
            m_outut_filename = argv[i];
        } else if (m_filename == null) {
            if (streq(argv[i], "-")) {
                m_filename = "stdin";
                m_source = malloc(MAX_STDIN_SOURCE_LEN);
                m_source_len = read(0, m_source, MAX_STDIN_SOURCE_LEN);
                m_source[m_source_len] = 0;
                if (m_source_len == MAX_STDIN_SOURCE_LEN) {
                    putsln("Source too long to use through stdin");
                    exit(1);
                }
            } else {
                m_filename = argv[i];
                let file = fopen(m_filename, 'r');
                m_source = fread_to_string(file, &m_source_len);
                fclose(file);
            }
        } else {
            print_usage_and_exit(argv[0], 1);
        }
    }
    if (m_filename == null) {
        print_usage_and_exit(argv[0], 1);
    }
}

fn main(argc: int, argv: char **): int {
    parse_cli_args(argc, argv);
    
    let lexer = lexer_new(m_filename, m_source, m_source_len);
    let ast = parse_program(lexer);

    if (m_dump_ast)
        dump_ast(ast, 0);

    let out_file = fopen(m_outut_filename, 'w');
    generate_program(ast, out_file);
    fclose(out_file); // TODO: Defer on self-host

    // puts("---------------------------\n");
    // puts("Total amount of memory used by malloc: ");
    // putu(__malloc_buf_pos);
    // putsln("\nDone.");
}