版本11和12间的区别
于2007-07-18 22:53:33修订的的版本11
大小: 41395
编辑: czk
备注:
于2007-07-19 01:59:11修订的的版本12
大小: 128
编辑: czk
备注:
删除的内容标记成这样。 加入的内容标记成这样。
行号 10: 行号 10:





== A.9 Statements ==

Except as described, statements are executed in sequence. Statements are executed for their effect, and do not have values. They fall into several groups.

    statement:
      labeled-statement
      expression-statement
      compound-statement
      selection-statement
      iteration-statement
      jump-statement

=== A.9.1 Labeled Statements ===

Statements may carry label prefixes.

    labeled-statement:
      identifier : statement
      case constant-expression : statement
      default : statement

A label consisting of an identifier declares the identifier. The only use of an identifier label is as a target of goto. The scope of the identifier is the current function. Because labels have their own name space, they do not interfere with other identifiers and cannot be redeclared. See Par.A.11.1.

Case labels and default labels are used with the switch statement (Par.A.9.4). The constant expression of case must have integral type.

Labels themselves do not alter the flow of control.

=== A.9.2 Expression Statement ===

Most statements are expression statements, which have the form

    expression-statement:
      expressionopt;

Most expression statements are assignments or function calls. All side effects from the expression are completed before the next statement is executed. If the expression is missing, the construction is called a null statement; it is often used to supply an empty body to an iteration statement to place a label.

=== A.9.3 Compound Statement ===

So that several statements can be used where one is expected, the compound statement (also called ``block'') is provided. The body of a function definition is a compound statement.

    compound-statement:
      { declaration-listopt statement-listopt }

    declaration-list:
      declaration
      declaration-list declaration

    statement-list:
      statement
      statement-list statement

If an identifier in the declaration-list was in scope outside the block, the outer declaration is suspended within the block (see Par.A.11.1), after which it resumes its force. An identifier may be declared only once in the same block. These rules apply to identifiers in the same name space (Par.A.11); identifiers in different name spaces are treated as distinct.

Initialization of automatic objects is performed each time the block is entered at the top, and proceeds in the order of the declarators. If a jump into the block is executed, these initializations are not performed. Initialization of static objects are performed only once, before the program begins execution.

=== A.9.4 Selection Statements ===

Selection statements choose one of several flows of control.

    selection-statement:
      if (expression) statement
      if (expression) statement else statement
      switch (expression) statement

In both forms of the if statement, the expression, which must have arithmetic or pointer type, is evaluated, including all side effects, and if it compares unequal to 0, the first substatement is executed. In the second form, the second substatement is executed if the expression is 0. The else ambiguity is resolved by connecting an else with the last encountered else-less if at the same block nesting level.

The switch statement causes control to be transferred to one of several statements depending on the value of an expression, which must have integral type. The substatement controlled by a switch is typically compound. Any statement within the substatement may be labeled with one or more case labels (Par.A.9.1). The controlling expression undergoes integral promotion (Par.A.6.1), and the case constants are converted to the promoted type. No two of these case constants associated with the same switch may have the same value after conversion. There may also be at most one default label associated with a switch. Switches may be nested; a case or default label is associated with the smallest switch that contains it.

When the switch statement is executed, its expression is evaluated, including all side effects, and compared with each case constant. If one of the case constants is equal to the value of the expression, control passes to the statement of the matched case label. If no case constant matches the expression, and if there is a default label, control passes to the labeled statement. If no case matches, and if there is no default, then none of the substatements of the swtich is executed.

    In the first edition of this book, the controlling expression of switch, and the case constants, were required to have int type.

=== A.9.5 Iteration Statements ===

Iteration statements specify looping.

    iteration-statement:
      while (expression) statement
      do statement while (expression);
      for (expressionopt; expressionopt; expressionopt) statement

In the while and do statements, the substatement is executed repeatedly so long as the value of the expression remains unequal to 0; the expression must have arithmetic or pointer type. With while, the test, including all side effects from the expression, occurs before each execution of the statement; with do, the test follows each iteration.

