diff options
author | elioat <hi@eli.li> | 2024-04-19 14:58:08 -0400 |
---|---|---|
committer | elioat <hi@eli.li> | 2024-04-19 14:58:08 -0400 |
commit | 424301cbbe01a608cf7df8f4b3c9c2f856aa1740 (patch) | |
tree | b73e2e06c559d3b7ec391861458f202bb15bb977 /modal | |
parent | e80d2a31862110c8913358027905cbcf905274ce (diff) | |
download | tour-424301cbbe01a608cf7df8f4b3c9c2f856aa1740.tar.gz |
*
Diffstat (limited to 'modal')
-rw-r--r-- | modal/.gitignore | 1 | ||||
-rw-r--r-- | modal/logic.modal | 4 | ||||
-rw-r--r-- | modal/modal.c | 252 |
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 |