A picture of a life saver of the Titanic, the later representing about any C++ project...

Life Saver — Help to the Lisp programmer having to write C++ code

If you have to write a program in C++, condolences.

Now to relieve the pain somewhat, here are some libraries and tools that may be of use.

  1. Metaprogramming: OpenC++
  2. Sexps and Dynamic Data Structures: Lpp
  3. Writing Sexp-formated data: Rivest's SEXP
  4. Writing Lisp code in C++: InteLib
  5. Garbage Collection: BoehmGC

Colophon: The examples below are taken from the documentations of each of these libraries, and are copyrighted by their respective authors. The diagram is linked directly from the OpenC++ site. The Titanic life saver picture has been ruthelessly copied from the web. The examples are formated with the GNU emacs htmlize-region command.




Metaprogramming: OpenC++

OpenC++ is a pre-processor to C++, which extends C++ with a Meta Object Protocol (MOP), which allow you to do metaprogramming in a sane way (nothing to do with templates and boost hell).

[metal-level program .cc] --> <OpenC++ compiler> --> <C++ compiler> --> [C++ module .so],[base-level program .cc] --> [OpenC++ compiler] --> [C++ compiler] --> [object .o]
Notice that gcc 4.4.3 on Linux x86_64 can't compile occ programs:
/usr/include/wchar.h:220: parse error before `"wcschr"'
/usr/include/stdlib.h:525: parse error before `"at_quick_exit"'
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3
We'd probably need to use an older gcc.

Meta programs have the same form and syntax as normal C++ program, the only syntactic extensions being a metaclass keyword.

VerboseClass.cc:


// VerboseClass.mc
#include "mop.h"
class VerboseClass : public Class {
public:
    Ptree* TranslateMemberCall(Environment*, Ptree*, Ptree*,
                               Ptree*, Ptree*);
};
Ptree* VerboseClass::TranslateMemberCall(Environment* env,
                                         Ptree* object, Ptree* op, Ptree* member, Ptree* arglist)
{
    return Ptree::Make("(puts(\"%p()\"), %p)",
                       member,
                       Class::TranslateMemberCall(env, object,
                                                  op,
                                                  member, arglist));
}

person.cc:

// person.cc
#include <stdio.h>
metaclass VerboseClass Person; // metaclass declaration
class Person {
public:
    Person(int age);
    int Age() { return age; }
    int BirthdayComes() { return ++age; }
    2
    private:
    int age;
};
main()
{
    Person billy(24);
    printf("age %d\n", billy.Age());
    printf("age %d\n", billy.BirthdayComes());
}

When compiled with:

% occ -m -- -g VerboseClass.mc
% occ -- -g -o person person.cc

produces:

% person
Age()
age 24
BirthdayComes()
age 25

It also allow to easily define new control structures (patterned after the existing ones) such as:


{
    Matrix m;
    m.forall(e){ e = 0.0; }
}

Notice that the OpenC++ preprocessor is able to output the syntax tree of a C++ source in a processable form!


% myocc -s person.cc
[typedef [char] [* __gnuc_va_list] ;]
    :
    :
[metaclass VerboseClass Person nil ;]
[[[class Person nil [{ [
                        [public :]
                        [nil [Person ( [[[int] [i]]] )] [{ [
                                                            [[age = i] ;]
                                                            ] }]]
                        [[int] [Age ( nil )] [{ [
                                                 [return age ;]
                                                 ] }]]
                        [[int] [BirthdayComes ( nil )] [{ [
                                                           [return [++ age] ;]
                                                           ] }]]
                        [private :]
                        [[int] [age] ;]
                        ] }]]] ;]
