diff --git a/.gitignore b/.gitignore index a13e547..8e5688b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -bin -bin/* +bin/blang +build +build/* diff --git a/Makefile b/Makefile index 6a59115..3b07632 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,16 @@ all: $(TARGETS) clean: $(RM) $(TARGETS) -bin: - mkdir -p bin +build: + mkdir -p build -bin/blang: bin src/*.c - $(CC) $(CFLAGS) -o $@ src/*.c +build/blang.o: build src/blang.c src/blang.h + $(CC) -c -o $@ src/blang.c + +build/ops.o: build src/blang.h src/ops.c src/ops.h + $(CC) -c -o $@ src/ops.c + +bin/blang: build/blang.o build/ops.o + $(CC) $(CFLAGS) -o $@ build/*.o .PHONY: all clean diff --git a/README.md b/README.md index 858a041..dd624ba 100644 --- a/README.md +++ b/README.md @@ -12,21 +12,22 @@ the bang language Public domain. 2022 DTB. -# Examples +## Examples -## true(1) +### true(1) ``` -^ ; initialize state to 0 -% ; store state (0) into *stack -; stack is destroyed, state becomes the final value of *stack -; when the stack is destroyed, the program exits with the value of state -$ +; initialize hand to 0 +^ + +; set the chart pointer to 0 - this destroys the chart +; and the program exits with the value of the hand +* ``` -## Hello world: +### Hello world: ``` -; the <.> construct uses '<' to store the next value literally into state, -; does so, and uses '>' to output state literally +; the <.> construct uses '<' to literally 'palm' the next value +; (store into hand), does so, and uses '>' to 'toss' (output hand's value) <,>< >< ->^%$ +>^* ``` diff --git a/bin/blangfile b/bin/blangfile new file mode 100755 index 0000000..329e92f --- /dev/null +++ b/bin/blangfile @@ -0,0 +1,3 @@ +#!/bin/sh + +blang "$(cat "$@")" diff --git a/example/hello_world.blang b/example/hello_world.blang new file mode 100644 index 0000000..0c7b749 --- /dev/null +++ b/example/hello_world.blang @@ -0,0 +1,2 @@ +<,>< >< +>^* diff --git a/example/true.blang b/example/true.blang new file mode 100644 index 0000000..c01d48b --- /dev/null +++ b/example/true.blang @@ -0,0 +1,2 @@ +#!/usr/bin/env blangfile +^* diff --git a/src/blang.c b/src/blang.c index 400bf44..88a48ef 100644 --- a/src/blang.c +++ b/src/blang.c @@ -1,42 +1,24 @@ +#include #include #include -static unsigned char get = 0; -static unsigned char _stack[4]; -static unsigned char *stack = _stack; -static unsigned char *state; +#include "blang.h" +#include "ops.h" -int main(){ +int main(int argc, char **argv){ + struct State s; int c; - while((c = getchar()) != EOF){ - if(stack == (unsigned char *)0) - return (char)state; - if(get){ - state = (char *)c; - get = 0; - continue; - } - switch(c){ - case ' ': - case '\n': - case '\r': - case '\t': - case '\v': - break; - case '!': state = stack; break; - case '$': stack = state; state = (char *)*_stack; break; - case '%': *stack = (char)state; break; - case '^': state = (char *)0; break; - case '+': ++state; break; - case '-': --state; break; - case '>': putchar((char)state); break; - case '<': get = 1; break; - case ':': - while((c = getchar()) != '\n') - if(c == EOF) - goto fin; - break; - } + void (*op)(struct State *); + + s.chart = *(argv+1); + s.counter = s.chart; + + for(s.counter = s.chart; ; ++s.counter){ + if(s.chart == (char *)0) + return (int)s.hand; + if((op = Ops_lookup(*s.counter)) == NULL) + return 127; + else + op(&s); } -fin: return 1; } diff --git a/src/blang.h b/src/blang.h new file mode 100644 index 0000000..1179111 --- /dev/null +++ b/src/blang.h @@ -0,0 +1,17 @@ +#if !defined _BLANG_H +# define _BLANG_H +# include +/* This has to be big enough to hold a char * without degradation. + * Adjust to architecture/system/environment/etc. */ +typedef uint64_t hand_t; + +/* Holds *argv; will not change between environments. */ +typedef char * chart_t; + +struct State{ + chart_t chart; + chart_t point; + chart_t counter; + hand_t hand; +}; +#endif diff --git a/src/ops.c b/src/ops.c new file mode 100644 index 0000000..998edc1 --- /dev/null +++ b/src/ops.c @@ -0,0 +1,112 @@ +#include +#include +#include + +#include "blang.h" + +/* no-op */ +void Ops_bang(struct State *s){ + return; +} + +void Ops_percent(struct State *s){ + *(s->chart) = s->hand; +} + +void Ops_carat(struct State *s){ + s->hand = 0; +} + +void Ops_ampersand(struct State *s){ + s->hand = (uint64_t)s->chart; +} + +void Ops_splat(struct State *s){ + s->chart = (char *)s->hand; +} + +void Ops_plus(struct State *s){ + ++(s->hand); +} + +void Ops_dash(struct State *s){ + --(s->hand); +} + +void Ops_lbrack(struct State *s){ + s->point = s->counter; +} + +void Ops_rbrack(struct State *s){ + s->counter = s->point; +} + +void Ops_left(struct State *s){ + s->hand = *++s->counter; +} + +void Ops_right(struct State *s){ + putc((char)s->hand, stdout); +} + +void Ops_what(struct State *s){ + if(!s->hand) + ++(s->counter); +} + +void Ops_semi(struct State *s){ + int c; + + while(strchr("!\n", *++s->counter) == NULL); +} + +void Ops_mirror(struct State *s){ + s->hand = !s->hand; +} + +void Ops_cross(struct State *s){ + char *i; + i = s->chart; + s->chart = (char *)s->hand; + s->hand = (uint64_t)i; +} + +const struct { + unsigned char name; + void (*f)(struct State *); +} OPS[] = { + { '#', Ops_semi }, + { '%', Ops_percent }, + { '^', Ops_carat }, + { '&', Ops_ampersand }, + { '*', Ops_splat }, + { '+', Ops_plus }, + { '-', Ops_dash }, + { '{', Ops_lbrack }, + { '}', Ops_rbrack }, + { ';', Ops_semi }, + { '>', Ops_right }, + { '<', Ops_left }, + { '?', Ops_what }, + { 'v', Ops_mirror }, + { '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 (*Ops_lookup(char op))(struct State *){ + 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..a318965 --- /dev/null +++ b/src/ops.h @@ -0,0 +1,4 @@ +#if !defined _BLANG_OPS +# define _BLANG_OPS 1 +void (*Ops_lookup(char op))(struct State *); +#endif