1998-05-20 10:25:30 -04:00
|
|
|
\section{wxExpr overview}\label{exproverview}
|
|
|
|
|
|
|
|
wxExpr is a C++ class reading and writing a subset of Prolog-like syntax,
|
|
|
|
supporting objects attribute/value pairs.
|
|
|
|
|
|
|
|
wxExpr can be used to develop programs with readable and
|
2004-05-04 04:27:20 -04:00
|
|
|
robust data files. Within wxWidgets itself, it is used to parse
|
1998-05-20 10:25:30 -04:00
|
|
|
the {\tt .wxr} dialog resource files.
|
|
|
|
|
|
|
|
{\bf History of wxExpr}
|
|
|
|
|
|
|
|
During the development of the tool Hardy within the AIAI, a need arose
|
|
|
|
for a data file format for C++ that was easy for both humans and
|
|
|
|
programs to read, was robust in the face of fast-moving software
|
|
|
|
development, and that provided some compatibility with AI languages
|
|
|
|
such as Prolog and LISP.
|
|
|
|
|
|
|
|
The result was the wxExpr library (formerly called PrologIO), which is able to read and write a
|
|
|
|
Prolog-like attribute-value syntax, and is additionally capable of
|
|
|
|
writing LISP syntax for no extra programming effort. The advantages of
|
|
|
|
such a library are as follows:
|
|
|
|
|
|
|
|
\begin{enumerate}\itemsep=0pt
|
|
|
|
\item The data files are readable by humans;
|
|
|
|
\item I/O routines are easier to write and debug compared with using binary files;
|
|
|
|
\item the files are robust: unrecognised data will just be ignored by the application
|
|
|
|
\item Inbuilt hashing gives a random access capability, useful for when linking
|
|
|
|
up C++ objects as data is read in;
|
|
|
|
\item Prolog and LISP programs can load the files using a single command.
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
The library was extended to use the ability to read and write
|
|
|
|
Prolog-like structures for remote procedure call (RPC) communication.
|
|
|
|
The next two sections outline the two main ways the library can be used.
|
|
|
|
|
|
|
|
\subsection{wxExpr for data file manipulation}\itemsep=0pt
|
|
|
|
|
|
|
|
The fact that the output is in Prolog syntax is irrelevant for most
|
|
|
|
programmers, who just need a reasonable I/O facility. Typical output
|
|
|
|
looks like this:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
diagram_definition(type = "Spirit Belief Network").
|
|
|
|
|
|
|
|
node_definition(type = "Model",
|
|
|
|
image_type = "Diamond",
|
|
|
|
attribute_for_label = "name",
|
|
|
|
attribute_for_status_line = "label",
|
|
|
|
colour = "CYAN",
|
|
|
|
default_width = 120,
|
|
|
|
default_height = 80,
|
|
|
|
text_size = 10,
|
|
|
|
can_resize = 1,
|
|
|
|
has_hypertext_item = 1,
|
|
|
|
attributes = ["name", "combining_function", "level_of_belief"]).
|
|
|
|
|
|
|
|
arc_definition(type = "Potentially Confirming",
|
|
|
|
image_type = "Spline",
|
|
|
|
arrow_type = "End",
|
|
|
|
line_style = "Solid",
|
|
|
|
width = 1,
|
|
|
|
segmentable = 0,
|
|
|
|
attribute_for_label = "label",
|
|
|
|
attribute_for_status_line = "label",
|
|
|
|
colour = "BLACK",
|
|
|
|
text_size = 10,
|
|
|
|
has_hypertext_item = 1,
|
|
|
|
can_connect_to = ["Evidence", "Cluster", "Model", "Evidence", "Evidence", "Cluster"],
|
|
|
|
can_connect_from = ["Data", "Evidence", "Cluster", "Evidence", "Data", "Cluster"]).
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
This is substantially easier to read and debug than a series of numbers and
|
|
|
|
strings.
|
|
|
|
|
|
|
|
Note the object-oriented style: a file comprises a series of {\it clauses}.
|
|
|
|
Each clause is an object with a {\it functor}\/ or object name, followed
|
|
|
|
by a list of attribute-value pairs enclosed in parentheses, and finished
|
|
|
|
with a full stop. Each attribute value may be a string, a word (no quotes),
|
|
|
|
an integer, a real number, or a list with potentially recursive elements.
|
|
|
|
|
|
|
|
The way that the facility is used by an application to read in a file is
|
|
|
|
as follows:
|
|
|
|
|
|
|
|
\begin{enumerate}\itemsep=0pt
|
|
|
|
\item The application creates a wxExprDatabase instance.
|
|
|
|
\item The application tells the database to read in the entire file.
|
|
|
|
\item The application searches the database for objects it requires,
|
|
|
|
decomposing the objects using the wxExpr API. The database may be hashed,
|
|
|
|
allowing rapid linking-up of application data.
|
|
|
|
\item The application deletes or clears the wxExprDatabase.
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
Writing a file is just as easy:
|
|
|
|
|
|
|
|
\begin{enumerate}\itemsep=0pt
|
|
|
|
\item The application creates a wxExprDatabase instance.
|
|
|
|
\item The application adds objects to the database using the API.
|
|
|
|
\item The application tells the database to write out the entire database,
|
|
|
|
in Prolog or LISP notation.
|
|
|
|
\item The application deletes or clears the wxExprDatabase.
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
To use the library, include "wxexpr.h".
|
|
|
|
|
|
|
|
\subsection{wxExpr compilation}
|
|
|
|
|
|
|
|
For UNIX compilation, ensure that YACC and LEX or FLEX are on your system. Check that
|
|
|
|
the makefile uses the correct programs: a common error is to compile
|
|
|
|
y\_tab.c with a C++ compiler. Edit the CCLEX variable in make.env
|
|
|
|
to specify a C compiler. Also, do not attempt to compile lex\_yy.c
|
|
|
|
since it is included by y\_tab.c.
|
|
|
|
|
|
|
|
For DOS compilation, the simplest thing is to copy dosyacc.c to y\_tab.c, and doslex.c to
|
|
|
|
lex\_yy.c. It is y\_tab.c that must be compiled (lex\_yy.c is included by
|
|
|
|
y\_tab.c) so if adding source files to a project file, ONLY add y\_tab.c
|
|
|
|
plus the .cc files. If you wish to alter the parser, you will need YACC
|
|
|
|
and FLEX on DOS.
|
|
|
|
|
|
|
|
The DOS tools are available at the AIAI ftp site, in the tools directory. Note that
|
|
|
|
for FLEX installation, you need to copy flex.skl into the directory
|
|
|
|
c:/lib.
|
|
|
|
|
|
|
|
If you are using Borland C++ and wish to regenerate lex\_yy.c and y\_tab.c
|
|
|
|
you need to generate lex\_yy.c with FLEX and then comment out the `malloc' and `free'
|
|
|
|
prototypes in lex\_yy.c. It will compile with lots of warnings. If you
|
|
|
|
get an undefined \_PROIO\_YYWRAP symbol when you link, you need to remove
|
|
|
|
USE\_DEFINE from the makefile and recompile. This is because the parser.y
|
|
|
|
file has a choice of defining this symbol as a function or as a define,
|
|
|
|
depending on what the version of FLEX expects. See the bottom of
|
|
|
|
parser.y, and if necessary edit it to make it compile in the opposite
|
|
|
|
way to the current compilation.
|
|
|
|
|
1999-12-05 05:07:00 -05:00
|
|
|
%To test out wxExpr compile the test program (samples/wxexpr/wxexpr.exe),
|
|
|
|
%and try loading test.exp into the test
|
|
|
|
%program. Then save it to another file. If the second is identical to the
|
|
|
|
%first, wxExpr is in a working state.
|
1998-05-20 10:25:30 -04:00
|
|
|
|
|
|
|
\subsection{Bugs}
|
|
|
|
|
|
|
|
These are the known bugs:
|
|
|
|
|
|
|
|
\begin{enumerate}\itemsep=0pt
|
2000-07-15 15:51:35 -04:00
|
|
|
\item Functors are permissible only in the main clause (object).
|
1998-05-20 10:25:30 -04:00
|
|
|
Therefore nesting of structures must be done using lists, not predicates
|
|
|
|
as in Prolog.
|
|
|
|
\item There is a limit to the size of strings read in (about 5000 bytes).
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
\subsection{Using wxExpr}
|
|
|
|
|
|
|
|
This section is a brief introduction to using the wxExpr package.
|
|
|
|
|
|
|
|
First, some terminology. A {\it wxExprDatabase}\/ is a list of {\it clauses},
|
|
|
|
each of which represents an object or record which needs to be saved to a file.
|
|
|
|
A clause has a {\it functor}\/ (name), and a list of attributes, each of which
|
|
|
|
has a value. Attributes may take the following types of value: string, word,
|
|
|
|
integer, floating point number, and list. A list can itself contain any
|
|
|
|
type, allowing for nested data structures.
|
|
|
|
|
|
|
|
Consider the following code.
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
wxExprDatabase db;
|
|
|
|
|
|
|
|
wxExpr *my_clause = new wxExpr("object");
|
|
|
|
my_clause->AddAttributeValue("id", (long)1);
|
|
|
|
my_clause->AddAttributeValueString("name", "Julian Smart");
|
|
|
|
db.Append(my_clause);
|
|
|
|
|
|
|
|
ofstream file("my_file");
|
|
|
|
db.Write(file);
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
This creates a database, constructs a clause, adds it to the database,
|
|
|
|
and writes the whole database to a file. The file it produces looks like
|
|
|
|
this:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
object(id = 1,
|
|
|
|
name = "Julian Smart").
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
To read the database back in, the following will work:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
wxExprDatabase db;
|
|
|
|
db.Read("my_file");
|
|
|
|
|
|
|
|
db.BeginFind();
|
|
|
|
|
|
|
|
wxExpr *my_clause = db.FindClauseByFunctor("object");
|
|
|
|
int id = 0;
|
|
|
|
wxString name = "None found";
|
|
|
|
|
|
|
|
my_clause->GetAttributeValue("id", id);
|
|
|
|
my_clause->GetAttributeValue("name", name);
|
|
|
|
|
|
|
|
cout << "Id is " << id << ", name is " << name << "\n";
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
Note the setting of defaults before attempting to retrieve attribute values,
|
|
|
|
since they may not be found.
|
|
|
|
|