网站开发应用
版主: (暂无) | 版副: kaka_nil | 嘉宾: 牡丹花下死 音乐新空气 man2004 lcyku aizibin anzhongyu8761 |在线/登录: 4504 / 218
发表新帖 发表回复
 4   1/1  1
<<上一篇|下一篇>>

>>标题:[原创] C#专题之C#的语法和句法分析   复制本帖地址

lq013
总版主 思多雅[天行健] 81080 126678 656 太平洋舰队元帅 04-02-29 优秀版主勋章 查看资料查看blog
发送消息

1#  2008-10-05 21:18:12

  顶部

C#专题之C#的语法和句法分析

作者:思多雅[天行健] 2008-10-05发布    
    正如前面的专题所说,编译从原理上来说包括了词法分析、语法分析、存储的组织与分配、中间语言、语法制导翻译、代码生成与优化这几大部分,下面我们来看看C#的语法分析和句法分析:

一、C#的语句分析:
    语法分析阶段把输入字符流转换为标记流。 

1.1 输入 
        input: 
            input-elementsopt 
        input-elements: 
            input-element 
            input-elements  input-element 
        input-element: 
            comment 
            white-space 
            token 

1.2 输入字符 
        input-character: 
            any Unicode character 

1.3 行结束符 
        line-terminator: 
            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) 

1.4 注释 
    C#支持两种形式的注释:规则注释和单行注释。 
规则注释以/*开始,并且以*/结束。规则注释可以占用一行的一部分,单行或多行。
比如:
        /* Hello, world program 
                This program writes “Hello, world” to the console 
        */ 
        class Hello 
        { 
            static void Main() { 
                Console.WriteLine("Hello, world"); 
             } 
        } 
    包括多个规则注释。 
单行注释开始与字符//并且延伸到行的结束。
// Hello, world program 
        //       This program writes “Hello, world” to the console 
        // 
         class Hello // any name will do for this class 
         { 
             static void Main() { // this method must be named "Main" 
                 Console.WriteLine("Hello, world"); 
              } 
         } 

介绍了多个单行注释。 
        comment: 
             regular-comment 
             one-line-comment 
        regular-comment: 
             / * rest-of-r egular-comment 

        rest-of-r egular-comment: 
             * rest-of-r egular-comment-star 
             not-star  rest-of-r egular-comment 
        rest-of-r egular-comment-star: 
             / 
             * rest-of-r egular-comment-star 
             not-star-or-slash  rest-of-r egular-comment 
        not-star: 
             Any input-character except * 
        not-star-or-slash: 
             Any input-character except * and / 
        one-line-comment: 
             / / one-line-comment-text      line-terminator 
        one-line-comment-text: 
             input-character 
             one-line-comment-text    input-character 
比如: 
        // This is a comment 
         int i; 
        /* This is a 
             multiline comment */ 
         int j; 

1.5 空白 
        white-space: 
             new-line 
             The tab character (U+0009) 
             The vertical tab character (U+000B) 
             The form feed character (U+000C) 
             The "control-Z" or "substitute" character (U+001A) 
             All characters with Unicode class "Zs" 
1.6 标记 
    C#有五种标记:标识符、关键字、数据符号、操作符和标点。因为空白像是标记的分割符,所以被忽略了。 
         token: 
             identifi er 
             keyword 
             literal 
             operator-or-punctuator 

-------思多雅[天行健]版权所有,首发太平洋论论坛,转载请注明-------

二、C#的句法分析 
    句法分析阶段就是把标记流转换为可执行代码。 

