diff --git a/examples/rules.modal b/examples/rules.modal new file mode 100644 index 0000000..2e01a22 --- /dev/null +++ b/examples/rules.modal @@ -0,0 +1,19 @@ +<> rule0 data +<> rule1 data-1 +<> rule2 +<> rule3 data-10 +<> rule4 data-100 + +?(?-) (Undefine an empty rule) + +>< rule2 + +?(?-) (Undefine the last rule) + +>< rule4 + +?(?-) (Undefine a non-existant rule) + +>< rule5 + +a sample program \ No newline at end of file diff --git a/makefile b/makefile index b785838..ccee82f 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ dest: run: all bin/modal @ bin/modal -q examples/hello.modal debug: all bin/modal-debug - @ bin/modal-debug examples/hello.modal + @ bin/modal-debug examples/rules.modal test: all bin/modal-debug bin/modal @ bin/modal -v @ bin/modal-debug -q examples/fizzbuzz.modal diff --git a/src/modal.c b/src/modal.c index 451279b..0a9ab35 100644 --- a/src/modal.c +++ b/src/modal.c @@ -22,6 +22,15 @@ copy(char *src, char *dst, int length) return dst; } +static int +slen(char *s) +{ + char *cap = s; + while(*cap++) + ; + return cap - s; +} + static char * walk(char *s) { @@ -233,10 +242,10 @@ parse_frag(char **side, char *s) { char c, *cap; while((c = *s) && c == ' ') s++; - if(c == ')') { + if(c == ')' || (c == '<' && s[1] == '>') || (c == '>' && s[1] == '<')) { *side = NULL; return s; - } else if((c == '<' && s[1] == '>') || (c == '>' && s[1] == '<') || (c == '(' && s[1] == ')')) { + } else if((c == '(' && s[1] == ')')) { *side = NULL; return s + 2; } else { @@ -257,14 +266,31 @@ find_rule(char *s, char *cap) if(*s == '(') s++, cap--; while(r < rules_) { char *ss = s, *a = r->a; - if(a) - while(*ss++ == *a++) - if(!*a && ss == cap) return r; + while(*ss++ == *a++) + if(!*a && ss == cap) return r; r++; } return NULL; } +static void +remove_rule(Rule *r) +{ + if(r < rules_ - 1) { + int distance = slen(r->a) + (r->b != NULL ? slen(r->b) : 0); + char *memsrc = (r + 1)->a; + copy(memsrc, r->a, dict_ - memsrc); + while(r < rules_ - 1) { + Rule *next = r + 1; + r->id = next->id, r->refs = next->refs; + r->a = next->a - distance; + r->b = next->b == NULL ? NULL : next->b - distance; + r++; + } + } + rules_--; +} + static int rewrite(void) { @@ -272,7 +298,7 @@ rewrite(void) while(*s == ' ') s++; while((c = *s)) { if(c == '(' || spacer(last)) { - Rule *r = NULL; + Rule *r; /* phase: undefine */ if(c == '>' && s[1] == '<') { s += 2; @@ -280,7 +306,7 @@ rewrite(void) cap = walk(s), r = find_rule(s, cap); if(r != NULL) { if(!quiet) fprintf(stderr, ">< (%s) (%s)\n", r->a ? r->a : "", r->b ? r->b : ""); - r->a = 0; + remove_rule(r); } while(*cap == ' ') cap++; return write_tail(cap); @@ -310,7 +336,7 @@ rewrite(void) } /* phase: match */ for(r = rules; r < rules_; r++) - if(r->a != NULL && apply_rule(r, s)) return 1; + if(apply_rule(r, s)) return 1; } *dst_++ = last = c, s++; } @@ -326,7 +352,7 @@ main(int argc, char **argv) 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, 17 May 2024.\n"); + case 'v': /* version */ return !printf("Modal Interpreter, 21 May 2024.\n"); case 'q': /* quiet */ quiet = 1; break; case 'p': /* debug */ debug = 1; break; case 'a': /* access */ access = 1; break;