• No se han encontrado resultados

LA CORONA CUESTIONADA. LA REVOLUCIÓN DE 1868

In document Trabajo de Fin de Grado (página 36-52)

It is convenient to store PC and W in some general purpose registers, especially the ones that are guaranteed to survive function calls unchanged (caller-saved): r13, r14, or r15.

7.3.1 Static Dictionary, Interpreter

We are going to start with a static dictionary of native words. Adapt the knowledge you received in section 5.4.

From now on we cannot define new words in runtime.

For this assignment we will use the following macro definitions:

• native, which accepts three arguments:

– Word name;

– A part of word identifier; and – Flags.

It creates and fills in the header in .data and a label in .text. This label will denote the assembly code following the macro instance.

As most words will not use flags, we can overload native to accept either two or three arguments. To do it, we create a similar macro definition which accepts two arguments and launches native with three arguments, the third being substituted by zero and the first two passed as-is, as shown in Listing 7-7.

Listing 7-7. native_overloading.asm

%macro native 2 native %1, %2, 0

%endmacro

Compare two ways of defining Forth dictionary: without macros (shown in Listing 7-8) and with them (shown in Listing 7-9).

Listing 7-8. forth_dict_example_nomacro.asm section .data

w_plus:

dq w_mul ; previous db '+',0

db 0 xt_plus:

dq plus_impl

section .text plus_impl:

pop rax add [rsp], rax jmp next

Listing  7-9. forth_dict_example_macro.asm native '+', plus

pop rax add [rsp], rax jmp next

Then define a macro colon, analogous to the previous one. Listing 7-10 shows its usage.

Listing 7-10. forth_colon_usage.asm colon '>', greater

dq xt_swap dq xt_less dq exit

Do not forget about docol address in every colon word! Then create and test the following assembly routines:

• find_word, which accepts a pointer to a null-terminated string and returns the address of the word header start. If there is no word with such name, zero is returned.

• cfa (code from address), which takes the word header start and skips the whole header till it reaches the XT value.

Using these two functions and the ones you have already written in section 2.7, you can write an interpreter loop. The interpreter will either push a number into the stack or fill the special stub, consisting of two cells, shown in Listing 7-11.

It should write the freshly found execution token to program_stub. Then it should point PC at the stub start and jump to next. It will execute the word we have just parsed, and then pass control back to interpreter.

Remember, that an execution token is just an address of an address of an assembly code. This is why the second cell of the stub points at the third, and the third stores the interpreter address—we simply feed this data to the existing Forth machinery.

Listing 7-11. forth_program_stub.asm program_stub: dq 0

xt_interpreter: dq .interpreter .interpreter: dq interpreter_loop

Figure 7-11 shows the pseudo code illustrating interpreter logic.

Remember that the Forth machine also has memory. We are going to pre-allocate 65536 Forth cells for it.

Question 122 should we allocate these cells in

.data

section, or are there better options?

To let Forth know where the memory is, we are going to create the word mem, which will simply push the memory starting address on top of the stack.

7.3.1.1 Word list

You should first make an interpreter that supports the following words:

• .S – prints all stack contents; does not change it. To implement it, save rsp before interpreter start.

• Arithmetic: + - * /, = <. The comparison operations push either 1 or 0 on top of the stack.

• Logic: and, not. All non-zero values are considered true; zero value is considered false.

In case of success these instructions push 1, otherwise 0. They also destruct their operands.

• Simple stack manipulations:

rot (a b c -- b c a) swap (a b -- b a) dup (a -- a a) drop (a -- )

• . ( a -- ) pops the number from the stack and outputs it.

Figure 7-11. Forth interpreter: pseudocode

• Input/output:

key ( -- c)—reads one character from stdin; The top cell in stack stores 8 bytes, it is a zero extended character code.

emit ( c -- )—writes one symbol into stdout.

number ( -- n )—reads a signed integer number from stdin (guaranteed to fit into one cell).

• mem—stores the user memory starting address on top of the stack.

• Working with memory:

! (address data -- )—stores data from stack starting at address.

c! (address char -- )—stores a single byte by address.

@ (address -- value)—reads one cell starting from address

c@ (address -- charvalue)—reads a single byte starting from address Then test the resulting interpreter.

Then create a memory region for the return stack and implement docol and exit. We recommend allocating a register to point at the return stack’s top.

Implement colon-words or and greater using macro colon and test them.

7.3.2 Compilation

Now we are going to implement compilation. It is easy!

1. We need to allocate other 65536 Forth cells for the extensible part of the dictionary.

2. Add a variable state, which is equal to 1 when in compilation mode, 0 for interpretation mode.

3. Add a variable here, which points at the first free cell in the preallocated dictionary space.

4. Add a variable last_word, which stores the address of the last word defined.

5. Add two new colon words, namely, : and ;.

Colon:

1: word ← stdin

2: Fill the new word’s header starting at here. Do not forget to update it!

3: Add docol address immediately at here; update here.

4: Update last_word.

5: state ← 1;

6: Jump to next.

Semicolon should be marked as Immediate!

1: here ← XT of the word exit ; update here.

2: state ← 0;

3: Jump to next.

6. Here is what the compiler loop looks like. You can implement it separately, or mix with interpreter loop you already implemented.

1: compiler loop:

2: word ← word from stdin 3: if word is empty then 4: exit

5: if word is present and has address addr then 6: xt ← cf a(addr)

7: if word is marked Immediate then 8: interpret word

9: else 10: [here] ← xt 11: here ← here + 8 12: else

13: if word is a number n then

14: if previous word was branch or 0branch then 15: [here] ← n

16: here ← here + 8 17: else

18: [here] ← xt lit 19: here ← here + 8 20: [here] ← n 21: here ← here + 8 22: else

23: Error: unknown word

Implement 0branch and branch and test them (refer to section 7.3.3 for a complete list of Forth words with their meanings).

In document Trabajo de Fin de Grado (página 36-52)

Documento similar