2.1 标识符 
标识符的规则符合统一字符编码标准3.0,除了下划线允许使用起首大写字母,格式化字符 (类Cf)不允许用于标识符而统一字符编码标准中的escape 字符允许用在标识符中。 
         identifi er: 
             available-identifi er 
             @    identifie r-or-keyword 
         available-identifi er: 
             An identifi er-or-keyword that is not a keyword 
         identifi er-or-keyword: 
             identifi er-start-character  identif ier-part-charactersopt 
         identifi er-start-character: 
             letter-character 
             underscore-character 
         identifi er-part-characters: 
             identifi er-part-character 
             identifi er-part-characters   identifi er-part-character 
         identifi er-part-character: 
             letter-character 
             combining-character 
             decimal-digit-character 
             underscore-character 
         letter-character: 
             A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nl 
             A unicode-character-escape-sequence representing a character of classes Lu, Ll, Lt, Lm, Lo, or Nl 
         combining-character: 
             A Unicode character of classes Mn or Mc 
             A unicode-character-escape-sequence representing a character of classes Mn or Mcdecimal-digit- 
             character: 
             A Unicode character of the class Nd 
             A unicode-character-escape-sequence representing a character of the class Nd 
underscore-character: 
           A Unicode character of the class Pc 
           A unicode-character-escape-sequence representing a character of the class Pc 

合法标识符的例子包括“identifier1”, “_identifier2”, 和 “@if”。 

前缀“@”使得可以在标识符中使用关键词。实际上字符@不是标识符的一部分,所以如果没有这个前缀,可能在另外一种语言中被视为通常的标识符。
注意:不是关键字也在标识符中使用前缀@是允许的,但是这是一种很不好的风格。 

示例: 
       class @class 
       { 
           static void @static(bool @bool) { 
              if (@bool) 
                  Console.WriteLine("true"); 
              else 
                  Console.WriteLine("false"); 
            } 
       } 
       class Class1 
       { 
           static void M { 
              @class.@static(true); 
            } 
       } 

定义了一个名为“class”的类,有一个静态方法名为“static”,他使用了一个名为“bool”的参数。 

2.2 关键字 
关键字是类似于标识符的保留字符序列,除非用@字符开头,否则不能用作标识符。 

       关键字: one of 
           abstract       base          bool          break          byte 
           case          catch          char          checked         class 
           const         continue        decimal       default        delegate 
           do            double          else         enum           event 
           explicit       extern         false        finally         fixed 
           float         for            foreach        goto          if 
           implicit       in            int           interface      internal 
           is            lock           long          namespace      new 
           null          object          operator      out           override 
           params         private       protected      public        readonly 
           ref           return          sbyte        sealed          short 
           sizeof         static        string         struct        switch 
           this          throw          true          try            typeof 
           uint          ulong          unchecked      unsafe         ushort 
           using         virtual         void         while 

2.3 数据符号 
数据符号是数值的源代码表示。 
literal: 
             boolean-literal 
             integer-literal 
             real-literal 
             character-literal 
             string-literal 
             null-literal 

2.3.1 二进制数据符号 
这里有两种二进制数值:true 和false。 
        boolean-literal: 
             true 
             false 

2.3.2 整数数据符号 
    整数数据符号有两种可能的形式:十进制和十六进制。 
        integer-literal: 
             decimal-integer-literal 
             hexadecimal-integer-literal 
        decimal-integer-literal: 
             decimal-digits  integer-type-suff ixopt 
        decimal-digits: 
             decimal-digit 
             decimal-digits  decimal-digit 
        decimal-digit:  one of 
             0  1  2     3  4  5  6  7  8          9 
        integer-type -suff ix: one of 
             U  u  L     l  UL  Ul       uL  ul  LU  Lu  lU          lu 
        hexadecimal-integer-literal: 
             0x hex-digits   integer-type-suff ixopt 
        hex-digits: 
             hex-digit 
             hex-digits  hex-digit 
        hex-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 

整数数据符号的类型按下面确定: 
1   如果数据符号没有后缀,它就有这些类型中的第一个,这些类型可以表示出它的数值:int、uint、 
    long、ulong 。 
2   如果数据符号有后缀U 或u,它就有这些类型中的第一个,这些类型可以表示出它的数值:uint, 
    ulong。 
