On 4/9/2021 at 1:31 AM, rje said:
The bit *I* find challenging is compiling to bytecode. I think it's a recursive descent parser, with an expression engine, and a bytecode emitter with forward referencing for handling blocks. Or maybe I can use a stack?
One way to simplify the compilation is to simplify the grammer.
For example, suppose that ALL infix operations are evaluated left to right, and without parentheses all right hand side operands are evaluated first. So: 3+5*8-4/3 means:
3+(5*(8-(4/3))). And suppose () are supported. Then you simply parse between operations and operands, push operands on an operand stack, push operations on an operations stack, and when you get to the end of the line you execute the operations stack. ")" goes ahead and executes the current operations stack, and "(" on the operations stack stops executing the operations stack and goes back to executing the bytecode.
So in practice, people get used to using () a lot.
Now function or procedure calls are just prefix operations, a "proc(" pushes the ( onto the operation stack then the proc, and in proc(x,y,z) the comma is just a separator: (x,y,z) gets executed as ( ... x y z ) on the operand stack and "proc" uses the top two entries on the operand stack. ")" doesn't care whether it is closing an expression or a procedure call, it just executes the current operation stack.