In the for statement, the first expression is evaluated once, and thus specifies initialization for the loop. There is no restriction on its type. The second expression must have arithmetic or pointer type; it is evaluated before each iteration, and if it becomes equal to 0, the for is terminated. The third expression is evaluated after each iteration, and thus specifies a re-initialization for the loop. There is no restriction on its type. Side-effects from each expression are completed immediately after its evaluation. If the substatement does not contain continue, a statement

    for (expression1; expression2; expression3) statement

is equivalent to

expression1;
while (expression2) {
    statement
    expression3;
}

Any of the three expressions may be dropped. A missing second expression makes the implied test equivalent to testing a non-zero element.

=== A.9.6 Jump statements ===

Jump statements transfer control unconditionally.

    jump-statement:
      goto identifier;
      continue;
      break;
      return expressionopt;

In the goto statement, the identifier must be a label (Par.A.9.1) located in the current function. Control transfers to the labeled statement.

A continue statement may appear only within an iteration statement. It causes control to pass to the loop-continuation portion of the smallest enclosing such statement. More precisely, within each of the statements

   while (...) { do { for (...) {
     ... ... ...
   contin: ; contin: ; contin: ;
   } } while (...); }

a continue not contained in a smaller iteration statement is the same as goto contin.

A break statement may appear only in an iteration statement or a switch statement, and terminates execution of the smallest enclosing such statement; control passes to the statement following the terminated statement.

A function returns to its caller by the return statement. When return is followed by an expression, the value is returned to the caller of the function. The expression is converted, as by assignment, to the type returned by the function in which it appears.

Flowing off the end of a function is equivalent to a return with no expression. In either case, the returned value is undefined.

== A.10 External Declarations ==

The unit of input provided to the C compiler is called a translation unit; it consists of a sequence of external declarations, which are either declarations or function definitions.

    translation-unit:
      external-declaration
      translation-unit external-declaration

    external-declaration:
      function-definition
      declaration

The scope of external declarations persists to the end of the translation unit in which they are declared, just as the effect of declarations within the blocks persists to the end of the block. The syntax of external declarations is the same as that of all declarations, except that only at this level may the code for functions be given.

=== A.10.1 Function Definitions ===

Function definitions have the form

    function-definition:
      declaration-specifiersopt declarator declaration-listopt compound-statement

The only storage-class specifiers allowed among the declaration specifiers are extern or static; see Par.A.11.2 for the distinction between them.

A function may return an arithmetic type, a structure, a union, a pointer, or void, but not a function or an array. The declarator in a function declaration must specify explicitly that the declared identifier has function type; that is, it must contain one of the forms (see Par.A.8.6.3).

      direct-declarator ( parameter-type-list )
      direct-declarator ( identifier-listopt )

where the direct-declarator is an identifier or a parenthesized identifier. In particular, it must not achieve function type by means of a typedef.

In the first form, the definition is a new-style function, and its parameters, together with their types, are declared in its parameter type list; the declaration-list following the function's declarator must be absent. Unless the parameter type list consists solely of void, showing that the function takes no parameters, each declarator in the parameter type list must contain an identifier. If the parameter type list ends with ``, ...'' then the function may be called with more arguments than parameters; the va_arg macro mechanism defined in the standard header <stdarg.h> and described in Appendix B must be used to refer to the extra arguments. Variadic functions must have at least one named parameter.

In the second form, the definition is old-style: the identifier list names the parameters, while the declaration list attributes types to them. If no declaration is given for a parameter, its type is taken to be int. The declaration list must declare only parameters named in the list, initialization is not permitted, and the only storage-class specifier possible is register.

