现在的位置: 首页 > 综合 > 正文

2 词法约定

2013年04月06日 ⁄ 综合 ⁄ 共 11311字 ⁄ 字号 评论关闭
 

1、在本国际标准中,程序文本被保存在称为源文件的单元内。一个源文件,加上通过预处理指令#include包含的头文件(17.4.1.2)和其他源文件(16.2),并除去被条件包含(16.1)预处理指令限定的代码行,称为翻译单元。[注:不需要对所有的C++程序单元同时进行翻译。]
2、[注:翻译单元和实例单元的翻译结果可保存在一个独立的文件或是库文件中。程序中独立的翻译单元之间可通过(例如)调用标识符具有外部链接属性的函数、操作标识符具有外部链接属性的数据或操作数据文件进行通信。可对翻译单元逐个进行翻译,之后再将它们链接以生成可执行程序(3.5)。]
2.1 翻译步骤
1、下列步骤说明了翻译的先后次序。(具体实现必须使这些步骤在行为上看起来是单独进行的,尽管实际上不同的步骤可能被合并在一起)
       1 如果必要,将物理源文件字符映射到基本源字符集(为行结束指示符引入换行字符),映射方式由实现定义。三字符序列(2.3)被替换为相应的单字符内部表示。任何不在基本源字符集(2.2)中的源文件字符被替换为表示此字符的通用字符名。(具体实现可以使用任何内部编码,只要出现在源文件中的真实扩展字符和其通用字符名表示(也就是使用/uXXXX的形式)被等价处理。)
       2 每一个紧跟在反斜杠后面的换行符都将随反斜杠一起被删除,由此将物理代码行粘结成逻辑代码行。如果在粘结成逻辑代码行后正好产生了一匹配通用字符名句法的字符序列,编译器的行为是未定义的。如果一非空源文件的结尾不是换行符,或结尾的换行符紧跟在反斜杠后面,编译器的行为也是未定义的。
       3 源文件被分解为预处理标记(2.4)和空白字符(包括注释)序列。源文件不能以不完整的标记或注释结尾(不完整标记的一个例子是缺少闭合”或>的header-name。不完整的注释可能出现在以未闭合的/*注释结尾的源文件中)。
       4 执行预处理指令,并展开宏调用。如果在标记连接(16.3.3)之后生成了匹配通用字符名句法的字符序列,编译器的行为是未定义的。#include预处理指令导致命名的头或源文件被递归地执行从步骤1到步骤4的处理工作。
       5 字符文字和字符串文字中的每一个源字符集成员,转义序列,或通用字符名被转换为执行字符集(2.13.2, 2.13.4)成员。
       6 对相邻的平凡字符串文字标记进行连接。对相邻的宽字符串文字标记进行连接。
       7 空白字符分隔标记不再有意义。每一个预处理标记被转换为一个标记(2.6)。对所得的标记进行语法和语义分析及翻译。[注:源文件、翻译单元和已翻译单元不必按文件进行排序,这些实体以及任何外部表示之间也不存在一对一的对应关系。以上描述只是概念性的,特定实现可使用不同的方法。]
8 已翻译的翻译单元和实例单元按如下方式组合:[注:其中的某些或全部可由库提供。]1检查每一个已翻译的翻译单元,生成需要实例化的单元列表。[注:这可能包含被显式请求(14.7.2)的实例。]2定位所需模板的定义。在定位过程中是否需要访问包含定义信息的翻译单元源文件是由实现定义的。[注:一种实现可能在已翻译的翻译单元中集成了足够的信息,从而不再需要使用源文件来辅助定位模板的定义信息。]3执行所有必要的实例化,产生实例单元。[注:实例单元类似于已翻译的翻译单元,不过不再包含对未实例化的模板的引用,也不再包含模板定义。]如果任何实例化失败,那么程序是非法的。
       9 解析所有的外部对象和函数引用。对库组件进行链接,以确保对未在当前翻译中定义的函数和对象的外部引用有效。所有此类翻译器的输出被集成为一程序镜像,此镜像包含了在其执行环境中执行的必要信息。
2.2字符集
1、基本源字符集由96个字符组成:空格符,表示水平制表符、垂直制表符、换页和换行的控制字符,以及下列91个图形字符:
a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
_ { } [ ] # ( ) < > % : ; . ? * + - / ˆ & | ˜ ! = , / " ’
2、通用字符名提供了一种表示其他字符的方式:
hex-quad:
hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit
universal-character-name:
/u hex-quad
/U hex-quad hex-quad
通用字符名/UNNNNNNNN所代表的字符对应于ISO/IEC 10646中的NNNNNNNN字符;通用字符名/uNNNN所代表的字符对应于ISO/IEC 10646中的0000NNNN字符。如果通用字符名的十六进制数值小于0x20或在0x7F-x09F之间(包括0x7F和0x9F),或通用字符名代表的是一个基本源字符集中的字符,那么程序是非法的。
3、基本执行字符集基本执行宽字符集均必须包含基本源字符集中的所有成员,加上表示警告/a、退格/b和回车/r的控制字符,以及空字符(或空宽字符)。空字符(或空宽字符)的所有位均为零。对于每一个基本执行字符集,其成员的取值(编码值)应该非负并且各不相同。无论是在基本源字符集还是在基本执行字符集中,位于上述十进制列表中0后面的每一个字符值均应比前一个字符的值大一(也就是说,如果字符00x30编码,那么字符1的编码必须为0x31。我们在实际的编程中也常利用这一特性,如判断一字符a是否为数字可使用代码a>=’0’ && a<=’9’。对于字母的编码没有这一强制性要求,所以使用代码c>=’a’ && c <=’z’来判断字符c是否是小写字母是不具有兼容性的,虽然在ASCII等众多编码中确实如此)执行字符集执行宽字符集分别是基本执行字符集和基本执行宽字符集的超集。执行字符集的成员编码是由实现定义的,任何附加的成员都是实现相关的。
2.3 三字符序列
1、在进行任何其他处理之前,每一个在源文件中出现的下述三字符序列都由表1所示的单字符所替换。
表1 三字符序列
三字符    替换字符
三字符    替换字符
三字符    替换字符
??=         #
??(         [
??<         {
??/          /
??)         ]
??>         }
??’          ^
??!         |
??-          ~
2、例如:
??=define arraycheck(a,b) a??(b??) ??!??! b??(a??)
被替换为
#define arraycheck(a,b) a[b] || b[a]
3、不存在其他的三字符序列。每一个没有形成上述三字符序列的?保持不变。
2.4 预处理标记
preprocessing-token:
header-name
identifier
pp-number
character-literal
string-literal
preprocessing-op-or-punc
each non-white-space character that cannot be one of the above
1、每一个被转换为标记(2.6)的预处理标记必须具有关键字、标识符、文字、操作符或标点的词法形式。
2、从翻译步骤3到6中,预处理标记是语言最小的词法元素。预处理标记可分为以下几类:头名字标识符预处理数字字符文字字符串文字预处理操作符或标点,以及不属于上述预处理标记类别的单个非空白字符。如果单引号或双引号匹配了最后一个类别(即在程序中出现了未配对的单引号或双引号),编译器的行为是未定义的。预处理标记可被空白分隔;空白由注释(2.7),空白字符(空格,水平制表符,换行符,垂直制表符和换页符),或注释和空白字符组成。在16章将看到,特定情况下,翻译步骤4中的空白(或没有空白)不仅仅起分隔预处理标记的作用。空白只有作为头名字的一部分,或位于字符文字和字符串文字的引号之间时才能出现在预处理标记中。
3、如果输入流的一部分已被解析为一连串的预处理标记,这时输入指针定位在一个特定的字符上,那么下一个预处理标记是能够组成合法预处理标记的最长字符序列,即使这可能导致之后的词法分析失败。
4、例如:程序片断1Ex被分析为一个预处理数字标记(它不是一个有效的浮点或整型文字标记),尽管将其分析为两个预处理标记1和Ex可能会产生一个有效的表达式(如当Ex是定义为+1的宏时)。类似的,程序片断1E1也被分析为一预处理数字(它是一个有效的浮点文字标记),而不管E是否是一个宏名。
5、例如:假定x和y为内建类型,程序片断x+++++y被分析为x ++ ++ + y,上述分析不符合递增操作符的约束,尽管分析结果x ++ + ++ y能生成一个正确的表达式。
2.5 替换标记
1、替换标记用来表示一部分操作符和标点符号。
2、除了拼写不同之外,替换标记在所有方面都等同于其所对应的基本标记。表2定义了替换标记集合。
表2 替换标记
替换标记      基本标记
替换标记      基本标记
替换标记      基本标记
    <%             {
    and            &&
   and_eq          &=
    >%             }
    bitor            |
    or_eq           |=
    <:              [
     or             ||
    xor_eq          ^=
    >:              ]
     xor            ^
     not            !
    %:             #
    compl           ˜
    not_eq          !=
   %:%:           ##
    bitand           &
 
2.6 标记
token:
identifier
keyword
literal
operator
punctuator
1、共有五种标记:标识符、关键字、文字(包括字符串文字,字符文字和数字文字)、操作符和其它分隔符(标点符号)。如下所述,空格、水平和垂直制表符、换行符、换页符和注释(统称为“空白”)将被忽略,除非需要它们用来对标记进行分隔。[注:有时需要空白来分隔相邻的标识符、关键字、数字文字和包含字母字符的替换标记。]
2.7 注释
1、/*为块注释的开始标志,块注释以*/字符结束。块注释不允许嵌套。行注释以//字符开始,以换行符结束。如果在行注释中出现了换页符或垂直制表符,那么在此换页符或垂直制表符和结束注释的换行符之间,只允许出现空白字符;无须诊断。[注:注释字符//, /*和*/在行注释中无特殊意义,与其他字符同等对待。类似的,注释字符//和/*在块注释中也无特殊意义。]
2.8 头名字
header-name:
<h-char-sequence>
"q-char-sequence"
 
h-char-sequence:
h-char
h-char-sequence h-char
 
h-char:
any member of the source character set except new-line and >
 
q-char-sequence:
q-char
q-char-sequence q-char
 
q-char:
any member of the source character set except new-line and "
1、头名字预处理标记只允许出现在#include预处理指令(16.2)中。如16.2所述,两种形式的头名字序列均按编译器自定义的方式映射到头文件或外部源文件名。
2、如果字符’和/之一,或字符序列/*和//之一出现在q-char-sequenceh-char-sequence中,或者字符”出现在h-char-sequence中,编译器的行为是未定义的。(因此,如果头名字中包含转义字符,编译器的行为是未定义的。)
2.9 预处理数字
pp-number:
digit
. digit
pp-number digit
pp-number nondigit
pp-number e sign
pp-number E sign
pp-number .
1、在词法上,预处理数字标记涵盖了所有的整型文字标记(2.13.1)和所有的浮点文字标记(2.13.3)。
2、预处理数字在成功地转换为一个整型文字标记或浮点文字标记之后(作为翻译步骤7的一部分,2.1)才能确定其类型和取值。
2.10 标识符
identifier:
nondigit
identifier nondigit
identifier digit
 
nondigit: one of
universal-character-name
_ a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
 
digit: one of
0 1 2 3 4 5 6 7 8 9
1、标识符为一任意长的字母和数字序列。为标识符中的每一个通用字符名所指派的字符,其在ISO 10646中的编码应位于附录E所制定的范围之内。大写和小写字母是不同的。所有字符都是区分大小写的。
2、此外,某些标识符是保留给C++实现和标准库(17.4.3.1.2)使用的,不可用于其它地方;无须诊断。
2.11 关键字
1、表3所示的标识符保留为关键字(也就是说,它们在步骤7中被无条件的视为关键字):
表3 关键字
asm        do             if                 return         typedef
auto      double         inline             short         typeid
bool      dynamic_cast int                signed         typename
break     else          long              sizeof         union
case      enum          mutable            static         unsigned
catch     explicit      namespace         static_cast  using
char      export         new                struct         virtual
class     extern         operator          switch         void
const     false         private            template      volatile
const_cast float         protected         this          wchar_t
continue  for            public             throw         while
default    friend         register          true
delete     goto          reinterpret_cast try
2、再者,表4所示的某些操作符和标点的替换表示(2.5)也被保留,不可用于他处:
表4 替换表示
and    and_eq bitand bitor compl not
not_eq or     or_eq xor    xor_eq
 
2.12 操作符和标点
1、C++程序的词法表示包括许多特殊的预处理标记,这些预处理标记或者用于预处理器语法中,或者被转换为操作符和标点标记:
preprocessing-op-or-punc: one of
{       }       [       ]       #       ##      (       )
<:      :>      <%      %>      %:      %:%:    ;       :       ...
new         delete ?       ::      .       .*
+       -       *       /       %       ˆ       &       |       ˜
!       =       <       >       +=      -=      *=      /=      %=
ˆ=      &=      |=      <<      >>      >>=         <<=    ==      !=
<=      >=      &&      ||      ++      --      ,       ->*         ->
and         and_eq bitand bitor  compl  not         not_eq
or      or_eq  xor         xor_eq
每个preprocessing-op-or-punc在翻译步骤7中被转换为单个的标记(2.1)。
2.13 文字
1、共有以下几种文字(在本国际标准中,术语“文字”通常指那些在ISO C中被称为“常量”的标记):
literal:
integer-literal
character-literal
floating-literal
string-literal
boolean-literal
2.13.1 整型文字
integer-literal:
decimal-literal integer-suffixopt
octal-literal integer-suffixopt
hexadecimal-literal integer-suffixopt
 
decimal-literal:
nonzero-digit
decimal-literal digit
 
octal-literal:
0
octal-literal octal-digit
 
hexadecimal-literal:
0x hexadecimal-digit
0X hexadecimal-digit
hexadecimal-literal hexadecimal-digit
 
nonzero-digit: one of
1 2 3 4 5 6 7 8 9
 
octal-digit: one of
0 1 2 3 4 5 6 7
 
hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
 
integer-suffix:
unsigned-suffix long-suffixopt
long-suffix unsigned-suffixopt
 
unsigned-suffix: one of
u U
 
long-suffix: one of
l L
1、整型文字为不含小数点和指数部分的数字序列。整型文字可带有一指定其数制的前缀和一指明其类型的后缀。数字序列在词法上的第一个数字为最高位。十进制整型文字以非0的数字开头,由十进制数字序列组成。八进制整型文字以数字0开头,由八进制数字(8和9不是八进制数字)序列组成。十六进制整型文字以0x或0X开头,由十六进制数字(包括所有的十进制数字,字母a到f和A到F(对应于十进制数值10到15))序列组成。[例如:数值十二可表示为12,014或0XC。]
2、整型文字的类型取决于它的形式、值和后缀。对于没有后缀的十进制数字,其类型为下列能表示其值的第一个类型:int, long int;如果其值无法用long int类型表示,程序的行为是未定义的。对于没有后缀的八进制或十六进制数字,其类型为下列能表示其值的第一个类型:int, unsigned int, long int, unsigned long int。对于后缀为u或U的整型文字,其类型为下列能表示其值的第一个类型:unsigned int, unsigned long int。对于后缀为l或L的整型文字,其类型为下列能表示其值的第一个类型:long int, unsigned long int。如果整型文字具有后缀ul, lu, uL, Lu, Ul, lU, UL或LU,其类型为unsigned long int。
3、如果在程序的某翻译单元中,包含了一个所有允许类型都不能表示的整型文字,此程序是非法的。
2.13.2 字符文字                                                      
character-literal:
c-char-sequence
L’c-char-sequence
 
c-char-sequence:
c-char
c-char-sequence c-char
 
c-char:
any member of the source character set except
the single-quote , backslash /, or new-line character
escape-sequence
universal-character-name
 
escape-sequence:
simple-escape-sequence
octal-escape-sequence
hexadecimal-escape-sequence
 
simple-escape-sequence: one of
/’ /" /? //
/a /b /f /n /r /t /v
 
octal-escape-sequence:
/ octal-digit
/ octal-digit octal-digit
/ octal-digit octal-digit octal-digit
 
hexadecimal-escape-sequence:
/x hexadecimal-digit
hexadecimal-escape-sequence hexadecimal-digit
1、字符文字为被单引号括起来的单个或多个字符,例如’x’。字符文字具有可选的前缀L,例如L’x’。不具有前缀L的字符文字为普通字符文字,也称为窄字符文字。只包含单个c-char的普通字符文字具有char类型,其数值等于c-char在执行字符集中的编码值。包含多个c-char的普通字符文字称为多字符文字。多字符文字具有int类型,其取值由实现定义。
2、以字母L开头的字符文字,如L’x’,为宽字符文字。宽字符文字的类型为wchar_t。对于只包含单个c-char的宽字符文字,其数值等于c-char在执行宽字符集中的编码值。包含多个c-char的宽字符文字的取值由实现定义。
3、某些非图形字符、单引号’、双引号”、问号?和反斜杠/可按表5表示。
表5 转义序列
new-line                    NL (LF)            /n
horizontal tab             HT                       /t
vertical tab                VT                       /v
backspace                 BS                       /b
carriage return          CR                     /r
form feed                   FF                       /f
alert                            BEL                    /a
backslash                  /                          //
question mark          ?                         /?
single quote              ’                          /’
double quote           "                         /"
octal number             ooo                    /ooo
hex number                hhh                   /xhhh
在字符文字中,双引号”和问号?即可通过它们自身表示,也可分别通过转移序列/”和/?表示。但是单引号’和反斜杠/只能分别通过转移序列/’和//表示。如果反斜杠之后的字符不在表5所指定的范围之内,程序的行为是未定义的。每个转移序列对应于一个字符。
4、由反斜杠后跟一个、两个或三个八进制数字构成的转移序列/ooo,用于指定期望字符的值。由反斜杠后跟x及一个或多个十六进制数字构成的转移序列/xhhh,也用于指定期望字符的值。对于十六进制序列中的数字的数目不作限制。八进制序列和十六进制序列分别由第一个非八进制数字的字符和第一个非十六进制数字的字符中止。如果字符文字的值超出了编译器为char(普通文字)或wchar_t(宽文字)定义的数值范围,其取值是不定的。
5、通用字符名被转换为其所命名的字符在执行字符集中的编码值。如果不存在此编码,通用字符名被转换为由实现定义的编码值。[注:在翻译步骤1中,只要在源文本中遇到了一个扩展字符,便将其转换为通用字符名。因此,所有的扩展字符都是通过通用字符名表示的。然而,真实的编译器可以使用自己内定的字符集,只要保证结果一致。]
2.13.3 浮点文字
floating-literal:
fractional-constant exponent-partopt floating-suffixopt
digit-sequence exponent-part floating-suffixopt
 
fractional-constant:
digit-sequenceopt . digit-sequence
digit-sequence .
 
exponent-part:
e signopt digit-sequence
E signopt digit-sequence
 
sign: one of
+ -
 
digit-sequence:
digit
digit-sequence digit
 
floating-suffix: one of
f l F L
1、浮点文字依次由整数部分、小数点、小数部分、e或E、可选的有符号整型指数和可选的类型后缀组成。整数和小数部分均由十进制数字序列组成。整数部分或小数部分可被省略,但不能同时省略;小数点或字母e(E)和指数可被省略,但不能同时省略。整数部分、可选的小数点和可选的小数部分共同构成浮点文字的基本部分(significant part)。指数部分(如果存在)指定了基本部分需要乘上的10的幂乘值,最终结果称为扩展值(scaled value)。也就是说,扩展值等于基本部分所表示的值乘以指数的10的幂乘。扩展值也是浮点文字所期望表达的真实值。如果扩展值在浮点文字类型所能表示的范围之内,浮点文字的结果取扩展值,否则浮点文字的结果取其类型所能表示的靠扩展值最近的值(可能比扩展值大,也可能比扩展值小),具体方式由编译器自行决定。不具后缀的浮点文字的类型为double。后缀f或F指定类型float,后缀l或L指定类型long double。如果扩展值超出了浮点文字类型所能表示的范围,程序是非法的。(标准在前面指明,如果扩展值溢出的话,结果取靠扩展值最近的值,此处又强调当浮点文字的扩展值溢出时程序非法,不知是否自相矛盾。vc在遇到溢出的浮点文字时,会报告“error C2177: constant too big”错误。)
2.13.4 字符串文字
string-literal:
"s-char-sequenceopt"
L"s-char-sequenceopt"
 
s-char-sequence:
s-char
s-char-sequence s-char
 
s-char:
any member of the source character set except
the double-quote ", backslash /, or new-line character
escape-sequence
universal-character-name
1、字符串文字为被双引号括起来的字符序列(如2.13.2所定义),其可具有可选的字母前缀L,例如”…”或L”…”。不具有前缀L的字符串文字为普通字符串文字,也称为窄字符串

抱歉!评论已关闭.