% This is a file written using noweb
%
% $Id: pretzel.nw,v 1.2 1996/09/02 16:21:23 gaertner Exp gaertner $
%

\documentclass{article}
\usepackage{a4,version,pretzeldoc,noweb}
\begin{document}

\includeversion{bigspecs}
%\includeversion{impls}
%\excludeversion{bigspecs}% without elaborate specification
\excludeversion{impls}% without implementation



\title{{Pretzel -- The Program\\}
\vskip5pt\normalsize Version 2.0}
\author{Felix G\"artner}
\maketitle


\begin{abstract}
    This document describes the implementation of pretzel, the
    universal prettyprinter generator.
\end{abstract}


\tableofcontents


\section{Introduction}

Do literate programming tools need to do prettyprinting? This is
a question much discussed not only in the academic community. As a
result of this discussion such tools can be divided into those
that do prettyprinting and those that don't. Those people that like
a nicely formatted source code however don't always have the
same taste concerning formatting and so it is a great drawback
that the majority of literate programming tools has the style of
prettyprinting `hard wired' into the system itself and is (to be
nice) very inflexible.

This paper describes the main program of the ``pretzel'' project. The
this project is an attempt to encapsulate the problems of prettyprinting
and allow future tools to be simpler and more flexible, because they
can concentrate on other important features and mustn't waste their
energy on the intricate details of prettyprinting. In short: pretzel is
a prettyprinter generator.

The concept of pretzel is visualized in figure \ref{concept-fig}. It
takes a formal specification of how a given language should be
prettyprinted as input and produces a prettyprinter that behaves
as specified.

\begin{figure}[h]
\begin{center}
\setlength{\unitlength}{0.012500in}%
\begin{picture}(42,69)(57,735)
\put( 57,795){\makebox(0,0)[lb]{formal description}}
\thinlines
\put( 90,786){\vector( 0,-1){ 36}}
\put( 63,735){\makebox(0,0)[lb]{prettyprinter}}
\put( 99,765){\makebox(0,0)[lb]{pretzel}}
\end{picture}
\end{center}
\caption{The concept of pretzel.}
\label{concept-fig}
\end{figure}

The way in which the ``style'' of prettyprinting is defined is
closely related to the prettyprinting method used by the
generated prettyprinter. The main idea of this method is
that the source code is parsed and enhanced with formatting
instructions for a typesetter. The actual typesetting is then done
by a typesetter program. For a detailed description see the main
documentation of this project.

The formal definitions of the prettyprinting ``style'' have to be
supplied by the user in two files:
 %
\begin{itemize}
\item a formatted token file (with suffix {\tt .ft}) and
\item a formatted grammar file (with suffix {\tt .fg}).
\end{itemize}
 %
In short, the formatted token file contains the way in
which each individual language token is formatted. It defines such
things as printing reserved words in bold face or how to typeset
individual symbols. The formatted grammar file on the other hand
defines the more global format, e.g.~indentation or line breaks.
For more information and a complete example again see the main
documentation of this project.

Figure \ref{detailed-concept} shows a more detailed view of
the way in which pretzel works. Because the resulting prettyprinter
works using a parser, we have to supply both a parser and a scanner.
These two parts of the prettyprinter will be called the {\em prettyprinting
scanner} and the {\em prettyprinting parser}. Pretzel doesn't create
these parts directly, but produces source for scanner and parser
generators. In this version the generated code is compliant to the
standard GNU tools {\em flex} and {\em Bison}.

\begin{figure}
\begin{center}
\setlength{\unitlength}{0.012500in}%
\begin{picture}(119,169)(13,648)
\thinlines
\put(102,792){\vector( 0,-1){ 27}}
\put( 36,747){\vector( 0,-1){ 30}}
\put(105,747){\vector( 0,-1){ 27}}
\put( 36,687){\line( 0,-1){ 12}}
\put( 36,675){\line( 1, 0){ 30}}
\put( 66,675){\vector( 0,-1){ 12}}
\put(105,684){\line( 0,-1){  9}}
\put(105,675){\line(-1, 0){ 30}}
\put( 75,675){\vector( 0,-1){ 12}}
\put( 39,810){\makebox(0,0)[b]{formatted }}
\put( 39,795){\makebox(0,0)[b]{token file}}
\put(105,810){\makebox(0,0)[b]{formatted}}
\put(105,795){\makebox(0,0)[b]{grammar file}}
\put( 36,789){\vector( 0,-1){ 24}}
\put( 36,753){\makebox(0,0)[b]{flex source}}
\put( 72,678){\makebox(0,0)[b]{CC}}
\put(105,753){\makebox(0,0)[b]{Bison source}}
\put( 33,705){\makebox(0,0)[b]{C code}}
\put( 33,690){\makebox(0,0)[b]{(scanner)}}
\put(105,705){\makebox(0,0)[b]{C code}}
\put(105,690){\makebox(0,0)[b]{(parser)}}
\put( 72,648){\makebox(0,0)[b]{pparse(istream*, ostream*)}}
\put( 69,774){\makebox(0,0)[b]{pretzel}}
\put( 72,732){\makebox(0,0)[b]{flex / Bison}}
\end{picture}
\end{center}
\caption{A more detailed overview over the concept of pretzel.}
\label{detailed-concept}
\end{figure}


Together with these tools you can generate the \C\ code for a
new \CPP\ prettyprinter class that looks somewhat like this:
 %
\begin{verbatim}
  class Pparse {       // abstract base class
  public:
    Pparse();
    ~Pparse();
    virtual int prettyprint(istream*, ostream*) = 0;
    virtual int prettyprint(istream*, Output*, ostream*) = 0;
  };

  class PPARSE_NAME : public Pparse {
    PPARSE_NAME();
    ~PPARSE_NAME();
    int prettyprint(istream*, ostream*);
    int prettyprint(istream*, Output*, ostream*);

    void debug_on();
    void debug_off();
  };
\end{verbatim}
 %
The name [[PPARSE_NAME]] can be redefined by the user and defaults to
[[Ppparse]].

\paragraph{Naming conventions:} Pretzel expects the two
input files to have the {\tt .ft} and {\tt .fg} suffixes. The
generated scanner and parser sources will have the same prefix, but
the suffixes are replaced by {\tt .l} (scanner) and {\tt .y}
(parser). Both generated files are self contained entities, i.e.~they
can be used seperately for different purposes.

\paragraph{Command line options:} We want to allow the
following options and command line parameters:

\begin{description}
\item[options:]\hfill\par
  \begin{itemize}
  \item \t{-q}\quad run quietly (no screen messages will be output)
  \item \t{-t}\quad process formatted token file only
  \item \t{-g}\quad process formatted grammar file
  \item \t{-d}\quad debug mode (see section below)
  \item \t{-h}\quad show full usage (help)
  \item \t{-o name}\quad names of the output files begin with \t{name}
  \end{itemize}
\item[parameters:]\hfill\par
  \begin{itemize}
  \item \t{name1}\quad prefix of the two input files (suffixes \t{.ft}
        and \t{.fg} will be assumed); meaning of this parameter changes
        if the following parameter is given
  \item \t{name2}\quad name of the formatted grammar file; if this name
	is given, the parameter \t{file1} is the name of the formatted token
	file
  \end{itemize}
\end{description}

Thus, we end up with the following usage:
\begin{center}
\tt pretzel [-qtgdh] [-o outfile] (prefix $\vert$ file1 file2)
\end{center}

The options \t{-t} and \t{-g} are mutually exclusive, i.e.~you can't
choose both at the same time. The other options are tackled from left
to right.

@ This is an overview of the entire program. The named sections will be
filled up step by step in the course of this text.

<<implementation>>=
<<Header files to include>>
<<Macro definitions>>
<<Global variables>>
<<Functions>>
<<The main program>>


@ The following line is printed out every time pretzel is run.

<<Macro definitions>>=
#define banner "This is pretzel, version 2.0."
@

Here's a first set of header files that we'll surely need. Others
will be included later.

<<Header files to include>>=
#include <iostream>
#include <stdlib.h>

using namespace std;

@

And since some (really old) operating systems don't have the
common [[EXIT_FAILURE]] and [[EXIT_SUCCESS]] macros defined
(in [[stdlib.h]]), we'll define them here.

<<Header files to include>>=
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif
@


@ Pretzel will have a debug option at the command line. If you use
the \t{-d} option the program will print out to the screen
several lines of text about what it is doing. To indicate if
we're in debug mode, I'll have a global variable [[mode]] that can either
hold [[debug]] or [[normal]] values.

<<Macro definitions>>=
#define normal 	0
#define debug	1

@ During program development I will use a macro [[PRETZEL_DEBUG]] for the
same purpose.  If this macro is defined the program will run as if the
\t{-d} option has been set. I chose this tactic to test the code that
analyses the options.

<<Global variables>>=
#ifdef PRETZEL_DEBUG
int mode = debug;
#else
int mode = normal;
#endif

@ To print out debug messages I'll use a function called
[[debug_message]] that takes a string and outputs it to the standard
error stream if we're debugging. A newline character is automatically
added.

<<Functions>>=
void debug_message ( char* s )
{
    if (mode == debug) {
        cerr << s << endl;
    }
    return;
}

@ Finally, you might ask: Why calling a system like this ``pretzel''?
To be honest, I had severe problems in finding something appropriate,
but looking at my dictionary I had an idea! The system here is a
generator for prettyprinters, i.e.~it is more than a prettyprinter.
Looking for more about the word ``pretty'' I came across ``pretzel'',
which was the word that immediately followed it (at least in my
dictionary).






\section{The plan of the program}

The plan of attack is very simple: This program has to process the two
given files from the beginning and turn them into valid flex and Bison
files. We want to accept command line parameters as stated above.
The [[main]] program is easily stated. Note that we have to output the
banner line after we've processed the command line, because the
user might have used the {\tt -q} option.

<<The main program>>=
int main( int argc, char *argv[] )
{
<<Variables local to [[main]]>>
debug_message("Starting the main program...");
<<Process command line>>
<<Print the banner line>>
<<Process the formatted token file if wanted>>
<<Process the formatted grammar file if wanted>>
<<Say goodbye>>
debug_message("Ending gracefully...");
return(EXIT_SUCCESS);
}

@ If we encounter a fatal error, we'll simply output a short message
and quit.

<<Functions>>=
void fatal_error( char* s ) {
    cerr << "fatal error: " << s << endl;
    exit(EXIT_FAILURE);
}
@





\section{Processing the command line}

In the introduction I've given an oveview over the options that
pretzel has.  Which of the command line arguments are used is stored
in the following [[int]] variables. The option is either [[ON]] or
[[OFF]]. All options are [[OFF]] initially. The debug option is an
exception here, because it is handled by the global [[mode]] variable
and because it might be on initially due to the [[PRETZEL_DEBUG]] macro.

<<Macro definitions>>=
#define ON 0
#define OFF 1

@ Table \ref{tab:optvars} shows the variables and the associated
meaning they carry.

\begin{table}
\begin{center}
\begin{tabular}{IlIlI}
\hline
variable	& option \\
\hline
[[be_quiet]]	& \tt -q	\\
[[ft_only]] 	& \tt -t	\\
[[fg_only]]	& \tt -g	\\
[[full_usage]]	& \tt -h	\\
\hline
\end{tabular}
\end{center}
\caption{Variables that store options.}
\label{tab:optvars}
\end{table}

<<Global variables>>=
int be_quiet = OFF;
int ft_only = OFF; /* want to have both files by default */
int fg_only = OFF;
int full_usage = OFF;


@ Now that we know about [[be_quiet]], we can tell the program to output
the banner line only if wanted.

<<Print the banner line>>=
if (be_quiet==OFF) {
    cout << banner << endl;
}

@ Saying bye bye is similar.

<<Say goodbye>>=
if (be_quiet==OFF) {
    cout << "No errors found." << endl;
}



@ Now we turn to the names of the input files. There are at most
two input files:
 %
\begin{enumerate}

\item the formatted token file and

\item the formatted grammar file.

\end{enumerate}
 %
The names of these input files are stored in the variables
[[ft_filename]] and [[fg_filename]].

<<Macro definitions>>=
#define MAX_STRING_LENGTH	100
@

<<Global variables>>=
char ft_filename [ MAX_STRING_LENGTH ];
char fg_filename [ MAX_STRING_LENGTH ];

@ Now we turn to the output files. The output files are in analogy
to the input files
 %
\begin{enumerate}

\item the scanner source file and

\item the parser source file.

\end{enumerate}
 %
The names of the output files are stored in the follwing two
variables.  Their names will be pieced together at run time.

<<Global variables>>=
char scanner_filename [ MAX_STRING_LENGTH ];
char parser_filename  [ MAX_STRING_LENGTH ];

@ If the {\tt -o} option is used we need a place to store this
prefix. This will be done in the global [[outfile_prefix]]. It's
important that it is initialised to the empty string because this will
be used as an indication whether the {\tt -o} option has been used or
not.

<<Global variables>>=
char outfile_prefix [ MAX_STRING_LENGTH ] = "";

@ Now that we have discussed the names of the files, we will meet these
files in person. Input comes from two input file streams [[ft_file]]
and [[fg_file]].

<<Global variables>>=
ifstream ft_file;
ifstream fg_file;

@ Output goes to these two output file streams.

<<Global variables>>=
ofstream scanner_file;
ofstream parser_file;

@ We need the {\tt fstream.h} header to do this.

<<Header files to include>>=
#include<fstream>

using namespace std;

@ Of course not all of the input and output streams are really used
during every run of the program. For instance there will be no need of
[[ft_file]] if the \t{-g} (process only formatted grammar file) option
is used.








\subsection{Getting the options}

Now we come to the tricky part where the command line options are
investigated. To analyse the command line options we will use
the [[getopt]] subroutine from the following library.

<<Header files to include>>=
#include<unistd.h>

@ These variables will be used by [[getopt]].

<<Global variables>>=
extern int optind;
extern char *optarg;
extern int opterr;

@ The [[opterr]] variable must be set to 0 because we don't
want [[getopt]] to issue error messages.

<<Tell [[getopt]] to shut up>>=
opterr=0; 	/* don't let [[getopt]] issue error messages */

@ The following code analyses the options. If the given options are
confusing a message about correct usage will be output on the screen. The
[[errorflag]] variable is used to check this. The extra pair of brackets
limit the scope of the [[errorflag]].

<<Process command line>>=
{
int errorflag = OFF;
debug_message("Starting to analyse the command line...");
<<Tell [[getopt]] to shut up>>
<<Analyse the command line options; set the error flag if necessary>>
<<Analyse the command line parameters; set error flag if necessary>>
<<Display all options and parameters to the terminal if debugging>>
if (errorflag==ON) {
	<<Issue a usage notice to the terminal and exit>>
}
debug_message("Command line options and parameters okay!");
} /* get rid of the errorflag */


@ Here we are now looking at the {\em command line options} first.
The extra brackets are used to eliminate the character [[c]].

<<Analyse the command line options; set the error flag if necessary>>=
{
int c; /* used to store the character returned by [[getopt]] */
debug_message("Beginning to analyse the command line options...");
while (( c = getopt(argc, argv, "qtgdho:") ) != EOF) {
        switch (c) {
		<<Cases in the options loop>>
                default: debug_message("Unknown option");
			 errorflag=ON; /* this case also for `?' */
        } /* switch */
} /* while */
} /* get rid of [[c]] */