In both styles of function definition, the parameters are understood to be declared just after the beginning of the compound statement constituting the function's body, and thus the same identifiers must not be redeclared there (although they may, like other identifiers, be redeclared in inner blocks). If a parameter is declared to have type ``array of type,'' the declaration is adjusted to read ``pointer to type;'' similarly, if a parameter is declared to have type ``function returning type,'' the declaration is adjusted to read ``pointer to function returning type.'' During the call to a function, the arguments are converted as necessary and assigned to the parameters; see Par.A.7.3.2.

    New-style function definitions are new with the ANSI standard. There is also a small change in the details of promotion; the first edition specified that the declarations of float parameters were adjusted to read double. The difference becomes noticable when a pointer to a parameter is generated within a function.

A complete example of a new-style function definition is

   int max(int a, int b, int c)
   {
       int m;

       m = (a > b) ? a : b;
       return (m > c) ? m : c;
   }

Here int is the declaration specifier; max(int a, int b, int c) is the function's declarator, and { ... } is the block giving the code for the function. The corresponding old-style definition would be

   int max(a, b, c)
   int a, b, c;
   {
       /* ... */
   }

where now int max(a, b, c) is the declarator, and int a, b, c; is the declaration list for the parameters.

=== A.10.2 External Declarations ===

External declarations specify the characteristics of objects, functions and other identifiers. The term ``external'' refers to their location outside functions, and is not directly connected with the extern keyword; the storage class for an externally-declared object may be left empty, or it may be specified as extern or static.

Several external declarations for the same identifier may exist within the same translation unit if they agree in type and linkage, and if there is at most one definition for the identifier.

Two declarations for an object or function are deemed to agree in type under the rule discussed in Par.A.8.10. In addition, if the declarations differ because one type is an incomplete structure, union, or enumeration type (Par.A.8.3) and the other is the corresponding completed type with the same tag, the types are taken to agree. Moreover, if one type is an incomplete array type (Par.A.8.6.2) and the other is a completed array type, the types, if otherwise identical, are also taken to agree. Finally, if one type specifies an old-style function, and the other an otherwise identical new-style function, with parameter declarations, the types are taken to agree.

If the first external declarator for a function or object includes the static specifier, the identifier has internal linkage; otherwise it has external linkage. Linkage is discussed in Par.11.2.

An external declaration for an object is a definition if it has an initializer. An external object declaration that does not have an initializer, and does not contain the extern specifier, is a tentative definition. If a definition for an object appears in a translation unit, any tentative definitions are treated merely as redundant declarations. If no definition for the object appears in the translation unit, all its tentative definitions become a single definition with initializer 0.

Each object must have exactly one definition. For objects with internal linkage, this rule applies separately to each translation unit, because internally-linked objects are unique to a translation unit. For objects with external linkage, it applies to the entire program.

    Although the one-definition rule is formulated somewhat differently in the first edition of this book, it is in effect identical to the one stated here. Some implementations relax it by generalizing the notion of tentative definition. In the alternate formulation, which is usual in UNIX systems and recognized as a common extension by the Standard, all the tentative definitions for an externally linked object, throughout all the translation units of the program, are considered together instead of in each translation unit separately. If a definition occurs somewhere in the program, then the tentative definitions become merely declarations, but if no definition appears, then all its tentative definitions become a definition with initializer 0.

== A.11 Scope and Linkage ==

A program need not all be compiled at one time: the source text may be kept in several files containing translation units, and precompiled routines may be loaded from libraries. Communication among the functions of a program may be carried out both through calls and through manipulation of external data.

Therefore, there are two kinds of scope to consider: first, the lexical scope of an identifier which is the region of the program text within which the identifier's characteristics are understood; and second, the scope associated with objects and functions with external linkage, which determines the connections between identifiers in separately compiled translation units.

=== A.11.1 Lexical Scope ===

Identifiers fall into several name spaces that do not interfere with one another; the same identifier may be used for different purposes, even in the same scope, if the uses are in different name spaces. These classes are: objects, functions, typedef names, and enum constants; labels; tags of structures or unions, and enumerations; and members of each structure or union individually.

    These rules differ in several ways from those described in the first edition of this manual. Labels did not previously have their own name space; tags of structures and unions each had a separate space, and in some implementations enumerations tags did as well; putting different kinds of tags into the same space is a new restriction. The most important departure from the first edition is that each structure or union creates a separate name space for its members, so that the same name may appear in several different structures. This rule has been common practice for several years.

