From 744572c99c8a161722455f905a7b6ff197f570a8 Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Apr 21 2024 16:35:04 +0000 Subject: bytebeat --- diff --git a/simple/bytebeat/build.sh b/simple/bytebeat/build.sh new file mode 100755 index 0000000..47bf2bb --- /dev/null +++ b/simple/bytebeat/build.sh @@ -0,0 +1 @@ +cc -Wall -O3 -DNDEBUG -lm main.c -o bytebeat diff --git a/simple/bytebeat/example.sh b/simple/bytebeat/example.sh new file mode 100755 index 0000000..4ebce02 --- /dev/null +++ b/simple/bytebeat/example.sh @@ -0,0 +1,3 @@ + +#./bytebeat 0 '10*(t>>6|t|t>>(t>>16))+(7&t>>11)' | aplay +./bytebeat 0 '(t<<3)*[8/9,1,9/8,6/5,4/3,3/2,0][[0xd2d2c8,0xce4088,0xca32c8,0x8e4009][t>>14&3]>>(0x3dbe4688>>((t>>10&15)>9?18:t>>10&15)*3&7)*3&7]' | aplay diff --git a/simple/bytebeat/funcs.c b/simple/bytebeat/funcs.c new file mode 100644 index 0000000..7f74dc1 --- /dev/null +++ b/simple/bytebeat/funcs.c @@ -0,0 +1,177 @@ + +#include "lexer.c" + + +typedef enum { + T_U32, + T_F32, +} Type; + +typedef enum { + M_VALUE = 0, + M_ARRAY, + M_INDEX, + M_PREFIX, + M_BINARY, + M_TERNARY, + M_FUNC, + M_FUNC2, +} Mode; + +typedef struct { + Type type; + union { + U32 u; + F32 f; + }; +} Var; + +typedef struct { + U32 t; + Var a, b, c; +} Params; + +typedef Var (*Func)(Params p); + +typedef struct { + Mode mode; + int priority; + const char *key; + Func func; + U32 k; +} OpDesc; + + + +static inline Var vari(U32 u) + { Var v; v.type = T_U32; v.u = u; return v; } +static inline Var varf(F32 f) + { Var v; v.type = T_F32; v.f = f; return v; } + +static inline int isint(Var v) + { return v.type == T_U32; } +static inline int isflt(Var v) + { return v.type == T_F32; } +static inline int isflt2(Var a, Var b) + { return isflt(a) || isflt(b); } + +static inline U32 asint(Var v) + { return isflt(v) ? (U32)v.f : v.u; } +static inline F32 asflt(Var v) + { return isflt(v) ? v.f : (F32)v.u; } + + + +Var f_var(Params p) + { return vari(p.t); } + +Var f_neg(Params p) + { return isflt(p.a) ? varf(-p.a.f) : vari(-p.a.u); } +Var f_pos(Params p) + { return p.a; } +Var f_not(Params p) + { return vari(~p.a.u); } +Var f_boolnot(Params p) + { return vari(!p.a.u); } +Var f_casti(Params p) + { return vari(asint(p.a)); } +Var f_castf(Params p) + { return vari(asflt(p.a)); } + +Var f_mul(Params p) + { return isflt2(p.a, p.b) ? varf(asflt(p.a) * asflt(p.b)) : vari(asint(p.a) * asint(p.b)); } +Var f_div(Params p) + { F32 a = asflt(p.a), b = asflt(p.b); return varf(b ? a/b : a); } +Var f_mod(Params p) + { U32 a = asint(p.a), b = asint(p.b); return vari(b ? a%b : a); } + +Var f_add(Params p) + { return isflt2(p.a, p.b) ? varf(asflt(p.a) + asflt(p.b)) : vari(asint(p.a) + asint(p.b)); } +Var f_sub(Params p) + { return isflt2(p.a, p.b) ? varf(asflt(p.a) - asflt(p.b)) : vari(asint(p.a) - asint(p.b)); } + +Var f_shl(Params p) + { return vari(asint(p.a) << asint(p.b)); } +Var f_shr(Params p) + { return vari(asint(p.a) >> asint(p.b)); } + +Var f_lt(Params p) + { return isflt2(p.a, p.b) ? vari(asflt(p.a) < asflt(p.b)) : vari(asint(p.a) < asint(p.b)); } +Var f_gt(Params p) + { return isflt2(p.a, p.b) ? vari(asflt(p.a) > asflt(p.b)) : vari(asint(p.a) > asint(p.b)); } +Var f_leq(Params p) + { return isflt2(p.a, p.b) ? vari(asflt(p.a) <= asflt(p.b)) : vari(asint(p.a) <= asint(p.b)); } +Var f_geq(Params p) + { return isflt2(p.a, p.b) ? vari(asflt(p.a) >= asflt(p.b)) : vari(asint(p.a) >= asint(p.b)); } + +Var f_eq(Params p) + { return vari(p.a.u == p.b.u); } +Var f_neq(Params p) + { return vari(p.a.u != p.b.u); } + +Var f_and(Params p) + { return vari(asint(p.a) & asint(p.b)); } +Var f_xor(Params p) + { return vari(asint(p.a) ^ asint(p.b)); } +Var f_or(Params p) + { return vari(asint(p.a) | asint(p.b)); } + +Var f_booland(Params p) + { return vari(p.a.u && p.b.u); } +Var f_boolor(Params p) + { return vari(p.a.u || p.b.u); } + +Var f_cond(Params p) + { return isflt2(p.b, p.c) ? (p.a.u ? varf(asflt(p.b)) : varf(asflt(p.c))) : (p.a.u ? vari(asint(p.b)) : vari(asint(p.c))); } + + +OpDesc ops[] = { + { M_VALUE, 0, "" }, + { M_VALUE, 0, "t", f_var }, + + { M_ARRAY, 0, "[" }, + { M_INDEX, 1, "[" }, + + { M_PREFIX, 2, "+", f_pos }, + { M_PREFIX, 2, "-", f_neg }, + { M_PREFIX, 2, "~", f_not }, + { M_PREFIX, 2, "!", f_boolnot }, + { M_PREFIX, 2, "(U32)", f_casti }, + { M_PREFIX, 2, "(int)", f_casti }, + { M_PREFIX, 2, "(unsigned)", f_casti }, + { M_PREFIX, 2, "(unsigned int)", f_casti }, + { M_PREFIX, 2, "(F32)", f_castf }, + { M_PREFIX, 2, "(float)", f_castf }, + { M_PREFIX, 2, "(double)", f_castf }, + + { M_BINARY, 3, "*", f_mul }, + { M_BINARY, 3, "/", f_div }, + { M_BINARY, 3, "%", f_mod }, + + { M_BINARY, 4, "+", f_add }, + { M_BINARY, 4, "-", f_sub }, + + { M_BINARY, 5, "<<", f_shl }, + { M_BINARY, 5, ">>", f_shr }, + + { M_BINARY, 6, "<", f_lt }, + { M_BINARY, 6, ">", f_gt }, + { M_BINARY, 6, "<=", f_leq }, + { M_BINARY, 6, ">=", f_geq }, + + { M_BINARY, 7, "==", f_eq }, + { M_BINARY, 7, "!=", f_neq }, + + { M_BINARY, 8, "&", f_and }, + { M_BINARY, 9, "^", f_xor }, + { M_BINARY, 10, "|", f_or }, + { M_BINARY, 11, "&&", f_booland }, + { M_BINARY, 12, "||", f_boolor }, + + { M_TERNARY, 13, "?", f_cond }, +}; +int opsCnt = sizeof(ops)/sizeof(*ops); + + + + diff --git a/simple/bytebeat/lexer.c b/simple/bytebeat/lexer.c new file mode 100644 index 0000000..008668a --- /dev/null +++ b/simple/bytebeat/lexer.c @@ -0,0 +1,208 @@ + +#include +#include +#include +#include +#include +#include + + + +typedef unsigned int U32; +typedef float F32; + + +typedef enum { + LT_NONE = 0, + LT_KEY, + LT_INT, + LT_FLOAT, +} LexType; + + +typedef struct { + LexType type; + union { + U32 u; + F32 f; + }; +} Lex; + + +typedef struct { + Lex *data; + size_t size; +} LexList; + + +const char **keys; +int keysCnt; + + + +static inline int iskey(const Lex *l, U32 k) + { return l && l->type == LT_KEY && l->u == k; } + +static inline const char* skipSpaces(const char *s) + { while(isspace(*s)) ++s; return s; } + + +void lexPrint(const Lex *l, FILE *f) { + if (!f) f = stdout; + switch(l->type) { + case LT_NONE: + fprintf(f, "[none]"); + break; + case LT_KEY: + if (l->u < keysCnt) fprintf(f, "[key:%d:%s]", l->u, keys[l->u]); + else fprintf(f, "[key:%d]", l->u); + break; + case LT_INT: + fprintf(f, "[int:%x:%d]", l->u, l->u); + break; + case LT_FLOAT: + fprintf(f, "[float:%x:%g]", l->u, l->f); + break; + default: + fprintf(f, "[unknown:%u:%08x]", l->type, l->u); + break; + } +} + + +void lexChainPrint(const Lex *l, FILE *f) { + do { lexPrint(l, f); } while((l++)->type); +} + + +int lexParseEnd(Lex *l, const char **p) { + const char *s = skipSpaces(*p); + if (*s) return 0; + l->type = LT_NONE; + *p = s; + return 1; +} + + +int lexParseKey(Lex *l, const char **p) { + const char *s = skipSpaces(*p); + size_t maxlen = 0; + U32 key = 0; + for(U32 i = 1; i < keysCnt; ++i) { + size_t len = strlen(keys[i]); + if (len > maxlen && 0 == strncmp(s, keys[i], len)) + { key = i; maxlen = len; } + } + if (!key) return 0; + l->type = LT_KEY; + l->u = key; + *p = s + maxlen; + return 1; +} + + +int lexParseNum(Lex *l, const char **p) { + const char *s = skipSpaces(*p); + const char *s0 = s; + + U32 factor = 10; + if (*s == '0') { + ++s; + if (*s >= '0' && *s <= '7') factor = 8; else + if (*s == 'x' || *s == 'X') { s0 = ++s; factor = 16; } + } + + U32 iv = 0; + double fv = 0; + while(1) { + U32 d = 0; + if (*s >= '0' && *s <= '9') d = *s - '0'; else + if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10; else + if (*s >= 'A' && *s <= 'F') d = *s - 'A' + 10; else + break; + if (d >= factor) break; + iv = iv*factor + d; + fv = fv*factor + d; + ++s; + } + + int success = 0; + if (s > s0) { + l->type = LT_INT; + l->u = iv; + *p = s; + success = 1; + } + if (factor != 10) return success; + s0 = s; + + if (*s == '.') { + ++s; + double f = 1; + while(*s >= '0' && *s <= '9') + fv += (f *= 0.1)*(*s++ - '0'); + } + + if (s > s0 && (*s == 'e' || *s == 'E')) { + double e = 0; + double sign = (*s == '-' || *s == '+') && (*s++ == '-') ? -1 : 1; + s0 = s; + while(*s >= '0' && *s <= '9') + e = e*10 + (*s++ - '0'); + fv *= pow(10, e*sign); + } + + if (s <= s0) return success; + if (*s == 'f') ++s; + + l->type = LT_FLOAT; + l->f = fv; + *p = s; + return 1; +} + + + + +void lexListDeinit(LexList *ll) + { free(ll->data); memset(ll, 0, sizeof(*ll)); } + + +Lex* lexListAdd(LexList *ll) { + ++ll->size; + ll->data = (Lex*)realloc(ll->data, sizeof(*ll->data) * ll->size); + if (!ll->data) { fprintf(stderr, "out of memory\n"); exit(1); } + Lex *l = ll->data + ll->size - 1; + memset(l, 0, sizeof(*l)); + return l; +} + + +void lexListPrint(const LexList *ll, FILE *f) { + if (!f) f = stdout; + fprintf(f, "count %zu: ", ll->size); + for(size_t i = 0; i < ll->size; ++i) + lexPrint(ll->data + i, f); + fprintf(f, "\n"); +} + + +int lexListParse(LexList *ll, const char *s) { + lexListDeinit(ll); + Lex *l = lexListAdd(ll); + while(1) { + if (lexParseEnd(l, &s)) break; + if (!lexParseKey(l, &s) && !lexParseNum(l, &s)) + { fprintf(stderr, "lex parse error at: %s\n", s); return 0; } + l = lexListAdd(ll); + } + return 1; +} + + +Lex* lexParse(const char *s) { + LexList ll = {}; + lexListParse(&ll, s); + return ll.data; +} + diff --git a/simple/bytebeat/main.c b/simple/bytebeat/main.c new file mode 100644 index 0000000..b8dc007 --- /dev/null +++ b/simple/bytebeat/main.c @@ -0,0 +1,47 @@ + +#include "parser.c" + + +void run(U32 count, const char *code) { + prepareKeys(); + Lex *l = lexParse(code); + //lexChainPrint(l, stderr); fprintf(stderr, "\n"); + Op *op = opParse(l); + //opPrint(op, stderr, 0); + for(U32 t = 0; !count || t < count; ++t) + fputc(asint(opCall(op, t)) & 0xff, stdout); + opDestroy(op); + free(l); +} + + +void run2(U32 count, const char *codeL, const char *codeR) { + prepareKeys(); + Lex *ll = lexParse(codeL); + Lex *lr = lexParse(codeR); + Op *opl = opParse(ll); + Op *opr = opParse(lr); + for(U32 t = 0; !count || t < count; ++t) { + fputc(asint(opCall(opl, t)) & 0xff, stdout); + fputc(asint(opCall(opr, t)) & 0xff, stdout); + } + opDestroy(opl); + opDestroy(opr); + free(ll); + free(lr); +} + + + +int main(int argc, char **argv) { + if (argc < 3 || argc > 4) { + fprintf(stderr, "Usage:\n bytebeat []\n"); + exit(1); + } + + U32 count = (U32)atoll(argv[1]); + if (argc >= 4) run2(count, argv[2], argv[3]); + else run(count, argv[2]); + return 0; +} + diff --git a/simple/bytebeat/parser.c b/simple/bytebeat/parser.c new file mode 100644 index 0000000..1099a15 --- /dev/null +++ b/simple/bytebeat/parser.c @@ -0,0 +1,331 @@ + + +#include "funcs.c" + + +enum { + K_NONE = 0, + K_POPEN, + K_PCLOSE, + K_BPOPEN, + K_BCLOSE, + K_COMMA, + K_COLON, +}; +const char *baseKeys[] = { "", "(", ")", "[", "]", ",", ":" }; + + +typedef struct Op { + const OpDesc *desc; + Var v; + struct Op *a, *b, *c; +} Op; + + + +void prepareKeys() { + if (keys) return; + keys = (const char**)calloc(1, sizeof(baseKeys) + sizeof(char*)*opsCnt); + if (!keys) { fprintf(stderr, "out of memory\n"); exit(1); } + memcpy(keys, baseKeys, sizeof(baseKeys)); + keysCnt = sizeof(baseKeys)/sizeof(*baseKeys); + + for(int i = 0; i < opsCnt; ++i) { + OpDesc *d = &ops[i]; + d->k = 0; + if (!d->key || !*d->key) continue; + for(int j = 1; j < keysCnt; ++j) + if (0 == strcmp(keys[j], d->key)) { d->k = j; break; } + if (!d->k) { + d->k = keysCnt; + keys[keysCnt++] = d->key; + } + } +} + + + +Op* opCreate(const OpDesc *d) { + Op *op = (Op*)calloc(1, sizeof(*op)); + if (!op) { fprintf(stderr, "out of memory\n"); exit(1); } + op->desc = d; + return op; +} + + +void opDestroy(Op *op) { + if (!op) return; + opDestroy(op->a); + opDestroy(op->b); + opDestroy(op->c); + free(op); +} + + +Var opCall(Op *op, U32 t); + + +Op* opSubItem(Op *op, U32 t, U32 idx) { + while(op && op->desc) { + if (op->desc->mode == M_ARRAY) { + while(op && idx) { op = op->b; --idx; } + return op ? op->a : op; + } else + if (op->desc->mode == M_INDEX) { + U32 i = asint(opCall(op->b, t)); + op = opSubItem(op->a, t, i); + } else { + return op; + } + } + return NULL; +} + + +Var opCall(Op *op, U32 t) { + if (!op || !op->desc) return vari(0); + if (!op->desc->func) { + if (op->desc->mode == M_INDEX) { + U32 idx = asint(opCall(op->b, t)); + Op *o = opSubItem(op->a, t, idx); + return opCall(o, t); + } + if (op->desc->mode == M_ARRAY) + return opCall(op->a, t); + return op->v; + } + Params p = { t, opCall(op->a, t), opCall(op->b, t), opCall(op->c, t) }; + return op->desc->func(p); +} + + +void opPrint(Op *op, FILE *f, int level) { + if (!f) f = stdout; + for(int i = 0; i < level; ++i) + fprintf(f, " "); + if (!op || !op->desc) + { fprintf(f, "nop\n"); return; } + if (!op->desc->func && op->desc->mode != M_ARRAY && op->desc->mode != M_INDEX) + { fprintf(f, "value: %d, %d, %g\n", op->v.type, op->v.u, op->v.f); return; } + fprintf(f, "%d:%d:%s:\n", op->desc->mode, op->desc->priority, op->desc->key); + ++level; + opPrint(op->a, f, level); + opPrint(op->b, f, level); + opPrint(op->c, f, level); +} + + +Op* opParsePart(const Lex **l, int priority); + + +Op* opParseParentheses(const Lex **p) { + const Lex *l = *p; + if (iskey(l++, K_POPEN)) { + Op *op = opParsePart(&l, INT_MAX); + if (op && iskey(l++, K_PCLOSE)) + return *p = l, op; + opDestroy(op); + } + return NULL; +} + + +Op* opParseValue(const Lex **p, const OpDesc *d) { + const Lex *l = *p; + if ( d->k ? iskey(l, d->k) : (l->type == LT_INT || l->type == LT_FLOAT) ) { + Op *op = opCreate(d); + op->v.type = l->type == LT_FLOAT ? T_F32 : T_U32; + op->v.u = l->u; + return *p = l + 1, op; + } + return NULL; +} + + +Op* opParseArray(const Lex **p, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k)) { + Op *op = opCreate(d), *o = op; + while(1) { + o->a = opParsePart(&l, INT_MAX); + if (iskey(l, K_BCLOSE)) return *p = l + 1, op; + if (!iskey(l++, K_COMMA)) break; + o->b = opCreate(d); + o = o->b; + }; + opDestroy(op); + } + return NULL; +} + + +Op* opParseIndex(const Lex **p, Op *a, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k)) { + Op *b = opParsePart(&l, INT_MAX); + if (b && iskey(l++, K_BCLOSE)) { + Op *op = opCreate(d); + op->a = a; + op->b = b; + return *p = l, op; + } + opDestroy(b); + } + return NULL; +} + + +Op* opParsePrefix(const Lex **p, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k)) { + Op *sub = opParsePart(&l, d->priority); + if (sub) { + Op *op = opCreate(d); + op->a = sub; + return *p = l, op; + } + } + return NULL; +} + + +Op* opParseBinary(const Lex **p, Op *a, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k)) { + Op *b = opParsePart(&l, d->priority); + if (b) { + Op *op = opCreate(d); + if (b->desc->priority == d->priority) { + op->a = a; + op->b = b->a; + b->a = op; + op = b; + } else { + op->a = a; + op->b = b; + } + return *p = l, op; + } + } + return NULL; +} + + +Op* opParseTernary(const Lex **p, Op *a, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k)) { + Op *b = opParsePart(&l, d->priority - 1); + if (b && iskey(l++, K_COLON)) { + Op *c = opParsePart(&l, d->priority); + if (c) { + Op *op = opCreate(d); + op->a = a; + op->b = b; + op->c = c; + return *p = l, op; + } + } + opDestroy(b); + } + return NULL; +} + + +Op* opParseFunc(const Lex **p, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k) && iskey(l++, K_POPEN)) { + Op *sub = opParsePart(&l, INT_MAX); + if (sub && iskey(l++, K_PCLOSE)) { + Op *op = opCreate(d); + op->a = sub; + return *p = l, op; + } + opDestroy(sub); + } + return NULL; +} + + +Op* opParseFunc2(const Lex **p, const OpDesc *d) { + const Lex *l = *p; + if (iskey(l++, d->k) && iskey(l++, K_POPEN)) { + Op *a = opParsePart(&l, INT_MAX); + if (a && iskey(l++, K_COMMA)) { + Op *b = opParsePart(&l, INT_MAX); + if (b && iskey(l++, K_PCLOSE)) { + Op *op = opCreate(d); + op->a = a; + op->b = b; + return *p = l, op; + } + opDestroy(b); + } + opDestroy(a); + } + return NULL; +} + + +Op* opParsePart(const Lex **p, int priority) { + //static int level = 0; + //printf("opParsePart:%d:%d:", level, priority); + //lexChainPrint(*p, NULL); + //printf("\n"); + //++level; + + const Lex *l = *p; + Op *op = opParseParentheses(&l); + for(int i = 0; i < opsCnt; ++i) { + //printf(" i = %d\n", i); + const OpDesc *d = &ops[i]; + if (d->priority > priority) break; + switch(d->mode) { + case M_VALUE: + if (!op) op = opParseValue(&l, d); + break; + case M_ARRAY: + if (!op) op = opParseArray(&l, d); + break; + case M_INDEX: + if (op) { + Op *o = opParseIndex(&l, op, d); + if (o) { op = o; i = 0; } + } + break; + case M_PREFIX: + if (!op) op = opParsePrefix(&l, d); + break; + case M_BINARY: + if (op) { + Op *o = opParseBinary(&l, op, d); + if (o) { op = o; i = 0; } + } + break; + case M_TERNARY: + if (op) { + Op *o = opParseTernary(&l, op, d); + if (o) { op = o; i = 0; } + } + break; + case M_FUNC: + if (!op) op = opParseFunc(&l, d); + break; + case M_FUNC2: + if (!op) op = opParseFunc2(&l, d); + break; + } + } + if (op) *p = l; + + //--level; + return op; +} + + +Op* opParse(const Lex *l) { + Op *op = opParsePart(&l, INT_MAX); + if (!op || l->type != LT_NONE) + { fprintf(stderr, "parse error at: "); lexChainPrint(l, stderr); fprintf(stderr, "\n"); } + return op; +} +