@ The command line options are handled from left to right. The debug
option {\tt -d} overrides the quiet option {\tt -q}, i.e.~if both are
given, pretzel prints out debug messages, but doesn't print normal
stuff, like the banner line. Only if {-q} is given on its own, pretzel
won't output anything.

So first let's have a look at the options that can change the path of
the output. The simplest one is probably {\tt -q}.  The \t{-q} option
turns off all regular output.

<<Cases in the options loop>>=
case 'q': be_quiet = ON;  break;


@ The {\tt -d} option sets the mode to [[debug]]. This causes pretzel to
output debug messages during its run. (If you want to debug the
processing of the command line options, you must compile this program
with the [[PRETZEL_DEBUG]] macro defined. Then the [[mode]] is set to
[[debug]] when it is declared.)

<<Cases in the options loop>>=
case 'd': mode = debug; break;


@ The {\tt -o} option defines the prefix of the output files. We'll simply
copy the string given on the command line to our [[outfile_prefix]] storage.

<<Cases in the options loop>>=
case 'o':
    strncpy(outfile_prefix,optarg, MAX_STRING_LENGTH);
    outfile_prefix[MAX_STRING_LENGTH -1] = '\0';
    break;

@ For these cases we need the header file that copes with strings.

<<Header files to include>>=
#include<string.h>

