G

G Programming Language
git clone http://git.omkov.net/G
Log | Tree | Refs | README | Download

G/src/main.c (146 lines, 4.5 KiB) -rw-r--r-- download

0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
// Copyright (C) 2021, Jakob Wakeling
// All rights reserved.

#include "analyse.h"
#include "init.h"
#include "llvm.h"
#include "log.h"
#include "parse.h"
#include "util/error.h"
#include "util/optget.h"
#include "util/util.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

static struct {
	bool bflag, Bflag, cflag, Eflag, pflag, Pflag, qflag, Sflag;
} args = {};

static char *output = null;
static int verbosity = 0;

static const char *const help;
static const char *const version;

static void compile(const char *file, char *src, uptr len);
static void compile_file(const char *file);

static void opt_f(const char *arg);
static void opt_O(const char *arg);
static void opt_W(const char *arg);

int main(int ac, char *av[]) { A0 = av[0];
	struct opt opt = OPTGET_INIT;
	opt.str = "bBcEf:O:pPqSvW:";
	opt.lops = (struct lop[]){
		{ "help",    ARG_NUL, 256 },
		{ "version", ARG_NUL, 257 },
		{ null, 0, 0 }
	};

	for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) {
	case 'b': { args.bflag = true; } break; /* Output LLVM IR files */
	case 'B': { args.Bflag = true; } break; /* Output LLVM bitcode files */
	case 'c': { args.cflag = true; } break; /* Output object files */
	case 'E': { args.Eflag = true; } break; /* Output lexer tokens */
	case 'f': { opt_f(opt.arg);    } break; /* Configure formatting */
	case 'o': { output = opt.arg;  } break; /* Specify output file */
	case 'O': { opt_O(opt.arg);    } break; /* Configure optimisation */
	case 'p': { args.pflag = true; } break; /* Output parser AST */
	case 'P': { args.Pflag = true; } break; /* Output analyser AST */
	case 'q': { args.qflag = true; } break; /* Silence certain outputs (for benchmarking) */
	case 'S': { args.Sflag = true; } break; /* Output assembly files */
	case 'v': { verbosity += 1;    } break; /* Increase verbosity */
	case 'W': { opt_W(opt.arg);    } break; /* Configure warnings and errors */
	case 256: { fputs(help, stdout);    } return 0;
	case 257: { fputs(version, stdout); } return 0;
	default: {} return 1;
	}

	if (opt.ind == ac) { error(1, "Missing operand"); }
	else for (char **p = &av[opt.ind]; *p; ++p) { compile_file(*p); }

	return 0;
}

static void compile(const char * file, char *src, uptr len) {
	initialise();

	lex l = lex_init(file, src, len);
	if (args.Eflag) { lex_debug(&l); goto end; }

	ast *a = parse(&l);
	if (args.pflag) { if (!args.qflag) { ast_print(a, 0); } goto end; }
	if (has_error()) { exit(1); }

	assert(a->k == AK_PROG); analyse(a);
	if (args.Pflag) { if (!args.qflag) { ast_print(a, 0); } goto end; }
	if (has_error()) { exit(1); }

	if (args.bflag) { llvm(a, strdup(file), llvm_ir); }
	else if (args.Bflag) { llvm(a, strdup(file), llvm_bc); }
	else if (args.Sflag) { llvm(a, strdup(file), llvm_asm); }
	else { llvm(a, strdup(file), llvm_obj); }
	if (has_error()) { exit(1); }

	end:; return;
}

static void compile_file(const char *file) {
	FILE *fi; char *fb; size_t fl;

	if (!(fi = fopen(file, "r"))) { error(1, "%s: %s", file, SERR); }
	fseek(fi, 0, SEEK_END); fl = ftell(fi); rewind(fi);

	fb = malloc((fl + 1) * sizeof (*fb));
	fread(fb, 1, fl, fi); fb[fl] = 0; fclose(fi);

	compile(file, fb, fl); free(fb); return;
}

/* Configure formatting */
static void opt_f(const char *arg) {}

/* Configure optimisation */
static void opt_O(const char *arg) {}

/* Configure warnings and errors */
static void opt_W(const char *arg) {
	if (strcmp(arg, "0") == 0) { log_level = 0; }
	else if (strcmp(arg, "1") == 0) { log_level = 1; }
	else if (strcmp(arg, "2") == 0) { log_level = 2; }
	else if (strcmp(arg, "3") == 0) { log_level = 3; }
	else if (strcmp(arg, "4") == 0) { log_level = 4; }
	else if (strcmp(arg, "error") == 0) { log_waerr = true; }
	else { note(null, 0, 0, 1, "-W%s: unknown warning option", arg); }
}

static const char *const help =
	"G - G Programming Language\n"
	"Usage: g file...\n"
	"Options:\n"
	"  -b,       Output LLVM IR files\n"
	"  -B,       Output LLVM bitcode files\n"
	"  -c,       Output object files\n"
	"  -E,       Output lexer tokens\n"
	// "  -f,       Configure formatting\n"
	// "  -o file,  Specify output file\n"
	// "  -O,       Configure optimisation\n"
	"  -p,       Output parser AST\n"
	"  -P,       Output analyser AST\n"
	"  -q,       Silence certain outputs (for benchmarking)\n"
	"  -S,       Output assembly files\n"
	// "  -v,       Increase verbosity \n"
	// "  -W,       Configure warnings and errors\n"
	"  --help    Display help information\n"
	"  --version Display version information\n"
;

static const char *const version =
	"G, version " VERSION "\n"
	"Copyright (C) 2021, Jakob Wakeling\n"
	"All rights reserved.\n"
;