Studying note of GCC-3.4.6 source (88)

5.12. Parse Translation-unit – declaration sequence

In cp_parser_declaration_seq_opt , declarations are handled by cp_parser_declaration . So normally, token it should process is only “end of file” (CPP_EOF). “}” and “;” come from abnormal cases. In such high level function, this extra “}” just means the parse can’t go on, but let above cp_parser_translation_unit to generate error message (usually, it because the error in declaration, so more corrective error message should have been produced).

 

6221 static void

6222 cp_parser_declaration_seq_opt ( cp_parser * parser)                                        in parser.c

6223 {

6224   while (true)

6225   {

6226     cp_token *token;

6227

6228     token = cp_lexer_peek_token (parser->lexer);

6229

6230     if (token->type == CPP_CLOSE_BRACE

6231        || token->type == CPP_EOF)

6232       break ;

6233

6234     if (token->type == CPP_SEMICOLON)

6235     {

6236       /* A declaration consisting of a single semicolon is

6237         invalid. Allow it unless we're being pedantic.  */

6238       if (pedantic && !in_system_header )

6239            pedwarn ("extra `;'");

6240           cp_lexer_consume_token (parser->lexer);

6241       continue ;

6242     }

6243

6244     /* The C lexer modifies PENDING_LANG_CHANGE when it wants the

6245       parser to enter or exit implicit `extern "C"' blocks.  */

6246     while (pending_lang_change > 0)

6247     {

6248       push_lang_context (lang_name_c);

6249       --pending_lang_change ;

6250     }

6251     while (pending_lang_change < 0)

6252     {

6253       pop_lang_context ();

6254       ++pending_lang_change ;

6255     }

6256

6257     /* Parse the declaration itself.  */

6258     cp_parser_declaration (parser);

6259   }

6260 }

 

pending_lang_change will be used if the system header files doesn’t support C+ as well as C. For our assuming target, it is not true. So lines from 6246 to 6255 in cp_parser_declaration_seq_opt are skipped as result.

According to [3], the abbreviate syntax tree for declaration is shown in below.

declaration

block- declaration

function-definition

template-declaration

explicit-instantiation

linkage-specification

namespace-definition

GNU Ext __extension__ declaration

5.12.1.      First example to study the compiling procedure

To better understand how parser works and how the tree is constructed and what it contains, it is better go through the procedure of compiling a real program. To see the ability of the compiler to accommodate C++ standard, we need select the program carefully to let it cover most topic of the language.

Here we use the notable generic library LOKI as the example. The source files we select are those of SmallObj which defines high performance architecture to allocate and deallocate small size objects. Here we skip the step performed by preprocessor, previous section has explain this operation very clearly.

In the source file SmallObject.cc, after the duplicate inclusion defense macro, are the statements:

 

21    #include "Threads.h"                                                                           in Smallobject.c

22    #include "Singleton.h"

23    #include <cstddef>

24    #include <vector>

 

The first two included files are part of the project, the rest are system headers. It is one of the practice recommended by some company (include the company I serve) – includes the closest header file first, the rearer it appears the more common its purpose.

The procedure of reading in included file is covered by previous section too, we also can skip it safely. First in file Threads.h, we see following code snippet (ignore macros):

 

34    namespace Loki