@ The \t{-t} and \t{-g} options turn on their corresponding option
tags. Care is taken that not both are on at the same time.

<<Cases in the options loop>>=
case 't': if (fg_only==ON)
		errorflag = ON;
	  else ft_only=ON;
          break;
case 'g': if (ft_only==ON)
		errorflag = ON;
	  else fg_only=ON;
          break;


@ Finally we have to record whether the user wanted to see the full usage.

<<Cases in the options loop>>=
case 'h': full_usage=ON; break;



@ Now we can handle the command line parameters.  We can have at most
two of them. The meaning of the first parameter depends on the actual
number of parameters. If there is only one parameter given, it
specifies the prefix of both formatted token and grammar file.  If two
parameters are given, the first is the name of the formatted token and the
second is the name of the formatted grammar file.

The value of [[argc]] is the number of parameters (including options)
plus one. [[optind]] is an index into [[argv]] and specifies which string
will be processed next. At this point of the program there are only two
possible correct situations:
 %
\begin{enumerate}

\item Either there is only one parameter left in [[argv]] and
    thus [[optind]]=[[argc-1]],

\item or there are still two parameters left; this is described by
    [[optind]]=[[argc-2]].

\end{enumerate}
 %
If a correct number of parameters is left in [[argv]] the
following precondition for this code fragment must hold:

