1/* -*- C -*-
2// -------------------------------------------------------------------
3// MiniExp - Library for handling lisp expressions
4// Copyright (c) 2005 Leon Bottou
5//
6// This software is subject to, and may be distributed under, the
7// GNU General Public License, either Version 2 of the license,
8// or (at your option) any later version. The license should have
9// accompanied the software or you may obtain a copy of the license
10// from the Free Software Foundation at http://www.fsf.org .
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16// -------------------------------------------------------------------
17*/
18
19#ifndef MINIEXP_H
20#define MINIEXP_H
21
22#ifdef __cplusplus
23extern "C" {
24# ifndef __cplusplus
25}
26# endif
27#endif
28
29#ifndef MINILISPAPI
30# ifdef WIN32
31# ifdef DLL_EXPORT
32# define MINILISPAPI __declspec(dllexport)
33# else
34# define MINILISPAPI __declspec(dllimport)
35# endif
36# endif
37#endif
38#ifndef MINILISPAPI
39# define MINILISPAPI /**/
40#endif
41
42#include <stddef.h>
43
44/* -------------------------------------------------- */
45/* LISP EXPRESSIONS */
46/* -------------------------------------------------- */
47
48/* miniexp_t --
49 Opaque pointer type representing a lisp expression,
50 also known as s-expression.
51 S-expressions can be viewed as a simple and powerful
52 alternative to XML. DjVu uses s-expressions to handle
53 annotations. Both the decoding api <ddjvuapi.h> and
54 program <djvused> use s-expressions to describe the
55 hidden text information and the navigation
56 information */
57
58
59typedef struct miniexp_s* miniexp_t;
60
61
62/* There are four basic types of lisp expressions,
63 numbers, symbols, pairs, and objects.
64 The latter category can represent any c++ object
65 that inherits class <miniobj_t> defined later in this file.
66 The only such objects defined in this file are strings. */
67
68
69/* -------- NUMBERS -------- */
70
71/* Minilisp numbers can represent any integer
72 in range [-2^29...2^29-1] */
73
74
75/* miniexp_numberp --
76 Tests if an expression is a number. */
77
78static inline int miniexp_numberp(miniexp_t p) {
79 return (((size_t)(p)&3)==3);
80}
81
82/* miniexp_to_int --
83 Returns the integer corresponding to a lisp expression.
84 Assume that the expression is indeed a number. */
85
86static inline int miniexp_to_int(miniexp_t p) {
87 return (((int)(size_t)(p))>>2);
88}
89
90/* miniexp_number --
91 Constructs the expression corresponding to an integer. */
92
93static inline miniexp_t miniexp_number(int x) {
94 return (miniexp_t) (size_t) ((x<<2)|3);
95}
96
97
98
99/* -------- SYMBOLS -------- */
100
101/* The textual representation of a minilisp symbol is a
102 sequence of printable characters forming an identifier.
103 Each symbol has a unique representation and remain
104 permanently allocated. To compare two symbols,
105 simply compare the <miniexp_t> pointers. */
106
107
108/* miniexp_symbolp --
109 Tests if an expression is a symbol. */
110
111static inline int miniexp_symbolp(miniexp_t p) {
112 return ((((size_t)p)&3)==2);
113}
114
115/* miniexp_to_name --
116 Returns the symbol name as a string.
117 Returns NULL if the expression is not a symbol. */
118
119MINILISPAPI const char* miniexp_to_name(miniexp_t p);
120
121/* miniexp_symbol --
122 Returns the unique symbol expression with the specified name. */
123
124MINILISPAPI miniexp_t miniexp_symbol(const char *name);
125
126
127
128/* -------- PAIRS -------- */
129
130/* Pairs (also named "cons") are the basic building blocks for
131 minilisp lists. Each pair contains two expression:
132 - the <car> represents the first element of a list.
133 - the <cdr> usually is a pair representing the rest of the list.
134 The empty list is represented by a null pointer. */
135
136
137/* miniexp_nil --
138 The empty list. */
139
140#define miniexp_nil ((miniexp_t)(size_t)0)
141
142/* miniexp_dummy --
143 An invalid expression used to represent
144 various exceptional conditions. */
145
146#define miniexp_dummy ((miniexp_t)(size_t)2)
147
148/* miniexp_listp --
149 Tests if an expression is either a pair or the empty list. */
150
151static inline int miniexp_listp(miniexp_t p) {
152 return ((((size_t)p)&3)==0);
153}
154
155/* miniexp_consp --
156 Tests if an expression is a pair. */
157
158static inline int miniexp_consp(miniexp_t p) {
159 return p && miniexp_listp(p);
160}
161
162/* miniexp_length --
163 Returns the length of a list.
164 Returns 0 for non lists, -1 for circular lists. */
165
166MINILISPAPI int miniexp_length(miniexp_t p);
167
168/* miniexp_car --
169 miniexp_cdr --
170 Returns the car or cdr of a pair. */
171
172static inline miniexp_t miniexp_car(miniexp_t p) {
173 if (miniexp_consp(p))
174 return ((miniexp_t*)p)[0];
175 return miniexp_nil;
176}
177
178static inline miniexp_t miniexp_cdr(miniexp_t p) {
179 if (miniexp_consp(p))
180 return ((miniexp_t*)p)[1];
181 return miniexp_nil;
182}
183
184/* miniexp_cXXr --
185 Represent common combinations of car and cdr. */
186
187MINILISPAPI miniexp_t miniexp_caar (miniexp_t p);
188MINILISPAPI miniexp_t miniexp_cadr (miniexp_t p);
189MINILISPAPI miniexp_t miniexp_cdar (miniexp_t p);
190MINILISPAPI miniexp_t miniexp_cddr (miniexp_t p);
191MINILISPAPI miniexp_t miniexp_caddr(miniexp_t p);
192MINILISPAPI miniexp_t miniexp_cdddr(miniexp_t p);
193
194/* miniexp_nth --
195 Returns the n-th element of a list. */
196
197MINILISPAPI miniexp_t miniexp_nth(int n, miniexp_t l);
198
199/* miniexp_cons --
200 Constructs a pair. */
201
202MINILISPAPI miniexp_t miniexp_cons(miniexp_t car, miniexp_t cdr);
203
204/* miniexp_rplaca --
205 miniexp_rplacd --
206 Changes the car or the cdr of a pair. */
207
208MINILISPAPI miniexp_t miniexp_rplaca(miniexp_t pair, miniexp_t newcar);
209MINILISPAPI miniexp_t miniexp_rplacd(miniexp_t pair, miniexp_t newcdr);
210
211/* miniexp_reverse --
212 Reverses a list in place. */
213
214MINILISPAPI miniexp_t miniexp_reverse(miniexp_t p);
215
216
217/* -------- OBJECTS (GENERIC) -------- */
218
219/* Object expressions represent a c++ object
220 that inherits class <miniobj_t> defined later.
221 Each object expression has a symbolic class name
222 and a pointer to the c++ object. */
223
224/* miniexp_objectp --
225 Tests if an expression is an object. */
226
227static inline int miniexp_objectp(miniexp_t p) {
228 return ((((size_t)p)&3)==1);
229}
230
231/* miniexp_classof --
232 Returns the symbolic class of an expression.
233 Returns nil if the expression is not an object. */
234
235MINILISPAPI miniexp_t miniexp_classof(miniexp_t p);
236
237/* miniexp_isa --
238 If <p> is an instance of class named <c> or one of
239 its subclasses, returns the actual class name.
240 Otherwise returns miniexp_nil. */
241
242MINILISPAPI miniexp_t miniexp_isa(miniexp_t p, miniexp_t c);
243
244
245/* -------- OBJECTS (STRINGS) -------- */
246
247/* miniexp_stringp --
248 Tests if an expression is a string. */
249
250MINILISPAPI int miniexp_stringp(miniexp_t p);
251
252/* miniexp_to_str --
253 Returns the c string represented by the expression.
254 Returns NULL if the expression is not a string.
255 The c string remains valid as long as the
256 corresponding lisp object exists. */
257
258MINILISPAPI const char *miniexp_to_str(miniexp_t p);
259
260/* miniexp_string --
261 Constructs a string expression by copying string s. */
262
263MINILISPAPI miniexp_t miniexp_string(const char *s);
264
265/* miniexp_substring --
266 Constructs a string expression by copying
267 at most n character from string s. */
268
269MINILISPAPI miniexp_t miniexp_substring(const char *s, int n);
270
271/* miniexp_concat --
272 Concat all the string expressions in list <l>. */
273
274MINILISPAPI miniexp_t miniexp_concat(miniexp_t l);
275
276
277
278
279
280/* -------------------------------------------------- */
281/* GARBAGE COLLECTION */
282/* -------------------------------------------------- */
283
284
285/* The garbage collector reclaims the memory allocated for
286 lisp expressions no longer in use. It is automatically
287 invoked by the pair and object allocation functions when
288 the available memory runs low. It is however possible to
289 temporarily disable it.
290
291 The trick is to determine which lisp expressions are in
292 use at a given moment. This package takes a simplistic
293 approach. All objects of type <minivar_t> are chained and
294 can reference an arbitrary lisp expression. Garbage
295 collection preserves all lisp expressions referenced by a
296 minivar, as well as all lisp expressions that can be
297 accessed from these. When called automatically,
298 garbage collection also preserves the sixteen most recently
299 created miniexps in order to make sure that temporaries do
300 not vanish in the middle of complicated C expressions.
301
302 The minivar class is designed such that C++ program can
303 directly use instances of <minivar_t> as normal
304 <miniexp_t> variables. There is almost no overhead
305 accessing or changing the lisp expression referenced by a
306 minivar. However, the minivar chain must be updated
307 whenever the minivar object is constructed or destructed.
308
309 Example (in C++ only):
310 miniexp_t copy_in_reverse(miniexp_t p) {
311 minivar_t l = miniexp_nil;
312 while (miniexp_consp(p)) {
313 l = miniexp_cons(miniexp_car(p), l);
314 p = miniexp_cdr(p);
315 }
316 return l;
317 }
318
319 When to use minivar_t instead of miniexp_t?
320
321 * A function that only navigates properly secured
322 s-expressions without modifying them does not need to
323 bother about minivars.
324
325 * Only the following miniexp functions can cause a
326 garbage collection: miniexp_cons(), miniexp_object(),
327 miniexp_string(), miniexp_substring(),
328 miniexp_concat(), miniexp_pprin(), miniexp_pprint(),
329 miniexp_gc(), and minilisp_release_gc_lock(). A
330 function that does not cause calls to these functions
331 does not need to bother about minivars.
332
333 * Other functions should make sure that all useful
334 s-expression are directly or indirectly secured by a
335 minivar_t object. In case of doubt, use minivars
336 everywhere.
337
338 * Function arguments should remain <miniexp_t> in order
339 to allow interoperability with the C language. As a
340 consequence, functions must often copy their arguments
341 into minivars in order to make sure they remain
342 allocated. A small performance improvement can be
343 achieved by deciding that the function should always be
344 called using properly secured arguments. This is more
345 difficult to get right.
346
347 C programs cannot use minivars as easily as C++ programs.
348 Wrappers are provided to allocate minivars and to access
349 their value. This is somehow inconvenient. It might be
350 more practical to control the garbage collector
351 invocations with <minilisp_acquire_gc_lock()> and
352 <minilisp_release_gc_lock()>... */
353
354
355/* minilisp_gc --
356 Invokes the garbage collector now. */
357
358MINILISPAPI void minilisp_gc(void);
359
360/* minilisp_info --
361 Prints garbage collector statistics. */
362
363MINILISPAPI void minilisp_info(void);
364
365/* minilisp_acquire_gc_lock --
366 minilisp_release_gc_lock --
367 Temporarily disables automatic garbage collection.
368 Acquire/release pairs may be nested.
369 Both functions return their argument unmodified.
370 This is practical because <minilisp_release_gc_lock>
371 can invoke the garbage collector. Before doing
372 so it stores its argument in a minivar to
373 preserve it.
374
375 Example (in C):
376 miniexp_t copy_in_reverse(miniexp_t p) {
377 miniexp_t l = 0;
378 minilisp_acquire_gc_lock(0);
379 while (miniexp_consp(p)) {
380 l = miniexp_cons(miniexp_car(p), l);
381 p = miniexp_cdr(p);
382 }
383 return minilisp_release_gc_lock(l);
384 }
385
386 Disabling garbage collection for a long time
387 increases the memory consumption. */
388
389MINILISPAPI miniexp_t minilisp_acquire_gc_lock(miniexp_t);
390MINILISPAPI miniexp_t minilisp_release_gc_lock(miniexp_t);
391
392/* minivar_t --
393 The minivar type. */
394#ifdef __cplusplus
395class minivar_t;
396#else
397typedef struct minivar_s minivar_t;
398#endif
399
400/* minivar_alloc --
401 minivar_free --
402 Wrappers for creating and destroying minivars in C. */
403
404MINILISPAPI minivar_t *minivar_alloc(void);
405MINILISPAPI void minivar_free(minivar_t *v);
406
407/* minivar_pointer --
408 Wrappers to access the lisp expression referenced
409 by a minivar. This function returns a pointer
410 to the actual miniexp_t variable. */
411
412MINILISPAPI miniexp_t *minivar_pointer(minivar_t *v);
413
414/* minilisp_debug --
415 Setting the debug flag runs the garbage collector
416 very often. This is extremely slow, but can be
417 useful to debug memory allocation problems. */
418
419MINILISPAPI void minilisp_debug(int debugflag);
420
421/* minilisp_finish --
422 Deallocates everything. This is only useful when using
423 development tools designed to check for memory leaks.
424 No miniexp function can be used after calling this. */
425
426MINILISPAPI void minilisp_finish(void);
427
428
429/* -------------------------------------------------- */
430/* INPUT/OUTPUT */
431/* -------------------------------------------------- */
432
433/* Notes about the textual representation of miniexps.
434
435 - Special characters are:
436 * the parenthesis <(> and <)>,
437 * the double quote <">,
438 * the vertical bar <|>,
439 * the dieze character <#>, when followed by an
440 ascii character with a non zero entry in the
441 dieze character array.
442 * any other ascii character with a non zero entry
443 in the macro character array.
444
445 - Symbols are represented by their name.
446 Vertical bars <|> can be used to delimit names that
447 contain blanks, special characters, non printable
448 characters, non ascii characters, or
449 can be confused for a number.
450
451 - Numbers follow the syntax specified by the C
452 function strtol() with base=0.
453
454 - Strings are delimited by double quotes.
455 All C string escapes are recognized.
456 Non printable ascii characters must be escaped.
457
458 - List are represented by an open parenthesis <(>
459 followed by the space separated list elements,
460 followed by a closing parenthesis <)>.
461 When the cdr of the last pair is non zero,
462 the closed parenthesis is preceded by
463 a space, a dot <.>, a space, and the textual
464 representation of the cdr.
465
466 - When the parser encounters an ascii character corresponding
467 to a non zero function pointer in the macro character array,
468 the function is invoked and must return a possibly empty
469 list of miniexps to be returned by subsequent
470 invocations of the parser. The same process happens when
471 the parser encounters a dieze character followed by an
472 ascii character corresponding to a non zero function pointer
473 int the dieze character array. */
474
475
476/* miniexp_pname --
477 Returns a string containing the textual representation
478 of a minilisp expression. Set argument <width> to zero
479 to output a single line, or to a positive value to
480 perform pretty line breaks for this intended number of columns.
481 This function can cause a garbage collection to occur. */
482
483MINILISPAPI miniexp_t miniexp_pname(miniexp_t p, int width);
484
485
486/* miniexp_io_t --
487 This structure is used to describe how to perform input/output
488 operations. Input/output operations are performed through function
489 pointers <fputs>, <fgetc>, and <ungetc>, which are similar to their
490 stdio counterparts. Variable <data> defines four pointers that can
491 be used as a closure by the I/O functions.
492 When <p_print7bits> is nonzero and points to a nonzero integer, all
493 non-ascii characters in strings are output as octal escapes. When both
494 <p_macrochar> and <p_macroqueue> are non zero, a non zero entry in
495 <p_macrochar[c]> defines a special parsing function that is called when
496 <miniexp_read_r> encounters the character <c> (in range 0 to 127.)
497 When both <p_diezechar> and <p_macroqueue> are non zero, a non zero
498 entry in <p_diezechar[c]> defines a special parsing function that
499 is called when <miniexp_read_r> encounters the character '#' followed
500 by character <c> (in range 0 to 127.) These parsing functions return
501 a list of <miniexp_t> that function <miniexp_read_r> returns one-by-one
502 before processing more input. This list is in fact stored in the
503 variable pointed by <io.p_macroqueue>. */
504
505typedef struct miniexp_io_s miniexp_io_t;
506typedef miniexp_t (*miniexp_macrochar_t)(miniexp_io_t*);
507
508struct miniexp_io_s
509{
510 int (*fputs)(miniexp_io_t*, const char*);
511 int (*fgetc)(miniexp_io_t*);
512 int (*ungetc)(miniexp_io_t*, int);
513 void *data[4];
514 int *p_print7bits;
515 miniexp_macrochar_t *p_macrochar;
516 miniexp_macrochar_t *p_diezechar;
517 minivar_t *p_macroqueue;
518 minivar_t *p_reserved;
519};
520
521/* miniexp_io_init --
522 Initialize a default <miniexp_io_t> structure
523 that reads from stdin and prints to stdout.
524 Field <data[0]> is used to hold the stdin file pointer.
525 Field <data[1]> is used to hold the stdout file pointer.
526 Fields <p_print7bits>, <p_macrochar>, <p_diezechar>
527 and <p_macroqueue> are set to point to zero-initialized
528 shared variables. */
529
530MINILISPAPI void miniexp_io_init(miniexp_io_t *io);
531
532/* miniexp_io_set_{input,output} --
533 Override the file descriptor used for input or output.
534 You must call <miniexp_io_init> before. */
535
536#if defined(stdin)
537MINILISPAPI void miniexp_io_set_output(miniexp_io_t *io, FILE *f);
538MINILISPAPI void miniexp_io_set_input(miniexp_io_t *io, FILE *f);
539#endif
540
541/* miniexp_read_r --
542 Reads an expression by repeatedly
543 invoking <minilisp_getc> and <minilisp_ungetc>.
544 Returns <miniexp_dummy> when an error occurs. */
545
546MINILISPAPI miniexp_t miniexp_read_r(miniexp_io_t *io);
547
548/* miniexp_prin_r, miniexp_print_r --
549 Prints a minilisp expression by repeatedly invoking <minilisp_puts>.
550 Only <minilisp_print> outputs a final newline character.
551 These functions are safe to call anytime. */
552
553MINILISPAPI miniexp_t miniexp_prin_r(miniexp_io_t *io, miniexp_t p);
554MINILISPAPI miniexp_t miniexp_print_r(miniexp_io_t *io, miniexp_t p);
555
556/* miniexp_pprin_r, miniexp_pprint_r --
557 Prints a minilisp expression with reasonably pretty line breaks.
558 Argument <width> is the intended number of columns.
559 Only <minilisp_pprint> outputs a final newline character.
560 These functions can cause a garbage collection to occur. */
561
562MINILISPAPI miniexp_t miniexp_pprin_r(miniexp_io_t *io, miniexp_t p, int w);
563MINILISPAPI miniexp_t miniexp_pprint_r(miniexp_io_t *io, miniexp_t p, int w);
564
565/* miniexp_io, miniexp_read, miniexp_{,p}prin{,t} --
566 Variable <miniexp_io> contains the pre-initialized input/output data
567 structure that is used by the non-reentrant input/output functions. */
568
569extern MINILISPAPI miniexp_io_t miniexp_io;
570MINILISPAPI miniexp_t miniexp_read(void);
571MINILISPAPI miniexp_t miniexp_prin(miniexp_t p);
572MINILISPAPI miniexp_t miniexp_print(miniexp_t p);
573MINILISPAPI miniexp_t miniexp_pprin(miniexp_t p, int width);
574MINILISPAPI miniexp_t miniexp_pprint(miniexp_t p, int width);
575
576/* miniexp_macrochar, miniexp_macroqueue --
577 Function <miniexp_io_init> causes the corresponding pointers in the
578 <miniexp_io_t> structure to point to these variables. A non zero entry in
579 <io.macrochar> defines a special parsing function that runs when
580 <miniexp_read_r> encounters the corresponding character. The parsing
581 function return a list of <miniexp_t> that function <miniexp_read_r>
582 returns one-by-one before processing more input. This list is in fact
583 stored in the variable pointed to by <io.macroqueue>. */
584
585extern MINILISPAPI miniexp_macrochar_t miniexp_macrochar[128];
586extern MINILISPAPI minivar_t miniexp_macroqueue;
587
588
589/* Backward compatibility. */
590extern MINILISPAPI int (*minilisp_puts)(const char *);
591extern MINILISPAPI int (*minilisp_getc)(void);
592extern MINILISPAPI int (*minilisp_ungetc)(int);
593extern MINILISPAPI miniexp_t (*minilisp_macrochar_parser[128])(void);
594extern MINILISPAPI miniexp_t (*minilisp_diezechar_parser[128])(void);
595extern MINILISPAPI int minilisp_print_7bits;
596#if defined(stdin)
597MINILISPAPI void minilisp_set_output(FILE *f);
598MINILISPAPI void minilisp_set_input(FILE *f);
599#endif
600
601/* -------------------------------------------------- */
602/* STUFF FOR C++ ONLY */
603/* -------------------------------------------------- */
604
605#ifdef __cplusplus
606# ifndef __cplusplus
607{
608# endif
609} // extern "C"
610
611typedef void minilisp_mark_t(miniexp_t *pp);
612
613/* -------- MINIVARS -------- */
614
615/* minivar_t --
616 A class for protected garbage collector variables. */
617
618class MINILISPAPI
619minivar_t
620{
621 miniexp_t data;
622 minivar_t *next;
623 minivar_t **pprev;
624public:
625 minivar_t();
626 minivar_t(miniexp_t p);
627 minivar_t(const minivar_t &v);
628 operator miniexp_t&() { return data; }
629 miniexp_t* operator&() { return &data; }
630 minivar_t& operator=(miniexp_t p) { data = p; return *this; }
631 minivar_t& operator=(const minivar_t &v) { data = v.data; return *this; }
632 ~minivar_t() { if ((*pprev = next)) next->pprev = pprev; }
633#ifdef MINIEXP_IMPLEMENTATION
634 static minivar_t *vars;
635 static void mark(minilisp_mark_t*);
636#endif
637};
638
639
640/* -------- MINIOBJ -------- */
641
642
643/* miniobj_t --
644 The base class for c++ objects
645 represented by object expressions. */
646
647class MINILISPAPI
648miniobj_t {
649 public:
650 virtual ~miniobj_t();
651
652 /* --- stuff defined by MINIOBJ_DECLARE --- */
653 /* classname: a symbol characterizing this class. */
654 static const miniexp_t classname;
655 /* classof: class name symbol for this object. */
656 virtual miniexp_t classof() const = 0;
657 /* isa -- tests if this is an instance of <classname>. */
658 virtual bool isa(miniexp_t classname) const;
659
660 /* --- optional stuff --- */
661 /* pname: returns a printable name for this object.
662 The caller must deallocate the result with delete[]. */
663 virtual char *pname() const;
664 /* mark: iterates over miniexps contained by this object
665 for garbage collecting purposes. */
666 virtual void mark(minilisp_mark_t*);
667 /* destroy: called by the garbage collector to
668 deallocate the object. Defaults to 'delete this'. */
669 virtual void destroy();
670
671};
672
673/* MINIOBJ_DECLARE --
674 MINIOBJ_IMPLEMENT --
675 Useful code fragments for implementing
676 the mandatory part of miniobj subclasses. */
677
678#define MINIOBJ_DECLARE(cls, supercls, name) \
679 public: static const miniexp_t classname; \
680 virtual miniexp_t classof() const; \
681 virtual bool isa(miniexp_t) const;
682
683#define MINIOBJ_IMPLEMENT(cls, supercls, name)\
684 const miniexp_t cls::classname = miniexp_symbol(name);\
685 miniexp_t cls::classof() const {\
686 return cls::classname; }\
687 bool cls::isa(miniexp_t n) const {\
688 return (cls::classname==n) || (supercls::isa(n)); }
689
690
691/* miniexp_to_obj --
692 Returns a pointer to the object represented by an lisp
693 expression. Returns NULL if the expression is not an
694 object expression.
695*/
696
697static inline miniobj_t *miniexp_to_obj(miniexp_t p) {
698 if (miniexp_objectp(p))
699 return ((miniobj_t**)(((size_t)p)&~((size_t)3)))[0];
700 return 0;
701}
702
703/* miniexp_object --
704 Create an object expression for a given object. */
705
706MINILISPAPI miniexp_t miniexp_object(miniobj_t *obj);
707
708
709#endif /* __cplusplus */
710
711
712
713
714
715/* -------------------------------------------------- */
716/* THE END */
717/* -------------------------------------------------- */
718
719#endif /* MINIEXP_H */
720