3   如果数据符号有后缀L 或l,If the literal is suffixed by L or l, 它就有这些类型中的第一个,这些类型可以表示出它的数值:long, ulong。 
4  如果数据符号有后缀UL、Ul、uL、ul、LU、Lu、lU或lu,它的类型就是ulong。 
   如果用整数数据符号表示的数值超出了ulong 类型,就会产生错误。 

同时,为了允许最小的可能的int 和long 数值可以用十进制整数描述,存在下面两个规则: 
1   当一个十进制整数数据符号的数值为2147483648 (231),并且没有整数类型后缀,而操作数有一元负操作符(§错误!未找到引用源。)时,结果是int 类型的常数,数值为-2147483648 (-231)。在所有其它情况下,这样的一个十进制整数数据符号是uint 类型。 
2   当一个十进制整数数据符号的数值为9223372036854775808 (263),并且没有整数类型后缀或整数类型后缀L 或l,而操作数有一元负操作符(§错误!未找到引用源。)时,结果是long 类型的常数,数值为-9223372036854775808 (-263)。在所有其它情况下,这样的一个十进制整数数据符号是ulong 类型。 

2.3.2.1 实数据符号 
       real-literal: 
          decimal-digits . decimal-digits exponen t-par topt real-type-suff ixopt 
           . decimal-digits exponent-partopt real-typ e-suff ixopt 
          decimal-digits exponent-part real-type-suff ixopt 
          decimal-digits real-type-suff ix 
       exponent-part: 
          e signopt decimal-digits 
          E signopt decimal-digits 
       sign:  one of 
          +  - 
       real-type-suff ix:  one of 
          F  f  D    d  M  m 

如果没有指定real 类型后缀,实数据符号的类型是double。不然的话,实类型后缀决定了实数据符号,相应的规则如下: 
1  一个实数据以F 或f 为后缀是float 类型。例如数据符号1f、1.5f、1e10f、和-123.456F都是float类型数据。 
2  一个实数据以D 或d 为后缀是double 类型。例如数据符号1d、1.5d、1e10d、和-123.456d都是double 类型数据。 
3  一个实数据以M 或m 为后缀是decimal类型。例如数据符号1m、1.5m、1e10m、和-123.456m都是decimal类型数据。 
这里要重点注意一下,如果所指定的数据符号不能用指定类型表示,在编译时会产生错误。 

2.3.2.2 字符数据符号 
字符数据符号是一个用号括起来的单个字符,如'a'。 
       character-literal: 
           ' character ' 
       character: 
           single-character 
           simple-escape-sequence 
           hexadecimal-escape-sequence 
           unicode-character-escape-sequence 
       single-character: 
            Any character except  ' (U+0027), \ (U+005C), and new-line 
       simple-escape-sequence:  one of 
           \'  \"  \\  \0  \a  \b  \f  \n  \r  \t  \v 
       hexadecimal-escape-sequence: 
           \x hex-digit  hex-digitopt  hex-digitopt hex-digitopt 
在一个单转意符序列或一个十六进制转意符序列中,一个跟在反斜杠字符(\)后面的字符必然是下面的字符之一:  '、"、\、0、a、b、f、n、r、t、x、v,否则,在编译是会发生错误。 

一个简单的转意符序列表示了统一的字符编码的字符编码,如下表所示。 
         转意序列              字符名称             Unicode 编码 

         \'                Single quote      0x0027 

         \"                Double quote      0x0022 

         \\                Backslash         0x005C 

         \0               Null               0x0000 

         \a               Alert              0x0007 

         \b                Backspace         0x0008 

         \f                Form feed         0x000C 

         \n               New line           0x000A 

         \r                Carriage return   0x000D 

         \t                Horizontal tab    0x0009 

         \v               Vertical tab       0x000B 