\begin{center}
[[argc-2]] $\leq$ [[optind]] $\leq$ [[argc-1]]
\end{center}

<<Analyse the command line parameters; set error flag if necessary>>=
debug_message("Beginning to analyse the parameters...");
if (!( ( argc-2<= optind) && (optind <=argc-1) )) {
	debug_message("Wrong number of parameters!");
	errorflag=ON;
} else {  /* we have a correct number (one ore two) parameters */
	if (optind==argc-1) {
		debug_message("One command line parameter");
		<<Only one command line parameter is given>>
	} else {
		debug_message("Two command line parameters");
		<<Two command line parameters are given>>
	}
}

@ If only one parameter is given, this name defines the beginning
of the output files. Any suffix is ignored, so don't mention {\tt .ft}
or {\tt .fg} to pretzel.

<<Macro definitions>>=
#define ft_suffix	".ft"
#define fg_suffix	".fg"
@

<<Only one command line parameter is given>>=
strncpy(ft_filename, argv[argc-1], MAX_STRING_LENGTH);
strcat(ft_filename, ft_suffix );
strncpy(fg_filename, argv[argc-1], MAX_STRING_LENGTH);
strcat(fg_filename, fg_suffix );


@ If two parameters are given we assume that they contain the
full filenames.

<<Two command line parameters are given>>=
strncpy(ft_filename, argv[argc-2], MAX_STRING_LENGTH);
strncpy(fg_filename, argv[argc-1], MAX_STRING_LENGTH);

