]>
Commit | Line | Data |
---|---|---|
1 | \section{wxExpr overview}\label{exproverview} | |
2 | ||
3 | wxExpr is a C++ class reading and writing a subset of Prolog-like syntax, | |
4 | supporting objects attribute/value pairs. | |
5 | ||
6 | wxExpr can be used to develop programs with readable and | |
7 | robust data files. Within wxWindows itself, it is used to parse | |
8 | the {\tt .wxr} dialog resource files. | |
9 | ||
10 | {\bf History of wxExpr} | |
11 | ||
12 | During the development of the tool Hardy within the AIAI, a need arose | |
13 | for a data file format for C++ that was easy for both humans and | |
14 | programs to read, was robust in the face of fast-moving software | |
15 | development, and that provided some compatibility with AI languages | |
16 | such as Prolog and LISP. | |
17 | ||
18 | The result was the wxExpr library (formerly called PrologIO), which is able to read and write a | |
19 | Prolog-like attribute-value syntax, and is additionally capable of | |
20 | writing LISP syntax for no extra programming effort. The advantages of | |
21 | such a library are as follows: | |
22 | ||
23 | \begin{enumerate}\itemsep=0pt | |
24 | \item The data files are readable by humans; | |
25 | \item I/O routines are easier to write and debug compared with using binary files; | |
26 | \item the files are robust: unrecognised data will just be ignored by the application | |
27 | \item Inbuilt hashing gives a random access capability, useful for when linking | |
28 | up C++ objects as data is read in; | |
29 | \item Prolog and LISP programs can load the files using a single command. | |
30 | \end{enumerate} | |
31 | ||
32 | The library was extended to use the ability to read and write | |
33 | Prolog-like structures for remote procedure call (RPC) communication. | |
34 | The next two sections outline the two main ways the library can be used. | |
35 | ||
36 | \subsection{wxExpr for data file manipulation}\itemsep=0pt | |
37 | ||
38 | The fact that the output is in Prolog syntax is irrelevant for most | |
39 | programmers, who just need a reasonable I/O facility. Typical output | |
40 | looks like this: | |
41 | ||
42 | \begin{verbatim} | |
43 | diagram_definition(type = "Spirit Belief Network"). | |
44 | ||
45 | node_definition(type = "Model", | |
46 | image_type = "Diamond", | |
47 | attribute_for_label = "name", | |
48 | attribute_for_status_line = "label", | |
49 | colour = "CYAN", | |
50 | default_width = 120, | |
51 | default_height = 80, | |
52 | text_size = 10, | |
53 | can_resize = 1, | |
54 | has_hypertext_item = 1, | |
55 | attributes = ["name", "combining_function", "level_of_belief"]). | |
56 | ||
57 | arc_definition(type = "Potentially Confirming", | |
58 | image_type = "Spline", | |
59 | arrow_type = "End", | |
60 | line_style = "Solid", | |
61 | width = 1, | |
62 | segmentable = 0, | |
63 | attribute_for_label = "label", | |
64 | attribute_for_status_line = "label", | |
65 | colour = "BLACK", | |
66 | text_size = 10, | |
67 | has_hypertext_item = 1, | |
68 | can_connect_to = ["Evidence", "Cluster", "Model", "Evidence", "Evidence", "Cluster"], | |
69 | can_connect_from = ["Data", "Evidence", "Cluster", "Evidence", "Data", "Cluster"]). | |
70 | \end{verbatim} | |
71 | ||
72 | This is substantially easier to read and debug than a series of numbers and | |
73 | strings. | |
74 | ||
75 | Note the object-oriented style: a file comprises a series of {\it clauses}. | |
76 | Each clause is an object with a {\it functor}\/ or object name, followed | |
77 | by a list of attribute-value pairs enclosed in parentheses, and finished | |
78 | with a full stop. Each attribute value may be a string, a word (no quotes), | |
79 | an integer, a real number, or a list with potentially recursive elements. | |
80 | ||
81 | The way that the facility is used by an application to read in a file is | |
82 | as follows: | |
83 | ||
84 | \begin{enumerate}\itemsep=0pt | |
85 | \item The application creates a wxExprDatabase instance. | |
86 | \item The application tells the database to read in the entire file. | |
87 | \item The application searches the database for objects it requires, | |
88 | decomposing the objects using the wxExpr API. The database may be hashed, | |
89 | allowing rapid linking-up of application data. | |
90 | \item The application deletes or clears the wxExprDatabase. | |
91 | \end{enumerate} | |
92 | ||
93 | Writing a file is just as easy: | |
94 | ||
95 | \begin{enumerate}\itemsep=0pt | |
96 | \item The application creates a wxExprDatabase instance. | |
97 | \item The application adds objects to the database using the API. | |
98 | \item The application tells the database to write out the entire database, | |
99 | in Prolog or LISP notation. | |
100 | \item The application deletes or clears the wxExprDatabase. | |
101 | \end{enumerate} | |
102 | ||
103 | To use the library, include "wxexpr.h". | |
104 | ||
105 | \subsection{wxExpr compilation} | |
106 | ||
107 | For UNIX compilation, ensure that YACC and LEX or FLEX are on your system. Check that | |
108 | the makefile uses the correct programs: a common error is to compile | |
109 | y\_tab.c with a C++ compiler. Edit the CCLEX variable in make.env | |
110 | to specify a C compiler. Also, do not attempt to compile lex\_yy.c | |
111 | since it is included by y\_tab.c. | |
112 | ||
113 | For DOS compilation, the simplest thing is to copy dosyacc.c to y\_tab.c, and doslex.c to | |
114 | lex\_yy.c. It is y\_tab.c that must be compiled (lex\_yy.c is included by | |
115 | y\_tab.c) so if adding source files to a project file, ONLY add y\_tab.c | |
116 | plus the .cc files. If you wish to alter the parser, you will need YACC | |
117 | and FLEX on DOS. | |
118 | ||
119 | The DOS tools are available at the AIAI ftp site, in the tools directory. Note that | |
120 | for FLEX installation, you need to copy flex.skl into the directory | |
121 | c:/lib. | |
122 | ||
123 | If you are using Borland C++ and wish to regenerate lex\_yy.c and y\_tab.c | |
124 | you need to generate lex\_yy.c with FLEX and then comment out the `malloc' and `free' | |
125 | prototypes in lex\_yy.c. It will compile with lots of warnings. If you | |
126 | get an undefined \_PROIO\_YYWRAP symbol when you link, you need to remove | |
127 | USE\_DEFINE from the makefile and recompile. This is because the parser.y | |
128 | file has a choice of defining this symbol as a function or as a define, | |
129 | depending on what the version of FLEX expects. See the bottom of | |
130 | parser.y, and if necessary edit it to make it compile in the opposite | |
131 | way to the current compilation. | |
132 | ||
133 | To test out wxExpr compile the test program (samples/wxexpr/wxexpr.exe), | |
134 | and try loading test.exp into the test | |
135 | program. Then save it to another file. If the second is identical to the | |
136 | first, wxExpr is in a working state. | |
137 | ||
138 | \subsection{Bugs} | |
139 | ||
140 | These are the known bugs: | |
141 | ||
142 | \begin{enumerate}\itemsep=0pt | |
143 | \item Functors are permissable only in the main clause (object). | |
144 | Therefore nesting of structures must be done using lists, not predicates | |
145 | as in Prolog. | |
146 | \item There is a limit to the size of strings read in (about 5000 bytes). | |
147 | \end{enumerate} | |
148 | ||
149 | \subsection{Using wxExpr} | |
150 | ||
151 | This section is a brief introduction to using the wxExpr package. | |
152 | ||
153 | First, some terminology. A {\it wxExprDatabase}\/ is a list of {\it clauses}, | |
154 | each of which represents an object or record which needs to be saved to a file. | |
155 | A clause has a {\it functor}\/ (name), and a list of attributes, each of which | |
156 | has a value. Attributes may take the following types of value: string, word, | |
157 | integer, floating point number, and list. A list can itself contain any | |
158 | type, allowing for nested data structures. | |
159 | ||
160 | Consider the following code. | |
161 | ||
162 | \begin{verbatim} | |
163 | wxExprDatabase db; | |
164 | ||
165 | wxExpr *my_clause = new wxExpr("object"); | |
166 | my_clause->AddAttributeValue("id", (long)1); | |
167 | my_clause->AddAttributeValueString("name", "Julian Smart"); | |
168 | db.Append(my_clause); | |
169 | ||
170 | ofstream file("my_file"); | |
171 | db.Write(file); | |
172 | \end{verbatim} | |
173 | ||
174 | This creates a database, constructs a clause, adds it to the database, | |
175 | and writes the whole database to a file. The file it produces looks like | |
176 | this: | |
177 | ||
178 | \begin{verbatim} | |
179 | object(id = 1, | |
180 | name = "Julian Smart"). | |
181 | \end{verbatim} | |
182 | ||
183 | To read the database back in, the following will work: | |
184 | ||
185 | \begin{verbatim} | |
186 | wxExprDatabase db; | |
187 | db.Read("my_file"); | |
188 | ||
189 | db.BeginFind(); | |
190 | ||
191 | wxExpr *my_clause = db.FindClauseByFunctor("object"); | |
192 | int id = 0; | |
193 | wxString name = "None found"; | |
194 | ||
195 | my_clause->GetAttributeValue("id", id); | |
196 | my_clause->GetAttributeValue("name", name); | |
197 | ||
198 | cout << "Id is " << id << ", name is " << name << "\n"; | |
199 | \end{verbatim} | |
200 | ||
201 | Note the setting of defaults before attempting to retrieve attribute values, | |
202 | since they may not be found. | |
203 |