view src/ploki/main.c @ 8427:1fc808cd5b1f

<b_jonas> learn can\'t is the most frequent word whose pronunciation varies between /\xc9\x91\xcb\x90/ and /\xc3\xa6/ depending on dialect. The list is: advance after answer ask aunt brass can\'t cast castle chance class command dance demand draft enhance example fast father glass graph grass half last laugh mask master nasty pass past path plant rather sample shan\'t staff task vast
author HackBot
date Thu, 09 Jun 2016 21:28:47 +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);
}