zig/src/main.cpp

200 lines
5.8 KiB
C++
Raw Normal View History

2015-08-06 07:22:21 +08:00
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#include "config.h"
#include "util.hpp"
2015-08-06 08:44:05 +08:00
#include "list.hpp"
#include "buffer.hpp"
2015-11-04 13:31:27 +08:00
#include "parser.hpp"
#include "tokenizer.hpp"
2015-11-05 15:05:25 +08:00
#include "error.hpp"
#include "codegen.hpp"
2015-08-06 07:22:21 +08:00
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
2015-11-05 15:05:25 +08:00
#include <inttypes.h>
2015-08-06 07:22:21 +08:00
2015-11-05 15:05:25 +08:00
static int usage(const char *arg0) {
fprintf(stderr, "Usage: %s [command] [options] target\n"
"Commands:\n"
" build create an executable from target\n"
"Options:\n"
" --output output file\n"
" --version print version number and exit\n"
" -Ipath add path to header include path\n"
2015-11-25 13:32:26 +08:00
" --release build with optimizations on\n"
" --strip exclude debug symbols\n"
" --static build a static executable\n"
2015-08-06 07:22:21 +08:00
, arg0);
return EXIT_FAILURE;
}
static Buf *fetch_file(FILE *f) {
2015-08-06 07:22:21 +08:00
int fd = fileno(f);
struct stat st;
if (fstat(fd, &st))
zig_panic("unable to stat file: %s", strerror(errno));
off_t big_size = st.st_size;
if (big_size > INT_MAX)
zig_panic("file too big");
int size = (int)big_size;
Buf *buf = buf_alloc_fixed(size);
size_t amt_read = fread(buf_ptr(buf), 1, buf_len(buf), f);
if (amt_read != (size_t)buf_len(buf))
2015-08-06 07:22:21 +08:00
zig_panic("error reading: %s", strerror(errno));
return buf;
}
2015-11-25 13:32:26 +08:00
static int build(const char *arg0, const char *in_file, const char *out_file,
ZigList<char *> *include_paths, bool release, bool strip, bool is_static)
{
2015-11-05 15:05:25 +08:00
static char cur_dir[1024];
2015-08-06 07:22:21 +08:00
if (!in_file || !out_file)
return usage(arg0);
FILE *in_f;
if (strcmp(in_file, "-") == 0) {
in_f = stdin;
2015-08-06 12:47:08 +08:00
char *result = getcwd(cur_dir, sizeof(cur_dir));
if (!result)
zig_panic("unable to get current working directory: %s", strerror(errno));
2015-08-06 07:22:21 +08:00
} else {
in_f = fopen(in_file, "rb");
if (!in_f)
zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno));
}
2015-11-02 13:21:33 +08:00
fprintf(stderr, "Original source:\n");
fprintf(stderr, "----------------\n");
Buf *in_data = fetch_file(in_f);
2015-11-02 13:21:33 +08:00
fprintf(stderr, "%s\n", buf_ptr(in_data));
2015-08-06 07:22:21 +08:00
fprintf(stderr, "\nTokens:\n");
2015-11-02 13:21:33 +08:00
fprintf(stderr, "---------\n");
2015-11-25 10:07:33 +08:00
ZigList<Token> *tokens = tokenize(in_data);
2015-08-06 08:44:05 +08:00
print_tokens(in_data, tokens);
2015-08-06 07:22:21 +08:00
fprintf(stderr, "\nAST:\n");
fprintf(stderr, "------\n");
AstNode *root = ast_parse(in_data, tokens);
assert(root);
2015-11-04 13:31:27 +08:00
ast_print(root, 0);
fprintf(stderr, "\nSemantic Analysis:\n");
fprintf(stderr, "--------------------\n");
2015-11-25 13:32:26 +08:00
CodeGen *codegen = create_codegen(root, buf_create_from_str(in_file));
codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
codegen_set_strip(codegen, strip);
codegen_set_is_static(codegen, is_static);
semantic_analyze(codegen);
ZigList<ErrorMsg> *errors = codegen_error_messages(codegen);
if (errors->length == 0) {
fprintf(stderr, "OK\n");
} else {
for (int i = 0; i < errors->length; i += 1) {
ErrorMsg *err = &errors->at(i);
fprintf(stderr, "Error: Line %d, column %d: %s\n",
err->line_start + 1, err->column_start + 1,
buf_ptr(err->msg));
}
return 1;
}
fprintf(stderr, "\nCode Generation:\n");
fprintf(stderr, "------------------\n");
code_gen(codegen);
2015-08-06 07:22:21 +08:00
fprintf(stderr, "\nLink:\n");
fprintf(stderr, "------------------\n");
2015-11-25 10:07:33 +08:00
code_gen_link(codegen, out_file);
fprintf(stderr, "OK\n");
2015-11-05 15:05:25 +08:00
return 0;
}
enum Cmd {
CmdNone,
CmdBuild,
};
int main(int argc, char **argv) {
char *arg0 = argv[0];
char *in_file = NULL;
char *out_file = NULL;
ZigList<char *> include_paths = {0};
2015-11-25 13:32:26 +08:00
bool release = false;
bool strip = false;
bool is_static = false;
2015-11-05 15:05:25 +08:00
Cmd cmd = CmdNone;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') {
if (strcmp(arg, "--version") == 0) {
printf("%s\n", ZIG_VERSION_STRING);
return EXIT_SUCCESS;
2015-11-25 13:32:26 +08:00
} else if (strcmp(arg, "--release") == 0) {
release = true;
} else if (strcmp(arg, "--strip") == 0) {
strip = true;
} else if (strcmp(arg, "--static") == 0) {
is_static = true;
2015-11-05 15:05:25 +08:00
} else if (i + 1 >= argc) {
return usage(arg0);
} else {
i += 1;
if (strcmp(arg, "--output") == 0) {
out_file = argv[i];
} else {
return usage(arg0);
}
}
} else if (arg[0] == '-' && arg[1] == 'I') {
include_paths.append(arg + 2);
} else if (cmd == CmdNone) {
if (strcmp(arg, "build") == 0) {
cmd = CmdBuild;
} else {
fprintf(stderr, "Unrecognized command: %s\n", arg);
return usage(arg0);
}
} else {
switch (cmd) {
case CmdNone:
zig_unreachable();
2015-11-05 15:05:25 +08:00
case CmdBuild:
if (!in_file) {
in_file = arg;
} else {
return usage(arg0);
}
break;
}
}
}
switch (cmd) {
case CmdNone:
return usage(arg0);
case CmdBuild:
2015-11-25 13:32:26 +08:00
return build(arg0, in_file, out_file, &include_paths, release, strip, is_static);
2015-11-05 15:05:25 +08:00
}
2015-11-05 15:06:36 +08:00
zig_unreachable();
2015-11-05 15:05:25 +08:00
}