2.3.2.3 字符串数据符号 
C# 支持两种形式的字符串数据符号:规则字符串数据符号和逐字的字符串数据符号。规则字符串数字 
符号由用双引号括起0 或更多字符组成,例如"Hello, world",并且也许会包括简单转意序列(例如\t 
表示tab 字符)和十六进制转意序列。 
逐字的字符串数据符号由一个@字符后面跟着双引号括起的0 或者更多字符组成。一个简单的例子是 
@"Hello, world"。在一个逐字字符串数据符号中,分割符间的字符通常认为是逐字的,只有引用转意序列例 
外。特别的是,简单转意序列和十六进制转意序列在逐字字符串数据符号中不支持。一个逐字字符串数据符号可 
能会跨越很多行。 
       string-literal: 
           regular-string-literal 
           verbatim-string-literal 
 regular-string-literal: 
             " regular-string-literal-charactersopt  " 
        regular-string-literal-characters: 
            regular-string-literal-character 
            regular-string-literal-characters   regular-string-literal-character 
        regular-string-literal-character: 
            single-regular-string-literal-character 
            simple-escape-sequence 
            hexadecimal-escape-sequence 
             unicode-character-escape-sequence 
        single-regular-string-literal-character: 
            Any character except " (U+0022), \ (U+005C), and new-line 
        verbatim-string-literal: 
             @" verbatim -string-literal-charactersopt   " 
        verbatim-string-literal-characters: 
            verbatim-string-literal-character 
            verbatim-string-literal-characters   verbatim-string-literal-character 
        verbatim-string-literal-character: 
            single-verbatim-string-literal-character 
            quote-escape-sequence 
        single-verbatim-string-literal-character: 
             any character except " 
        quote-escape-sequence: 
             "" 
示例 
        string a = "hello, world";                                 // hello, world 
        string b = @"hello, world";                                // hello, world 
        string c = "hello \t world";                               // hello         world 
        string d = @"hello \t world";                              // hello \t world 
        string e = "Joe said \"Hello\" to me";                     // Joe said "Hello" 
        string f = @"Joe said ""Hello"" to me";                    // Joe said "Hello" 
        string g = "\\\\sever\\share\\file.txt";  // \\server\share\file.txt 
        string h = @"\\server\share\file.txt";                     // \\server\share\file.txt 
        string i = "one\ntwo\nthree"; 
        string j = @"one 
        two 
        three"; 

介绍了多种字符串数据符号。最后一个字符串数据j 是逐字字符串数据,它横跨了很多行。在引号间的字符,包括空白如转行字符,都是逐字复制的。 

2.3.2.4 null 数据字符 
        null-literal: 
             null 

2.3.2.5操作符和标点 
这里有许多种操作符和标点。操作符用于表达式来描述操作涉及到一个或多个操作数。例如,表达式a 
+b 使用+操作符来把a 和b 相加。标点用于组织和分割。例如标点;是用来分割在声明列表中出现的声明。 
       operator-or-punctuator: one of 
           {      }      [      ]       (      )      .      ,       :      ; 
           +      -      *      /      %       &      |      ^       !     ~ 
           =       <      >      ?      ++      --     &&     ||     <<     >> 
           ==     !=     <=     >=     +=      -=     *=     /=     %=     &= 
           |=     ^=     <<=    >>=     -> 

2.3.2..6 Unicode 字符转意字符序列 
一个Unicode 字符转意字符序列代表了一个Unicode 字符。Unicode 字符转意字符序列在标识符,字符串数据符号和字符数据符号中是被允许的。 
       unicode-character-escape-sequence: 
           \u hex-digit hex-digit hex-digit hex-digit 
不能实现多重转换。例如字符串数据“\u005Cu005C”与 “\u005C” rather than “\\”是相等的。 (Unicode数值\u005C是字符 “\”。) 
示例:
       class Class1 
       { 
           static void Test(bool \u0066) { 
              char c = '\u0066'; 
              if (\u0066) 
                  Console.WriteLine(c.ToString()); 
            } 
       } 
