// Tiny didactic example infix compiler. See didcomp.py and // didcomp.en.md. Or online step-by-step visualization at // . // Given no arguments, translates the example formula " 3 + 5 * (x1 - // 20) " to this pseudo-assembly: // loadconst r0, 3 // loadconst r1, 5 // loadvar r2, x1 // loadconst r3, 20 // sub r2, r2, r3 // mul r1, r1, r2 // add r0, r0, r1 // Based on Darius Bacon’s eg_calc_compile // , // which is an improvement on its model // , // and on some remarks in Jack Crenshaw’s “Let’s Build a Compiler”. // // To the extent possible under law, Kragen Javier Sitaker has waived all // copyright and related or neighboring rights to Didcomp. This work is // published from Argentina. #include #include #include #include typedef struct token { char *s; int len; } token; static token cur; static char *input; static int eq(token t, char *s) { return strlen(s) == t.len && memcmp(s, t.s, t.len) == 0; } static int tokput(FILE *f, token t) { return fwrite(t.s, t.len, 1, f); } static token next() { token rv = cur; cur = (token){ cur.s + cur.len, 0 }; while (isspace(*cur.s)) cur.s++; if (isdigit(*cur.s)) { // Literal integer constant. while (isdigit(cur.s[cur.len])) cur.len++; } else if (isalpha(*cur.s)) { // Alphanumeric variable. while (isalpha(cur.s[cur.len]) || isdigit(cur.s[cur.len])) cur.len++; } else if (*cur.s) { // Any other non-whitespace, non-nul byte. cur.len = 1; } // fprintf(stderr, "tok is "); tokput(stderr, cur); fprintf(stderr, "\n"); return rv; } static void fail(char *what, token tok) { fprintf(stderr, "parse err %s at byte %zu: '", what, tok.s - input); tokput(stderr, tok); fprintf(stderr, "'\n"); exit(1); } static void start(char *s) { cur.s = input = s; next(); } static void end() { if (*cur.s) fail("trailing garbage", cur); } static void translate(int dep); static void translate_factor(int dep) { token tok = next(); if (isdigit(*tok.s)) { // Literal integer constant. printf("\tloadconst r%d, ", dep); tokput(stdout, tok); printf("\n"); } else if (isalpha(*tok.s)) { // Alphanumeric variable. printf("\tloadvar r%d, ", dep); tokput(stdout, tok); printf("\n"); } else if (eq(tok, "(")) { // Parenthesized expression. translate(dep); if (!eq(tok = next(), ")")) fail("missing )", tok); } else if (eq(tok, "-")) { // Unary negation. translate_factor(dep); printf("\tneg r%d\n", dep); } else { fail("expecting factor", tok); } } static void translate(int dep) { token op = {0}; // additive operation between terms for (;; next()) { // translate one or more terms int td = dep + (op.s ? 1 : 0); // term depth token top = {0}; // term op (multiplicative) for (;; next()) { // translate one or more factors translate_factor(td + (top.s ? 1 : 0)); if (top.s) { printf("\t%s r%d, r%d, r%d\n", eq(top, "*") ? "mul" : "div", td, td, td+1); } if (!eq(top = cur, "*") && !eq(top, "/")) break; } if (op.s) { printf("\t%s r%d, r%d, r%d\n", eq(op, "+") ? "add" : "sub", dep, dep, dep+1); } if (!eq(op = cur, "+") && !eq(op, "-")) break; } } int main(int argc, char **argv) { start(argc == 1 ? " 3 + 5 * (x1 - 20) " : argv[1]); translate(0); end(); return 0; }