@ The names of the output files are computed from the [[outfile_prefix]]
(if any) and the extensions \t{.l} for the scanner file and \t{.y} for
the parser file. If no outfile prefix was given, the prefixes of the
individual files are taken.

If only one file was specified and we haven't seen the {\tt -o}
option, we'll take the full name and ignore any suffixes that it may
have.

<<Only one command line parameter is given>>=
if (strlen(outfile_prefix) == 0) {
    strncpy(outfile_prefix, argv[argc-1], MAX_STRING_LENGTH);
}

@ If two names were given, we cut off possible standard suffixes
and take the remaining string as prefix. I'm not going to do
this code here \ldots [XXX]

<<Macro definitions>>=
#define default_prefix	"default.pp"
@

<<Two command line parameters are given>>=
if (strlen(outfile_prefix) == 0) {
    strncpy(outfile_prefix, default_prefix, MAX_STRING_LENGTH);
}


@ The output file names are now pieced together.

<<Macro definitions>>=
#define scanner_suffix	".l"
#define parser_suffix	".y"
@

<<Analyse the command line parameters; set error flag if necessary>>=
strncpy(scanner_filename, outfile_prefix, MAX_STRING_LENGTH);
strcat(scanner_filename, scanner_suffix);
strncpy(parser_filename, outfile_prefix, MAX_STRING_LENGTH);
strcat(parser_filename, parser_suffix);


