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.
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.
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).
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.3We'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.ccproduces:
% 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 ... ] }]] %
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)));}
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))
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 fileCompiled with:
g++ -Wall -g isomorph.cpp main.cpp -lintelib -o isomorph && ./isomorphwill produce:
((1 2) 3 4) ~~ (("a" "b") "c" "d") : T ((1 2) 3 4) ~~ ((1 2) (3 4)) : NIL
BoehmGC is probably the most under-used piece of software worldwide. It should be included in any application written in C or C++.