|
Wil Baden 2000-07-11, E 2000-08-21
Utility MARKUP converts source files to HTML.
MARKUP requires
Tool Belt,
Slurp, and
Quote in String.
For output redirection, Output Redirection is required after "Quote in String".
.BODY .Blockquote .COMMENTARY .Definition-Definition .Definition-Name .Definition-Term .Definitions .Example .Glossary .HTML .HTML-End .Headline .Needs .PROGRAM-TEXT .Stack-Effect .Tableau .Unordered-List Boldface Codify Commentary-Ends Commentary-Starts END-PAR Embolden Fragment Glossarizing HTML-BLOCK-FORMATTING HTML-BODY HTML-HEAD Hanging Hanging-Indent Is-a-Comment Italicise Italics Line-Indent MARKUP NEW-PAR OUTPUT-MARKUP Parse-for-HTML Portable-Name Save-as-Title Section TYPE-HTMLSource in any programming language is alternately commentary
and program text. MARKUP expects commentary
to be in a style of plaintext representing simple HTML layout.
MARKUP will insert HTML tags for the layout.
Commentary is distinguished from program text by a convention.
For Standard Forth, commentary starts with 0 [IF] at the
beginning of a line. Program text starts with a line that ends
with [THEN]. In the HTML the start of commentary will be
shown by a horizontal rule.
The convention can be revised for other dialects or languages.
Program text is shown as bold preformatted.
Commentary should be written as though it was the result of simple HTML. The formatting is selected by indentation, and appropriate tags will be inserted.
Indentation in commentary is independent of indentation in program text. Program text allows any kind of indentation.
Indentation in commentary is intended to give portable use of indenting for HTML layout. Indenting in the commentary should give the same result in all systems, and the desired layout should be obvious.
For those who tab three spaces at a time, one or two tabs is for preformatted example, three tabs are for section heading, four tabs for subsection heading, and greater than that for flush right. At present, tab characters should be replaced by the appropriate number of spaces.
* * *
Flush left is normal commentary. An empty line will end
a paragraph.
Single indent, 3-6 spaces, is preformatted example,
which may have further lines of arbitrary indentation,
and blank lines,
and ends at none of the above, that is,
flush left or slight indent
Double indent, 7-10 spaces, is one-line section heading.
Triple indent, 11-14 spaces, is one-line subsection heading.
Deep indent, 15 or more spaces, is to flush right the line.
Hanging indent ( optional stack effect )
is for definitions.
Slight indent, two spaces, is blockquote, ending at
non-empty line that is not indented 2 spaces.
* Space asterisk space
starts unordered list.
* * *
For character formatting,
In commentary, lines beginning with < that is not followed by white space will be copied as is. This gives full HTML for use in commentary.
The source file should begin with program text. Except for the first comment, this will be ignored.
The first comment will be used as the title and also the headline at the beginning of the page.
Program text may end with a line beginning with \\ and a
space. The rest of the file will be ignored.
Source must have had tabs converted to spaces. DETAB will do that.
In commentary, names between lines
GLOSSARY
and
/GLOSSARY
will generate links to target names in the definitions. Look at the .html source and the .txt plaintext of this file.
In commentary, names between lines
NEEDS
and
/NEEDS
will generate links to definitions in Tool Belt file.
Program Text 1\ *************************************************************
\ Turn On Output Redirection.
[DEFINED] OUTPUT-REDIRECTION [IF]
ALSO OUTPUT-REDIRECTION
[THEN]
\ *************************************************************
Commentary-Starts
( str len -- str len flag )
HTML-HEAD and .PROGRAM-TEXT.
Commentary-Ends
( str len -- str len flag )
.COMMENTARY.
Is-a-Comment
( str len -- str len flag )
HTML-HEAD.
: Commentary-Starts ( str len -- str len flag )
S" 0 [IF]" STARTS? ;
: Commentary-Ends ( str len -- str len flag )
S" [THEN]" ENDS? ;
: Is-a-Comment ( str len -- str len flag )
S" \ " STARTS? ;
Italics
( -- addr )
Boldface
( -- addr )
Fragment
( -- addr )
Glossarizing
( -- addr )
.Definition-Name.
Section
( -- addr )
VARIABLE Italics VARIABLE Fragment VARIABLE Boldface VARIABLE Glossarizing VARIABLE Section
TYPE-HTML
( src len -- )
<, >. and &.
Used throughout.
: TYPE-HTML ( src len -- )
BEGIN DUP 0> WHILE
CASE OVER C@
[CHAR] < OF ." <" ENDOF
[CHAR] > OF ." >" ENDOF
[CHAR] & OF ." &" ENDOF
EMIT
0 ENDCASE
1 /STRING
REPEAT 2DROP ( ) ;
END-PAR
( -- )
</P> if needed.
NEW-PAR
( -- )
<P> if not already there.
Line-Indent
( str len -- str len n )
Hanging-Indent
( src . str len -- src . str len flag )
: END-PAR ( -- )
OUT @ IF ." </P>" OUT OFF THEN ;
: NEW-PAR ( -- )
OUT @ 0= IF ." <P>" OUT ON THEN ;
: Line-Indent ( str len -- str len n )
2DUP BL SKIP NIP OVER SWAP - ;
: Hanging-Indent ( src . str len -- src . str len flag )
DUP
ANDIF OVER C@ IS-WHITE NOT
ANDIF VIEW-NEXT-LINE
Line-Indent 3 7 WITHIN NIP NIP
ORIF OVER C@ #TAB-CHAR =
THEN THEN THEN ;
Save-as-Title
( src . str len -- same )
HTML-HEAD.
HTML-HEAD
( str len -- str' len' )
CREATE The-Title 256 CHARS ALLOT
: Save-as-Title ( src . str len -- same )
The-Title C@ 0= IF
\ ." <!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML 3.2//EN"">" CR
." <HTML>" CR ." <HEAD>" CR
2DUP BL-SCAN BL-SKIP
." <TITLE>" 2DUP TYPE ." </TITLE>"
The-Title PLACE ( src . str len)
THEN ;
: HTML-HEAD ( src . -- src' . )
OUT OFF Fragment OFF Italics OFF Boldface OFF
Glossarizing OFF Section OFF
0 The-Title C!
BEGIN
DUP 0> NOT ABORT" Missing Commentary for HTML "
SPLIT-NEXT-LINE ( src . str1 len1)
Is-a-Comment
IF Save-as-Title THEN
Commentary-Starts NIP NIP
UNTIL
The-Title C@ 0= ABORT" Missing Title for HTML "
." </HEAD>" ;
.PROGRAM-TEXT
( src . str len -- src . )
.COMMENTARY.
: .PROGRAM-TEXT ( src . str len -- src . )
END-PAR 2DROP ( src .)
DUP 0> NOT IF EXIT THEN
BEGIN OVER C@ #EOL-CHAR = WHILE
SPLIT-NEXT-LINE 2DROP
REPEAT
COMMENTARY-STARTS NOT IF
." <SMALL>Program Text " Section 1 OVER +! @ . ." </SMALL>"
." <BR> <BR>"
THEN
." <B><PRE>"
BEGIN DUP 0> WHILE
SPLIT-NEXT-LINE ( src . str' len' )
Commentary-Starts NOT
ANDIF S" \\ " STARTS? NOT THEN
WHILE
TYPE-HTML CR
REPEAT
S" \\ " STARTS? IF 2DROP
DROP 0 2DUP
THEN
\ Commentary starts.
2DROP ( src .)
THEN
." </PRE></B><HR>" ;
.Tableau
( src . str len -- src . )
: .Tableau ( src . str len -- src . )
END-PAR
." <PRE>" CR
BEGIN
TYPE-HTML CR
SPLIT-NEXT-LINE
S" * *" STARTS?
UNTIL
TYPE-HTML CR
." </PRE>" ;
Italicise
( src len -- )
Parse-for-HTML.
: Italicize ( src len -- same )
Italics @ 0= IF
OVER 1+ C@ IS-ALNUM
ANDIF OVER 1- C@ IS-ALNUM NOT THEN
IF
." <I>"
Italics ON
ELSE
." _"
THEN
ELSE
OVER 1+ C@ DUP IS-ALNUM SWAP [CHAR] { = OR
IF \ _ before alphanumeric or { is for subscript.
." _"
ELSE
." </I>"
Italics OFF
THEN
THEN ;
Embolden
( src len -- )
Parse-for-HTML.
: Embolden ( src len -- same )
Boldface @ 0= IF
OVER 1- C@ IS-WHITE ANDIF OVER 1+ C@ IS-ALNUM THEN
IF
." <B>"
Boldface ON
ELSE \ A lonely * is a * still.
." *"
THEN
ELSE
OVER 1- C@ IS-ALNUM ANDIF OVER 1+ C@ IS-WHITE THEN
IF
." </B>"
Boldface OFF
ELSE \ A lonely * is a * still.
." *"
THEN
THEN ;
Codify
( src len -- )
Parse-for-HTML.
: Codify ( src len -- same )
Fragment @ 0= IF
OVER 1+ C@ IS-WHITE IF \ A lonely ` is a ` still.
." `"
ELSE \ Fragments begin with graphic..
." <B><CODE>"
Fragment ON
THEN
ELSE
." </CODE></B>"
Fragment OFF
THEN ;
Parse-for-HTML
( src len -- )
: Parse-for-HTML ( str len -- )
BEGIN DUP 0> WHILE
CASE OVER C@
[CHAR] < OF ." <" ENDOF
[CHAR] > OF ." >" ENDOF
[CHAR] & OF ." &" ENDOF
[CHAR] ` OF Codify ENDOF
[CHAR] _ OF Italicize ENDOF
[CHAR] * OF Embolden ENDOF
EMIT
0 ENDCASE
1 /STRING
REPEAT 2DROP ( ) ;
.Blockquote
( src . str len -- src' . str' len' )
: .Blockquote ( src . str len -- src' . str' len' )
END-PAR
." <BLOCKQUOTE><P>" CR
BEGIN ( src . src len)
Line-Indent 2 =
WHILE
2 /STRING Parse-for-HTML CR ( src .)
BEGIN
SPLIT-NEXT-LINE ( src . str' len')
DUP 0= WHILE 2DROP
." <BR><BR>"
REPEAT
REPEAT
." </P></BLOCKQUOTE>" CR ;
.Unordered-List
( src . str len -- src' . str' len' )
: .Unordered-List ( src . str len -- src' . str' len' )
END-PAR
." <UL>"
BEGIN
S" * " STARTS? IF ." <LI>" THEN
2 /STRING
Parse-for-HTML
BEGIN
SPLIT-NEXT-LINE ( src . str' len')
DUP 0= WHILE 2DROP
." <BR>"
REPEAT
Line-Indent 2 5 WITHIN
ORIF S" * " STARTS? THEN
WHILE CR REPEAT
CR ." </UL>" CR ;
.Example
( src . str len -- src' . str' len' )
: .Example ( src . str len -- src' . str' len' )
END-PAR
." <B><PRE>" CR
BEGIN
TYPE-HTML CR
SPLIT-NEXT-LINE
Line-Indent 3 < OVER 0= NOT AND
UNTIL
." </PRE></B>" CR ;
Portable-Name
.Definition-Name
( str len -- str' len' )
: Portable-Name ( str len -- )
BEGIN DUP WHILE
OVER C@ DUP IS-ALPHA IF
EMIT
ELSE
BASE @ >R HEX
0 <# # # #> TYPE
R> BASE !
THEN
1 /STRING
REPEAT 2DROP ;
: .Definition-Name ( str len -- str' len')
OVER C@ [CHAR] ` = NOT IF \ Bold for first word.
2DUP BL SCAN /SPLIT 2DUP 2>R
." <B><CODE>" TYPE-HTML
ELSE \ Or fragment of words.
1 /STRING
2DUP [CHAR] ` SCAN /SPLIT 2DUP 2>R
." <B><CODE>" TYPE-HTML
1 /STRING
THEN ( str' len')
BL SKIP
DUP IF
#CHARS/LINE OVER - 19 MIN
R@ - 1 MAX 0 DO ." " LOOP \ At least one space
SPACE \ And one more, up to col 20.
THEN
." </CODE></B>"
Glossarizing @ IF
2R@ CR ." <A NAME=""" Portable-Name ." ""></A>" CR
THEN 2R> 2DROP ;
.Stack-Effect
( str len -- str' len' )
.Definition-Term
: .Stack-Effect ( str len -- str' len')
BEGIN S" ( " STARTS? WHILE
." ( " 2 /STRING
2DUP [CHAR] ) SCAN /SPLIT
." <I>" TYPE-HTML ." </I>"
." )" 1 /STRING
2DUP BL SKIP /SPLIT TYPE
REPEAT ;
: .Definition-Term ( src . str len -- src' . )
." <DT>"
.Definition-Name
.Stack-Effect
SPACE TYPE-HTML CR ;
.Definition-Definition
: .Definition-Definition ( src . -- src . str' len' )
." <DD>"
BEGIN
SPLIT-NEXT-LINE TRIM
DUP 0= ORIF \ Empty or
Line-Indent 3 7 WITHIN \ Single Indent
ORIF OVER C@ #TAB-CHAR =
THEN THEN
WHILE
DUP 0= IF
2DROP ." <BR>" CR \ Line Break
ELSE
BL-SKIP
Parse-for-HTML CR \ Continued Definition
THEN
REPEAT ;
.Definitions
( src . str len -- src' . str' len' )
: .Definitions ( src . str len -- src . str' len' )
END-PAR
." <DL>"
BEGIN
.Definition-Term
.Definition-Definition
Hanging-Indent NOT
UNTIL
." </DL>" CR ;
.Glossary
( src . str len -- src' . )
: Glossarize ( str len -- )
." <A HREF=""#"
2DUP Portable-Name
." "">"
2DUP TYPE-HTML
." </A> " CR
2DROP ;
: .Glossary ( src . str len -- src' . )
Glossarizing ON
2DROP ( src .)
BEGIN
SPLIT-NEXT-LINE ( src' . str len)
S" /GLOSSARY" 2OVER COMPARE \ 0= NOT
WHILE
BEGIN BL-SKIP DUP WHILE
2DUP BL-SCAN /SPLIT
Glossarize
REPEAT 2DROP
REPEAT 2DROP ;
.Needs
( src . str len -- src' . )
: Source-in-Tool-Belt ( str len -- )
." <A HREF=""toolbelt.html#"
2DUP Portable-Name
." "">"
2DUP TYPE-HTML
." </A> " CR
2DROP ;
: .Needs ( src . str len -- src' . )
2DROP ." <SMALL>"
BEGIN
SPLIT-NEXT-LINE ( src' . str len)
S" /NEEDS" 2OVER COMPARE \ 0= NOT
WHILE
BEGIN BL-SKIP DUP WHILE
2DUP BL-SCAN /SPLIT
Source-in-Tool-Belt
REPEAT 2DROP
REPEAT 2DROP ." </SMALL>" ;
HTML-BLOCK-FORMATTING
( src . str len -- src' . str' len' )
.COMMENTARY.
Handles Definitions, Example, Blockquote, and Lists.
: HTML-BLOCK-FORMATTING ( src . str len -- src' . str' len' )
BEGIN
Hanging-Indent \ OUT @ 0= AND
IF
.Definitions
ELSE
Line-Indent 3 7 WITHIN IF \ Single-Indent
.Example
ELSE
Line-Indent 2 = IF \ Slight-Indent
.Blockquote
ELSE
S" * " STARTS? IF \ <sp>*<sp>
.Unordered-List
ELSE EXIT THEN
THEN THEN THEN
AGAIN ;
.COMMENTARY
( src . -- src' . )
HTML-BODY.
: .COMMENTARY ( src . str len -- src' . )
TRIM DUP 0= IF 2DROP END-PAR EXIT THEN
S" GLOSSARY" 2OVER COMPARE 0= IF .Glossary EXIT THEN
S" NEEDS" 2OVER COMPARE 0= IF .Needs EXIT THEN
Line-Indent 7 11 WITHIN IF
END-PAR BL SKIP
." <H3>" TYPE-HTML ." </H3>"
EXIT THEN
Line-Indent 11 15 WITHIN IF
END-PAR BL SKIP
." <H4>" TYPE-HTML ." </H4>"
EXIT THEN
Line-Indent 15 < NOT IF
END-PAR BL SKIP
." <P ALIGN=RIGHT>" TYPE-HTML ." </P>"
EXIT THEN
HTML-BLOCK-FORMATTING
S" * *" STARTS? IF
.Tableau
EXIT THEN
OVER C@ [CHAR] < =
ANDIF OVER 1+ C@ IS-WHITE NOT THEN
IF
TYPE CR
EXIT THEN
Commentary-Ends IF
.PROGRAM-TEXT
EXIT THEN
NEW-PAR Parse-for-HTML ;
.Headline
( -- )
.BODY
( src . -- )
.HTML-End
( -- )
: .Headline ( -- )
\ Knuth's colors.
." <BODY BGCOLOR=""#F8F4E7"" TEXT=""#552800"" LINK=""#0000A0"" VLINK=""#A000A0"" ALINK=""#00A000"">" CR
The-Title C@ 15 40 WITHIN IF
." <CENTER>"
." <H2>" The-Title COUNT TYPE-HTML ." </H2>" CR
." </CENTER>"
ELSE
." <H2>" The-Title COUNT TYPE-HTML ." </H2>" CR
THEN ;
: .BODY ( src size -- )
BEGIN DUP 0> WHILE
SPLIT-NEXT-LINE ( src' . str len)
.COMMENTARY CR ( src' .)
REPEAT
END-PAR 2DROP ;
: .HTML-End ( -- )
." <P><A HREF=""index.html"">Go back to Neil Bawd's home page.</A></P>" CR
." </BODY>" CR
." </HTML>" CR ;
HTML-BODY
( src . -- )
: HTML-BODY ( src . -- )
.Headline
.BODY ( )
.HTML-End ;
.HTML
( src length -- )
MARKUP
( "file.txt" -- )
[DEFINED] OUTPUT-REDIRECTION [IF]
PREVIOUS
[THEN]
: .HTML ( src length -- ) TRIM HTML-HEAD HTML-BODY ;
: MARKUP ( "file.txt" -- )
BL WORD COUNT ( str len)
R/O OPEN-FILE FILE-CHECK ( file-id)
DUP SLURP ( . src length)
.HTML ( file-id)
BURP
CLOSE-FILE FILE-CHECK ;
OUTPUT-MARKUP
( "file.txt file.html" -- )
ALSO
OUTPUT-REDIRECTION.
[DEFINED] OUTPUT-REDIRECTION [IF]
: OUTPUT-MARKUP ( "file.txt file.html" -- )
'OUTPUT OFF
BL WORD COUNT ( str len)
R/O OPEN-FILE FILE-CHECK ( infile)
BL WORD COUNT PAD PLACE
PAD COUNT DELETE-FILE DROP
PAD COUNT W/O CREATE-FILE FILE-CHECK ( . outfile)
>OUTPUT ( infile)
DUP SLURP .HTML BURP
'OUTPUT @ CLOSE-FILE FILE-CHECK
0 >OUTPUT
CLOSE-FILE FILE-CHECK ;
[THEN]