22.10.2013 Views

4 - Forth Interest Group

4 - Forth Interest Group

4 - Forth Interest Group

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

line) and format specifiers (such as %d, which says to print<br />

the top stack word as a decimal integer). When printf ()<br />

executes, it prints the string, acting on the escape sequences<br />

and replacing the format specifiers with values from the<br />

argument list. If you're thinking of linking <strong>Forth</strong> and C you<br />

already know this, and know that the fragment<br />

int x;<br />

. . .<br />

x = 1234;<br />

printf("\nHere's an integer<br />

value : \nx=%d. ", x) ;<br />

will print<br />

Here's an integer value:<br />

x=1234<br />

We can go partway with this in <strong>Forth</strong>. The following<br />

sequence<br />

: PRINT-INT<br />

Z" \nHere1s an integer value:\nx=%d."<br />

PRINTF ;<br />

1234 PRINT-INT<br />

will yield<br />

\nHere1s an integer value:\nx=1234.<br />

at least with Borland C. This<br />

shouldn't have been surprising:<br />

since the escape sequences<br />

are unambiguous at compile<br />

time the C compiler can pro-<br />

cess them before writing the<br />

OBJ file, but the format speci-<br />

fications can only be replaced<br />

by strings representing the<br />

appropriate values at run time.<br />

For further examples of C<br />

function calls, see the sample<br />

code. One is particularly<br />

important: the call to the C<br />

function exit () , defined as<br />

0 1 EXTERN C-EXIT<br />

- exit.<br />

Because a C program sets<br />

up certain parameters, cap-<br />

tures various interrupts, etc.,<br />

when it starts up, and we<br />

really don't want to know what<br />

those are, we need to exit<br />

from <strong>Forth</strong> in a way that will<br />

cause C to clean up after itself<br />

as well. The way to do this in<br />

C is either to exit through the bottom of the main ( ) function<br />

or to call exit ( ) explicitly with a parameter that tells DOS<br />

what the exit condition was (zero means "good," anything<br />

else means "bad"). So instead of BYE we can execute GOOD-<br />

BYE defined as<br />

: GOOD-BYE 0 C-EXIT ;<br />

and avoid having our machine lock up on us unexpectedly<br />

while we're in the middIe of something else later.<br />

Portability issues aside, the actual coding of EXTERN and,<br />

later, SAVE-OBJ and SAVE-EXE is also necessarily somewhat<br />

implementation (and personal preference) dependent.<br />

I chose an 83-standard, indirect-threaded <strong>Forth</strong> for this<br />

project because it is probably still the most widely available<br />

model, and I used Guy Kelly's implementation because it's<br />

the single-segment version I'm most familiar with. I could<br />

have used F83 with perhaps no changes not already mentioned<br />

except the need to use an unfamiliar editor. More<br />

serious adjustments would have to be made for directthreading<br />

or subroutine-threading (one hesitates to contemplate<br />

token-threading), not to mention other standards,<br />

including the forthcoming ANS.<br />

The code works and, working, should speak for itself, but<br />

here's a little more detail:<br />

The definingword EXTERN has two parts. CODE-EXTERN<br />

creates <strong>Forth</strong> code words by compiling bytes in memory with<br />

C, . This is not a job for CREATE.. .DOES> since each external<br />

reference needs its own code body. The only unusual things<br />

\ no thread field<br />

\ locat<br />

CC BuFC, \ M=l, loc = segment:offset<br />

0 BUFC, \ offset in record, in 4Z .LEDATA always 0<br />

\ fixdat<br />

56 BUFC, \ F=O, frame det by target, T=O, ext index<br />

XREF# @ BUFC,<br />

WR.REC ;<br />

--><br />

\ For details of the FIXUPP record try the MS-DOS ENCYCLOPEDIA.<br />

Screen 24<br />

\ SAVE-OBJ: WR.CODE 01JAN93 RA 29DEC92<br />

HEX DEFER 'WR.SEG DEFER 'WR.FIX<br />

: WR.FIX WR.PATCH.TARGET WR.FIXUPP ;<br />

: WRlCODEREC \ step through the memory image<br />

CUR-XLINK @ ?DUP \ and the EXTERN linked list<br />

IF XLINK>FIXADR MEW@ - ?DUP<br />

IF 400 UMIN 'WR.SEG ELSE 'WR.FIX >NXT-XLINK THEN<br />

ELSE TOP.ADDR MEW@ - 400 UMIN 'WR.SEG<br />

THEN ;<br />

: (WR.CODE)<br />

0 MEMP ! >lST-XLINK<br />

BEGIN WRlCODEREC MEMP@ TOP.ADDR U< O= UNTIL ;<br />

: WR.CODE 1 SEG-INX !<br />

[ ' ] WR. LEDATA IS 'WR. SEG<br />

[']WR.FIX IS 'WR.FIX<br />

1 I<br />

November 1993 December 18 <strong>Forth</strong> Dimensions

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!