@ This text will always be output if an error is discorvered during
analysis of the command line. If the \t{-h} option was used the
message will be a little longer than normal.

<<Issue a usage notice to the terminal and exit>>=
cerr	<< banner << endl
	<< "Usage: "
	<< argv[0]
	<< " [-qtgdh] [-o outfile] (prefix | file1 file2)"
	<< endl;
<<Issue the rest of the usage notice if required>>
exit(EXIT_FAILURE);

@ Here is the full notice.

<<Issue the rest of the usage notice if required>>=
if (full_usage==ON) {
cerr	<< "Options:" << endl
	<< "   -q       run quietly" << endl
	<< "   -t       process formatted token file only" << endl
	<< "   -g       process formatted grammat file only" << endl
	<< "            (options -t and -g are mutually exclusive)" << endl
	<< "   -d       print debug information to the screen" << endl
	<< "   -h       print full usage (help)" << endl
	<< "   -o name  output files begin with `name'" << endl
	<< "Parameters:" << endl
	<< "   prefix   prefix of the input file names (extensions" << endl
	<< "            `.ft' and `.fg' are assumed)" << endl
	<< "   file1    full name of the formatted token file" << endl
	<< "   file2    full name of the formatted grammar file" << endl
	<< endl;
} else {
cerr	<< "Say `"
	<< argv[0]
	<< " -h' for full usage." << endl;
}



@ If we are debugging we want to check that the program has analysed the
options correctly. We use the following macro to shorten the code.

<<Macro definitions>>=
#define display_status(option) {			\
	if (option==ON) cerr << "ON" << endl;		\
	else cerr << "OFF" << endl;			\
}

@ The options will only be output if we are debugging.

<<Display all options and parameters to the terminal if debugging>>=
if (mode == debug) {
	<<Now display the options>>
}

@ This code prints a nice table filled with information about command
line otions and parameters.

<<Now display the options>>=
cerr 	<< "These are the chosen options:" << endl
	<< "         quiet (-q): "; display_status(be_quiet);
cerr	<< "   tokens only (-t): "; display_status(ft_only);
cerr	<< "  grammar only (-g): "; display_status(fg_only);
cerr 	<< "          help (-h): "; display_status(full_usage);
cerr	<< "     outfile prefix: " << outfile_prefix << endl
	<< "  scanner file name: " << scanner_filename << endl
	<< "   parser file name: " << parser_filename << endl
	<< "These are the specified parameters:" << endl
	<< "  name of token file: " << ft_filename << endl
	<< "name of grammar file: " << fg_filename << endl;
cerr 	<< endl;
@







