[dir] Zum Verzeichnisinhalt     [exercise] Zur Musterlösung     [download] (SHIFT + Linke Maustaste)
@p maximum_input_line_length = infinity
@t title titlefont left "Exercise: Generating a HTML bookmark file"

Consider a simple file format (.bmf == "bookmark file")
to specify the contents of a bookmark web page.
Such a specification contains web links consting of URL/Name pairs
which are grouped into different subjects. 
The Eli generated processor is to translate such specifications into 
HTML files containing title, a table of contents with links to the
different sections and for each section the list of named links.

Here is an example bookmark file specification in this format

@N@<travel.bmf@>@{ 
bookmarks "My favorite travel links"

"Maps"
{ 
   "Hamburg"         "http://www.city.net/countries/germany/hamburg/maps/" 
   "Mobile, Alabama" "http://www.travelbase.com/auto/guides/mobile-area-al.html" 
   "Ski Maps"        "http://www.skimaps.com/Archive/europe.html"
}

"Train"
{ 
  "Deutsche Bahn Fahrplan"  "http://www.bahn.de/fahrplan.htm" 
  "Amtrak Schedules"        "http://www.mcs.net/~dsdawdy/Amtrak/amtrak.html"
}

"Hotels"
{ 
  "All the Hotels on the Web" "http://www.all-hotels.com/" 
}
@}

From the specification "travel.bmf" 
our Eli generated processor is to generate
the following HTML source code:

@N@<travel.html@>@{ 
<HTML>
<HEAD>
<TITLE>
My favorite travel links
</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>My favorite travel links</H1>
<H3>Table of Contents</H3>
<UL>
<LI> <A HREF="#position_Maps">Maps</A>
<LI> <A HREF="#position_Train">Train</A>
<LI> <A HREF="#position_Hotels">Hotels</A>
</UL>
<P>
<P>
<A NAME="position_Maps"></A>
<H3>Maps</H3>
<P>
<UL><LI><A HREF="http://www.city.net/countries/germany/hamburg/maps/">Hamburg</A></UL>
<P>
<UL><LI><A HREF="http://www.travelbase.com/auto/guides/mobile-area-al.html">Mobile, Alabama</A></UL>
<P>
<UL><LI><A HREF="http://www.skimaps.com/Archive/europe.html">Ski Maps</A></UL>
<P>
<A NAME="position_Train"></A>
<H3>Train</H3>
<P>
<UL><LI><A HREF="http://www.bahn.de/fahrplan.htm">Deutsche Bahn Fahrplan</A></UL>
<P>
<UL><LI><A HREF="http://www.mcs.net/~dsdawdy/Amtrak/amtrak.html">Amtrak Schedules</A></UL>
<P>
<A NAME="position_Hotels"></A>
<H3>Hotels</H3>
<P>
<UL><LI><A HREF="http://www.all-hotels.com/">All the Hotels on the Web</A></UL>

</BODY>
</HTML>

@}

@A@<Specification of the lexical and syntactical structure@>

The concrete syntax in extended BNF format:

@O@<syntax.con@>@{ 
bookmarks : title sections.
sections : section +.
title : 'bookmarks' string.
section : section_name '{' links '}'.
links : link +.
section_name : string.
link : link_name link_url.
link_name : string.
link_url : string.
@}

For the specification of the lexical structure of terminal string
we use one of Eli's canned symbol description to make
our strings look like string literals in C. 
Changing the standard processor for C_STRING_LIT 
to "c_mkstr" removes the quotes surrounding the strings.

@O@<string.gla@>@{ 
string:     C_STRING_LIT [c_mkstr]
@}

@A@<Output patterns for HTML text generation@>


Some useful ptg patterns for generating HTML text and
concatenating generated text:

@O@<ptgbasics.ptg@>@{
Seq:	$ $
@}


@O@<htmlbasics.ptg@>@{ 

/* top level heading */
Heading:
	"<H1>" $1 string "</H1>\n"

/* smaller heading */
Subheading:
	"<H3>" $1 string "</H3>\n"

/* paragraph */
Paragraph:
	"<P>\n" $1 

/* lists and list elements */
List : "<UL>\n" $ "</UL>\n"
Listelement : "<P><LI>" $ "</LI>\n" 
@}


@A@<Computations for output text generation@>


We need C strings (char*) as attribute types. The "Strings" module
contains the definition for type "CharPtr":

@O@<cstring.specs@>@{ 
 $/Tech/Strings.specs
@}


