2.1 翻译的阶段
一个C#程序由一个或多个源文件组成。一个源文件是一个统一字符编码的字符的有序序列。源文件通常和文件系统中的文件有一一对应关系,但是这个对应关系并不需要。
从概念来讲,一个程序在编译时有四步:
1.予处理,一种文本到文本的转换,这使得可以对程序文本进行条件包含和删除。
2.语法分析,它把输入字符序列转换为一个标记序列。
3.句法分析,它把标记序列转换为可执行代码。
2.2 文法符号
C#的词汇和句子的文法散布在整个文章中。词汇文法定义如能把字符组合为形式标记;句子的文法定义了如何把标记组合为C#程序。
文法生成包括无词尾符号和有词尾符号。在文法生成当中,无词尾符号用意大利体表示,而有词尾符号用定宽字体。每一个无词尾符号定义为一系列产品(production)。这一系列产品的第一行是无词尾符号的名称,接下来是一个冒号。对于一个产品,每个连续的锯齿状的行的右手边同左手边类似是无词尾符号。例子:
nonsense:
terminal1
terminal2
定义了一个名为 nonsense 的无词尾符号,有两个产品,一个在右手边是terminal1,一个在左手边是terminal2。
选项通常列为单独的一行,虽然有时有很多选项,短语“one of”会在选项前面。这里有一个对把每个选项都列在单独一行的简单缩写的方法。例子
letter: one of
ABCabc
简写为:
letter: one of
A
B
C
a
b
c
如identifieropt ,一个写在下方的前缀 “opt”用来作为简写来指明一个可选的符号。例子
whole:
first-part second-partopt last-part
是下面的缩写:
whole:
first-part last-part
first-part second-part last-part
2.3 预处理
预阶段是一个文本到文本的转换阶段,在预处理过程中,使能进行代码的条件包含和排除。
pp-unit:
pp-groupopt
pp-group:
pp-group-part
pp-group pp-group-part
pp-group-part:
pp-tokensopt new-line
pp-declaration
pp-if-section
pp-control-line
pp-line-number
pp-tokens:
pp-token
pp-tokens pp-token
pp-token:
identifier
keyword
literal
operator-or-punctuator
new-line:
The carriage return character (U+000D)
The line feed character (U+000A)
The carriage return character followed by a line feed character
The line separator character (U+2028)
The paragraph separator character (U+2029)
2.3.1 预处理声明
在预处理过程中,为了使用名称可以被定义和取消定义。#define定义一个标识符。#undef“反定义”一个标识符,如果一个标识符在以前已经被定义了,那么它就变成了不明确的。如果一个标识符已经被定义了,它的语意就等同于true;如果一个标识符没有意义,那么它的语意等同于false。
pp-declaration:
#define pp-identifier
#undef pp-identifier
例子:
#define A
#undef B
class C
{
#if A
void F() {}
#else
void G() {} [Page]
#endif
#if B
void H() {}
#else
void I() {}
#endif
}
变为:
class C
{
void F() {}
void I() {}
}
如果有一个 pp-unit, 声明就必须用pp-token元素进行。换句话说,#define和#undef必须在文件中任何“真正代码”前声明,否则在编译时会发生错误。因此,也许会像下面的例子一样散布#if和#define:
#define A
#if A
#define B
#endif
namespace N
{
#if B
class Class1 {}
#endif
}
因为#define放在了真实代码后面,所以下面的例子是非法的:
#define A
namespace N
{
#define B
#if B
class Class1 {}
#endif
}
一个#undef也许会“反定义”一个没有定义的名称。下面的例子中定义了一个名字并且对它进行了两次反定义,第二个#undef没有效果,但还是合法的。
#define A
#undef A
#undef A
2.3.2 #if, #elif, #else, #endif
pp-if-section 用来对程序文本的一部件进行有条件地包括和排除。
pp-if-section:
pp-if-group pp-elif-groupsopt pp-else-groupopt pp-endif-line
pp-if-group:
#if pp-expression new-line pp-groupopt
pp-elif-groups
pp-elif-group
pp-elif-groups pp-elif-group
pp-elif-group:
#elif pp-expression new-line groupopt
pp-else-group:
#else new-line groupopt
pp-endif-line
#endif new-line
例子:
#define Debug
class Class1
{
#if Debug
void Trace(string s) {}
#endif
}
变成:
class Class1
{
void Trace(string s) {}
}
如果这部分可以嵌套。例子:
#define Debug// Debugging on
#undef Trace// Tracing off
class PurchaseTransaction
{
void Commit() {
#if Debug
CheckConsistency();
#if Trace
WriteToLog(this.ToString());
#endif
#endif
CommitHelper();
}
}
2.3.3 预处理控制行
特性#error 和 #warning 使得代码可以把警告和错误的条件报告给编译程序,来查出标准的编译时的 警告和错误。
pp-control-line:
#error pp-message
#warning pp-message