Multi-digit numbers. Write number() that reads digits in a loop, building up a value: multiply the running total by 10, add the digit.
To parse 345: 3 * 10 + 4 = 34, then 34 * 10 + 5 = 345. Stop when the next char isn't a digit.
check("42", 42);
check("100+23", 123);
check("12*12", 144);
fn number() i64 {
var val: i64 = 0;
while (cur() >= '0' and cur() <= '9') {
val = val * 10 + digit(cur());
pos += 1;
}
return val;
}
Replace the single-digit reads in eval with calls to number():
fn eval(input: []const u8) i64 {
source = input;
pos = 0;
var val: i64 = number();
while (cur() != 0) {
const op: u8 = cur();
pos += 1;
const right: i64 = number();
val = switch (op) {
'+' => val + right,
'-' => val - right,
'*' => val * right,
'/' => @divTrunc(val, right),
else => val,
};
}
return val;
}
Watch out: there is no pos += 1 after the number() calls. The single-character version (digit(cur())) needed pos += 1 after each read to advance past that one character. But number() reads multiple characters and is responsible for leaving pos at the next unread byte.
This is the rule from now on: a function that reads one character expects the caller to advance. A function that reads a token (number(), later read_name(), etc.) advances on its way out. Adding a stray pos += 1 after a token-reader will skip the next character -- a classic source of "my parser ate the operator" bugs.