typesolver.cc
Go to the documentation of this file.
00001 #include "CPPParser.hpp"
00002 #include "CPPLexer.hpp"
00003 #include "typesolver.hh"
00004 #include <typelib/registry.hh>
00005 #include <utilmm/stringtools.hh>
00006 #include "packing.hh"
00007 #include <typelib/typevisitor.hh>
00008 
00009 #include <iostream>
00010 #include <numeric>
00011 #include <sstream>
00012 #include <cassert>
00013 
00014 using namespace std;
00015 using namespace Typelib;
00016 using utilmm::join;
00017 
00018 ostream& operator << (ostream& io, TypeSolver::CurrentTypeDefinition const& def)
00019 {
00020     return io << "  " << join(def.name, " ") << " [" << join(def.array, ", ") << "] " << def.pointer_level;
00021 }
00022 
00023 TypeSolver::TypeSolver(const antlr::ParserSharedInputState& state, Registry& registry, bool cxx_mode)
00024     : CPPParser(state), m_class_object(0), m_registry(registry), m_cxx_mode(cxx_mode)
00025     , m_opaques_forced_alignment(true), m_opaques_ignore(false) {}
00026 
00027 TypeSolver::TypeSolver(antlr::TokenStream& lexer, Registry& registry, bool cxx_mode)
00028     : CPPParser(lexer), m_class_object(0), m_registry(registry), m_cxx_mode(cxx_mode)
00029     , m_opaques_forced_alignment(true), m_opaques_ignore(false) {}
00030 
00031 void TypeSolver::setupOpaqueHandling(bool forced_alignment, bool ignore)
00032 {
00033     m_opaques_forced_alignment = forced_alignment;
00034     m_opaques_ignore = ignore;
00035 }
00036 void TypeSolver::defineOpaqueAlignment(std::string const& type_name, size_t value)
00037 {
00038     cerr << type_name << " is aligned on " << value << endl;
00039     m_opaques_alignment[type_name] = value;
00040 }
00041 
00042 void TypeSolver::setTypename(std::string const& name)
00043 {
00044     std::string type_name = name, alias_name = name;
00045     // add "struct", "enum" or "union" prefixes to the right name, according to
00046     // the value of m_cxx_mode
00047     { std::string* prefixed_name;
00048         if (m_cxx_mode) prefixed_name = &alias_name;
00049         else            prefixed_name = &type_name;
00050 
00051         if (m_class_type == tsENUM)
00052             *prefixed_name = "enum " + *prefixed_name;
00053         else if (m_class_type == tsUNION)
00054             *prefixed_name = "union " + *prefixed_name;
00055         else if (m_class_type == tsSTRUCT)
00056             *prefixed_name = "struct " + *prefixed_name;
00057     }
00058 
00059     m_class_object->setName(m_registry.getFullName(type_name));
00060     m_registry.add(m_class_object);
00061     if (m_cxx_mode)
00062         m_registry.alias(m_class_object->getName(), m_registry.getFullName(alias_name));
00063 }
00064 
00065 void TypeSolver::beginTypeDefinition(TypeSpecifier class_type, const std::string& name)
00066 {
00067     if (m_class_object)
00068         throw NestedTypeDefinition(name, m_class_object->getName());
00069 
00070     m_class_type = class_type;
00071     if (m_class_type == tsENUM)
00072         m_class_object = new Enum("");
00073     else
00074         m_class_object = new Compound("");
00075 
00076     if (name != "" && name != "anonymous")
00077         setTypename(name);
00078 }
00079 
00080 void TypeSolver::beginClassDefinition(TypeSpecifier class_type, const std::string& name)
00081 {
00082     beginTypeDefinition(class_type, name);
00083     CPPParser::beginClassDefinition(class_type, name);
00084 }
00085 
00086 void TypeSolver::endClassDefinition()
00087 {
00088     if (!m_class_object->getName().empty()) // typedef struct {} bla handled later in declarationID
00089         buildClassObject();
00090 
00091     CPPParser::endClassDefinition();
00092 }
00093 
00094 void TypeSolver::enterNamespace(std::string const& name)
00095 {
00096     m_namespace.push_back(name);
00097     m_registry.setDefaultNamespace( "/" + utilmm::join(m_namespace, "/") );
00098 }
00099 
00100 void TypeSolver::exitNamespace()
00101 {
00102     m_namespace.pop_back();
00103     m_registry.setDefaultNamespace( "/" + utilmm::join(m_namespace, "/") );
00104 }
00105 
00106 void TypeSolver::beginEnumDefinition(const std::string& name)
00107 {
00108     if (m_class_object)
00109     {
00110         CurrentTypeDefinition& def = pushNewType();
00111         def.name.push_back("enum");
00112         def.name.push_back(name);
00113     }
00114     else
00115         beginTypeDefinition(tsENUM, name);
00116     CPPParser::beginEnumDefinition(name);
00117 }
00118 
00119 void TypeSolver::enumElement(const std::string& name, bool has_value, int value)
00120 {
00121     if (m_class_type != tsENUM)
00122         throw NestedTypeDefinition(m_current.front().name.back(), m_class_object->getName());
00123 
00124     Enum& enum_type = dynamic_cast<Enum&>(*m_class_object);
00125     if (!has_value)
00126         value = enum_type.getNextValue();
00127     
00128     enum_type.add(name, value);
00129     m_constants[name] = value;
00130     CPPParser::enumElement(name, has_value, value);
00131 }
00132 
00133 void TypeSolver::endEnumDefinition()
00134 {
00135     CPPParser::endEnumDefinition();
00136 
00137     if (m_class_type != tsENUM)
00138         return;
00139 
00140     if (! m_class_object->getName().empty()) // typedef union {} bla handled later in declarationID
00141         buildClassObject();
00142 }
00143 
00144 void TypeSolver::beginTypedef()
00145 {
00146     pushNewType();
00147     CPPParser::beginTypedef();
00148 }
00149 
00150 int TypeSolver::getIntConstant(std::string const& name)
00151 {
00152     map<string, int>::iterator it = m_constants.find(name);
00153     if (it != m_constants.end())
00154         return it->second;
00155     else
00156         throw InvalidConstantName(name);
00157 }
00158 
00159 int TypeSolver::getTypeSize(CurrentTypeDefinition const& def)
00160 {
00161     string def_name = join(def.name, " ");
00162     Type const* t = m_registry.build(def_name);
00163     if (t)
00164         return t->getSize();
00165     else
00166         throw InvalidTypeName(def_name);
00167 }
00168 
00169 Type& TypeSolver::buildClassObject()
00170 {
00171     CurrentTypeDefinition& def = pushNewType();
00172     def.name.push_back(m_class_object->getName());
00173 
00174     if (m_class_type == tsSTRUCT)
00175     {
00176         size_t size = 0;
00177         Compound& compound(dynamic_cast<Compound&>(*m_class_object));
00178         try {
00179             size = Packing::getSizeOfCompound(compound);
00180             compound.setSize(size);
00181         }
00182         catch(Typelib::UnsupportedType)
00183         {
00184             // If opaques_ignore is set, just simply let it be.
00185             if (!m_opaques_ignore)
00186                 throw;
00187         }
00188     }
00189 
00190     Type* object = m_class_object;
00191     m_class_object = 0;
00192     m_class_type = 0;
00193     return *object;
00194 }
00195 
00196 void TypeSolver::beginFieldDeclaration()
00197 { 
00198     pushNewType();
00199     CPPParser::beginFieldDeclaration();
00200 }
00201 void TypeSolver::endFieldDeclaration()
00202 { CPPParser::endFieldDeclaration(); }
00203 
00204 
00205 void TypeSolver::foundSimpleType(const std::list<std::string>& full_type)
00206 {
00207     if (!m_current.empty() && m_current.front().name.empty())
00208     {
00209         m_current.front().name = full_type;
00210     }
00211 
00212     CPPParser::foundSimpleType(full_type);
00213 }
00214 
00215 void TypeSolver::classForwardDeclaration(TypeSpecifier ts, DeclSpecifier ds, const std::string& name)
00216 {
00217     CurrentTypeDefinition& def = pushNewType();
00218     if (ts == tsSTRUCT)
00219         def.name.push_back("struct");
00220     else if (ts == tsUNION)
00221         def.name.push_back("union");
00222 
00223     def.name.push_back(name);
00224 
00225     CPPParser::classForwardDeclaration(ts, ds, name);
00226 }
00227 
00228 BOOST_STATIC_ASSERT( sizeof(vector<int8_t>) == sizeof(vector<double>) );
00229 BOOST_STATIC_ASSERT( sizeof(set<int8_t>) == sizeof(set<double>) );
00230 BOOST_STATIC_ASSERT( sizeof(map<int8_t,int16_t>) == sizeof(map<double,float>) );
00231 struct TemplateDef {
00232     char const* name;
00233     size_t size;
00234 };
00235 TemplateDef const ALLOWED_TEMPLATES[] = {
00236     { "std/vector", sizeof(vector<int>) },
00237     { "std/set", sizeof(set<int>) },
00238     { "std/map", sizeof(map<int, int>) },
00239     { 0, 0 }
00240 };
00241 
00242 Typelib::Type const& TypeSolver::buildCurrentType()
00243 {
00244     if (m_current.empty())
00245         throw TypeStackEmpty("buildCurrentType");
00246 
00247     CurrentTypeDefinition type_def = popType();
00248     std::auto_ptr<TypeBuilder> builder;
00249 
00250     // Check if type_def.name is an allowed container (vector, map, set). If it
00251     // is the case, make sure that it is already defined in the registry
00252     if (!type_def.template_args.empty())
00253     {
00254         typedef Container::AvailableContainers Containers;
00255         typedef std::list<std::string> stringlist;
00256 
00257         string fullname = join(type_def.name, "/");
00258         if (fullname[0] != '/')
00259             fullname = "/" + fullname;
00260 
00261         Containers containers = Container::availableContainers();
00262         Containers::const_iterator factory = containers.find(fullname);
00263         if (factory == containers.end())
00264             throw Undefined(fullname);
00265         
00266         std::list<Type const*> template_args;
00267         for (stringlist::const_iterator it = type_def.template_args.begin();
00268                 it != type_def.template_args.end(); ++it)
00269         {
00270             template_args.push_back( m_registry.build( *it ) );
00271         }
00272 
00273         Type const* container_t =
00274             &(*factory->second)(m_registry, template_args);
00275         builder.reset(new TypeBuilder(m_registry, container_t));
00276     }
00277     else
00278     {
00279         builder.reset(new TypeBuilder(m_registry, type_def.name));
00280     }
00281 
00282     if (type_def.pointer_level)
00283         builder->addPointer(type_def.pointer_level);
00284 
00285     while (!type_def.array.empty())
00286     {
00287         builder->addArrayMinor(type_def.array.front());
00288         type_def.array.pop_front();
00289     }
00290 
00291     Type const& type = builder->getType();
00292     return type;
00293 }
00294 
00295 void TypeSolver::resetPointerLevel()
00296 {
00297     if (!m_current.empty())
00298         m_current.front().pointer_level = 0;
00299 }
00300 
00301 void TypeSolver::incrementPointerLevel()
00302 {
00303     if (!m_current.empty())
00304         m_current.front().pointer_level++;
00305 }
00306 
00307 TypeSolver::CurrentTypeDefinition TypeSolver::popType()
00308 {
00309     if (m_current.empty())
00310         throw TypeStackEmpty("popType");
00311 
00312     CurrentTypeDefinition def = m_current.front();
00313     m_current.pop_front();
00314     return def;
00315 }
00316 TypeSolver::CurrentTypeDefinition& TypeSolver::pushNewType()
00317 {
00318     m_current.push_front( CurrentTypeDefinition() );
00319     return m_current.front();
00320 }
00321 int TypeSolver::getStackSize() const { return m_current.size(); }
00322 
00323 void TypeSolver::declaratorID(const std::string& name, QualifiedItem qi)
00324 {
00325     if (m_class_object && m_class_object->getName().empty() && qi == qiType) // typedef (struct|union|enum) { } NAME;
00326     {
00327         setTypename(name);
00328         Type& new_type = buildClassObject();
00329         if (! m_cxx_mode)
00330             m_registry.alias(new_type.getName(), m_registry.getFullName(name), "");
00331     }
00332     else if (m_class_object) // we are building a compound
00333     {
00334         if (m_class_type != tsENUM)
00335         {
00336             // Keep it here to readd it afterwards. This handles definitions
00337             // like
00338             //   TYPE a, *b, c[10], d;
00339             // I.e. TYPE remains the same but the modifiers are reset.
00340             CurrentTypeDefinition def = m_current.front();
00341 
00342             Compound& compound     = dynamic_cast<Compound&>(*m_class_object);
00343             Type const& field_type = buildCurrentType();
00344             if (m_class_type == tsUNION)
00345                 compound.addField(name, field_type, 0);
00346             else if (m_class_type == tsSTRUCT)
00347             {
00348                 size_t offset = 0;
00349                 if (field_type.getCategory() != Type::Opaque)
00350                     offset = Packing::getOffsetOf( compound, field_type );
00351                 else
00352                 {
00353                     size_t explicit_alignment = 0;
00354                     AlignmentMap::const_iterator it = m_opaques_alignment.find(field_type.getName());
00355                     if (it != m_opaques_alignment.end())
00356                         explicit_alignment = it->second;
00357                     
00358                     size_t natural_offset  = 0;
00359                     Compound::FieldList const& fields(compound.getFields());
00360                     if (!fields.empty())
00361                     {
00362                         Field const& last_field = fields.back();
00363                         natural_offset = last_field.getOffset() + last_field.getType().getSize();
00364                     }
00365 
00366                     if (explicit_alignment)
00367                         offset = Packing::getOffsetOf( compound, field_type, explicit_alignment );
00368                     else if (m_opaques_ignore)
00369                         offset = Packing::getOffsetOf( compound, field_type, natural_offset );
00370                     else
00371                         throw std::runtime_error("do not know how to compute alignment of the opaque field " + name + ": no explicit alignment value provided");
00372 
00373                     if (m_opaques_forced_alignment && natural_offset != offset)
00374                     {
00375                         ostringstream msg;
00376                         msg << name << " needs to be explicitely aligned on " << explicit_alignment << " bytes, but "
00377                             << offset - natural_offset << " padding bytes are missing";
00378 
00379                         throw std::runtime_error(msg.str());
00380                     }
00381                 }
00382 
00383                 compound.addField( name, field_type, offset );
00384             }
00385             else 
00386                 throw UnsupportedClassType(m_class_type);
00387 
00388             def.pointer_level = 0;
00389             def.array.clear();
00390             m_current.push_front(def);
00391         }
00392     }
00393     else if (qi == qiType)
00394     {
00395         Type const& type = buildCurrentType();
00396         string base_name = m_registry.getFullName(type.getName());
00397         string new_name  = m_registry.getFullName(name);
00398 
00399         Type const* base_type = m_registry.get(base_name);
00400         if (! base_type)
00401             throw Undefined(base_name);
00402 
00403         // Ignore cases where the aliased type already exists and is equivalent
00404         // to the source type.
00405         Type const* aliased_type = m_registry.get(new_name);
00406         if (aliased_type)
00407         {
00408             if (!aliased_type->isSame(*base_type))
00409                 throw AlreadyDefined(new_name);
00410         }
00411         else
00412             m_registry.alias( base_name, new_name );
00413 
00414     }
00415 
00416     CPPParser::declaratorID(name, qi);
00417 }
00418 
00419 void TypeSolver::declaratorArray(int size)
00420 {
00421     if (!m_current.empty())
00422         m_current.front().array.push_back(size);
00423 
00424     CPPParser::declaratorArray(size);
00425 }
00426 
00427 void TypeSolver::end_of_stmt()
00428 { 
00429     while (! m_current.empty())
00430         popType();
00431     CPPParser::end_of_stmt(); 
00432 }
00433 
00434 void TypeSolver::setTemplateArguments(int count)
00435 {
00436     if (m_current.empty())
00437         throw TypeStackEmpty("setTemplateArguments");
00438 
00439     std::list<std::string> template_args;
00440     while (count)
00441     {
00442         Type const& arg_type = buildCurrentType();
00443         template_args.push_front(arg_type.getName());
00444         --count;
00445     }
00446 
00447     m_current.front().template_args = template_args;
00448 }
00449 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41