Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Last active September 24, 2022 15:25
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pervognsen/e61c6b91fca7275d90692831e2a55c9a to your computer and use it in GitHub Desktop.
Save pervognsen/e61c6b91fca7275d90692831e2a55c9a to your computer and use it in GitHub Desktop.
// Lexer
#define TOK_CHAR(ch1, tok1) \
case ch1: \
next_ch(); \
tok = TOK_##tok1; \
tok_prec = 0; \
break;
#define TOK_EXPR(ch1, tok1, prec1, lexpr1, rexpr1) \
case ch1: \
next_ch(); \
tok = TOK_##tok1; \
tok_prec = PREC_##prec1; \
tok_lexpr = expr_##lexpr1; \
tok_rexpr = expr_##rexpr1; \
break;
#define TOK_EXPR_EXPR(ch1, tok1, prec1, lexpr1, rexpr1, ch2, tok2, prec2, lexpr2, rexpr2) \
case ch1: \
next_ch(); \
if (match_ch(ch2)) { \
tok = TOK_##tok2; \
tok_prec = PREC_##prec2; \
tok_lexpr = expr_##lexpr2; \
tok_rexpr = expr_##rexpr2; \
} else { \
tok = TOK_##tok1; \
tok_prec = PREC_##prec1; \
tok_lexpr = expr_##lexpr1; \
tok_rexpr = expr_##rexpr1; \
} \
break;
switch (ch) {
// ...
TOK_CHAR('\0', EOF)
TOK_CHAR('{', LBRACE)
TOK_CHAR('}', RBRACE)
TOK_CHAR(']', RBRACK)
TOK_CHAR(')', RPAREN)
TOK_CHAR(',', COMMA)
TOK_CHAR(':', COLON)
TOK_EXPR('(', LPAREN, BASE, paren, call)
TOK_EXPR('[', LBRACK, BASE, error, index)
TOK_EXPR('~', BNOT, UNARY, bnot, error)
TOK_EXPR('/', DIV, MUL, error, div)
TOK_EXPR('%', MOD, MUL, error, mod)
TOK_EXPR('^', XOR, ADD, error, xor)
TOK_EXPR('-', SUB, ADD, neg, add)
TOK_EXPR('?', COND, COND, error, cond)
TOK_EXPR_EXPR('&', BAND, MUL, addr, band, '&', AND, AND, error, and)
TOK_EXPR_EXPR('|', BOR, ADD, error, bor, '|', OR, OR, error, or)
TOK_EXPR_EXPR('!', NOT, UNARY, not, error, '=', NE, CMP, error, ne)
TOK_EXPR_EXPR('<', LT, CMP, error, lt, '=', LE, CMP, error, le)
TOK_EXPR_EXPR('>', GT, CMP, error, gt, '=', GE, CMP, error, ge)
TOK_EXPR_EXPR('*', MUL, MUL, deref, mul, '=', MULSET, SET, error, mulset)
TOK_EXPR_EXPR('+', ADD, ADD, error, add, '=', ADDSET, SET, error, addset)
TOK_EXPR_EXPR('=', SET, SET, error, set, '=', EQ, CMP, error, eq)
}
// Parser
#define EXPR_UNARY(name) \
void expr_##name(Value *dest) { \
next(); \
expr_binary(dest, PREC_UNARY - 1); \
do_##name(dest); \
}
#define EXPR_BINARY(name, prec) \
void expr_##name(Value *dest) { \
Value src = {0}; \
expr_binary(&src, PREC_##prec); \
do_##name(dest, &src); \
}
void expr_error(Value *dest) {
error("Unexpected token in expression.");
}
void expr_binary(Value *dest, Prec min_prec) {
tok_lexpr(dest);
while (tok_prec > min_prec) {
void (*op_rexpr)(Value *) = tok_rexpr;
next();
op_rexpr(dest);
}
}
void expr(Value *dest) {
expr_binary(dest, PREC_EXPR);
}
void expr_int(Value *dest) {
do_int(dest, tok_int);
next();
}
void expr_paren(Value *dest) {
next();
expr(dest);
expect(TOK_RPAREN);
}
void expr_call(Value *dest) {
int num_args = 0;
Value args[MAX_ARGS];
if (!match(TOK_RPAREN)) {
expr(&args[num_args++]);
while (match(TOK_COMMA)) {
if (num_args == MAX_ARGS) {
error("Exceeded argument limit");
}
expr(&args[num_args++]);
}
expect(TOK_RPAREN);
}
do_call(dest, args, num_args);
}
EXPR_UNARY(neg)
EXPR_UNARY(bnot)
EXPR_UNARY(not)
EXPR_UNARY(deref)
EXPR_UNARY(addr)
EXPR_BINARY(index, BASE)
EXPR_BINARY(mul, MUL)
EXPR_BINARY(div, MUL)
EXPR_BINARY(mod, MUL)
EXPR_BINARY(band, MUL)
EXPR_BINARY(add, ADD)
EXPR_BINARY(sub, ADD)
EXPR_BINARY(xor, ADD)
EXPR_BINARY(bor, ADD)
EXPR_BINARY(eq, CMP)
EXPR_BINARY(ne, CMP)
EXPR_BINARY(lt, CMP)
EXPR_BINARY(le, CMP)
EXPR_BINARY(gt, CMP)
EXPR_BINARY(ge, CMP)
EXPR_BINARY(and, AND)
EXPR_BINARY(or, OR)
EXPR_BINARY(cond, COND)
EXPR_BINARY(set, SET)
EXPR_BINARY(addset, SET)
EXPR_BINARY(mulset, SET)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment