about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorelioat <hi@eli.li>2024-04-19 14:58:08 -0400
committerelioat <hi@eli.li>2024-04-19 14:58:08 -0400
commit424301cbbe01a608cf7df8f4b3c9c2f856aa1740 (patch)
treeb73e2e06c559d3b7ec391861458f202bb15bb977
parente80d2a31862110c8913358027905cbcf905274ce (diff)
downloadtour-424301cbbe01a608cf7df8f4b3c9c2f856aa1740.tar.gz
*
-rw-r--r--modal/.gitignore1
-rw-r--r--modal/logic.modal4
-rw-r--r--modal/modal.c252
3 files changed, 257 insertions, 0 deletions
diff --git a/modal/.gitignore b/modal/.gitignore
new file mode 100644
index 0000000..d08a843
--- /dev/null
+++ b/modal/.gitignore
@@ -0,0 +1 @@
+modal
\ No newline at end of file
diff --git a/modal/logic.modal b/modal/logic.modal
new file mode 100644
index 0000000..7699841
--- /dev/null
+++ b/modal/logic.modal
@@ -0,0 +1,4 @@
+<> (eq ?x ?x) (#t)
+<> (eq ?x ?y) (#f)
+
+.. (eq fox bat)
\ No newline at end of file
diff --git a/modal/modal.c b/modal/modal.c
new file mode 100644
index 0000000..c7bf0f8
--- /dev/null
+++ b/modal/modal.c
@@ -0,0 +1,252 @@
+/* 
+	by https://wryl.tech/
+ 	from https://wiki.xxiivv.com/site/modal
+ 	cc modal.c -o modal
+*/
+
+#include <stdio.h>
+
+typedef struct {
+	int id;
+	char *a, *b;
+} Rule;
+
+static int flip, rmin = 0xff, rmax = 0x00, cycles = 0x10000;
+static Rule rules[0x1000], lambda, *rules_ = rules;
+static char dict[0x8000], *dict_ = dict;
+static char bank_a[0x4000], *src_ = bank_a;
+static char bank_b[0x4000], *dst_ = bank_b;
+static char *regs[0x100];
+
+#define spacer(c) (c <= ' ' || c == '(' || c == ')')
+
+static char *
+walk(char *s)
+{
+	char c;
+	int depth = 0;
+	if(*s == '(') {
+		while((c = *s++)) {
+			if(c == '(') depth++;
+			if(c == ')') --depth;
+			if(!depth) return s;
+		}
+	}
+	while((c = *s) && !spacer(c)) s++;
+	return s;
+}
+
+static int
+set_reg(int r, char *b)
+{
+	if(regs[r]) {
+		char *a = regs[r], *aa = walk(a), *bb = walk(b);
+		while(a < aa && b < bb)
+			if(*a++ != *b++) return 0;
+	} else {
+		regs[r] = b;
+		if(r < rmin) rmin = r;
+		if(r > rmax) rmax = r;
+	}
+	return 1;
+}
+
+static void
+put_reg(char r)
+{
+	char c, *s = regs[(int)r], *ss;
+	if(!s) {
+		*dst_++ = '?', *dst_++ = r;
+		return;
+	}
+	ss = walk(s);
+	if(r == '*') {
+		int i, depth = 0;
+		if(*s == '(') { /* special explode tuple */
+			s++;
+			while(s < ss) {
+				while((c = *s) && !spacer(c))
+					*dst_++ = c, s++;
+				*dst_++ = ' ';
+				*dst_++ = '(', s++, depth++;
+			}
+		} else { /* special explode token */
+			while((c = *s++) && !spacer(c))
+				*dst_++ = c, *dst_++ = ' ', *dst_++ = '(', depth++;
+		}
+		for(i = 0; i < depth; i++)
+			*dst_++ = ')';
+	} else if(r == '.') { /* special unpack */
+		if(*s == '(') s++, --ss;
+		while(s < ss) *dst_++ = *s++;
+	} else if(r == '^') { /* special join */
+		if(*s == '(') s++, --ss;
+		while(s < ss && (c = *s++))
+			if(!spacer(c)) *dst_++ = c;
+	} else if(r == '~') { /* special stdin */
+		while(fread(&c, 1, 1, stdin) && c >= ' ')
+			*dst_++ = c;
+	} else if(r == ':') { /* special stdout */
+		if(*s == '(') s++, --ss;
+		while(s < ss) {
+			c = *s++;
+			if(c == '\\') {
+				switch(*s++) {
+				case 't': putc(0x09, stdout); break;
+				case 'n': putc(0x0a, stdout); break;
+				case 's': putc(0x20, stdout); break;
+				}
+			} else
+				putc(c, stdout);
+		}
+	} else
+		while(s < ss) *dst_++ = *s++;
+}
+
+static char *
+match_rule(Rule *r, char *p)
+{
+	int i;
+	char c, last = 0, *a = r->a, *b = p;
+	if(rmax) {
+		for(i = rmin; i <= rmax; i++)
+			regs[i] = 0;
+		rmin = 0xff, rmax = 0x00;
+	}
+	while((c = *a)) {
+		if(spacer(last) && c == '?') {
+			if(!set_reg(*(++a), b)) return NULL;
+			a++, b = walk(b);
+			continue;
+		}
+		if(c != *b) return NULL;
+		a++, b++, last = c;
+	}
+	c = *b;
+	return spacer(c) ? b : NULL;
+}
+
+static int
+commit_rule(Rule *r, char *s, int create)
+{
+	while((*dst_++ = *s++))
+		;
+	*dst_++ = 0;
+	if((flip = !flip))
+		src_ = bank_b, dst_ = bank_a;
+	else
+		src_ = bank_a, dst_ = bank_b;
+	if(create)
+		fprintf(stderr, "<> (%s) (%s)\n", r->a, r->b);
+	else
+		fprintf(stderr, "%02d %s\n", r->id, src_);
+	return 1;
+}
+
+static int
+write_rule(Rule *r, char last, char *res)
+{
+	char c, *b = r->b, *origin = dst_;
+	while((c = *b++))
+		if(spacer(last) && c == '?')
+			put_reg(*b++);
+		else
+			*dst_++ = c, last = c;
+	if(dst_ == origin) {
+		while(*res == ' ') res++;
+		if(*res == ')' && *(dst_ - 1) == ' ') dst_--;
+	}
+	return commit_rule(r, res, 0);
+}
+
+static char *
+parse_frag(char *s)
+{
+	char c, *ss;
+	while((c = *s) && c <= ' ') s++;
+	if(*s != ')' && !(*s == '<' && s[1] == '>')) {
+		ss = walk(s);
+		if(*s == '(') {
+			s++;
+			while(s < ss - 1) *dict_++ = *s++;
+			s++;
+		} else
+			while(s < ss) *dict_++ = *s++;
+	}
+	*dict_++ = 0;
+	return s;
+}
+
+static char *
+create_rule(Rule *r, int id, char *s)
+{
+	r->id = id, s += 2;
+	r->a = dict_, s = parse_frag(s);
+	r->b = dict_, s = parse_frag(s);
+	return s;
+}
+
+static int
+rewrite(void)
+{
+	char c, last = 0, *cap, *s = src_, *res;
+	while((c = *s) && c <= ' ') s++;
+	while((c = *s)) {
+		if(spacer(last)) {
+			Rule *r;
+			if(*s == '<' && s[1] == '>') {
+				r = rules_++;
+				s = create_rule(r, rules_ - rules - 1, s);
+				while((c = *s) && c <= ' ') s++;
+				return commit_rule(r, s, 1);
+			}
+			if(*s == '?' && s[1] == '(') {
+				r = &lambda, cap = walk(s + 1);
+				create_rule(&lambda, -1, s), s = cap;
+				while((c = *s) && c <= ' ') s++;
+				if((res = match_rule(&lambda, s)) != NULL)
+					return write_rule(&lambda, last, res);
+			}
+			for(r = rules; r < rules_; r++)
+				if((res = match_rule(r, s)) != NULL)
+					return write_rule(r, last, res);
+		}
+		*dst_++ = last = c;
+		s++;
+	}
+	*dst_++ = 0;
+	return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+	FILE *f;
+	int i;
+	char c, *w = bank_a;
+	if(argc < 2)
+		return !printf("usage: modal [-vqn] source.modal\n");
+	for(i = 1; i < argc && *argv[i] == '-'; i++) {
+		switch(argv[i][1]) {
+		case 'v': /* version */ return !printf("Modal Interpreter, 18 Apr 2024.\n");
+		case 'q': /* quiet */ fclose(stderr); break;
+		case 'n': /* infinite */ cycles = 0xffffffff; break;
+		}
+	}
+	if(!(f = fopen(argv[i], "r")))
+		return !fprintf(stdout, "Invalid Modal file: %s.\n", argv[i]);
+	while(fread(&c, 1, 1, f)) {
+		c = c <= 0x20 ? 0x20 : c;
+		if(w > bank_a) {
+			if(c == ' ' && *(w - 1) == '(') continue;
+			if(c == ')' && *(w - 1) == ' ') w--;
+			if(c == ' ' && *(w - 1) == ' ') w--;
+		}
+		*w++ = c;
+	}
+	while(*(--w) <= ' ') *w = 0;
+	fclose(f);
+	while(rewrite())
+		if(!cycles--) return !fprintf(stdout, "Modal rewrites exceeded.\n");
+	return 0;
+}
\ No newline at end of file