The lexical scope of an object or function identifier in an external declaration begins at the end of its declarator and persists to the end of the translation unit in which it appears. The scope of a parameter of a function definition begins at the start of the block defining the function, and persists through the function; the scope of a parameter in a function declaration ends at the end of the declarator. The scope of an identifier declared at the head of a block begins at the end of its declarator, and persists to the end of the block. The scope of a label is the whole of the function in which it appears. The scope of a structure, union, or enumeration tag, or an enumeration constant, begins at its appearance in a type specifier, and persists to the end of a translation unit (for declarations at the external level) or to the end of the block (for declarations within a function).

If an identifier is explicitly declared at the head of a block, including the block constituting a function, any declaration of the identifier outside the block is suspended until the end of the block.

=== A.11.2 Linkage ===

Within a translation unit, all declarations of the same object or function identifier with internal linkage refer to the same thing, and the object or function is unique to that translation unit. All declarations for the same object or function identifier with external linkage refer to the same thing, and the object or function is shared by the entire program.

As discussed in Par.A.10.2, the first external declaration for an identifier gives the identifier internal linkage if the static specifier is used, external linkage otherwise. If a declaration for an identifier within a block does not include the extern specifier, then the identifier has no linkage and is unique to the function. If it does include extern, and an external declaration for is active in the scope surrounding the block, then the identifier has the same linkage as the external declaration, and refers to the same object or function; but if no external declaration is visible, its linkage is external.

== A.12 Preprocessing ==

A preprocessor performs macro substitution, conditional compilation, and inclusion of named files. Lines beginning with #, perhaps preceded by white space, communicate with this preprocessor. The syntax of these lines is independent of the rest of the language; they may appear anywhere and have effect that lasts (independent of scope) until the end of the translation unit. Line boundaries are significant; each line is analyzed individually (bus see Par.A.12.2 for how to adjoin lines). To the preprocessor, a token is any language token, or a character sequence giving a file name as in the #include directive (Par.A.12.4); in addition, any character not otherwise defined is taken as a token. However, the effect of white spaces other than space and horizontal tab is undefined within preprocessor lines.

Preprocessing itself takes place in several logically successive phases that may, in a particular implementation, be condensed.

   1. First, trigraph sequences as described in Par.A.12.1 are replaced by their equivalents. Should the operating system environment require it, newline characters are introduced between the lines of the source file.
   2. Each occurrence of a backslash character \ followed by a newline is deleted, this splicing lines (Par.A.12.2).
   3. The program is split into tokens separated by white-space characters; comments are replaced by a single space. Then preprocessing directives are obeyed, and macros (Pars.A.12.3-A.12.10) are expanded.
   4. Escape sequences in character constants and string literals (Pars. A.2.5.2, A.2.6) are replaced by their equivalents; then adjacent string literals are concatenated.
   5. The result is translated, then linked together with other programs and libraries, by collecting the necessary programs and data, and connecting external functions and object references to their definitions.

=== A.12.1 Trigraph Sequences ===

The character set of C source programs is contained within seven-bit ASCII, but is a superset of the ISO 646-1983 Invariant Code Set. In order to enable programs to be represented in the reduced set, all occurrences of the following trigraph sequences are replaced by the corresponding single character. This replacement occurs before any other processing.

         ??= # ??( [ ??< {
         ??/ \ ??) ] ??> }
         ??' ^ ??! | ??- ~

No other such replacements occur.

    Trigraph sequences are new with the ANSI standard.

=== A.12.2 Line Splicing ===

Lines that end with the backslash character \ are folded by deleting the backslash and the following newline character. This occurs before division into tokens.

=== A.12.3 Macro Definition and Expansion ===

A control line of the form

    # define identifier token-sequence