介绍了许多\u0066 的使用,它是字母“f”的字符转意序列。这个程序等价于 
       class Class1 
       { 
           static void Test(bool f) { 
              char c = 'f'; 
              if (f) 
                  Console.WriteLine(c.ToString()); 
            } 
       } 

-------思多雅[天行健]版权所有,首发太平洋论论坛,转载请注明-------
三、学习建议
学习这一章,有三个好的建议:
自己根据本专题后续的的一些实例自己体验一下;
到图书馆找些《编译原理》的书,多看一下;
实再不然,先知道有这么一回事,然后回过头再来学习这一部分。
天行健,君子以自强不息!我的博客:http://blog.pconline.com.cn/lq013
思多雅源自中华民族源远流长的质朴哲学与古希腊思辨哲学的结合,代表着严密与严谨的思想与行动。
lq013
总版主 思多雅[天行健] 81080 126678 656 太平洋舰队元帅 04-02-29 优秀版主勋章 查看资料查看blog
发送消息

3#  2008-10-05 21:35:45

  顶部

编译程序是现代计算机系统的基本组成部分.
   从功能上看,一个编译程序就是一个语言翻译程序,它把一种语言(称作源语言)书写的程序翻译成与之等价的用另一种语言(称作目标语言)表示的程序.

引用嘉宾:aizibin的聊天记录,与大家一起分享
天行健,君子以自强不息!我的博客:http://blog.pconline.com.cn/lq013
思多雅源自中华民族源远流长的质朴哲学与古希腊思辨哲学的结合,代表着严密与严谨的思想与行动。
lq013
总版主 思多雅[天行健] 81080 126678 656 太平洋舰队元帅 04-02-29 优秀版主勋章 查看资料查看blog
发送消息

4#  2008-10-05 21:46:15

  顶部

1. 词法分析
任务:分析由字符组成的源程序,把它们识别成为一个一个的具有独立意义的“单词”,并识别出与其有关的属性(如标识符、数等),再转换成某种统一的内部形式,以供其它部分使用。

2. 语法分析
任务:在词法分析的基础上,根据语言的语法规则,把单词序列分解成各类语法单位,如程序、语句、表达式等。

3.语义处理
根据语法结构分析其含义,审查源程序有无语义错误,并为代码生成收集类型信息。
例如:类型检查,设x为整型,则
x:=10.5        {语义错}

又如,x:1..8; y:real; A:integer;
  A:=10;   
x:=A;       {语义正确?}
y:=A;
4. 中间代码生成
任务:将源程序变成一种内部表示形式。这种内部形式叫中间代码。例如三元式、4元式等。(初步的翻译)
中间代码的选择原则:
①容易生成
②容易翻译成目标机代码(与目标机体系结构较一致)
③下一步优化要方便

5. 优化
任务:对前阶段产生的中间代码进行变换或改造,使生成的目标代码更为高效(时/空节省)。
6.目标代码生成
任务:把优化过的中间代码变换成特定机器上的绝对指令代码或汇编代码。(本阶段和机器指令打交道多,比较复杂)。
J1--------------------------------------------------------------------j1
【例】假定有如下程序段。
begin
  var sum,first,count:real;
  sum:=first+count*10
end.
(1)词分
单词(内部形式) 属性     单词(内部形式) 属性
beginsy 保留字      varsy 保留字
sum(id1) 标识符      comma 分界符
first(id2) 标识符      comma 界限符
count(id3) 标识符      colon 界限符
realcon 类型符      semicolon 界限符
sum 标识符      becomes 运算符
first 标识符      plus 运算符
count 标识符      times 运算符
10 数字      endsy 保留字
period 界限符

空格的作用应注意;
字符b、e、g、i、n构成了单词begin。
:和=构成单词:=
上述赋值语句可表示为:id1:=id2+id3*10
内部形式为:
id1 becomes id2 plus id3 times 10

(2)语分
怎么知道这个程序段是正确的?必须知道这个赋值语句是语法上正确的!编译程序要依据文法规则来考察:
<tu1.4.doc>
能推出一棵分析树便为正确的。
上述分析树(Parse tree)也能够表示成语法树(Syntax tree):
<id1.doc>

