cgal/Benchmark/doc_tex/Benchmark/visitor.tex

280 lines
15 KiB
TeX

% -------------------------------------------------------------------------
\subsection{Visitor Design Pattern for the Parser\label{visitor}}
To ease the use of the parser, we provide a visitor interface,
following the visitor design pattern~\cite{cgal:ghjv-dpero-95}. An
application would derive its own visitor from the
\texttt{Benchmark\_visitor} base class. This design choice makes the
parser independent of application types, such as long integers.
Instead, the parser keeps almost all recognized literals in strings of
type \texttt{std::string}.
The visitor has various functions that will be called from the parser
with suitable parameters when the parser recognizes certain grammar
rules. The visitor can then rely on the fact that the file is well
formed and just process the parameters. Typically the visitor will
store the objects found in the benchmark file in an internal data
structure for later use in the application. The visitor has to convert
the string parameters to the application specific types, for example,
for long integers for curve coefficients.
\subsubsection{A First Visitor\label{checker}}
We start with an example for a basic visitor that just checks a
benchmark file for correct syntax, i.e., it does not actually process
the objects in the file. Programs using the visitor will look similar,
but they will typically implement more member functions of the base
class interface, see Section~\ref{functions}. This example program
exists in source code in the distribution at
\verb|BMTools/parser/src/check_syntax.C|.
\begin{verbatim}
#include <iostream>
#include <benchmark_visitor.hpp>
struct Checker : public Benchmark_visitor {
Checker() {}
\end{verbatim}
\noindent
The visitor class \texttt{Checker} is derived from the
\texttt{Benchmark\_visitor} base class and has a default constructor.
The base class defines the interface for all visitors in terms of
virtual member functions that we can override in the derived class.
All member functions have sensible defaults that simplify the
implementation of a visitor that accepts only a subset of the objects.
For example, all object accepting member functions default to a call
to the error handler with a ``token not handled'' error message. We
explain in Section~\ref{functions} the available member functions and
in Section~\ref{extend} how the \texttt{Benchmark\_visitor} can be
extended. Here, we just override the particular error handler for
the ``token not handled'' error message and disable the error message,
since we are just interested in accepting all tokens but do not handle
them individually.
\begin{verbatim}
virtual void token_not_handled( std::string s) {}
\end{verbatim}
\noindent
In other typical visitor implementations this function would not be
overwritten because it is not called when the visitor recognizes and
processes a parameter properly. An example of such a processing is the
following handling of the classification entries, which is handled
with the \texttt{classification} member function in the visitor that
accepts six string parameters for the different classification
entries. We implement a validness test that checks the parameters for
proper values.
\begin{verbatim}
virtual void accept_classification( std::string problem,
std::string geom,
std::string clas,
std::string family,
std::string instance,
std::string release) {
if ((problem != "Arrangement") && (problem != "CSG")
&& (problem != " "))
error_handler( "classification error");
if ((geom != "Lines") && (geom != "Circles") && (geom != "Conics")
&& (geom != "Cubics") && (geom != "Quartics")
&& (geom != "ArbitraryDegreeCurves") && ( geom != "Quadrics")
&& (geom != "Tori") && (geom != "Planes") && (geom != " "))
error_handler( "classification error" );
if ((clas != "FullCurves") && (clas != "Ellipses")
&& (clas != "BoundedArcs") && (clas != "UnboundedArcs")
&& (clas != "FullSurfaces") && (clas != "BoundedPatches")
&& (clas != "UnboundedPatches") && (clas != " "))
error_handler( "classification error" );
}
\end{verbatim}
\noindent
In addition, we use the benchmark name for a suitable diagnostic
output. For this, we override the implementation of the
\texttt{accept\_benchmark\_name} member function that accepts one
string parameters for the name. However, the base class implementation
of this function stores the name in the base class for later access
with the \texttt{benchmark\_name} member function, for example for
error messages, that we want to preserve. The easiest solution is to
call the implementation of the member function in the base class as
well. That finishes our visitor implementation.
\begin{verbatim}
virtual void accept_benchmark_name( std::string s) {
Benchmark_visitor::accept_benchmark_name(s);
std::cerr << "name '" << s << "', ";
}
};
\end{verbatim}
\noindent
It follows a simple main program that checks all files given by their
filenames on the command line for syntax errors and prints a suitable
diagnostic message.
\begin{verbatim}
int main( int argc, char* argv[] ) {
int exit_status = 0;
for ( int i = 1; i < argc; ++i) {
Checker check;
std::cerr << "File '" << argv[i] << "', ";
if ( benchmark_parse_file( argv[i], & check)) {
std::cerr << "is o.k." << std::endl;
} else {
std::cerr << "is malformed." << std::endl;
exit_status = 1;
}
}
return exit_status;
}
\end{verbatim}
\noindent
A similar global parser function allows parsing from an already opened
\CC\ stream. However, a stream is lacking useful diagnostic
information---filename and line number---that we provide explicitly
for this global parser function, where the line number has the
sensible default to start at one. Both functions return \texttt{true}
if the file parses without error, and \texttt{false} otherwise. The
full function signatures are:
\begin{verbatim}
bool benchmark_parse_file( std::string name, Benchmark_visitor* v);
bool benchmark_parse_stream( std::istream& in, std::string name,
Benchmark_visitor* v, int n = 1);
\end{verbatim}
\subsubsection{Benchmark Visitor Functions\label{functions}}
In the following table the functions that exist in the
\ccc{Benchmark_visitor} class are listed. The \$-bison syntax
denotes the value of the arguments in the grammar rule, typically the
integer and strings, counting terminal symbols, non-terminal symbols,
and also the blocks in curly braces. For their semantic specification
see Section~\ref{grammar} and Section~\ref{extend}. The statements in
curly braces
% \Open\ts{...}\Close\
\texttt{\{...\}}
are function calls to the visitor.
They come in two flavors, either a single function call, such as in
\texttt{accept\_integer(\$1)} for integers, if the entry has a small
constant number of parameters and only a few variants, or a pair of
functions that enclose the parsing of the parameters and form a proper
bracketing, such as for polynomials with
\ccc{begin_polynomial_1()} and \ccc{end_polynomial_1()},
where its integer coefficients are detected between these two function
calls.
A typical visitor would maintain a list of integers, initialize
it in the \ccc{begin_polynomial_1()} call, stores all integers
accepted in the \ccc{accept_integer(\$1)} function in this list,
and builds a new polynomial from the list in the
\ccc{end_polynomial_1()} function. In general, a visitor
implementation would work with stacks to reflect the recursive nature
of the grammar.
\begin{ccTexOnly}
\begin{tabular}{*{2}{| l} |} \hline
Object & grammar rule with visitor function \\ \hline \hline
Integer & {\bf Integer} \{accept\_integer(\$1);\} \\ \hline
Rational & {\bf Rational ( Integer , Integer )} \{accept\_rational(\$3, \$5);\} \\ \hline
Infty & {\bf MINUS\_INFTY} \{accept\_infty(\$1);\} \\
& {\bf PLUS\_INFTY} \{accept\_infty(\$1);\} \\ \hline
Orientation & {\bf COUNTERCLOCKWISE} \\
& {\bf CLOCKWISE} \\
& {\bf VOID} \\ \hline
Integer\_sequence & {\bf Integer} \{accept\_integer(\$1);\} \\
& Integer\_sequence {\bf \Large ,} {\bf Integer} \{accept\_integer(\$3);\} \\ \hline
Point\_2 & {\bf Point\_2 ( Integer , Integer )} \{accept\_point\_2(\$3, \$5);\} \\
& {\bf Point\_2 ( Integer , Integer , Integer )} \{accept\_point\_2(\$3, \$5, \$7);\} \\
& {\bf Point\_2 ( Rational ( Integer , Integer ) , Rational ( Integer , Integer ) )}\\
& \ \ \ \ \{accept\_point\_2(\$5, \$7, \$12, \$14);\} \\ \hline
Polynomial & {\bf Polynomial\_1} \{begin\_polynomial\_1();\} {\bf \Large (} Integer\_sequence {\bf \Large )}\\
& \ \ \ \ \{end\_polynomial\_1();\} \\ \hline
AlgebraicReal & {\bf AlgebraicReal} \{begin\_algebraic\_real();\} {\bf \Large (}\\
& \ \ {\bf Polynomial\_1} \{begin\_polynomial\_1();\}\\
& \ \ \ \ \ {\bf \Large (} Integer\_sequence {\bf \Large )}\\
& \ \ \ \ \ \ \ \ \ \{end\_polynomial\_1();\} {\bf \Large ,} \\
& \ \ Rational {\bf \Large ,} Rational {\bf \Large ,} \\
& \ \ {\bf Integer} \{accept\_integer(\$15);\} {\bf \Large )} \\
& \ \ \ \ \{end\_algebraic\_real();\} \\ \hline
LineSegment & {\bf LineSegment\_2} \{begin\_line\_segment\_2();\} {\bf \Large (} Point\_2 {\bf \Large ,} \\
& \ \ \ \ \ \ \ \ \ \ Point\_2 {\bf \Large )} \{end\_line\_segment\_2();\}\\ \hline
Circle & {\bf Circle\_2} \{begin\_circle\_2();\} {\bf \Large (} Point\_2 {\bf \Large ,} \\
& {\bf Integer} \{accept\_integer(\$6);\} {\bf \Large )} \{end\_circle\_2();\} \\
Circle & {\bf Circle\_2} \{begin\_circle\_2();\} {\bf \Large (} Point\_2 {\bf \Large ,} Rational {\bf \Large )} \{end\_circle\_2();\} \\ \hline
Conic & {\bf Conic\_2 ( Integer, Integer, Integer, Integer, Integer, Integer )} \\
& \{accept\_conic\_2 (\$3, \$5, \$7, \$9, \$11, \$13);\}\\ \hline
ConicPoint & {\bf ConicPoint\_2} \{begin\_conic\_point\_2();\} {\bf (} Conic , \\
& \ \ AlgebraicReal {\bf \Large ,} Integer {\bf \Large )} \\
& \ \ \ \ \ \ \ \ \ \{end\_conic\_point\_2();\}\\
& {\bf ConicPoint\_2} \{begin\_conic\_point\_2();\} {\bf (} Conic , \\
& \ \ Infty {\bf \Large ,} Integer {\bf \Large )} \\
& \ \ \ \ \ \ \ \ \ \{end\_conic\_point\_2();\}\\
& {\bf ConicPoint\_2} \{begin\_conic\_point\_2();\} {\bf (} Conic , \\
& \ \ AlgebraicReal {\bf \Large ,} Infty {\bf \Large )} \\
& \ \ \ \ \ \ \ \ \ \{end\_conic\_point\_2();\}\\ \hline
ConicArc & {\bf ConicArc\_2} \{begin\_conic\_arc\_2();\} {\bf \Large (} Conic {\bf \Large ,} \\
& \ \ ConicPoint {\bf \Large ,} \\
& \ \ ConicPoint {\bf \Large ,} \\
& \ \ orientation \{accept\_orientation(\$10);\} {\bf \Large )} \\
& \{end\_conic\_arc\_2();\}\\
& {\bf ConicArc\_2} \{begin\_conic\_arc\_2();\} {\bf \Large (} ConicPoint {\bf \Large )} \{end\_conic\_arc\_2();\}\\ \hline
Cubic & {\bf Cubic\_2 (} \\
& \ \ {\bf Integer , Integer , Integer , Integer , Integer ,} \\
& \ \ {\bf Integer , Integer , Integer , Integer , Integer )} \\
& \{accept\_cubic\_2 (\$3, \$5, \$7, \$9, \$11, \$13, \$15, \$17, \$19, \$21);\}\\ \hline
Quadric & {\bf Quadric\_3 (} \\
& \ \ {\bf Integer , Integer , Integer , Integer , Integer ,} \\
& \ \ {\bf Integer , Integer , Integer , Integer , Integer )} \\
& \{accept\_quadric\_3 (\$3, \$5, \$7, \$9, \$11, \$13, \$15, \$17, \$19, \$21);\}\\ \hline
\end{tabular}
\end{ccTexOnly}
\begin{ccHtmlOnly}
<div align="center">
<table cellpadding=3 border="1">
<tr><th>Object</th><th>Grammar rule with visitor function</th></tr>
<tr><td>Integer</td><td><b>Integer</b>{accept_integer($1);}</td></tr>
<tr><td>Rational</td><td><b>Rational(Integer, Integer)</b> {accept_rational($3, $5);}</td></tr>
<tr><td>Infty</td><td><b>MINUS_INFTY</b> {accept_infty($1);}<br>
<b>PLUS_INFTY</b> {accept_infty($1);}</td></tr>
<tr><td>Orientation</td><td><b>COUNTERCLOCKWISE</b><br>
<b>CLOCKWISE</b><br>
<b>VOID</b></td></tr>
<tr><td>Integer_sequence</td>
<td><b>Integer} {accept_integer($1);}<br>
Integer_sequence, <b>Integer</b> {accept_integer($3);}</td></tr>
<tr><td>Point_2</td>
<td><b>Point_2(Integer,Integer)</b> {accept_point_2($3, $5);}<br>
<b>Point_2(Integer,Integer,Integer)</b> {accept_point_2($3, $5, $7);}<br>
<b>Point_2(Rational(Integer,Integer),Rational(Integer,Integer))</b> {accept_point_2($5, $7, $12, $14);}</td></tr>
<tr><td>Polynomial</td><td><b>Polynomial_1</b> {begin_polynomial_1();}<b>(</b>Integer_sequence<b>)</b>{end_polynomial_1();}</td></tr>
<tr><td>AlgebraicReal</td>
<td><b>AlgebraicReal</b> {begin_algebraic_real();}<b>(</b><br>
<b>Polynomial_1} {begin_polynomial_1();}<b>(</b>Integer_sequence<b>)</b>{end_polynomial_1();}<b>,</b>Rational<b>,</b>Rational<b>,</b><b>Integer} {accept_integer($15);}<br>
<b>)</b> {end_algebraic_real();}</td></tr>
<tr><td>LineSegment</td><td><b>LineSegment_2</b> {begin_line_segment_2();}<b>(</b>Point_2<b>,</b>Point_2<b>)</b>{end_line_segment_2();}</td></tr>
<tr><td>Circle<br>
Circle</td><td><b>Circle_2</b> {begin_circle_2();}<b>(</b>Point_2<b>,</b><b>Integer</b> {accept_integer($6);}<b>)</b> {end_circle_2();}<br>
<b>Circle_2</b> {begin_circle_2();}<b>(</b>Point_2<b>,</b>Rational<b>)</b> {end_circle_2();}</td></tr>
<tr><td>Conic</td>
<td><b>Conic_2(Integer,Integer,Integer,Integer,Integer,Integer)</b> {accept_conic_2 ($3, $5, $7, $9, $11, $13);}</td></tr>
<tr><td>ConicPoint</td>
<td><b>ConicPoint_2</b> {begin_conic_point_2();}<b>(}Conic,AlgebraicReal<b>,</b>Integer<b>)</b> {end_conic_point_2();}<br>
<b>ConicPoint_2</b> {begin_conic_point_2();}<b>(}Conic,Infty<b>,</b>Integer<b>)</b> {end_conic_point_2();}<br>
<b>ConicPoint_2</b> {begin_conic_point_2();}<b>(}Conic,AlgebraicReal<b>,</b>Infty<b>)</b> {end_conic_point_2();}</td></tr>
<tr><td>ConicArc</td>
<td><b>ConicArc_2</b> {begin_conic_arc_2();} <b>(</b>Conic<b>,</b>ConicPoint<b>,</b>ConicPoint<b>,</b>orientation {accept_orientation($10);}<b>)</b> {end_conic_arc_2();}<br>
<b>ConicArc_2</b> {begin_conic_arc_2();} <b>(</b>ConicPoint<b>)</b> {end_conic_arc_2();}</td></tr>
<tr><td>Cubic</td>
<td><b>Cubic_2(Integer,Integer,Integer,Integer,Integer,Integer,Integer,Integer,Integer,Integer)</b> {accept_cubic_2($3, $5, $7, $9, $11, $13, $15, $17, $19, $21);}</td></tr>
<tr><td>Quadric</td><td><b>Quadric_3(Integer,Integer,Integer,Integer,Integer,Integer,Integer,Integer,Integer,Integer)</b> {accept_quadric_3($3, $5, $7, $9, $11, $13, $15, $17, $19, $21);}
</table>
</div>
\end{ccHtmlOnly}