I have seen a lot of posts regarding one pass and multi pass compilers and I think the basic parts of a One Pass Compiler as follows.
- Lexical Analysis
- Parse and Syntax Check
- Symbol Table
- Code Generation
But I have a question, that I cannot understand. How does Expression work in one pass compiler ( Without AST )
Let's take 1 + 2 / 3
as an example. Suppose you need to generate assembly code for this. After create a parser, how does generate assembly from it? ( Directly ) How does assembly code generate without any errors?
Can you explain this with examples? Please tell me if there is a problem in this question. I am new to Stackoverflow :)
The simplest way for a single-shot compiler process something like a=b*c[i]+d*e;
would be to process each token as it is encountered:
a
Generate code to push the address of a
onto the stack=
Record the fact that the top item on the stack will be used as the target of an assignment.b
Generate code to push the address of b
onto the stack*
Generate code to pop the address (of b
), fetch the object there, and push it.c
Generate code to push the address of c
onto the stack[
Record the fact that the top item on the stack will be the left operand of [
and evaluate the following expressioni
Generate code to push the address of i
onto the stack]
Generate code to pop the address (of i
), fetch the object there, and push it.i
and the address of c
, add them, and push that result+
Generate code to pop the address (of c[i]
), fetch the object there, and push itc[i]
and b
), multiply them, and push the result+
d
Generate code to push the address of d
onto the stack*
Generate code to pop the address, fetch the object there, and push it.e
Generate code to push the address of e
onto the stacke
), fetch the object there, and push ite
and d
), multiply them, and push the resultd*e
and b*c[i]
), add them, and push the resultb*c[i]+d*e
) and address a
and store the value to the addressNote that on many platform, performance may be enormously improved if code generation for operations which end with a push is deferred until the next operation is generated, and if pops that immediately follow pushes are consolidated with them; further, it may be useful to have the compiler record the fact that the left hand side of the assignment operator is a
, rather than generating code to push that address, and then have the assignment operator perform a store directly to a
rather that computing the address first and then using it for the store. On the other hand, the approach as described will be able to generate machine code for everything up to the exact byte of machine code being processed, without having to keep track of much beyond pending operations that will need to be unwound.