\section{Processing the input files}

Now we come to the main part of this program.  Our aim is to mangle
the input files in such a way that we end up with valid scanner and
parser source files. The only thing to look out for if the user
actually wants us to do the job.

The actual work of generating the output files is done within two
\CPP\ classes:
 %
\begin{itemize}

\item [[Pscan_builder]], that builds the prettyprinting scanner from
    a formatted token file (see {\tt ftparse.nw}) and

\item [[Pparse_builder]], that builds a prettyprinting parser (see file
    {\tt fgparse.nw}.

\end{itemize}
 %
Both classes have a member function [[build]] that takes an input
stream and an output stream pointer. They read from the input stream
and write to the output stream.

<<Header files to include>>=
#include"ftparse.h"
#include"fgparse.h"

@

These are the two objects that we'll use to build the output files.

<<Variables local to [[main]]>>=
Pscan_builder scanner_generator;
Pparse_builder parser_generator;

@ The formatted token file is only processed if the [[fg_only]] tag is
set off.

<<Process the formatted token file if wanted>>=
if (fg_only==OFF) {
	<<Now process the formatted token file>>
}

@ If we aren't supposed to be quiet, we give an indication of what
we're doing.

<<Now process the formatted token file>>=
if (be_quiet == OFF) {
    cout << "Processing the formatted token file ("
	<< ft_filename << " -> " << scanner_filename << ")." << endl;
}


@ First of all we have to open the two files and see if they are
there.

<<Now process the formatted token file>>=
ft_file.open(ft_filename);
if (!ft_file) {
    fatal_error("Opening formatted token file failed.");
}

@ Then we have to open the scanner file for output.

<<Now process the formatted token file>>=
scanner_file.open(scanner_filename);
if (!scanner_file) {
    fatal_error("Opening scanner file failed.");
}

@ Next we'll call our handy routine that does the job for us. We have to
check for errors though.

<<Now process the formatted token file>>=
if (scanner_generator.build(&ft_file, &scanner_file) != 0) {
    cerr << scanner_generator.error_text()
	<< " in line " << scanner_generator.error_line()
	<< " of `" << ft_filename << "'." << endl;
    fatal_error("Exiting.");
}

@ We're sure to close the two files again.

<<Now process the formatted token file>>=
ft_file.close();
scanner_file.close();


@ The processing of the formatted grammar file is nearly an exact copy
of the above sections. The only things changed are the names of the
files and the name of the generator function.

<<Process the formatted grammar file if wanted>>=
if (ft_only==OFF) {
	<<Now process the formatted grammar file>>
}

@ Again, we'll say what we're doing.

<<Now process the formatted grammar file>>=
if (be_quiet == OFF) {
    cout << "Processing the formatted grammar file ("
	<< fg_filename << " -> " << parser_filename << ")." << endl;
}


@ First of all we have to open the two files again and see if they are
there.

<<Now process the formatted grammar file>>=
fg_file.open(fg_filename);
if (!fg_file) {
    fatal_error("Opening formatted grammar file failed.");
}

@ Then we have to open the parser file for output.

<<Now process the formatted grammar file>>=
parser_file.open(parser_filename);
if (!parser_file) {
    fatal_error("Opening parser file failed.");
}

@ Next we'll call our handy routine that does the job for us.

<<Now process the formatted grammar file>>=
if (parser_generator.build(&fg_file, &parser_file) != 0) {
    cerr << parser_generator.error_text()
	<< " in line " << parser_generator.error_line()
	<< " of `" << fg_filename << "'." << endl;
    fatal_error("Exiting.");
}

@ We're sure to close the two files again.

<<Now process the formatted grammar file>>=
fg_file.close();
parser_file.close();
@

That's all folks.



\end{document}


%
% $Log: pretzel.nw,v $
% Revision 1.2  1996/09/02  16:21:23  gaertner
% Added missing #include<string.h>
%
% Revision 1.1  1996/03/21  09:06:57  gaertner
% Initial revision
%
%


