diff src/ploki/main.c @ 4223:ac0403686959

<oerjan> rm -rf src/ploki; mv ploki src
author HackBot
date Fri, 20 Dec 2013 22:18:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ploki/main.c	Fri Dec 20 22:18:50 2013 +0000
@@ -0,0 +1,307 @@
+#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);
+}