view src/ploki/main.c @ 12292:d51f2100210c draft

<kspalaiologos> `` cat <<<"asmbf && bfi output.b" > /hackenv/ibin/asmbf
author HackEso <hackeso@esolangs.org>
date Thu, 02 Jan 2020 15:38:21 +0000
parents ac0403686959
children
line wrap: on
line source

#include "IO.h"
#include "Str.h"
#include "atechit.h"
#include "compile.h"
#include "deparse.h"
#include "expr.h"
#include "inc.h"
#include "main.h"
#include "main_io.h"
#include "main_label.h"
#include "main_opt.h"
#include "main_var.h"
#include "mars.h"
#include "opt.h"
#include "parse.h"
#include "random.h"
#include "re.h"
#include "run.h"
#include "text.h"
#include "transmogrify.h"
#include "val.h"
#include "venus.h"
#include "version.h"
#include "xmalloc.h"
#include "zz.h"

#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NAME     "ploki"
#define WARN(x)  fprintf(stderr, "%s: %s: %s\n", Prog, x, strerror(errno))

const char *Prog = NAME;
IO *In, *Out, *Err;
struct venus Venus;
struct mars Mars;
struct Options Opt;
t_vr_container *Var_plain, *Var_hash;

static int my_mars_end_flag;
static void my_mars_end(void) {
	if (!my_mars_end_flag) {
		ma_end(&Mars);
	}
}

static void my_venus_end(void) {
	ve_end(&Venus);
}

static struct text text;
static void my_text_off(void) {
	text_off(&text);
}

static void xv_delete(void *v) {
	v_delete(v);
}

static void xsh_delete(void *sh) {
	sh_delete(sh);
}

static void var_end(void) {
	if (Var_plain) {
		vr_delete(Var_plain);
		Var_plain = 0;
	}
	if (Var_hash) {
		vr_delete(Var_hash);
		Var_hash = 0;
	}
}

static char *s_lastof(const char *s, const char *set) {
	const char *t = s + strlen(s);
	while (t > s) {
		--t;
		if (strchr(set, *t)) {
			return (char *)t;  /* const correctness is for C++ programmers! */
		}
	}
	return NULL;
}

static void usage(void) {
	printf(
			"Usage: %s [OPTIONS] [FILE [ARG]...]\n"
			"\n"
			"Available options:\n"
			"\n"
			"  -h           print a short help message and exit\n"
			"  -v           print version and configuration info and exit\n"
			"  -MO=Deparse  turn the compiled program back into ploki source\n"
			"  -O           disable any optimizations\n"
			"  -d FLAGS     print debugging info\n"
			"               FLAGS must be one or more of the following:\n"
			"                 h   hash tables\n"
			"                 o   opcode execution\n"
			"                 r   regex engine\n"
			"\n"
			"%s"
			, Prog,
			"Interpret FILE as ploki program and execute it, unless -MO=Deparse is\n"
			"specified. With no FILE, or when FILE is -, read from standard input.\n"
			"Any ARGs are passed through to the program.\n"
		  );
}

static void printinc(void) {
	size_t i;
	for (i = 0; inc_ludes[i]; ++i) {
		printf(" \"%s\"", inc_ludes[i]);
	}
}