The generated HTML page is ouptut at the root of the abstract
structure tree. For simplicity we use a fix output file name "out.html".

@O@<pageframe.ptg@>@{ 
/* frame (with page title) for a HTML page */
Frame: 	"<HTML>\n"
	"<HEAD>\n"
	"<TITLE>\n" 
	$1 string           /* page title */
	"\n</TITLE>\n"
	"</HEAD>\n"
	"<BODY BGCOLOR=\"#FFFFFF\">\n"
	$2                  /* page content */ 
	"\n</BODY>\n"
        "</HTML>\n"
@}

@O@<pageoutput.lido@>@{ 
RULE :	bookmarks ::= title sections
COMPUTE PTGOutFile("out.html", 
	  PTGFrame(
	     title.titlestring,
             bookmarks.page));
END;
@}

The title of the HTML page is given in context "title ::= 'bookmarks' string".
The value of the terminal "string" is an index to the 
string storage table containing the string's  representation.
This string representation is returned by the predefined
function "StringTable()".

@O@<title.lido@>@{ 
ATTR titlestring : CharPtr;
RULE :	title ::= 'bookmarks' string
COMPUTE	title.titlestring = StringTable(string);
END;
@}

The overall HTML page structure simply consists of
heading, table of contents and the sections containing the bookmarks.
We use the attribute "page" to represent this structure at the root
of the tree.
 

@O@<pagestructure.lido@>@{ 
ATTR page : PTGNode;
RULE :	bookmarks ::= title sections
COMPUTE bookmarks.page = 
	        PTGSeq(PTGHeading(title.titlestring),
		       PTGSeq(bookmarks.toc,
		              PTGParagraph(bookmarks.text)));
END;
@}

The table of contents contains one entry for each section. 
The entry is connected to its section by a local link.

@O@<tocentry.ptg@>@{ 
/* HTML list element containg a section name and a local link to
   the corresponding section */
Tocentry : "<LI> <A HREF=\"#position_" $1 string "\">" $1 string "</A>\n"
@}


To construct the table of contens we make use of Lido's remote
attribute access construct "CONSTITUENTS". It accesses all
section_name nodes in the structure tree combinig them to a
sequence of entries for the table of contents list.


@O@<tableofcontents.lido@>@{ 
ATTR toc : PTGNode;
ATTR name : CharPtr;

RULE :	bookmarks ::= title sections
COMPUTE bookmarks.toc = 
           PTGSeq(PTGSubheading("Table of Contents"),
                  PTGList(CONSTITUENTS section_name.name
                          WITH (PTGNode, PTGSeq, PTGTocentry, PTGNull)));
END;

RULE : section_name ::= string
COMPUTE section_name.name = StringTable(string);
END;
@}

The text for each bookmark section consists of the section heading
followed by a list of links. Each section has a label by which it can
directly be accessed from the corresponding table of contents entry. 


@O@<locallabel.ptg@>@{ 
Locallabel: "<A NAME=\"position_" $1 string  "\"></A>\n"
@}

The HTML texts that are generated for the different sections 
have to be concatenated to
yield the overall sections text at the root of the tree. 

@O@<sectiontext.lido@>@{ 
ATTR text : PTGNode;
ATTR linktext : PTGNode;

RULE :	bookmarks ::= title sections
COMPUTE bookmarks.text = CONSTITUENTS section.text
                         WITH (PTGNode, PTGSeq, PTGParagraph, PTGNull);
END;

RULE :	section ::= section_name '{' links '}'
/* the section has 3 components: label, heading and links,
   instead of defining a dedicated 3-parameter pattern, we use two nested
   "PTGSeq" patterns:
*/
COMPUTE section.text = PTGSeq(PTGLocallabel(section_name.name),
	                      PTGSeq(PTGSubheading(section_name.name),
				     section.linktext));

/***************************** SOLUTION *************************************/

	section.linktext = CONSTITUENTS link.text
                           WITH (PTGNode, PTGSeq, PTGParagraph, PTGNull);
END;


RULE :	link ::= link_name link_url
COMPUTE link.text = PTGHyperlink(link_url.name, link_name.name);
END;

RULE :	link_name ::= string
COMPUTE link_name.name = StringTable(string);
END;

RULE :	link_url ::= string
COMPUTE link_url.name = StringTable(string);
END;
@}

The ptg pattern for hyperlinks.

@O@<hyperlink.ptg@>@{ 
/* hyperlink */
Hyperlink : "<UL><LI>" "<A HREF=\"" $1 string "\">" $2 string "</A></UL>\n"
@}