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 robust data files. Within wxWidgets itself, it is used to parse the .wxr dialog resource files.
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:
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.
wxExpr for data file manipulation
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"]).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 clauses. Each clause is an object with a 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:
Writing a file is just as easy:
To use the library, include "wxexpr.h".
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.
These are the known bugs:
This section is a brief introduction to using the wxExpr package.
First, some terminology. A wxExprDatabase is a list of clauses, each of which represents an object or record which needs to be saved to a file. A clause has a 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.
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);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:
object(id = 1, name = "Julian Smart").To read the database back in, the following will work:
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";Note the setting of defaults before attempting to retrieve attribute values, since they may not be found.