An Introduction to Coral's Interface with C++ ------------------------------------------ For those interested in writing C++ programs that use the Coral library, we provide the following reference to help them get started. We have also provided some sample programs to demonstrate the use of these functions. Table of Contents Line ----------------- ------ Introduction 25 Using Coral's C++ Interface 36 Discussion of Sample Programs 59 Embedded Coral (and using the translator) 72 List of Coral C++ functions and methods for Coral types 127 Incrementally Loading Programs into Coral 609 Using Coral with Tk/Tcl (coralsh) 615 Introduction ------------ Coral provides an interface to C++ to allow those users who wish to use the Coral Database within their own programs. This can be done using Coral's embedded mode, which allows Coral code to appear inside of your C++ program the same as it would appear at the Coral prompt. For more speed and flexibility, Coral's C++ interface can be used directly. Most programs use a mixture of these two approaches as appropriate for their needs. Using Coral's C++ Interface --------------------------- The classes, functions and methods considered to be in Coral's C++ interface are described later in this reference. The functions listed are the ones that we are willing to half-heartedly commit to not changing the interface to in the near future. If you are interested in portability to future versions of Coral, you should attempt to limit yourself to these operations whenever possible. A C++ program using Coral should call init_coral() before attempting any operations related to Coral, and exit_coral() when finished. The prototypes for these functions are given later in this reference. For most of the sample Coral C++ programs these functions are simply called at the beginning and end of main(). Unless specifically mentioned otherwise, all functions in this document that return a pointer expect you to delete the pointer when you are finished with it. For complex objects, there is some structure sharing, but it is handled internally via reference counting, so deleting the pointer is always 'The Right Thing To Do'. Discussion of Sample Programs (and using the translator) -------------------------------------------------------- The sample programs are at programs/examples/C++ The examples are all '.S' files, which require the translator to convert them to C++. There is also a Makefile which shows how to compile these into executables. The examples demonstrate embedding coral into a C++ program, passing parameters from C++ to Coral, and scanning Coral relations from C++. Embedded Coral -------------- Declarative Coral code can also appear directly inside your C++ program, we refer to this as Embedded Coral. To use this mode, you should call init_coral() at the beginning of main() and exit_coral() at the end. You may then simply include the embedded Coral code by surrounding it with the embedding brackets '\[' and '\]'. For example: \[ data(2,3). data(foo,9.2). ?data(X,Y). \] Is a valid section of a C++ program that will result in the relation data(arity 2) being defined, inserting the facts shown, and listing the bindings for the query on stdout. The transformation to valid C++ code is performed by a program called the 'translator' that is included in the Coral distribution. The sample Makefile included in the C++ Interface directory demonstrates the proper use of the translator. Generally, files containing Embedded Coral are suffixed with '.S', from which the translator then generates a '.C' file with the same base name. Embedded Coral allows certain C++ types to be passed into the embedded section as arguments. For the proper type of the object to be known, the type must be supplied in a special cast. Plese note that the paranthesis around the type, as well as the dollar signs, are required. For example: int j = 2; double r = 9.2; char *name = "foo"; \[ data( ($int) $j, 3). data( ($string) $name, ($double) $r). ? data(X,Y). \] The currently allowed types, and the appropriate parameter casts are given by the following table: Cast Equivalent C++ Type ---- ------------------- $int int $double double $string or $char* char* $CArg* or $Cor_CArg* Cor_CArg* $chunk or $void* A pointer to anything. (see the param?.S example programs for examples of usage) List of Coral C++ functions and methods for Coral types ------------------------------------------------------- This section discusses the function available to a programmer using the Coral C++ interface. It also lists the major coral types visible from the C++ interface, and their more useful methods. In many cases, there are functions available from the interface that are exact parallels to methods available for the appropriate class; this is simply our attempt to be hip by making the interface more object-oriented, the older functions remain for backward compatibilty. Type Line ---- ------ Cor_CArg 151 Cor_CArgStack 311 Cor_ArgList 360 Cor_Tuple 421 Cor_Relation 459 Cor_ScanDesc 510 Miscellaneous Functions 543 Cor_CArg: ---------- A CArg is a coral argument. It can hold a number, string, list, set or functor (a fact), it can also be empty. The constructors/destructor for CArg: Cor_CArg(void); Cor_CArg(const Cor_CArg& a); Cor_CArg(int n); Cor_CArg(double d); Cor_CArg(const char *name); ~Cor_CArg(); Cor_CArg *make_arg (char *name); Cor_CArg *make_arg (Cor_CArg& name); For creating a CArg that holds a functor term (ie 'rel(foo,2,bar)'.) Cor_CArg *make_arg (char *func_name, Cor_ArgList *args); These functions create CArg's that store a Coral variable. The var_num parameter uniquely identifies a variable; variables with the same var_num are considered the same. 'print_name' is the name that will be shown if this variable is printed, it is not used internally. Cor_CArg *make_var (int var_num); Cor_CArg *make_var (char *print_name, int var_num); Cor_CArg *make_var (Cor_CArg *print_name, int var_num); This empties out the current contents of a CArg, returning it to an empty state. void Cor_CArg::init(); These methods set a new value (and type) for a CArg. Cor_CArg& Cor_CArg::operator= (const Cor_CArg& a); Cor_CArg& Cor_CArg::operator= (int i); Cor_CArg& Cor_CArg::operator= (double d); void Cor_CArg::set_num(int ival); void Cor_CArg::set_num(double dval); void Cor_CArg::set_chunk(void *chnk); A method for printing a CArg onto a stream. This method will quote the CArg if it contains any whitespace, special characters, or starts with a capital letter or digit. (To print without these quotes, print the char* returned by 'carg.symbol()'.) friend ostream& operator<< (ostream& out, const Cor_CArg& carg); This method tests if a CArg is empty, as it would be after an init(). int Cor_CArg::is_empty() const; Tests to see if two CArgs are equal. int Cor_CArg::equals(const Cor_CArg& arg2) const; int Cor_CArg::equals(char *str) const; This method returns the type of object that is stored in this CArg. The enumerated type definition is also shown below. There are also methods to test for a specific type. CArgKind Cor_CArg::Kind() const; enum CArgKind { EMPTY_ARG, // Empty INT_ARG, // An integer DOUBLE_ARG, // A double SYMBOL_ARG, // A symbol (char *) OTHER_ARG, // A complex type (set, list, functor, etc) CHUNK_ARG // A pointer to a chunk of memory }; int Cor_CArg::is_num() const; int Cor_CArg::isConstant() const; int Cor_CArg::is_int() const; int Cor_CArg::is_short() const; int Cor_CArg::is_long() const; int Cor_CArg::is_float() const; int Cor_CArg::is_double() const; int Cor_CArg::is_string() const; int Cor_CArg::is_symbol() const; int Cor_CArg::is_chunk() const; int is_int (const Cor_CArg& c); int is_long (const Cor_CArg& c); int is_short (const Cor_CArg& c); int is_float (const Cor_CArg& c); int is_double (const Cor_CArg& c); int is_symbol (const Cor_CArg& c); int is_string (const Cor_CArg& c); int is_chunk (const Cor_CArg& c); int is_num (const Cor_CArg& c); int is_constant (const Cor_CArg& c); int is_var (const Cor_CArg& c); int is_functor (const Cor_CArg& c); int is_nil (const Cor_CArg& c); int is_list (const Cor_CArg& c); These methods return the value of a CArg, they do no error checking, assuming that you have the type right. double Cor_CArg::NumDval() const; int Cor_CArg::NumIval() const; Returns the symbol stored and its length, they do no error checking. char *Cor_CArg::symbol() const; int Cor_CArg::symlen() const; Returns the chunk stored: void *Cor_CArg::chunk(); Functions to extract the info from a CArg (no error checking is done). int make_int (const Cor_CArg& c); short make_short (const Cor_CArg& c); long make_long (const Cor_CArg& c); float make_float (const Cor_CArg& c); double make_double (const Cor_CArg& c); char *make_string (const Cor_CArg& c); char *functor_name (const Cor_CArg& c); Cor_ArgList *functor_args (const Cor_CArg& c); These functions create/operate on Coral lists (ie: '[a,b,c]') Creates a new empty list. Cor_CArg *make_nil (void); Adds the CArg 'car' to the front of the list 'cdr'. Cor_CArg *make_cons (const Cor_CArg& car, const Cor_CArg& cdr); Creates a new list from a variable list of CArg's given. All items in the vararg list should be of type 'Cor_CArg*'. Cor_CArg *make_list (int num_arg, ...); Ex: Cor_CArg *two = new Cor_CArg(2); Cor_CArg *pi = new Cor_CArg(3.14); Cor_CArg *foo = new Cor_CArg("foo"); Cor_CArg *list = make_list( 3, two, foo, pi ); Now 'list' contains the Coral list '[2,foo,3.14]' Returns the length of this list. int list_length( Cor_CArg& list ); Returns the car and cdr of the list given. For those not familar with Lisp, 'car' is the first element of the list, while 'cdr' is the list without the first element. Cor_CArg *make_car (const Cor_CArg& list); Cor_CArg *make_cdr (const Cor_CArg& list); Functions to test if a CArg is a list, and if it is nil. int is_nil (const Cor_CArg& c); int is_list (const Cor_CArg& c); Cor_CArgStack: --------------- A CArgStack is a dynamic stack for holding pointers to CArg's, it can also be considered an array by indexing into it using the get_ith(), dup_ith() methods. The constructors/destructor for CArgStack: Cor_CArgStack(int dp=1); ~Cor_CArgStack(); A method for printing a CArgStack onto a stream. The CArgs in the stack are printed out seperated by commas. (printed in FIFO order) friend ostream& operator<< (ostream& out, const Cor_CArgStack& ca_list); Add a CArg to the stack void Cor_CArgStack::push(Cor_CArg*); Returns the current number of CArgs stored. int Cor_CArgStack::count(); Gets a pointer to the ith element of the stack, leaving the element there. (counts from 0 being the first element inserted.) Cor_CArg *Cor_CArgStack::get_ith(int i); Gets a _copy_ of the ith element of the stack, leaving the element there. (counts from 0 being the first element inserted.) Cor_CArg *Cor_CArgStack::dup_ith(int i); Removes the last element from the stack and returns it. Cor_CArg *Cor_CArgStack::pop(); Copies the contents of a CArgStack to another (duplicating all elements) void Cor_CArgStack::copy(Cor_CArgStack&); Fills the ArgList given with the contents of the CArgStack, emptying the CArgStack in the process. void Cor_CArgStack::build_arglist(Cor_ArgList& args); Empties out the stack - deleting each element. void Cor_CArgStack::empty(); Checks if the stack is empty. void Cor_CArgStack::is_empty(); Duplicate the stack (and all elements). Cor_CArgStack *Cor_CArgStack::dup(); Cor_ArgList: ------------- An ArgList stores coral argument lists. The constructors/destructor for ArgList: Cor_ArgList(int size); Cor_ArgList(const Cor_ArgList &); Cor_ArgList(); ~Cor_ArgList(); void Cor_ArgList::operator=(const Cor_ArgList&); int Cor_ArgList::count() const; int Cor_ArgList::arity() const; Cor_CArg& Cor_ArgList::operator[] (int i) const; const Cor_CArg& Cor_ArgList::arg(int i) const; Returns true if all the arguments are NumArgs or Symbols int Cor_ArgList::isConstant(); Methods for printing an ArgList onto a stream. The CArgs in the arglist are printed out seperated by commas. friend ostream& operator<< (ostream& out, const Cor_ArgList& al); void Cor_ArgList::printon(ostream *file) const; Make a duplicate of this ArgList. Cor_ArgList *Cor_ArgList::dup(); Creates an ArgList with the CArgs specified. All items in vararg list should be of type 'Cor_CArg*' Cor_ArgList *make_arglist (int len, ...); A destructive version of the above (deletes arguments). This call is useful to avoid temporary variables, as you can imbed the calls to make_arg(). Cor_ArgList *make_arglist_d (int len, ...); Ex. Cor_ArgList *al = make_arglist_d(2, make_arg("one"), make_arg("two")); Versions which take CArg references instead. References cannot be passed through '...' but these three versions allow ArgLists to be created with 1, 2, or 3 CArg references. Cor_ArgList *make_arglist (const Cor_CArg& a1); Cor_ArgList *make_arglist (const Cor_CArg& a1, const Cor_CArg& a2); Cor_ArgList *make_arglist (const Cor_CArg& a1, const Cor_CArg& a2, const Cor_CArg& a3); Concatenates two ArgLists into a new one. The new ArgList created does not rely on the continued existance of its constituent ArgList's (they can be deleted). Cor_ArgList *concat_arglists (Cor_ArgList *al1, Cor_ArgList *al2); Creates an ArgList of the length specified, with all arguments being unique variables. Cor_ArgList *make_vararglist (int n); Cor_Tuple: ----------- A Tuple is an ArgList with some extra information about which variables are free/bound. The constructors/destructor for Tuple: Cor_Tuple() Cor_Tuple(int arity); Cor_Tuple(Cor_ArgList& a); Cor_Tuple(Cor_ArgList *arglist); ~Cor_Tuple(); Cor_Tuple *make_tuple(int arity); Cor_Tuple *make_tuple(Cor_ArgList *arglist); Returns true if all variables are free. int Cor_Tuple::default_bindenv() const; Returns true if all arguments are ground (bound). int Cor_Tuple::isConstant(); void Cor_Tuple::do_delete(); int Cor_Tuple::is_deleted(); Cor_ArgList& Cor_Tuple::args(); int Cor_Tuple::arity() const; Cor_CArg& Cor_Tuple::arg(int i) const; Cor_CArg& Cor_Tuple::operator[] (int i) const; void update_tuple (Cor_Tuple *tuple, int arg_pos, Cor_CArg& new_val); Methods for printing a Tuple onto a stream. The CArgs in the tuple's arglist are printed out seperated by commas. friend ostream& operator<< (ostream& out, const Cor_Tuple& tuple); void Cor_Tuple::printon(ostream *file) const; Cor_Relation: -------------- Cor_Relation( int arity, int delta_indexed = -1 ); Cor_Relation(); int Cor_Relation::arity() const; void Cor_Relation::print_name(ostream *file); int Cor_Relation::isConstant(); int Cor_Relation::tuple_count(); void Cor_Relation::printon(ostream *file) const; void Cor_Relation::printon(ostream *file, char *) const; void Cor_Relation::print_facts(ostream *file, Cor_ArgList *arglist = NULL, int as_table=0) const; int Cor_Relation::insert_tuple(Cor_Tuple *tuple) = 0; Empty tuples out of the relation. Delete the tuples only if the deleteTuples arg is not 0. void Cor_Relation::empty_relation(int deleteTuples = 0); int Cor_Relation::tuple_delete(Cor_Tuple *tuple); int Cor_Relation::tuple_insert(Cor_Tuple *tuple); int Cor_Relation::tuple_update(Cor_Tuple *tuple_old, Cor_Tuple *tuple_new); void update_tuple (Cor_Relation *rel, Cor_Tuple *old_tuple, Cor_Tuple *new_tuple); void delete_id_tuple (Cor_Relation *rel, Cor_Tuple *tuple); void delete_tuple (Cor_Relation *rel, Cor_Tuple *tuple); Cor_Relation *make_rel(char *rel_name, int arity); Cor_Relation *find_relation (char *db_rel_name, int arity); Some _macros_ to simply moving through a Relation (without a Cor_ScanDesc, see next section on Cor_ScanDesc to perform a scan.) FOR_EACH_TUPLE(Cor_Tuple *tuple, Cor_Relation *rel) FOR_EACH_MATCHING_TUPLE(Cor_Tuple *tuple, Cor_Relation *rel, Cor_Tuple *match_tuple) END_EACH_TUPLE(Cor_Tuple *tuple); Cor_ScanDesc: -------------- The ScanDesc class provides the facility of scans over coral relations. Cor_ScanDesc(Cor_Relation *rel); Cor_ScanDesc(Cor_Relation *rel, Cor_Tuple *match_tuple); ~Cor_ScanDesc(); Cor_Tuple *Cor_ScanDesc::next_tuple(); int Cor_ScanDesc::no_match(); Cor_ScanDesc *open_scan( char *query ); // NEW! Use the query in 'query' to find a relation, and open a scan on that relation, using the form (again from 'query') to specify the tuples which will match. The query should appear the same as it would from the Coral prompt, with a few exceptions. If the relation isn't found, or Coral can't parse a fact from the string given, NULL is returned. 1) No expressions (unary minus is okay. ie '-3') 2) There must not be a space between a functor's name and the starting parenthesis of its argument list. The relation name may not be quoted. Ex: Cor_ScanDesc *sd; sd = open_scan( "myrel(2,X,Y,[3,X,1])" ); Miscellaneous Functions ----------------------- Initialize Coral. This call should be done at the beginning of main() to initialize Coral. void init_coral(char *program_name); To shutdown Coral. void exit_coral(void); To parse a single fact from a buffer. (See the restrictions listed with the open_scan() function.) Cor_Tuple *Cor_parseFact(char *fact_buff, Cor_CArg& rel_name, int *arity=NULL); The query is a tuple for the relation, and any facts in the relation that unify with the query tuple are answers to the query. For example, (X,Y) is a query that returns all tuples in a binary relation. Similarly, (1,Y) returns all tuples that have a 1 in the first column. It adds the answer tuples to the relation result. If the result parameter is NULL, a new relation is allocated and the result points to it. Returns: The number of answer tuples. A result < 0 implies error. int call_coral(char *exp_pred_name, Cor_Tuple *query, Cor_Relation *&result); Relation *queries must contain queries on the relation. It adds the answer tuples to the relation result. If the result parameter is NULL, a new relation is allocated and result points to it. Returns: The number of answer tuples. A result < 0 implies error. int call_coral(char *exp_pred_name, Cor_Relation *queries, Cor_Relation *&result); Interface functions for calling the imperative module: The user needs to write a routine with signature Cor_Relation *pred_solver (Cor_Tuple *query); -or- Cor_Tuple *pred_solver (Cor_Tuple *query); for the predicate `pred', and add a declaration matching the form: int add_builtin (char *pred, int arity, UserRelProc pred_solver); -or- int add_builtin (char *pred, int arity, UserTupleProc pred_solver); where `arity' is the arity of the relation named by `pred'. int add_builtin (char *pred, int arity, UserRelProc pred_solver); int add_builtin (char *pred, int arity, UserTupleProc pred_solver); Macros to return, indicating failure. BUILTIN_FAIL_RETURN (returns int) VOID_BUILTIN_FAIL_RETURN (returns void) Incrementally Loading Programs into Coral ----------------------------------------- Incremental Loading is not currently operational. Using Coral with Tk/Tcl (coralsh) --------------------------------- The debugging/query explanation tool 'Explain' is written in Tk/Tcl with a shell extended to provide coral commands. This shell, 'coralsh', is created by a normal make of the program (or comes precompiled with the precompiled versions). The commands added to the shell are documented here so that it can be used independently. The shell 'coralsh' is actually the combination of TkX/TclX, Coral, and 'treesh', a Tk/Tcl Tree Widget written by Allan Brighton. Needless to say, I will only explain the commands created by Coral here, for information about the abilities/usage of TkX/TclX or the Tree Widget you will need to consult their documentation. There are 13 commands added to the shell by coral, or actually one command ("coral") with 13 sub-commands. These commands were written to provide the necessary hooks to implement 'Explain' in Tcl. Note that the subcommand 'parse' provides an ability similar to the embedded mode in C++. coral init ?program_name? coral exit coral consult file ?file? Consult 1 or more files. coral open coral_query coral close scan_id coral get_tuple scan_id ?-dispose? ?-args? ?list? coral sprint tuple_id "Prints" the item specified to coral sprint arg_id the normal result string. coral arg tuple_id index Returns arg_id coral delete arg_id ?arg_id...? Deletes the space allocated coral delete tuple_id ?tuple_id...? for these tuples and args. coral ident arg_id Returns type of arg (one of: empty, int, double, string, list, functor or chunk) coral tcl_list ?-args? arg_id Returns coral list of arg_id as a tcl list coral parse string ?string? Parse the string as coral input coral list_rels List out the currently defined relations.