Saturday 10 November 2007

Compare in forth

Compare is a string comparison word in Forth
compare (c-addr-1 len1 c-addr-2 len2 -- n )

This takes two strings and leaves a flag. (0 for a match. -1 less than. +1 greater than.)
Typically this is written in either C or Assembler and documented in some kind of psuedo-pascal such as source-index := source-index + 1;

Wednesday 7 November 2007

Ping from forth (Swiftforth)




\
\ ping sites from swiftforth by Alban 7/10/2007
\
REQUIRES winsock
LIBRARY ICMP.DLL OPENDLLS
0 IMPORT: IcmpCreateFile
8 IMPORT: IcmpSendEcho
1 IMPORT: IcmpCloseHandle

CLASS ICMP_OPTIONS
CVARIABLE TTL
CVARIABLE TOS
CVARIABLE Flags
CVARIABLE Size
VARIABLE Data

: init
32 TTL C!
0 TOS C!
0 Flags C!
0 Size C!
0 Data ! ;

END-CLASS



CLASS ICMP_ECHO_REPLY
VARIABLE Address
VARIABLE Status
VARIABLE RTTime
HVARIABLE DataSize
HVARIABLE Reserved
VARIABLE DataPtr
ICMP_OPTIONS BUILDS OPTS
64 BUFFER: Data
: init
32 DataSize H!
Data DataPtr ! ;
END-CLASS

CLASS PINGER
VARIABLE hICMP
VARIABLE ipAddress
VARIABLE lastStatus
VARIABLE timeout
ICMP_OPTIONS BUILDS OPTS
ICMP_ECHO_REPLY BUILDS ER
256 BUFFER: Request-data
: init-socks
$101 PAD :: WSAStartup drop ;
: init-send-buffer
z" 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ 9876543210"
zcount Request-data zplace ;

: >address ( z" -- )
ZCOUNT PAD ZPLACE
PAD :: inet_addr DUP 1+ ?EXIT
DROP
PAD :: gethostbyname DUP IF 3 CELLS + @ @ @ THEN
DUP 0= IF -1 ABORT" PINGER invalid host error" THEN
ipAddress ! ;

: create-file :: IcmpCreateFile hICMP ! ;

: init init-socks create-file init-send-buffer
OPTS init ER init
5000 timeout ! ;

: close hICMP @ :: IcmpCloseHandle ;

: send-ping hICMP @ ipAddress @ Request-Data 32
OPTS TTL ER Address 62 timeout @ :: IcmpSendEcho lastStatus ! ;

: rtt er RTTime c@ ;

: results rtt ." ms " . ;

: ping PAD 64 ERASE ( ping named site )
BL WORD HERE COUNT PAD SWAP CMOVE
PAD >address
send-ping drop
results ;
END-CLASS


PINGER BUILDS ICMP
ICMP init

\ usage examples
\ icmp ping www.apple.com
\ icmp ping www.bbc.co.uk
\ z" 10.10.10.1" icmp >address
\ icmp send-ping icmp rtt .



Saturday 3 November 2007

duped by forth

Forth being a stack language a common exercise is writing a definition of 2DUP that copies the top two items on the stack.

It is cheating to look into the guts of your favourite forth compiler.

I figured quickly that -

: 2DUP dup rot dup rot swap ;

Would work - but it is not exactly going to be fast to execute five steps.

It is a bad sign that dup rot is in there twice so is there some word that does dup rot already?
Well there doesn’t seem to be.

However the word over is also a kind of dup but it duplicates the 2nd value on the stack and brings it the top.

So my second attempt is : 2DUP (n1 n2 - - n1 n2 n1 n2 ) over over ;

This decompiles as:-
8 # EBP SUB EBX 4 [EBP] MOV 8 [EBP] EAX MOV EAX 0 [EBP] MOV
so has to be quite good..

This decompiles the same as the built in definition on the system that I am using (which uses EBP as the data stack and ESP as the return stack.)
There other bad ways of writing 2DUP one way is to use tuck instead of the first over

: 2DUP tuck over ;

This also works but is worse code as tuck does more work than over does.

One annoying thing about forth is that forth kernels tend to be written in assembly language – there is a long tradition of doing that for performance.

It is a shame that more use is not made of optimizing meta-compilers so that more of Forth can be written in Forth and then we could see how the experts would write these standard words.