0
[IF]
Forth to XML converter
Main contributors:
Brad Eckert brad1NO@SPAMtinyboot.com Original author
Ed Beroset berosetNO@SPAMmindspring.com XML, XSLT, some fixes
Dirk Busch dirkNO@SPAMschneider-busch.de Added some features
Revision 11. See bottom for revision history.
This ANS Forth program is public domain. It translates ANS Forth to XML with
the intent that the XML is then postprocesed by XSLT to create documentation
of the Forth program.
Hyperlinks to the ANS Forth draft standard are inserted for all ANS
standard words. Hyperlinks to user definitions are included.
Usage: XML FileName Generates XML file from Forth source.
Output file is Filename with .HTM extension.
q [forth code] Outputs XML for 1 line to screen
Keep in mind that whatever path you use for the input filename will be in the
output files, so don't use a drive letter etc. if the XML is intended for
distribution on CD or a web site.
q is for debugging. You can use "linenum ?" to show the line number if an
ABORT occurs. The XML is about 6 times as big as the Forth source because of
all the links, color changes and whitespace.
INCLUDEd files produce corresponding XML pages. If a file can't be found,
it is skipped. Otherwise it is nested.
When you INCLUDE this file some redefinition complaints may occur. That's
okay since you won't be loading an application on top of this. You can make
a text version of this file by cut-and-paste to a text editor. The browser's
save-as-text function will work too. This file is only 80 columns wide. Note
that the browser may wrap after 80 columns when saving as a text file.
Users of specific Forths can extend the hyperlink table to point to anchors
in a glossary for that particular Forth.
This code has been tested under Win32forth, SwiftForth, VFX and Gforth.
You can change the following nestable options:
[THEN]
ONLY
FORTH
ALSO
DEFINITIONS
\
------------------------------------------------------------------------------
\
Configuration - You can change this option:
1
VALUE
nestable
\
T if INCLUDE nested files
\
------------------------------------------------------------------------------
:
undefined
( <name> -- f )
BL
WORD
FIND
NIP
0=
;
undefined
NOOP
[IF]
:
NOOP
;
[THEN]
undefined
BOUNDS
[IF]
:
BOUNDS
OVER
+
SWAP
;
[THEN]
undefined
/STRING
[IF]
:
/STRING
TUCK
-
>R
CHARS
+
R>
;
[THEN]
undefined
C+!
[IF]
:
C+!
SWAP
OVER
C@
+
SWAP
C!
;
[THEN]
undefined
FDROP
[IF]
:
FDROP
;
( no floating point? fake it )
[THEN]
undefined
>FLOAT
[IF]
:
>FLOAT
DROP
C@
[CHAR] 0
[CHAR] 9
1+
WITHIN
;
[THEN]
undefined
SCAN
[IF]
:
SCAN
( addr len char -- addr' len' )
>R
BEGIN
DUP
WHILE
OVER
C@
R@
<>
WHILE
1
/STRING
REPEAT
THEN
R>
DROP
;
[THEN]
undefined
SKIP
[IF]
:
SKIP
( addr len char -- addr' len' )
>R
BEGIN
DUP
WHILE
OVER
C@
R@
=
WHILE
1
/STRING
REPEAT
THEN
R>
DROP
;
[THEN]
:
+PLACE
( addr len a -- )
2DUP
2>R
COUNT
CHARS
+
SWAP
MOVE
2R>
C+!
;
:
PLACE
( addr len a -- )
0
OVER
C!
+PLACE
;
:
UPC
( c -- C )
DUP
[CHAR] a
[CHAR] z
1+
WITHIN
IF
32
-
THEN
;
:
STRING,
( addr len -- )
DUP
C,
HERE
SWAP
DUP
ALLOT
MOVE
;
0
VALUE
outf
\
output to file
1
VALUE
screen-only
\
screen is for testing
:
werr
ABORT"
Error writing file"
;
:
out
screen-only
IF
TYPE
ELSE
outf
WRITE-FILE
werr
THEN
;
:
outln
screen-only
IF
TYPE
CR
ELSE
outf
WRITE-LINE
werr
THEN
;
WORDLIST
CONSTANT
hyperlinks
\
list of hyperlinks
WORDLIST
CONSTANT
superlinks
\
hyperlinks that can't change
CREATE
quot
34
C,
:
onequote
( -- )
quot
1
out
;
:
quote
( c-addr -- )
onequote
COUNT
out
onequote
;
VARIABLE
attrib
:
/a
( -- )
attrib
@
IF
S"
</a>"
out
THEN
0
attrib
!
;
:
,$
( a len -- )
DUP
C,
BOUNDS
?DO
I
C@
C,
LOOP
;
\
text to dictionary
:
,|
( <text> -- )
[CHAR] |
WORD
COUNT
-TRAILING
,$
;
:
line
( a line# -- )
0
?DO
COUNT
+
LOOP
COUNT
out
;
\
output one string
:
boiler
( addr -- )
BEGIN
COUNT
DUP
WHILE
2DUP
+
>R
outln
R>
REPEAT
2DROP
;
:
newline
( -- )
S"
<br />"
outln
;
:
.<
( -- )
S"
<"
out
;
:
.>
( -- )
S"
>"
out
;
:
./
( -- )
S"
/"
out
;
CREATE
misctext
\
various attribute strings
,|
<a
href="
|
\
0
,|
<a
name="x
|
\
1
,|
">
|
\
2
,|
<a
href="#x
|
\
3
,|
<a
std="#
|
\
4
,|
<a
file="
|
\
5
,|
"
href="#x
|
\
6
0
C,
VARIABLE
tagtype
\
current tagtype
VARIABLE
intag
\
within tag
:
<href="
misctext
0
line
;
:
<anchor="
misctext
1
line
;
:
">
misctext
2
line
;
:
<#ref="
misctext
3
line
;
:
<std="
misctext
4
line
;
:
<file="
misctext
5
line
;
:
with_href
misctext
6
line
;
:
emittag
( tagtype -- )
\
change font tagtype
1
intag
!
S"
<tag type="
out
quote
.>
;
:
tag
( <tagname> <string> -- )
CREATE
BL
WORD
COUNT
STRING,
DOES>
tagtype
!
;
\
NAME STRING
\
---- ------
tag
unknown
unknown
tag
commentary
commentary
tag
numeric
numeric
tag
errors
errors
tag
values
values
tag
userwords
userwords
tag
userdefiner
userdefiner
tag
variables
variables
tag
core_ws
core_ws
tag
core_ext_ws
core_ext_ws
tag
block_ws
block_ws
tag
double_ws
double_ws
tag
exception_ws
exception_ws
tag
facilities_ws
facilities_ws
tag
file_ws
file_ws
tag
fp_ws
fp_ws
tag
local_ws
local_ws
tag
malloc_ws
malloc_ws
tag
progtools_ws
progtools_ws
tag
searchord_ws
searchord_ws
tag
string_ws
string_ws
CREATE
begin_header
\
begin of XML file
,|
<?xml
version="1.0"?>
|
,|
<forth>
|
0
C,
CREATE
end_header_part1
\
end of XML file part 1 /7/
,|
</forth>
|
0
C,
:
settagtype
( -- )
\
select next tagtype
tagtype
@
emittag
;
:
closetag
( -- )
intag
@
IF
S"
</tag>"
out
0
intag
!
THEN
;
\
In order to represent all ASCII chars as text, some puncuation needs to be
\
changed to make it XML compatible.
VARIABLE
bltally
:
outh
( a n -- )
\
XMLized text output
0
bltally
!
BOUNDS
?DO
I
C@
CASE
[CHAR] &
OF
S"
&"
out
ENDOF
[CHAR] <
OF
S"
<"
out
ENDOF
[CHAR] >
OF
S"
>"
out
ENDOF
[CHAR] "
OF
S"
""
out
ENDOF
169
OF
S"
©"
out
ENDOF
BL
OF
bltally
@
0=
IF
S"
"
ELSE
S"
 "
THEN
out
1
bltally
+!
ENDOF
I
1
out
0
bltally
!
ENDCASE
LOOP
;
:
outhattr
( a n -- )
\
XMLized text output
BOUNDS
?DO
I
C@
CASE
[CHAR] &
OF
S"
amp"
out
ENDOF
[CHAR] <
OF
S"
lt"
out
ENDOF
[CHAR] >
OF
S"
gt"
out
ENDOF
[CHAR] "
OF
S"
quot"
out
ENDOF
[CHAR] +
OF
S"
plus"
out
ENDOF
[CHAR] !
OF
S"
bang"
out
ENDOF
[CHAR] /
OF
S"
slash"
out
ENDOF
[CHAR] \
OF
S"
backslash"
out
ENDOF
[CHAR] '
OF
S"
apos"
out
ENDOF
[CHAR] =
OF
S"
equal"
out
ENDOF
[CHAR] -
OF
S"
dash"
out
ENDOF
[CHAR] @
OF
S"
at"
out
ENDOF
[CHAR] ;
OF
S"
semi"
out
ENDOF
[CHAR] *
OF
S"
star"
out
ENDOF
[CHAR] ?
OF
S"
question"
out
ENDOF
[CHAR] ~
OF
S"
tilde"
out
ENDOF
[CHAR] #
OF
S"
pound"
out
ENDOF
[CHAR] ,
OF
S"
comma"
out
ENDOF
[CHAR] $
OF
S"
dollar"
out
ENDOF
[CHAR] |
OF
S"
bar"
out
ENDOF
[CHAR] [
OF
S"
ltbracket"
out
ENDOF
[CHAR] (
OF
S"
ltparen"
out
ENDOF
[CHAR] {
OF
S"
ltbrace"
out
ENDOF
[CHAR] ]
OF
S"
rtbracket"
out
ENDOF
[CHAR] )
OF
S"
rtparen"
out
ENDOF
[CHAR] }
OF
S"
rtbrace"
out
ENDOF
169
OF
S"
copy"
out
ENDOF
BL
OF
S"
_"
out
ENDOF
I
1
out
ENDCASE
LOOP
;
:
end_header
( -- )
\
output end of XML file /7/
end_header_part1
boiler
;
:
label
( addr len -- )
/a
\
associate a label with a word
<anchor="
outhattr
">
1
attrib
!
;
\
Assuming this is running on a PC, we allocate enough storage that crashes from
\
string overflows can't happen.
CREATE
inbuf
260
CHARS
ALLOT
\
current line from file
CREATE
token
260
CHARS
ALLOT
\
last blank delimited string
CREATE
XPAD
260
CHARS
ALLOT
\
temporary pad for word storage
CREATE
EPAD
260
CHARS
ALLOT
\
temporary pad for evaluation
CREATE
fn
260
CHARS
ALLOT
\
file name
CREATE
fn1
260
CHARS
ALLOT
\
file name backup
CREATE
fn2
260
CHARS
ALLOT
\
global file name
CREATE
fn3
260
CHARS
ALLOT
\
index file name
CREATE
"str"
260
CHARS
ALLOT
\
parsed string storage
CREATE
uname
260
CHARS
ALLOT
\
: definition name
0
VALUE
inf
VARIABLE
nufile
\
T if nesting a file
VARIABLE
utype
\
type of defined word
VARIABLE
hstate
VARIABLE
linenum
VARIABLE
special
\
special action, 0=none
\
Defining word for hyperlinks to words in XML standards files.
:
std
( word 2nd_fn tagtype label -- )
CREATE
'
,
'
,
BL
WORD
COUNT
,$
DOES>
/a
DUP
>R
2
CELLS
+
<std="
COUNT
out
">
\
place hyperlink
1
attrib
!
R>
2@
SWAP
EXECUTE
EXECUTE
;
\
extra attributes
:
genXML
( -- )
\
generate pending XML
token
COUNT
DUP
IF
settagtype
THEN
outh
closetag
/a
0
token
!
;
:
isnumber?
( addr len -- f )
\
string converts to number?
0
0
2SWAP
>NUMBER
NIP
NIP
NIP
0=
;
:
hparse
( a len char -- a' len' )
>R
2DUP
R@
SKIP
R>
SCAN
BL
SCAN
2SWAP
2
PICK
-
token
+PLACE
;
:
>XPAD
( -- )
token
COUNT
BL
SKIP
XPAD
PLACE
;
\
move to temporary pad
:
hint
( addr len -- )
\
interpret one line...
BEGIN
0
token
!
BL
hparse
token
C@
WHILE
unknown
\
default tagtype
>XPAD
XPAD
COUNT
superlinks
SEARCH-WORDLIST
0=
\
fixed hyperlink?
IF
XPAD
COUNT
hyperlinks
SEARCH-WORDLIST
\
got a hyperlink for this?
ELSE
TRUE
THEN
IF
DEPTH
>R
EXECUTE
R>
DEPTH
<>
ABORT"
stack depth change in XML generator"
ELSE
XPAD
COUNT
BASE
@
10
=
IF
>FLOAT
IF
FDROP
numeric
THEN
\
valid float or integer
ELSE
isnumber?
IF
numeric
THEN
THEN
THEN
genXML
REPEAT
2DROP
newline
;
:
shortname
( -- )
fn
COUNT
2DUP
[CHAR] .
SCAN
NIP
-
EPAD
PLACE
;