An even simpler way imo, is explicit functions instead of a precedence table, then the code pretty much has the same structure as EBNF.
Need to parse * before +? Begin at add, have it call parse_mul for its left and right sides, and so on.
parse_mul() {
left = parse_literal()
while(is_mul_token()) { // left associative
right = parse_literal()
make_mul_node(left, right)
}
}
parse_add() {
left = parse_mul()
while(is_add_token()) { // left associative
right = parse_mul()
make_add_node(left, right)
}
}
Then just add more functions as you climb up the precedence levels.You lose in versatility, then you can't add user-defined operators, which is pretty easy with a Pratt parser.
With a couple of function pointers you can climb precedence with just functions:
... and so on for all operators