(3)语义处理
上述赋值语句中sum、first、count均为实型,但10为整型,在进行count*10的分析时,就要进行类型判断,结果是要将10转成实型。故在语法分析树上增加一语义处理结点。即:
id1-id2doc <id1-id2.doc>

(4)中间代码生成。
四元式:(操作,运算分量1,运算分量2,结果)
则,sum:=first+count*10可生成以下四元式序列:





① (inttoreal 10 -  t1)
② (* id3 t1  t2)
③ (+ id2 t2  t3)
④ (:= t3 - id1)

(5)优化
上述可优化成:
① (* id3 10.0  t1)
② (+ id2 t1 id1)
注意:
10在编译阶段转成了10.0;
t3可略,id2+t1直接存放在id1中即可;
t2也可略。
指令和临时单元都减少了!
(6)代码生成(使用有2个寄存器的机器)
① MOVF id3  R2
② MULF #10.0  R2
③ MOVF id2  R1   
④ ADDF R1     R2   
⑤ MOV R2     id1


对汇编目标代码也可以进行优化,如:
(A+B)*(C+D)

4元组为:
(+, A, B,  T1)
(+,C, D,  T2)
(*, T1,T2, T3)

用单地址、单累加器计算机的汇编语言,根据4元式生成以下代码:
LDA A
ADD B
STO T1
LDA C
ADD D
STO T2
LDA T1
MUL T2
STO T3


优化成:
LDA A
ADD B
STO T1
LDA C
ADD D
MUL T1
STO T2

四、编译阶段及其组合
上述6个部分的工作可以分为6个阶段来完成,一个部分对应一个阶段。这种划分是编译程序的逻辑组织。有时6个部分又缺了一、二个部分(合起来了),也就减少了遍(pass)。
如果把上述每个阶段都生成一个中间形式,则需要对源程序或其中间形式扫视6遍。这有时是十分不经济的。因为每一遍都要从外存上调入上一遍的结果,加工后再形成新的结果存于外存。但这样做逻辑关系清楚一些。
人们往往把几个阶段合在一起进行处理。比如,只要一次扫视源程序就得到等价的目标程序--一遍扫描。
又如,对源程序进行一遍扫描,生成一种中间形式,再对中间程序扫视一遍生成目标代码--二遍扫描。(前端+后端)
现代编译程序往往为虚拟机生成代码,然后在各个不同的具体机器上去执行这种代码,如Java(JVM),C#(MSIL)等。这有利于可移植性。亦称半编译半解释。(以后我们看到,在PL/0编译中就是这样做的。)
有时一遍很难达到目的,如ALGOL68允许名字先使用后定义,这往往就需要至少扫视2遍。

引用嘉宾:aizibin的聊天记录,与大家一起分享 

天行健,君子以自强不息!我的博客:http://blog.pconline.com.cn/lq013
思多雅源自中华民族源远流长的质朴哲学与古希腊思辨哲学的结合,代表着严密与严谨的思想与行动。
lq013
总版主 思多雅[天行健] 81080 126678 656 太平洋舰队元帅 04-02-29 优秀版主勋章 查看资料查看blog
发送消息

5#  2009-04-05 12:40:07

  顶部

顶起
与大家分享
天行健,君子以自强不息!我的博客:http://blog.pconline.com.cn/lq013
思多雅源自中华民族源远流长的质朴哲学与古希腊思辨哲学的结合,代表着严密与严谨的思想与行动。
发表新帖 发表回复
 4   1/1  1
<<上一篇|下一篇>>

软件论坛热帖

注册忘记密码帮助

火热论坛

太平洋电脑网论坛帖子仅代表作者本人意见,不代表网站立场。
请勿轻信特价、汇款、中奖等信息,请勿轻易透露个人资料,因此产生的一切后果,PConline不承担任何责任