diff --git a/src/ops.c b/src/ops.c new file mode 100644 index 0000000..001dc3b --- /dev/null +++ b/src/ops.c @@ -0,0 +1,90 @@ +#include +#include + +#include "blang.h" + +/* no-op */ +void Ops_bang(struct State *s){ + return; +} + +void Ops_dollar(struct State *s){ + s->chart = (char *)0; +} + +void Ops_percent(struct State *s){ + *(s->chart) = s->hand; +} + +void Ops_carat(struct State *s){ + s->state = 0; +} + +void Ops_ampersand(struct State *s){ + s->hand = s->chart; +} + +void Ops_plus(struct State *s){ + ++(s->state); +} + +void Ops_dash(struct State *s){ + --(s->state); +} + +void Ops_right(struct State *s){ + putc((char)s->state, stdout); +} + +void Ops_left(struct State *s){ + s->state = getc(stdin); +} + +void Ops_semi(struct State *s){ + while( + (c = getc(stdin)) != EOF + && strchr("!\n", c) == NULL + ); +} + +void Ops_cross(struct State *s){ + char *i; + i = s->chart; + s->chart = (char *)s->hand; + s->hand = (unsigned char)i; +} + +const struct { + unsigned char name; + void (*f)(struct State *); +} *OPS[] = { + { '$', Ops_dollar }, + { '%', Ops_percent }, + { '^', Ops_caret }, + { '&', Ops_ampersand }, + { '*', Ops_splat }, + { '+', Ops_plus }, + { '-', Ops_dash }, + { '>', Ops_right }, + { '<', Ops_left }, + { 'x', Ops_cross }, + + /* no-ops */ + { '!', Ops_bang }, + { ' ', Ops_bang }, + { '\n', Ops_bang }, + { '\r', Ops_bang }, + { '\t', Ops_bang }, + { '\v', Ops_bang } +}; + +/* Slower than a switch but you don't have to update it when you add new + * ops! */ +(void(struct State *)) Ops_lookup(char op){ + size_t i; + + for(i = 0; i < (sizeof OPS)/(sizeof *OPS); ++i) + if(op == OPS[i].name) + return OPS[i].f; + return NULL; +} diff --git a/src/ops.h b/src/ops.h new file mode 100644 index 0000000..0afee19 --- /dev/null +++ b/src/ops.h @@ -0,0 +1,4 @@ +#if !defined _BLANG_OPS +# define _BLANG_OPS 1 +(void(struct State *)) Ops_lookup(char op); +#endif