[nil nil [main ( nil )] [{ [
                            [[Person] [billy ( [24] )] ;]
                            [[printf [( ["age %d\n" , [billy . Age [( nil )]]] )]] ;]
                            [[printf [( ["age %d\n" , [billy . BirthdayComes ...
                                                       ] }]]
%




Sexps and Dynamic Data Structures: Lpp

Lpp is a C++ library of Lisp-like functions and macros, providing the various data types commonly found in Lisp, such as symbols, lists, hash-tables, etc.

Unfortunately, the latest versions of Lpp (1.21.2 and previous) don't compile with gcc-4.4.3; there are a lot of missing extern declarations...

     /////////////////////////////////////////////////////////////////
     // main.cc = Introduction Simple Data Base example.

     #include <Lpp.hh>

     // Data Base class.
     class DataBase {
       int size;
       let contents;
     public:
       DataBase();
       int getSize() {return size;}
       void addEntity(let);
       void setValue(let, let, let);
       let getValue(let, let);};

     // Data Base constructor.
     DataBase::DataBase() {size = 0; contents = makeHashTable();}

     // Add an entity to the Data Base.
     void DataBase::addEntity(let entity) {
       if (!gethash(entity, contents)) {
         puthash(entity, contents, 0);
         size++;}}

     // Set the value of an attribute for given entity.
     void DataBase::setValue(let entity, let attribute, let value) {
       let attributes = gethash(entity, contents);
       let old = assoc(attribute, attributes);
       if (old) rplacd(old, value);
       else {
         push(cons(attribute, value), attributes);
         puthash(entity, contents, attributes);}}

     // Return the value of an attribute for given entity.
     let DataBase::getValue(let entity, let attribute) {
       return cdr(assoc(attribute, gethash(entity, contents)));}




Writing Sexp-formated data in C: Rivest's SEXP

Ronald L. Rivest's SEXP format writes and reads data in a sexp-like format, with some provision for binary data.

It may be a nice alternative to JSON or XML. Of course, one can always read or parse Common Lisp sexps too.

A short example:


    (6:issuer3:bob)

    (4:icon[12:image/bitmap]9:xxxxxxxxx)

    (7:subject(3:ref5:alice6:mother))




Writing Lisp code in C++: InteLib

InteLib is a C++ library allowing us to write dynamic code, using a subset of C++ syntax similar to Lisp syntax, without any preprocessing.

isomorph.cpp:


 //       File isomorph.cpp
 #include <intelib/lisp/lisp.hpp>
 #include <intelib/lisp/lsymbol.hpp>
 #include <intelib/lfun_std.hpp>
 #include <intelib/lfun_sel.hpp>


 LSymbol ISOMORPHIC("ISOMORPHIC");

 static LFunctionalSymbol<LFunctionDefun> DEFUN("DEFUN");
 static LFunctionalSymbol<LFunctionCond> COND("COND");
 static LFunctionalSymbol<LFunctionAtom> ATOM("ATOM");
 static LFunctionalSymbol<LFunctionAnd> AND("AND");
 static LFunctionalSymbol<LFunctionCar> CAR("CAR");
 static LFunctionalSymbol<LFunctionCdr> CDR("CDR");

 static LListConstructor L;

 void LispInit_isomorphic() {
   static LSymbol TREE1("TREE1");
   static LSymbol TREE2("TREE2");
   ////////////////////////////////////////////////
   //
   (L|DEFUN, ISOMORPHIC, (L|TREE1, TREE2),
     (L|COND,
       (L|(L|ATOM, TREE1), (L|ATOM, TREE2)),
       (L|(L|ATOM, TREE2), NIL),
       (L|T, (L|AND,
         (L|ISOMORPHIC, (L|CAR, TREE1),
                        (L|CAR, TREE2)),
         (L|ISOMORPHIC, (L|CDR, TREE1),
                        (L|CDR, TREE2))
   )))).Evaluate();
   //
   ////////////////////////////////////////////////
 }
 //      end of file

main.cpp:

 // file main.cpp
 #include <stdio.h>
 #include <stdlib.h>
 #include <intelib/sexpress/sexpress.hpp>
 #include <intelib/sexpress/sstring.hpp>
 #include <intelib/lisp/lsymbol.hpp>

 extern LSymbol ISOMORPHIC;
 void LispInit_isomorphic();

 static LListConstructor L;

 void call_isomorph(const SReference &l1, const SReference &l2)
 {
     SReference res = (L|ISOMORPHIC, ~l1, ~l2).Evaluate();
     printf("%s ~~ %s : %s\n",
            l1->TextRepresentation().c_str(),
            l2->TextRepresentation().c_str(),
            res->TextRepresentation().c_str());
 }

 int main(int argc, char *argv[])
 {
     LispInit_isomorphic();
     SReference ls1 = (L|(L|1, 2), 3, 4);         // ((1 2) 3 4)
     SReference ls2 = (L|(L|"a", "b"), "c", "d"); // (("a" "b") "c" "d")
     SReference ls3 = (L|(L|1, 2), (L|3, 4));     // ((1 2) (3 4))
     call_isomorph(ls1, ls2);
     call_isomorph(ls1, ls3);
     return 0;
 }
 // end of file

Compiled with:

 g++ -Wall -g isomorph.cpp main.cpp -lintelib -o isomorph && ./isomorph

will produce:

 ((1 2) 3 4) ~~ (("a" "b") "c" "d") : T
 ((1 2) 3 4) ~~ ((1 2) (3 4)) : NIL




Garbage Collection: BoehmGC

BoehmGC is probably the most under-used piece of software worldwide. It should be included in any application written in C or C++.


| Mirror on informatimago.com | Mirror on free.fr |
Valid HTML 4.01!