35    {

36    ////////////////////////////////////////////////////////////////////////////////

37    // class template SingleThreaded

38    // Implementation of the ThreadingModel policy used by various classes

39    // Implements a single-threaded model; no synchronization

40    ////////////////////////////////////////////////////////////////////////////////

41   

42        template <class Host>

43        class SingleThreaded

44        {

45        public :

46            struct Lock

47            {

48                Lock() {}

49                Lock(const Host&) {}

50             };

51           

52            typedef Host VolatileType;

53   

54            typedef int IntType;

55   

56            static IntType AtomicAdd(volatile IntType& lval, IntType val)

57            { return lval += val; }

58           

59            static IntType AtomicSubtract(volatile IntType& lval, IntType val)

60            { return lval -= val; }

61   

62            static IntType AtomicMultiply(volatile IntType& lval, IntType val)

63            { return lval *= val; }

64           

65            static IntType AtomicDivide(volatile IntType& lval, IntType val)

66            { return lval /= val; }

67           

68            static IntType AtomicIncrement(volatile IntType& lval)

69            { return ++lval; }

70           

71            static IntType AtomicDivide(volatile IntType& lval)

72            { return --lval; }

73           

74            static void AtomicAssign(volatile IntType & lval, IntType val)

75            { lval = val; }

76           

77            static void AtomicAssign(IntType & lval, volatile IntType & val)

78            { lval = val; }

79        };

117   }

 

The secret and effect of the code is explain brilliantly in modern C++ design (author Andrei Alexandrescu). It is amazing.

5.12.2.      The first statement – NAMESPACE_DECL

The first statement seen by parser is “namespace Loki”, in cp_parser_declaration , it will be handle by following code:

 

cp_parser_declaration (continue)

 

6335   /* If the next token is `namespace', check for a named or unnamed

6336      namespace definition.  */

6337   else if (token1.keyword == RID_NAMESPACE

6338         && (/* A named namespace definition.  */

6339            (token2.type == CPP_NAME

6340         && (cp_lexer_peek_nth_token (parser->lexer, 3)->type

6341             == CPP_OPEN_BRACE))

6342             /* An unnamed namespace definition.  */

6343             || token2.type == CPP_OPEN_BRACE))

6344     cp_parser_namespace_definition (parser);

 

The abbreviate syntax tree for the namespace-definition is given below. A named namespace can be defined across the source files. All definitions will be combined tegother. Among them, the first definition seen by the compiler is original-namespace-definition, those seen later are extension-namespace-definition. But both definitions just have identical looking. On the contrary anonymous namespace can only be defined within a single file.

namespace-definition

named-namespace-definition

  |    original-namespace-definition

  |          namespace identifier { namespace-body }

  |                                declaration-seq [opt]

  |      extension-namespace-definition

  |          namespace original-namespace-name { namespace-body }

  |                        identifier

  unnamed-namespace-definition

      namespace { namespace-body }

 

9538       static void

9539       cp_parser_namespace_definition (cp_parser* parser)                               in parser.c

9540       {

9541         tree identifier;

9542      

9543         /* Look for the `namespace' keyword.  */

9544         cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");

9545      

9546         /* Get the name of the namespace. We do not attempt to distinguish

9547           between an original-namespace-definition and an

9548           extension-namespace-definition at this point. The semantic

9549           analysis routines are responsible for that.  */

9550         if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))

9551           identifier = cp_parser_identifier (parser);

9552         else

9553           identifier = NULL_TREE;

9554      

9555         /* Look for the `{' to start the namespace.  */

9556         cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");

9557         /* Start the namespace.  */

9558         push_namespace (identifier);

9559         /* Parse the body of the namespace.  */

9560         cp_parser_namespace_body (parser);

9561         /* Finish the namespace.  */

9562         pop_namespace ();

9563         /* Look for the final `}'.  */

9564         cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");

9565       }

 

Section Create namespace “std” covers the detail of pushing the scope of namespace. In short, after namespace Loki is pushed into global namespace, we should get the brief layout of tree as below figure. See that now namespace Loki is pointed by scope_chain as current binding scope.


 

 

Figure 46 : brief layout after pushing Loki namespace

cp_parser_namespace_body has below definition.

 

9572 static void

9573 cp_parser_namespace_body (cp_parser* parser)                                           in parser.c

9574 {

9575   cp_parser_declaration_seq_opt (parser);

9576 }

 

We re-enter cp_parser_declaration_seq_opt .

 

你可能感兴趣的:(header,tree,token,compiler,Semantic,preprocessor)