实现简易的C语言编译器(part 5)

        到这里,我们已经研究了词法分析中表达式和语句的描述和实现。这一部分,我们接着剖析声明这一块内容。

3.3 声明(declaration)

3.3.1 基本数据类型

        还是先从最简单的基本数据类型开始。对于如下的C语言代码:

int a;
char* b;
int** c;
int add(int x, int y);
int printf(char * format, ...)

由于C语言是强类型语言,声明必然是以类型符开始的。归纳上面几条声明的特点,就得到了关于类型符的描述:

type_specifier : INT
               | CHAR 

        类型符后面的则称之为变量。第一条声明,变量就是一个单独的标志符;紧接着后面的两条声明由于有指针的存在,需要用到前面递归的描述方法,直到遇到标志符为止。于是,声明的变量的描述就可以表述为:

declarator : ID
           | * declarator 

对于最后两条函数声明,括号是主要的特征。同时,又有含参数和不含参数的声明形式,可以扩展标志符的表示范围,得到下面的描述:

declarator : direct_declarator
           | * declarator 

direct_declarator : ID
                  | direct_declarator ( parameter_type_list ) 
                  | direct_declarator ( )

最终,上面的5条声明,包括变量或者函数,可以统一描述为:

variable_declaration : type_specifier declarator

和前面的表达式的描述方法非常类似,关键是要知道如何归纳抽象。需要说明的是,parameter_type_list就是对函数参数的表示方法,本质上也是变量的声明,只是可以用逗号隔开,进行多次声明:

parameter_type_list : variable_declaration
                    | parameter_type_list, variable_declaration

        这样,我们便得到了声明的最终表达形式:

declaration : variable_declaration ; 

        对于C语言中的基本数据类型的分析就到此为止。接着,我们继续分析C语言中另外三种非常重要并且也非常常用的数据类型:数组,结构体和枚举。

3.3.2 数组(Array)

        这里,我们只讨论最简单的一维数组。在C语言中,我们这样声明数组:

int arr[3];
int arr[] = {1, 2};

        先不考虑赋值操作(后面我们统一分析),有没有发现,数组的声明和函数的声明结构很类似,唯一的区别是圆括号和方括号。因此,只需要补充上面的描述:

direct_declarator : ID
                  | direct_declarator ( parameter_type_list ) 
                  | direct_declarator ( )
                  | direct_declarator [ const_expression ] 
                  | direct_declarator [ ]

这里,我们引入了const_expression,顾名思义,就是值为常数的表达式,可以简单描述为:

const_expression : primary_expression

因为数组定义必须首先分配固定大小的内存,我们会在生成汇编代码的时候详细地研究这一块内容。

3.3.3 结构体(Structure)

        结构体也是一种特殊的数据类型,主要的声明方式为:

struct Point {
    int x;
    int y;
};
struct Point point;

可以发现,结构体的声明和基本数据结构的声明类似,如果对应起来,就是这里是以struct 结构体名字开头,然后是变量名。也就是说,我们只需要再单独定义一种针对结构体的类型符即可,得到:

type_specifier : INT
               | CHAR 
               | struct_specifier

仔细分析结构体大括号的内部结构,其实就是由普通的数据类型的声明或者可能存在的嵌套的结构体声明组成的集合。因此,可以描述为:

struct_specifier : struct STRUCT_ID 
                 | struct STRUCT_ID { struct_declaration_list }

struct_declaration_list : struct_declaration
                        | struct_declaration_list  struct_declaration

struct_declaration : type_specifier declarator ;

为了和普通变量名的区别开来,这里引入了STRUCT_ID来单独表示结构体的名字,它和变量名是有区别的。

3.3.4 枚举(Enumerate)

        熟悉了结构体的描述,枚举也就大同小异了,我们常用的声明方式如下:

enum COLOR { RED, BLUE = 2, YELLOW };
enum { Mon, Wed, Fri } week;
enum COLOR color;

        仿照结构体的描述,更新后的类型符为:

type_specifier : INT
               | CHAR 
               | struct_specifier
               | enum_specifier

对于枚举声明中大括号内部的结构,再结构体的描述基础上,稍微变通一下,就可以得到下面的描述:

enum_specifier : enum ENUM_ID
               | enum ENUM_ID { enum_declarator_list }

enum_declarator_list : ENUM_MEMBER_ID
                     | enum_declarator_list, ENUM_MEMBER_ID

同样的,引入ENUM_ID来单独表示枚举名。由于枚举成员变量需要是一个常值,再引入ENUM_MEMBER_ID进行表示。

        至此,我们将表达式、语句和声明用我们自己规定的结构进行了抽象描述,完成了语法分析第一步的工作。再进入第二步内容的时候,我们看一看有没有什么遗漏的地方。当时存在,比如说在声明变量的同时进行初始化,也就是常说的: 定义

3.3.5 变量定义(Definition)

        在C语言中,允许我们采用如下的方式进行变量的声明:

int a = 1, *b;
char str[] = {'a', 'b', 'c'};
struct Point point = {0, 0};

即声明的同时进行变量的定义,也就是需要增加对变量进行赋值的描述。同时可以采用逗号分隔,声明多个变量,这种情况前面我们已经处理过了,只需要转换成_list形式即可。于是,补充之后对描述为:

declaration : type_specifier init_declarator_list ;

init_declarator_list : init_declarator
                     | init_declarator_list, init_declarator

init_declarator : declarator 
                | declarator = initializer

initializer : expression
            | { initializer_list }

initializer_list : initializer
                 | initializer_list, initializer

        看上去还是很好理解的,那么函数呢?C语言中,函数的定义为:

int printf(char * format, ...)
{
    ...
}

熟能生巧,一步到位:

function_definition : type_specifier declarator compound_statement

        至此,我们将会处理到的C语言结构已经全部用抽象的结构描述完毕。但是,对于一个完整的C编译器来说,还有很多内容没有涉及到。本质上来说,这些忽略的内容也是很好用抽象结构表示的,只是越往后,它们涉及的工作量将会非常多。因此,这里将其省略,只保留了相对来说易于理解和处理的部分,便于抓住对编译器的宏观认识和理解。
        这些描述目前都还只是零散的表示。为方便后续处理,需要将这些内容全部联系起来,我们将在下一部分详细研究。

实现简易的C语言编译器(part 0)
实现简易的C语言编译器(part 1)
实现简易的C语言编译器(part 2)
实现简易的C语言编译器(part 3)
实现简易的C语言编译器(part 4)
实现简易的C语言编译器(part 6)
实现简易的C语言编译器(part 7)
实现简易的C语言编译器(part 8)
实现简易的C语言编译器(part 9)
实现简易的C语言编译器(part 10)
实现简易的C语言编译器(part 11)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,731评论 2 9
  • 注:这是第三遍读《C语言深度解剖》,想想好像自从大学开始就没读完过几本书,其中谭浩强的那本《C语言程序设计(第四版...
    HavenXie阅读 1,716评论 1 6
  • 谨记 什么是价值?或许没有多少人能够明白,其实价值并不是实际存在的,它应该是一种体现,比如为城市点缀最美好的一面而...
    长风留言阅读 2,434评论 0 15
  • 记住了,今天是你与过去道别的分水岭 忘记烦恼,忘却所有忧伤 不要去贪恋太多, “不要去关注灵魂” 你只去关注你的亲...
    一池清荷_ce0e阅读 674评论 0 11
  • 吻到了秋天的额头 树叶泛黄俯冲大地 平静的丝绸还没有撕裂 轻松反射阳光的温暖 不必故作匆忙慌张 坐在塔影下 被美丽...
    团结巷徐阅读 163评论 0 0