causes the preprocessor to replace subsequent instances of the identifier with the given sequence of tokens; leading and trailing white space around the token sequence is discarded. A second #define for the same identifier is erroneous unless the second token sequence is identical to the first, where all white space separations are taken to be equivalent.

A line of the form

    # define identifier (identifier-list) token-sequence

where there is no space between the first identifier and the (, is a macro definition with parameters given by the identifier list. As with the first form, leading and trailing white space arround the token sequence is discarded, and the macro may be redefined only with a definition in which the number and spelling of parameters, and the token sequence, is identical.

A control line of the form

    # undef identifier

causes the identifier's preprocessor definition to be forgotten. It is not erroneous to apply #undef to an unknown identifier.

When a macro has been defined in the second form, subsequent textual instances of the macro identifier followed by optional white space, and then by (, a sequence of tokens separated by commas, and a ) constitute a call of the macro. The arguments of the call are the comma-separated token sequences; commas that are quoted or protected by nested parentheses do not separate arguments. During collection, arguments are not macro-expanded. The number of arguments in the call must match the number of parameters in the definition. After the arguments are isolated, leading and trailing white space is removed from them. Then the token sequence resulting from each argument is substituted for each unquoted occurrence of the corresponding parameter's identifier in the replacement token sequence of the macro. Unless the parameter in the replacement sequence is preceded by #, or preceded or followed by ##, the argument tokens are examined for macro calls, and expanded as necessary, just before insertion.

Two special operators influence the replacement process. First, if an occurrence of a parameter in the replacement token sequence is immediately preceded by #, string quotes (") are placed around the corresponding parameter, and then both the # and the parameter identifier are replaced by the quoted argument. A \ character is inserted before each " or \ character that appears surrounding, or inside, a string literal or character constant in the argument.

Second, if the definition token sequence for either kind of macro contains a ## operator, then just after replacement of the parameters, each ## is deleted, together with any white space on either side, so as to concatenate the adjacent tokens and form a new token. The effect is undefined if invalid tokens are produced, or if the result depends on the order of processing of the ## operators. Also, ## may not appear at the beginning or end of a replacement token sequence.

In both kinds of macro, the replacement token sequence is repeatedly rescanned for more defined identifiers. However, once a given identifier has been replaced in a given expansion, it is not replaced if it turns up again during rescanning; instead it is left unchanged.

Even if the final value of a macro expansion begins with with #, it is not taken to be a preprocessing directive.

    The details of the macro-expansion process are described more precisely in the ANSI standard than in the first edition. The most important change is the addition of the # and ## operators, which make quotation and concatenation admissible. Some of the new rules, especially those involving concatenation, are bizarre. (See example below.)

For example, this facility may be used for ``manifest-constants,'' as in

   #define TABSIZE 100
   int table[TABSIZE];

The definition

   #define ABSDIFF(a, b) ((a)>(b) ? (a)-(b) : (b)-(a))

defines a macro to return the absolute value of the difference between its arguments. Unlike a function to do the same thing, the arguments and returned value may have any arithmetic type or even be pointers. Also, the arguments, which might have side effects, are evaluated twice, once for the test and once to produce the value.

Given the definition

   #define tempfile(dir) #dir "%s"

the macro call tempfile(/usr/tmp) yields

   "/usr/tmp" "%s"

which will subsequently be catenated into a single string. After

   #define cat(x, y) x ## y

the call cat(var, 123) yields var123. However, the call cat(cat(1,2),3) is undefined: the presence of ## prevents the arguments of the outer call from being expanded. Thus it produces the token string

   cat ( 1 , 2 )3

and )3 (the catenation of the last token of the first argument with the first token of the second) is not a legal token. If a second level of macro definition is introduced,

   #define xcat(x, y) cat(x,y)

things work more smoothly; xcat(xcat(1, 2), 3) does produce 123, because the expansion of xcat itself does not involve the ## operator.

Likewise, ABSDIFF(ABSDIFF(a,b),c) produces the expected, fully-expanded result.

