Sunday 2 September 2018

A little bit of M8

So, some actual code from the console library I wrote yesterday.

: con.print.digit private
    , 15 and , 10 >= if 7 + swap then 48 + con.emit    
;


What this bit of code does is to take the value passed in A and print out 0-9a-f based on the lower 4 bits of A.

, 15 and

, is a bit like Enter in RPN, it swaps A and B. This puts A into B, 15 into A and then ands B into A.

, 10 >=

is very similar, it puts the anded value into B, and 10 into A. >= sets A to -1 if B >= A and 0 otherwise. This is deliberately the wrong way round so it is FORTH like, so to calculate 3 - 2 you do 3 , 2 - (M7 allowed you to just write 3 2 - which made it even more Forth like but it was a bit inefficient)

if  7 + swap then

If tests the current value of A, so if true (e.g. >= 10) then it puts 7 in A, adds B into A and puts the result back in B - 7 is the offset to display hex in ASCII correctly.

Note that neither >= or if is destructive of the value in B.

48 + con emit 

The value is still in B, possibly modified by the previous instructions. 48 is put into A, B is added into A, giving the ASCII value in A, which is then printed using con.emit

;

Compiles ret.

It looks a bit horrible but it works quite well once  you are used to it. Rather than remembering what's on the stack, you have to remember what is in A and B (and sometimes, the top of the return stack, which is used as an interim store). 

When I first wrote an early version I thought this would lead to an explosion in variables (replacing stack based elements) but this doesn't seem to have happened.

It gains its efficiency from not having a data stack which is changed all the time , even when you aren't really doing anything. The call stack stays as the call stack.  Nothing changes unless you ask it to, so you can use all kinds of operations on A and B just stays as it is, as in this example.

No comments:

Post a Comment