There are a number of unusual coding features, which developers working on phc should know about.
phc uses libtool, which can make debugging tricky [1]. When you want to call gdb on phc, you must use libtool. Instead of
gdb --args src/phc --help
you must use
libtool --mode=execute gdb --args src/phc --help
This may be abbreviated:
libtool e gdb --args src/phc --help
If you are working on, or debugging, compilation with phc, we have created a convenience wrapper wrapper to simplfiy this.
In gdb, tab-completion (for example for breakpoints) will not be available immediately. This is because phc is structured as a library, which is only loaded once the program starts. Tab-completion will begin to work once phc‘s execution starts.
We have found that gdb can be tempermental when working with phc. If you rebuild phc while working in gdb, you will need to restart gdb. gdb also has problems reading C++ values containing phc‘s objects. This can sometimes be worked around by finding the same value in a different context (perhaps after it has been casted, or passed to another function). Occasionally, dereferencing a pointer using -> can fail — try using . instead.
We use garbage collection in phc. That is, the compiler itself is linked to a garbage collection library, and we do not free any memory manually. As a result, any objects which store objects allocated by phc (such as objects representing AST classes), must be registered with the garbage collector.
This is very straightforward for classes. Simply inherit from GC_obj:
class MyClass: virtual public GC_obj
{
// Class implementation
...
}
STL containers are handled differently, as they provide a parameter for the allocator. If allocating an std::list, you may use
std::list<AST::Node*, phc_allocator<AST::Node*> > mylist.
However, we provide a number of convenience classes, which can be used without phc_allocator:
- List (in src/lib/List.h)
- Map (in src/lib/Map.h)
- Set (in src/lib/Set.h)
- Stack (in src/lib/Stack.h)
- Vector (in src/lib/Vector.h)
If you wish to override another STL container to use garbage collection, use this template:
template<typename _Tp, typename _Alloc = phc_allocator<_Tp> >
class List : public std::list<_Tp, _Alloc>, virtual public GC_obj
{
...
}
Since we use lists so frequently, foreach is used throughout the phc codebase. This is a macro for BOOST_FOREACH.
It is often combined with boost::tie, which splits an std::pair or tuple into their requisite fields, so it goes well with std::maps.
int key, value;
Map<int, int> mymap = some_function ();
foreach (tie(key, value), mymap)
{
...
}
Lists work very well with foreach, but can lead to long error messages if a List* is used instead of a List. If you come across error like this:
/usr/include/boost/range/mutable_iterator.hpp: In instantiation of ‘boost::range_mutable_iterator<MIR::Signature_list*>’:
/usr/include/boost/mpl/eval_if.hpp:38: instantiated from ‘boost::mpl::eval_if<mpl_::bool_<false>, boost::range_const_iterator<MIR::Signature_list*>, boost::range_mutable_iterator<MIR::Signature_list*> >’
/usr/include/boost/foreach.hpp:368: instantiated from ‘boost::foreach_detail_::foreach_iterator<MIR::Signature_list*, mpl_::bool_<false> >’
src/codegen/Generate_C.cpp:514: instantiated from here
/usr/include/boost/range/mutable_iterator.hpp:37: error: ‘MIR::Signature_list*’ is not a class, struct, or union type
src/codegen/Generate_C.cpp: In function ‘void function_declaration_block(std::ostream&, MIR::Signature_list*, String*)’:
src/codegen/Generate_C.cpp:514: error: no matching function for call to ‘deref(const boost::foreach_detail_::auto_any_base&, boost::foreach_detail_::type2type<MIR::Signature_list*, mpl_::bool_<false> >*)’
/usr/include/boost/foreach.hpp: In function ‘bool boost::foreach_detail_::done(const boost::foreach_detail_::auto_any_base&, const boost::foreach_detail_::auto_any_base&, boost::foreach_detail_::type2type<T*, C>*) [with T = MIR::Signature_list, C = mpl_::bool_<false>]’:
src/codegen/Generate_C.cpp:514: instantiated from here
/usr/include/boost/foreach.hpp:695: error: no match for ‘operator!’ in ‘!* boost::foreach_detail_::auto_any_cast [with T = MIR::Signature_list*, C = mpl_::bool_<false>](((const boost::foreach_detail_::auto_any_base&)((const boost::foreach_detail_::auto_any_base*)cur)))’
/usr/include/boost/foreach.hpp:695: note: candidates are: operator!(bool) <built-in>
it is likely that a List* was used in a foreach, instead of a List.
| [1] | The libtool documentation has more details. |