=== A.12.4 File Inclusion ===

A control line of the form

  # include <filename>

causes the replacement of that line by the entire contents of the file filename. The characters in the name filename must not include > or newline, and the effect is undefined if it contains any of ", ', \, or /*. The named file is searched for in a sequence of implementation-defined places.

Similarly, a control line of the form

  # include "filename"

searches first in association with the original source file (a deliberately implementation-dependent phrase), and if that search fails, then as in the first form. The effect of using ', \, or /* in the filename remains undefined, but > is permitted.

Finally, a directive of the form

  # include token-sequence

not matching one of the previous forms is interpreted by expanding the token sequence as for normal text; one of the two forms with <...> or "..." must result, and is then treated as previously described.

#include files may be nested.

=== A.12.5 Conditional Compilation ===

Parts of a program may be compiled conditionally, according to the following schematic syntax.

    preprocessor-conditional:
      if-line text elif-parts else-partopt #endif

    if-line:
      # if constant-expression
      # ifdef identifier
      # ifndef identifier

    elif-parts:
      elif-line text
      elif-partsopt

    elif-line:
      # elif constant-expression

    else-part:
      else-line text

    else-line:
      #else

Each of the directives (if-line, elif-line, else-line, and #endif) appears alone on a line. The constant expressions in #if and subsequent #elif lines are evaluated in order until an expression with a non-zero value is found; text following a line with a zero value is discarded. The text following the successful directive line is treated normally. ``Text'' here refers to any material, including preprocessor lines, that is not part of the conditional structure; it may be empty. Once a successful #if or #elif line has been found and its text processed, succeeding #elif and #else lines, together with their text, are discarded. If all the expressions are zero, and there is an #else, the text following the #else is treated normally. Text controlled by inactive arms of the conditional is ignored except for checking the nesting of conditionals.

The constant expression in #if and #elif is subject to ordinary macro replacement. Moreover, any expressions of the form

    defined identifier

or

    defined (identifier)

are replaced, before scanning for macros, by 1L if the identifier is defined in the preprocessor, and by 0L if not. Any identifiers remaining after macro expansion are replaced by 0L. Finally, each integer constant is considered to be suffixed with L, so that all arithmetic is taken to be long or unsigned long.

The resulting constant expression (Par.A.7.19) is restricted: it must be integral, and may not contain sizeof, a cast, or an enumeration constant.

The control lines

    #ifdef identifier
    #ifndef identifier

are equivalent to

    # if defined identifier
    # if ! defined identifier

respectively.

    #elif is new since the first edition, although it has been available is some preprocessors. The defined preprocessor operator is also new.

=== A.12.6 Line Control ===

For the benefit of other preprocessors that generate C programs, a line in one of the forms

    # line constant "filename"
    # line constant

causes the compiler to believe, for purposes of error diagnostics, that the line number of the next source line is given by the decimal integer constant and the current input file is named by the identifier. If the quoted filename is absent, the remembered name does not change. Macros in the line are expanded before it is interpreted.

=== A.12.7 Error Generation ===

A preprocessor line of the form

    # error token-sequenceopt

causes the preprocessor to write a diagnostic message that includes the token sequence.

=== A.12.8 Pragmas ===

A control line of the form

    # pragma token-sequenceopt

causes the preprocessor to perform an implementation-dependent action. An unrecognized pragma is ignored.

=== A.12.9 Null directive ===

A control line of the form

    #

has no effect.

=== A.12.10 Predefined names ===

Several identifiers are predefined, and expand to produce special information. They, and also the preprocessor expansion operator defined, may not be undefined or redefined.

__LINE__ A decimal constant containing the current source line number.
__FILE__ A string literal containing the name of the file being compiled.
__DATE__ A string literal containing the date of compilation, in the form "Mmmm dd yyyy"
__TIME__ A string literal containing the time of compilation, in the form "hh:mm:ss"
__STDC__ The constant 1. It is intended that this identifier be defined to be 1 only in standard-conforming implementations.

    #error and #pragma are new with the ANSI standard; the predefined preprocessor macros are new, but some of them have been available in some implementations.

== A.13 Grammar ==

Below is a recapitulation of the grammar that was given throughout the earlier part of this appendix. It has exactly the same content, but is in different order.

The grammar has undefined terminal symbols integer-constant, character-constant, floating-constant, identifier, string, and enumeration-constant; the typewriter style words and symbols are terminals given literally. This grammar can be transformed mechanically into input acceptable for an automatic parser-generator. Besides adding whatever syntactic marking is used to indicate alternatives in productions, it is necessary to expand the ``one of'' constructions, and (depending on the rules of the parser-generator) to duplicate each production with an opt symbol, once with the symbol and once without. With one further change, namely deleting the production typedef-name: identifier and making typedef-name a terminal symbol, this grammar is acceptable to the YACC parser-generator. It has only one conflict, generated by the if-else ambiguity.

    translation-unit:
      external-declaration
      translation-unit external-declaration

    external-declaration:
      function-definition
      declaration

    function-definition:
      declaration-specifiersopt declarator declaration-listopt compound-statement

    declaration:
      declaration-specifiers init-declarator-listopt;

    declaration-list:
      declaration
      declaration-list declaration

    declaration-specifiers:
      storage-class-specifier declaration-specifiersopt
      type-specifier declaration-specifiersopt
      type-qualifier declaration-specifiersopt

    storage-class specifier: one of
      auto register static extern typedef

    type specifier: one of
      void char short int long float double signed
      unsigned struct-or-union-specifier enum-specifier typedef-name

    type-qualifier: one of
      const volatile

    struct-or-union-specifier:
      struct-or-union identifieropt { struct-declaration-list }
      struct-or-union identifier

    struct-or-union: one of
      struct union

    struct-declaration-list:
      struct declaration
      struct-declaration-list struct declaration

    init-declarator-list:
      init-declarator
      init-declarator-list, init-declarator

    init-declarator:
      declarator
      declarator = initializer

    struct-declaration:
      specifier-qualifier-list struct-declarator-list;

    specifier-qualifier-list:
      type-specifier specifier-qualifier-listopt
      type-qualifier specifier-qualifier-listopt

    struct-declarator-list:
      struct-declarator
      struct-declarator-list , struct-declarator

    struct-declarator:
      declarator
      declaratoropt : constant-expression

    enum-specifier:
      enum identifieropt { enumerator-list }
      enum identifier

    enumerator-list:
      enumerator
      enumerator-list , enumerator

    enumerator:
      identifier
      identifier = constant-expression

    declarator:
      pointeropt direct-declarator

    direct-declarator:
      identifier
      (declarator)
      direct-declarator [ constant-expressionopt ]
      direct-declarator ( parameter-type-list )
      direct-declarator ( identifier-listopt )

    pointer:
      * type-qualifier-listopt
      * type-qualifier-listopt pointer

    type-qualifier-list:
      type-qualifier
      type-qualifier-list type-qualifier

    parameter-type-list:
      parameter-list
      parameter-list , ...

    parameter-list:
      parameter-declaration
      parameter-list , parameter-declaration

    parameter-declaration:
      declaration-specifiers declarator
      declaration-specifiers abstract-declaratoropt

    identifier-list:
      identifier
      identifier-list , identifier

    initializer:
      assignment-expression
      { initializer-list }
      { initializer-list , }

    initializer-list:
      initializer
      initializer-list , initializer

    type-name:
      specifier-qualifier-list abstract-declaratoropt

    abstract-declarator:
      pointer
      pointeropt direct-abstract-declarator

    direct-abstract-declarator:
      ( abstract-declarator )
      direct-abstract-declaratoropt [constant-expressionopt]
      direct-abstract-declaratoropt (parameter-type-listopt)

    typedef-name:
      identifier

    statement:
      labeled-statement
      expression-statement
      compound-statement
      selection-statement
      iteration-statement
      jump-statement

    labeled-statement:
      identifier : statement
      case constant-expression : statement
      default : statement

    expression-statement:
      expressionopt;

    compound-statement:
      { declaration-listopt statement-listopt }

    statement-list:
      statement
      statement-list statement

    selection-statement:
      if (expression) statement
      if (expression) statement else statement
      switch (expression) statement

    iteration-statement:
      while (expression) statement
      do statement while (expression);
      for (expressionopt; expressionopt; expressionopt) statement

    jump-statement:
      goto identifier;
      continue;
      break;
      return expressionopt;

    expression:
      assignment-expression
      expression , assignment-expression

    assignment-expression:
      conditional-expression
      unary-expression assignment-operator assignment-expression

    assignment-operator: one of
      = *= /= %= += -= <<= >>= &= ^= |=

    conditional-expression:
      logical-OR-expression
      logical-OR-expression ? expression : conditional-expression

    constant-expression:
      conditional-expression

    logical-OR-expression:
      logical-AND-expression
      logical-OR-expression || logical-AND-expression

    logical-AND-expression:
      inclusive-OR-expression
      logical-AND-expression && inclusive-OR-expression

    inclusive-OR-expression:
      exclusive-OR-expression
      inclusive-OR-expression | exclusive-OR-expression

    exclusive-OR-expression:
      AND-expression
      exclusive-OR-expression ^ AND-expression

    AND-expression:
      equality-expression
      AND-expression & equality-expression

    equality-expression:
      relational-expression
      equality-expression == relational-expression
      equality-expression != relational-expression

    relational-expression:
      shift-expression
      relational-expression < shift-expression
      relational-expression > shift-expression
      relational-expression <= shift-expression
      relational-expression >= shift-expression

    shift-expression:
      additive-expression
      shift-expression << additive-expression
      shift-expression >> additive-expression

    additive-expression:
      multiplicative-expression
      additive-expression + multiplicative-expression
      additive-expression - multiplicative-expression

    multiplicative-expression:
      multiplicative-expression * cast-expression
      multiplicative-expression / cast-expression
      multiplicative-expression % cast-expression

    cast-expression:
      unary expression
      (type-name) cast-expression

    unary-expression:
      postfix expression
      ++unary expression
      --unary expression
      unary-operator cast-expression
      sizeof unary-expression
      sizeof (type-name)

    unary operator: one of
      & * + - ~ !

    postfix-expression:
      primary-expression
      postfix-expression[expression]
      postfix-expression(argument-expression-listopt)
      postfix-expression.identifier
      postfix-expression->+identifier
      postfix-expression++
      postfix-expression--

    primary-expression:
      identifier
      constant
      string
      (expression)

    argument-expression-list:
      assignment-expression
      assignment-expression-list , assignment-expression

    constant:
      integer-constant
      character-constant
      floating-constant
      enumeration-constant

The following grammar for the preprocessor summarizes the structure of control lines, but is not suitable for mechanized parsing. It includes the symbol text, which means ordinary program text, non-conditional preprocessor control lines, or complete preprocessor conditional instructions.

    control-line:
      # define identifier token-sequence
      # define identifier(identifier, ... , identifier) token-sequence
      # undef identifier
      # include <filename>
      # include "filename"
      # line constant "filename"
      # line constant
      # error token-sequenceopt
      # pragma token-sequenceopt
      #
      preprocessor-conditional

    preprocessor-conditional:
      if-line text elif-parts else-partopt #endif

    if-line:
      # if constant-expression
      # ifdef identifier
      # ifndef identifier

    elif-parts:
      elif-line text
      elif-partsopt

    elif-line:
      # elif constant-expression

    else-part:
      else-line text

    else-line:
      #else

Appendix A - Reference Manual

Include(^TCPL/A\..*,,titlesonly)

TCPL/A_Reference_Manual (2008-05-22 11:45:59由czk编辑)

ch3n2k.com | Copyright (c) 2004-2020 czk.