$search
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