// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // Indexer.cc -- // // Author : Richard C. Bilson // Created On : Sun May 17 21:37:33 2015 // Last Modified By : Rob Schluntz // Last Modified On : Wed Aug 05 13:52:42 2015 // Update Count : 10 // #include "SynTree/Declaration.h" #include "SynTree/Type.h" #include "SynTree/Expression.h" #include "SynTree/Initializer.h" #include "SynTree/Statement.h" #include "Indexer.h" #include #include "utility.h" #define debugPrint(x) if ( doDebug ) { std::cout << x; } namespace SymTab { template< typename Container, typename VisitorType > inline void acceptAllNewScope( Container &container, VisitorType &visitor ) { visitor.enterScope(); acceptAll( container, visitor ); visitor.leaveScope(); } Indexer::Indexer( bool useDebug ) : doDebug( useDebug ) {} Indexer::~Indexer() {} void Indexer::visit( ObjectDecl *objectDecl ) { enterScope(); maybeAccept( objectDecl->get_type(), *this ); leaveScope(); maybeAccept( objectDecl->get_init(), *this ); maybeAccept( objectDecl->get_bitfieldWidth(), *this ); if ( objectDecl->get_name() != "" ) { debugPrint( "Adding object " << objectDecl->get_name() << std::endl ); idTable.addDecl( objectDecl ); } // if } void Indexer::visit( FunctionDecl *functionDecl ) { if ( functionDecl->get_name() == "" ) return; debugPrint( "Adding function " << functionDecl->get_name() << std::endl ); idTable.addDecl( functionDecl ); enterScope(); maybeAccept( functionDecl->get_functionType(), *this ); acceptAll( functionDecl->get_oldDecls(), *this ); maybeAccept( functionDecl->get_statements(), *this ); leaveScope(); } // A NOTE ON THE ORDER OF TRAVERSAL // // Types and typedefs have their base types visited before they are added to the type table. This is ok, since there is // no such thing as a recursive type or typedef. // // typedef struct { T *x; } T; // never allowed // // for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the // members are traversed, and then the complete type should be added (assuming the type is completed by this particular // declaration). // // struct T { struct T *x; }; // allowed // // It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that // traversal may modify the definition of the type and these modifications should be visible when the symbol table is // queried later in this pass. // // TODO: figure out whether recursive contexts are sensible/possible/reasonable. void Indexer::visit( TypeDecl *typeDecl ) { // see A NOTE ON THE ORDER OF TRAVERSAL, above // note that assertions come after the type is added to the symtab, since they are not part of the type proper // and may depend on the type itself enterScope(); acceptAll( typeDecl->get_parameters(), *this ); maybeAccept( typeDecl->get_base(), *this ); leaveScope(); debugPrint( "Adding type " << typeDecl->get_name() << std::endl ); typeTable.add( typeDecl ); acceptAll( typeDecl->get_assertions(), *this ); } void Indexer::visit( TypedefDecl *typeDecl ) { enterScope(); acceptAll( typeDecl->get_parameters(), *this ); maybeAccept( typeDecl->get_base(), *this ); leaveScope(); debugPrint( "Adding typedef " << typeDecl->get_name() << std::endl ); typeTable.add( typeDecl ); } void Indexer::visit( StructDecl *aggregateDecl ) { // make up a forward declaration and add it before processing the members StructDecl fwdDecl( aggregateDecl->get_name() ); cloneAll( aggregateDecl->get_parameters(), fwdDecl.get_parameters() ); debugPrint( "Adding fwd decl for struct " << fwdDecl.get_name() << std::endl ); structTable.add( &fwdDecl ); enterScope(); acceptAll( aggregateDecl->get_parameters(), *this ); acceptAll( aggregateDecl->get_members(), *this ); leaveScope(); debugPrint( "Adding struct " << aggregateDecl->get_name() << std::endl ); // this addition replaces the forward declaration structTable.add( aggregateDecl ); } void Indexer::visit( UnionDecl *aggregateDecl ) { // make up a forward declaration and add it before processing the members UnionDecl fwdDecl( aggregateDecl->get_name() ); cloneAll( aggregateDecl->get_parameters(), fwdDecl.get_parameters() ); debugPrint( "Adding fwd decl for union " << fwdDecl.get_name() << std::endl ); unionTable.add( &fwdDecl ); enterScope(); acceptAll( aggregateDecl->get_parameters(), *this ); acceptAll( aggregateDecl->get_members(), *this ); leaveScope(); debugPrint( "Adding union " << aggregateDecl->get_name() << std::endl ); unionTable.add( aggregateDecl ); } void Indexer::visit( EnumDecl *aggregateDecl ) { debugPrint( "Adding enum " << aggregateDecl->get_name() << std::endl ); enumTable.add( aggregateDecl ); // unlike structs, contexts, and unions, enums inject their members into the global scope acceptAll( aggregateDecl->get_members(), *this ); } void Indexer::visit( ContextDecl *aggregateDecl ) { enterScope(); acceptAll( aggregateDecl->get_parameters(), *this ); acceptAll( aggregateDecl->get_members(), *this ); leaveScope(); debugPrint( "Adding context " << aggregateDecl->get_name() << std::endl ); contextTable.add( aggregateDecl ); } void Indexer::visit( CompoundStmt *compoundStmt ) { enterScope(); acceptAll( compoundStmt->get_kids(), *this ); leaveScope(); } void Indexer::visit( ApplicationExpr *applicationExpr ) { acceptAllNewScope( applicationExpr->get_results(), *this ); maybeAccept( applicationExpr->get_function(), *this ); acceptAll( applicationExpr->get_args(), *this ); } void Indexer::visit( UntypedExpr *untypedExpr ) { acceptAllNewScope( untypedExpr->get_results(), *this ); acceptAll( untypedExpr->get_args(), *this ); } void Indexer::visit( NameExpr *nameExpr ) { acceptAllNewScope( nameExpr->get_results(), *this ); } void Indexer::visit( AddressExpr *addressExpr ) { acceptAllNewScope( addressExpr->get_results(), *this ); maybeAccept( addressExpr->get_arg(), *this ); } void Indexer::visit( LabelAddressExpr *labAddressExpr ) { acceptAllNewScope( labAddressExpr->get_results(), *this ); maybeAccept( labAddressExpr->get_arg(), *this ); } void Indexer::visit( CastExpr *castExpr ) { acceptAllNewScope( castExpr->get_results(), *this ); maybeAccept( castExpr->get_arg(), *this ); } void Indexer::visit( UntypedMemberExpr *memberExpr ) { acceptAllNewScope( memberExpr->get_results(), *this ); maybeAccept( memberExpr->get_aggregate(), *this ); } void Indexer::visit( MemberExpr *memberExpr ) { acceptAllNewScope( memberExpr->get_results(), *this ); maybeAccept( memberExpr->get_aggregate(), *this ); } void Indexer::visit( VariableExpr *variableExpr ) { acceptAllNewScope( variableExpr->get_results(), *this ); } void Indexer::visit( ConstantExpr *constantExpr ) { acceptAllNewScope( constantExpr->get_results(), *this ); maybeAccept( constantExpr->get_constant(), *this ); } void Indexer::visit( SizeofExpr *sizeofExpr ) { acceptAllNewScope( sizeofExpr->get_results(), *this ); if ( sizeofExpr->get_isType() ) { maybeAccept( sizeofExpr->get_type(), *this ); } else { maybeAccept( sizeofExpr->get_expr(), *this ); } } void Indexer::visit( AlignofExpr *alignofExpr ) { acceptAllNewScope( alignofExpr->get_results(), *this ); if ( alignofExpr->get_isType() ) { maybeAccept( alignofExpr->get_type(), *this ); } else { maybeAccept( alignofExpr->get_expr(), *this ); } } void Indexer::visit( AttrExpr *attrExpr ) { acceptAllNewScope( attrExpr->get_results(), *this ); if ( attrExpr->get_isType() ) { maybeAccept( attrExpr->get_type(), *this ); } else { maybeAccept( attrExpr->get_expr(), *this ); } } void Indexer::visit( LogicalExpr *logicalExpr ) { acceptAllNewScope( logicalExpr->get_results(), *this ); maybeAccept( logicalExpr->get_arg1(), *this ); maybeAccept( logicalExpr->get_arg2(), *this ); } void Indexer::visit( ConditionalExpr *conditionalExpr ) { acceptAllNewScope( conditionalExpr->get_results(), *this ); maybeAccept( conditionalExpr->get_arg1(), *this ); maybeAccept( conditionalExpr->get_arg2(), *this ); maybeAccept( conditionalExpr->get_arg3(), *this ); } void Indexer::visit( CommaExpr *commaExpr ) { acceptAllNewScope( commaExpr->get_results(), *this ); maybeAccept( commaExpr->get_arg1(), *this ); maybeAccept( commaExpr->get_arg2(), *this ); } void Indexer::visit( TupleExpr *tupleExpr ) { acceptAllNewScope( tupleExpr->get_results(), *this ); acceptAll( tupleExpr->get_exprs(), *this ); } void Indexer::visit( SolvedTupleExpr *tupleExpr ) { acceptAllNewScope( tupleExpr->get_results(), *this ); acceptAll( tupleExpr->get_exprs(), *this ); } void Indexer::visit( TypeExpr *typeExpr ) { acceptAllNewScope( typeExpr->get_results(), *this ); maybeAccept( typeExpr->get_type(), *this ); } void Indexer::visit( AsmExpr *asmExpr ) { maybeAccept( asmExpr->get_inout(), *this ); maybeAccept( asmExpr->get_constraint(), *this ); maybeAccept( asmExpr->get_operand(), *this ); } void Indexer::visit( UntypedValofExpr *valofExpr ) { acceptAllNewScope( valofExpr->get_results(), *this ); maybeAccept( valofExpr->get_body(), *this ); } void Indexer::visit( ContextInstType *contextInst ) { acceptAll( contextInst->get_parameters(), *this ); acceptAll( contextInst->get_members(), *this ); } void Indexer::visit( StructInstType *structInst ) { if ( ! structTable.lookup( structInst->get_name() ) ) { debugPrint( "Adding struct " << structInst->get_name() << " from implicit forward declaration" << std::endl ); structTable.add( structInst->get_name() ); } enterScope(); acceptAll( structInst->get_parameters(), *this ); leaveScope(); } void Indexer::visit( UnionInstType *unionInst ) { if ( ! unionTable.lookup( unionInst->get_name() ) ) { debugPrint( "Adding union " << unionInst->get_name() << " from implicit forward declaration" << std::endl ); unionTable.add( unionInst->get_name() ); } enterScope(); acceptAll( unionInst->get_parameters(), *this ); leaveScope(); } void Indexer::visit( ForStmt *forStmt ) { // for statements introduce a level of scope enterScope(); Visitor::visit( forStmt ); leaveScope(); } void Indexer::lookupId( const std::string &id, std::list< DeclarationWithType* > &list ) const { idTable.lookupId( id, list ); } DeclarationWithType* Indexer::lookupId( const std::string &id) const { return idTable.lookupId(id); } NamedTypeDecl *Indexer::lookupType( const std::string &id ) const { return typeTable.lookup( id ); } StructDecl *Indexer::lookupStruct( const std::string &id ) const { return structTable.lookup( id ); } EnumDecl *Indexer::lookupEnum( const std::string &id ) const { return enumTable.lookup( id ); } UnionDecl *Indexer::lookupUnion( const std::string &id ) const { return unionTable.lookup( id ); } ContextDecl * Indexer::lookupContext( const std::string &id ) const { return contextTable.lookup( id ); } void Indexer::enterScope() { if ( doDebug ) { std::cout << "--- Entering scope" << std::endl; } idTable.enterScope(); typeTable.enterScope(); structTable.enterScope(); enumTable.enterScope(); unionTable.enterScope(); contextTable.enterScope(); } void Indexer::leaveScope() { using std::cout; using std::endl; if ( doDebug ) { cout << "--- Leaving scope containing" << endl; idTable.dump( cout ); typeTable.dump( cout ); structTable.dump( cout ); enumTable.dump( cout ); unionTable.dump( cout ); contextTable.dump( cout ); } idTable.leaveScope(); typeTable.leaveScope(); structTable.leaveScope(); enumTable.leaveScope(); unionTable.leaveScope(); contextTable.leaveScope(); } void Indexer::print( std::ostream &os, int indent ) const { using std::cerr; using std::endl; cerr << "===idTable===" << endl; idTable.dump( os ); cerr << "===typeTable===" << endl; typeTable.dump( os ); cerr << "===structTable===" << endl; structTable.dump( os ); cerr << "===enumTable===" << endl; enumTable.dump( os ); cerr << "===unionTable===" << endl; unionTable.dump( os ); cerr << "===contextTable===" << endl; contextTable.dump( os ); #if 0 idTable.dump( os ); typeTable.dump( os ); structTable.dump( os ); enumTable.dump( os ); unionTable.dump( os ); contextTable.dump( os ); #endif } } // namespace SymTab // Local Variables: // // tab-width: 4 // // mode: c++ // // compile-command: "make install" // // End: //