The use of temp segments in array assigments.

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

The use of temp segments in array assigments.

JG1993
Hi,

I am have just finished the Average test program. Everything works fine, however when comparing my .vm file to the .vm file created by the official compiler I noticed that array assignments are handled in a different way.
The line let a[i] = 8 using the official compiler is translated like this:

pop local 2
push local 2
push local 0
add
push constant 8
pop temp 0
pop pointer 1
push temp 0
pop that 0

While mine translates it like this:
pop local 2
push local 2
push local 0
add
pop pointer 1
push constant 8
pop that 0
push constant 0

What is the purpose of the temp segments? I know that using the temp segments must have some reason, but I cant think of any.

Please help. :)
Reply | Threaded
Open this post in threaded view
|

Re: The use of temp segments in array assigments.

cadet1620
Administrator
JG1993 wrote

What is the purpose of the temp segments? I know that using the temp segments must have some reason, but I cant think of any.

Your code for let a[i] = 8

    push local 2    // i
    push local 0    // a
    add            
    pop pointer 1   // that -> a[i]
    push constant 8 // expression evaluated
    pop that 0      // a[i] = expression value
But what happens if the expression involves array indexing, for example let a[i] = a[i-1]?

Reading a[i-1] will need to use that and will clobber the a[i] address that you popped into that.

The a[i] address needs to stay on the stack during the expression evaluation. That's why temp[0] is used to hold the expression result.


--Mark

JG1993 wrote

What is the purpose of the temp segments? I know that using the temp segments must have some reason, but I cant think of any.

Reply | Threaded
Open this post in threaded view
|

Re: The use of temp segments in array assigments.

JG1993
Thanks!
Mat
Reply | Threaded
Open this post in threaded view
|

Re: The use of temp segments in array assigments.

Mat
In reply to this post by cadet1620
How about evaluating the right side of the let statement *before* calculating the address on the left side?

Reusing the same example as above:

// Evaluate the right side of the let statement
push constant 8 

// Evaluate the array offset
push local 2    // i

// Pop the previously-evaluated right-side into array[offset]
push local 0    // a
add            
pop pointer 1   // that -> a[i]
pop that 0      // a[i] = expression value

This seems intuitively correct to me. No matter how complicated the right-side expression and the array offset expression get, once evaluated they end up being just two values on the stack, which reduces to the above example. And both these expressions are evaluated before we even touch `that`, so there should be no interference.

A compiler implemented using this approach (no temp segment) passes the ComplexArrays test. But there could still be a failing case somewhere that's not covered. So I'd be happy to hear some opinions. :)

And thanks for this amazing book, I've been completely hooked since I started!
Reply | Threaded
Open this post in threaded view
|

Re: The use of temp segments in array assigments.

cadet1620
Administrator
Mat wrote
How about evaluating the right side of the let statement *before* calculating the address on the left side?

Reusing the same example as above:

// Evaluate the right side of the let statement
push constant 8 

// Evaluate the array offset
push local 2    // i

// Pop the previously-evaluated right-side into array[offset]
push local 0    // a
add            
pop pointer 1   // that -> a[i]
pop that 0      // a[i] = expression value
This is a functional way to generate code for array assignment.

Basically, it comes down to trade-offs between complexity of parsing versus complexity of code generation.
a[index-expression] = source-expression;
If you are using the simple recursive descent design presented in the book, then you have parsed and compiled the code for index-expression before you have encountered source-expression. The simple code generator has already written index-expression's code to the VM file.

One way to handle this is to compile index-expression to a memory buffer instead of the VM file. Then you can copy index-expression's code into the VM file at the point where you need it after parsing/compiling source-expression.

Another choice is to separate parsing and compiling so that your parser can return index-expression (or pointers to it in the source stream) so that your code generator can compile index-expression when it gets to the point where it needs to be evaluated.

And thanks for this amazing book, I've been completely hooked since I started!
Yes, it can be quite addicting; I've been hooked since I first encountered the course 6 years ago!

--Mark
Mat
Reply | Threaded
Open this post in threaded view
|

Re: The use of temp segments in array assigments.

Mat
I indeed deviated from the book's suggested approach and separated parsing and compiling. So yeah, it completely makes sense that I went for this solution while the built-in compiler went for the temp segment. Thanks for the explanation!
Reply | Threaded
Open this post in threaded view
|

Re: The use of temp segments in array assigments.

cadet1620
Administrator
Mat wrote
I indeed deviated from the book's suggested approach and separated parsing and compiling.
That's one of the great things about this course; there isn't a "correct" solution for anything, just correct results.

It really encourages exploration.  I've done major rewrites to my VM translator 3 times working to reduce generated code size.

--Mark