int main(int argc, char **argv) {
	IO *f;
	int c;

	if (argc > 0 && argv[0][0]) {
		Prog = argv[0];
	}

	while ((c = opt_get(argc, argv, "-:?M:Od:hv")) != -1) {
		switch (c) {
invalid_option:
			fprintf(stderr, "%s: invalid option `%c'\n", Prog, c);
			return EXIT_FAILURE;

			/* option aliasing */
			case '-':
				if (!opt_arg) {
					goto invalid_option;
				}
				if (!strncmp("help", opt_arg, strlen(opt_arg))) {
					case 'h':
					case '?':
						usage();
						return EXIT_SUCCESS;
				}
				if (!strncmp("version", opt_arg, strlen(opt_arg))) {
					case 'v':
						printf(
							"This is %s v%s\n"
							"%cvsnprintf %csleep %c/dev/urandom %s%s %cM_PI %cM_E\nINC contains:",
							NAME,
							Version,
							HAVE_VSNPRINTF_P  ? '+' : '-',
							HAVE_SLEEP_P      ? '+' : '-',
							HAVE_DEV_URANDOM_P ? '+' : '-',
							DIR_END ? "+DIRSEP:" : "-DIRSEP",
							DIR_END ? DIR_END : "",
							#ifdef M_PI
								'+'
							#else
								'-'
							#endif
							,
							#ifdef M_E
								'+'
							#else
								'-'
							#endif
						);
						printinc();
						fputs("\nWritten by Lukas Mai\n", stdout);
						return EXIT_SUCCESS;
				}
				fprintf(stderr, "%s: invalid option `%s'\n", Prog, opt_arg);
				return EXIT_FAILURE;

			case 'd':
				if (!opt_arg || !opt_arg[0]) {
					fprintf(stderr, "%s: option `%c' requires an argument\n", Prog, c);
					return EXIT_FAILURE;
				} else {
					const char *a = opt_arg;
					for (; *a; ++a) {
						switch (*a) {
							case 'h': Opt.debug |= DBG_HASH;  break;
							case 'o': Opt.debug |= DBG_OPS;   break;
							case 'r': Opt.debug |= DBG_REGEX; break;
							default:
								fprintf(stderr, "%s: option d's argument must be one of [hor], not `%s'\n", Prog, a);
							return EXIT_FAILURE;
						}
					}
				}
				break;

			case 'M':
				if (!opt_arg || strncmp(opt_arg, "O=Deparse", strlen(opt_arg))) {
					goto invalid_option;
				}
				Opt.deparse = 1;
				break;

			case 'O':
				Opt.unoptimize = 1;
				break;

			case '\0':
				c = opt_err;
				goto invalid_option;

			default:
				NOTREACHED;
		}
	}
	argc -= opt_ind;
	argv += opt_ind;

	randseed();

	atechit(xend);
	io_init();
	atechit(io_end);

	In = io_enter("(stdin)", stdin, IO_READ | IO_BUFFERED);
	Out = io_enter("(stdout)", stdout, IO_WRITE | IO_TRUNCATE | IO_AUTOFLUSH);
	Err = io_enter("(stderr)", stderr, IO_WRITE | IO_TRUNCATE | IO_AUTOFLUSH);

	if (!argv[0] || (argv[0][0] == '-' && argv[0][1] == '\0')) {
		f = io_incr(In);
	} else {
		if (!(f = io_open(argv[0], IO_READ | IO_BUFFERED))) {
			WARN(argv[0]);
			return EXIT_FAILURE;
		}
	}

	/* ignore empty files */
	{
		size_t p;
		for (p = 0; isspace(c = io_peek(f, p)); ++p)
			;
		if (c == EOF) {
			if (io_err(f)) {
				WARN(io_name(f, NULL));
				io_decr(f);
				return EXIT_FAILURE;
			} else {
				io_decr(f);
				return EXIT_SUCCESS;
			}
		}
	}

	re_init();
	atechit(re_end);
	atechit(var_end);
	Var_plain = vr_new(xv_delete);
	Var_hash = vr_new(xsh_delete);

	text_on(&text);
	atechit(my_text_off);
	ma_init(&Mars);
	atechit(my_mars_end);
	ve_init(&Venus);
	atechit(my_venus_end);

	{
		size_t tmp = 0;
		char *eop = NULL;
		char bkp = 00;
		if (argv[0]) {
			if (DIR_END && (eop = s_lastof(argv[0], DIR_END))) {
				size_t i;
				bkp = eop[1];
				eop[1] = '\0';
				for (i = 0; inc_ludes[i]; ++i) {
					if (inc_ludes[i][0] == '\0') {
						inc_ludes[i] = argv[0];
					}
				}
			}
		}
		parse(f, &text, &tmp);
		if (eop) {
			eop[1] = bkp;
		}
	}
	io_decr(f);

	expr_init();
	atechit(expr_end);

	compile(&text);
	if (!Opt.unoptimize) {
		transmogrify(&text);
	}

	my_mars_end_flag = 1;
	ma_end(&Mars);

	if (Opt.deparse) {
		deparse(&text);
		return 0;
	}

	run(&text, argc, argv);
}