/* satu: string analyzing table generator vi: set ts=8 sw=8: */ /* satu--string analyzing table generator * Copyright (C) 2003 Peter Backes * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #define TABCAP 128 /* Should be plenty */ typedef unsigned char tab_t[256]; static struct variab { char ident[16]; tab_t data; } table[TABCAP]; struct parstat { char error[84]; int ln; const char *fn; FILE *co, *ho; }; /* Sets range to specified values. * f: field * b: begin * e: end * s: start value * r: increment value */ void setrng(tab_t *f, int b, int e, int s, int r) { for (e = e < b ? b : e; b <= e; s += r) (*f)[b++] = s; } /* % comment * ^val rise operator * & bitwise and * | bitwise or * ! logical complement * #a m) m = (*l)[i]; for (i = 0; i < sizeof *r; i++) if ((*r)[i] != s) (*r)[i] = m + (*r)[i]; } void rotate(tab_t *l) { int i; for (i = 0; i < sizeof *l; i++) if ((*l)[i]) (*l)[i]--; else (*l)[i] = 0xFF; } void comple(tab_t *l) { int i; for (i = 0; i < sizeof *l; i++) (*l)[i] = !(*l)[i]; } void bitwor(tab_t *l, /*const*/ tab_t *r) { int i; for (i = 0; i < sizeof *l; i++) (*l)[i] |= (*r)[i]; } void bitwnd(tab_t *l, /*const*/ tab_t *r) { int i; for (i = 0; i < sizeof *l; i++) (*l)[i] &= (*r)[i]; } /* Multiplies table with a scalar. */ void settab(tab_t *l, /*const*/ tab_t *r, int s) { int i; for (i = 0; i < sizeof *l; i++) (*l)[i] = (*r)[i] * s; } struct variab *findvar(char *ident) { struct variab *curr; for (curr = table; curr < table + TABCAP; curr++) if (!strcmp(curr->ident, ident)) return curr; else if (!*curr->ident) break; return NULL; } int isident(int c) { return isalnum(c) || c == '_'; } const char *lex(const char *b, char *s, int (*c)(int), int (*d)(int), int l) { /* b: bottom of input. * s: symbol storage buffer. * c: character set constraining topmost character. * d: character set of word to scan, NULL if nothing * is to be matched. * l: symbol length restriction. */ register const char *t = b; /* Skip leading space. */ while (isspace(*t) && *t != '\r' && *t != '\n') t++; /* On zero length restriction, only report position behind space. */ if (!l) return t; if (!(*c)(*t)) return NULL; for (b = t, *s++ = *t++; t - b < l && d && (*d)(*t); *s++ = *t++); *s++ = '\0'; while (d && (*d)(*t)) t++; return t; } int getesc(int i) { switch (i) { case 'a': return '\a'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; case '0': return '\0'; default: return i; } } const char *gettab(tab_t *f, const char *top, struct parstat *ps) { int inve; /* invert flag. */ top += inve = *top == '!'; if (*top == '\'' && ((top[1] == '\\' && top[2] != '\0' && top[2] != '\n' && top[3] == '\'') || (top[1] != '\\' && top[1] != '\0' && top[1] != '\n' && top[2] == '\''))) { int b = (unsigned char) (*++top == '\\' ? getesc(*++top) : *top), e = b, r = 0, s; top++; if ((*++top == '-' || *top == '>') && top[1] == '\'' && ((top[2] == '\\' && top[3] != '\0' && top[3] != '\n' && top[4] == '\'') || (top[2] != '\\' && top[2] != '\0' && top[2] != '\n' && top[3] == '\''))) { r = *top++ == '>'; e = (unsigned char) *++top == '\\' ? getesc(*++top) : *top; top += 2; } if (!(s = *top != '=') && isdigit(*++top)) while (isdigit(*top)) s = *top++ - '0' + s * 10; setrng(f, b, e, s, r); } else if (isdigit(*top)) { int b = 0, e = 0, r = 0, s; while (isdigit(*top)) e = b = *top++ - '0' + b * 10; if ((*top == '-' || *top == '>') && isdigit(top[1])) { r = *top++ == '>'; e = 0; while (isdigit(*top)) e = *top++ - '0' + e * 10; } if (!(s = *top != '=') && isdigit(*++top)) while (isdigit(*top)) s = *top++ - '0' + s * 10; setrng(f, b, e, s, r); } else if (isalpha(*top)) { char ident[16], *dst = ident; struct variab *v; while (isalnum(*top) && dst < ident + sizeof ident - 1) *dst++ = *top++; *dst++ = '\0'; while (isalpha(*top)) top++; if ((v = findvar(ident)) == NULL) { snprintf(ps->error, sizeof ps->error, "undefined " "identifier '%s'", ident); return NULL; } if (*top == '=' && isdigit(*++top)) { int s = 0; while (isdigit(*top)) s = *top++ - '0' + s * 10; settab(f, &v->data, s); } else memcpy(f, v->data, sizeof v->data); } else return NULL; if (inve) comple(f); return top; } void output(struct parstat *ps, const char *n, const struct variab *v, int s) { int i; fprintf(ps->ho, "extern const unsigned char %s[%d];\n", n, s); fprintf(ps->co, "const unsigned char %s[%d] = {\n\t", n, s); switch (s) { case 32: for (i = 0; i < 32; i++) { /* Data base. */ const unsigned char *b = v->data + i * 8; fprintf(ps->co, "0x%02X", b[0] | b[1] << 1 | b[2] << 2 | b[3] << 3 | b[4] << 4 | b[5] << 5 | b[6] << 6 | b[7] << 7); if (i != 31) fprintf(ps->co, i % 8 == 7 ? ", \n\t" : ", "); } break; case 64: for (i = 0; i < 64; i++) { const unsigned char *b = v->data + i * 4; fprintf(ps->co, "0x%02X", b[0] | b[1] << 2 | b[2] << 4 | b[3] << 6); if (i != 63) fprintf(ps->co, i % 8 == 7 ? ", \n\t" : ", "); } break; case 128: for (i = 0; i < 128; i++) { const unsigned char *b = v->data + i * 2; fprintf(ps->co, "0x%02X", b[0] | b[1] << 4); if (i != 127) fprintf(ps->co, i % 8 == 7 ? ", \n\t" : ", "); } break; case 256: for (i = 0; i < 256; i++) { fprintf(ps->co, "0x%02X", v->data[i]); if (i != 255) fprintf(ps->co, i % 8 == 7 ? ", \n\t" : ", "); } break; } fprintf(ps->co, "\n};\n"); } const char *gen_dlst(const char *top, struct parstat *ps) { char name[32], buf[16], ident[16]; struct variab *v; int s = 0; top = lex(top, name, &isalpha, &isident, sizeof name - 1); if (top == NULL) return NULL; top = lex(top, buf, &ispunct, NULL, sizeof buf - 1); if (top == NULL || *buf != '[') return NULL; top = lex(top, buf, &isdigit, &isdigit, sizeof buf - 1); if (top == NULL) return NULL; else s = atoi(buf); top = lex(top, buf, &ispunct, NULL, sizeof buf - 1); if (top == NULL || *buf != ']') return NULL; top = lex(top, buf, &ispunct, NULL, sizeof buf - 1); if (top == NULL || *buf != '=') return NULL; top = lex(top, ident, &isalpha, &isalnum, sizeof ident - 1); if (top == NULL) return NULL; printf("[%s[%d] <== %s]\n", name, s, ident); if ((v = findvar(ident)) == NULL) printf("%s:%d: identifier %s undefined\n", ps->fn, ps->ln, ident); else output(ps, name, v, s); return lex(top, NULL, NULL, NULL, 0); } const char *gen_data(const char *top, struct parstat *ps) { /* data name[size]=ident, */ do if ((top = gen_dlst(top, ps)) == NULL) return NULL; while (*top++ == ','); return *--top != '%' && *top != '\n' && *top != '\0' ? NULL : top; } const char *gen_defl(const char *top, struct parstat *ps, tab_t *l) { unsigned char r[256] = {}; void (*op)(tab_t *l, /*const*/ tab_t *r); int rise; /* rise flag */ switch (*top++) { case '|': op = &bitwor; break; case '&': op = &bitwnd; break; default: return NULL; } top = lex(top, NULL, NULL, NULL, 0); top += rise = *top == '^'; if ((top = gettab(&r, top, ps)) == NULL) return NULL; if (rise) serial(l, &r, 0); (*op)(l, &r); return lex(top, NULL, NULL, NULL, 0); } const char *gen_def(const char *top, struct parstat *ps) { char ident[16]; struct variab *v; int rota; /* rotate flag */ unsigned char l[256] = {}; top = lex(top, ident, &isalpha, &isalnum, sizeof ident - 1); if (top == NULL) return NULL; top = lex(top, NULL, NULL, NULL, 0); top += rota = *top == '^'; if ((top = gettab(&l, top, ps)) == NULL) return NULL; top = lex(top, NULL, NULL, NULL, 0); while (*top == '|' || *top == '&') if ((top = gen_defl(top, ps, &l)) == NULL) return NULL; if (rota) rotate(&l); if ((v = findvar(ident)) == NULL && (v = findvar("")) == NULL) { printf("%s:%d: table capacity exceeded, no room for '%s'\n", ps->fn, ps->ln, ident); return top; } printf("[%s%s%s]\n", v->ident, v->ident ? "" : " <-- ", ident); strcpy(v->ident, ident); memcpy(v->data, l, sizeof l); return *top != '%' && *top != '\n' && *top != '\0' ? NULL : top; } void gen(const char *fn, FILE *si, FILE *co, FILE *ho) { struct parstat ps = {{}, 0, fn, co, ho}; char line[512], cmd[16]; const char *top; while ((top = fgets(line, sizeof line, si)) != NULL) { ps.ln++; top = lex(top, NULL, NULL, NULL, 0); if (*top == '%' || *top == '\n' || *top == '\0') continue; top = lex(top, cmd, &isalnum, &isalnum, sizeof cmd - 1); if (top != NULL) { if (!strcasecmp(cmd, "def")) top = gen_def(top, &ps); else if (!strcasecmp(cmd, "data")) top = gen_data(top, &ps); else printf("%s:%d: unknown keyword '%s'\n", ps.fn, ps.ln, cmd); } if (top == NULL) { printf("%s:%d: %s\n", fn, ps.ln, *ps.error ? ps.error : "syntax error"); *ps.error = '\0'; continue; } } } int main(int argc, char *argv[]) { const char *cofn = NULL, *hofn = NULL; /* c and h output file name */ FILE *si, *co, *ho; /* source input, c output, h output */ int opt; while ((opt = getopt(argc, argv, "o:h:")) != -1) switch (opt) { case 'o': cofn = optarg; break; case 'h': hofn = optarg; break; } if (cofn == NULL || hofn == NULL) { fprintf(stderr, "output unspecified.\n"); return EXIT_FAILURE; } if ((co = fopen(cofn, "w")) == NULL) { fprintf(stderr, "Can't open %s for output.\n", cofn); return EXIT_FAILURE; } if ((ho = fopen(hofn, "w")) == NULL) { fprintf(stderr, "Can't open %s for output.\n", hofn); fclose(co); return EXIT_FAILURE; } for (;optind < argc; optind++) { if ((si = fopen(argv[optind], "r")) == NULL) { fprintf(stderr, "Couldn't open %s, skipped.\n", argv[optind]); continue; } gen(argv[optind], si, co, ho); fclose(si); } fclose(ho); fclose(co); return EXIT_SUCCESS; }