扩充C0文法编译器开发笔记(一)符号表

零、简介

  这是一个编译大作业。

一、扩充C0文法

  文法包括 常量说明和定义、变量说明和定义、无返回值函数定义和调用、有返回值函数定义和调用、条件语句、while循环语句、情况语句、赋值语句、返回语句、读语句、写语句,支持加减乘除四则运算、整数比较运算。包含一维数组、不包含实型、不包含for循环语句。程序由main方法进入。具体文法见下:

 1 <加法运算符> ::= +|-
 2 <乘法运算符>  ::= *|/
 3 <关系运算符>  ::=  <|<=|>|>=|!=|==
 4 <字母>   ::= _|a|...|z|A|...|Z
 5 <数字>   ::= 0|<非零数字>
 6 <非零数字>  ::= 1|...|9
 7 <字符>    ::=   ‘<加法运算符>‘|‘<乘法运算符>‘|‘<字母>‘|‘<数字>‘
 8 <字符串>   ::=  "{十进制编码为32,33,35-126的ASCII字符}"
 9 <程序>    ::= [<常量说明>][<变量说明>]{<有返回值函数定义>|<无返回值函数定义>}<主函数>
10 <常量说明> ::=  const<常量定义>;{ const<常量定义>;}
11 <常量定义>   ::=   int<标识符>=<整数>{,<标识符>=<整数>}
12                               | char<标识符>=<字符>{,<标识符>=<字符>}
13 <无符号整数>  ::= <非零数字>{<数字>}
14 <整数>        ::= [+|-]<无符号整数>|0
15 <标识符>    ::=  <字母>{<字母>|<数字>}
16 <声明头部>   ::=  int<标识符> | char<标识符>
17 <变量说明>  ::= <变量定义>;{<变量定义>;}
18 <变量定义>  ::= <类型标识符>(<标识符>|<标识符>‘[’<无符号整数>‘]’){,(<标识符>|<标识符>‘[’<无符号整数>‘]’ )}
19 <常量>   ::=  <整数>| <字符>
20 <类型标识符>      ::=  int | char
21 <有返回值函数定义>  ::=  <声明头部>‘(’<参数>‘)’ ‘{’<复合语句>‘}’
22 <无返回值函数定义>  ::= void<标识符>‘(’<参数>‘)’‘{’<复合语句>‘}’
23 <复合语句>   ::=  [<常量说明>][<变量说明>]<语句列>
24 <参数>    ::= <参数表>
25 <参数表>    ::=  <类型标识符><标识符>{,<类型标识符><标识符>}| <空>
26 <主函数>    ::= void main‘(’‘)’ ‘{’<复合语句>‘}’
27 <表达式>    ::= [+|-]<项>{<加法运算符><项>}
28 <项>     ::= <因子>{<乘法运算符><因子>}
29 <因子>    ::= <标识符>|<标识符>‘[’<表达式>‘]’|<整数>|<字符>|<有返回值函数调用语句>|‘(’<表达式>‘)’
30 <语句>    ::= <条件语句>|<循环语句>| ‘{’<语句列>‘}’|<有返回值函数调用语句>;
31                              |<无返回值函数调用语句>;|<赋值语句>;|<读语句>;|<写语句>;|<空>; |<情况语句>|<返回语句>;
32 <赋值语句>   ::=  <标识符>=<表达式>|<标识符>‘[’<表达式>‘]’=<表达式>
33 <条件语句>  ::=  if ‘(’<条件>‘)’<语句>[else<语句>]
34 <条件>    ::=  <表达式><关系运算符><表达式>|<表达式> //表达式为0条件为假,否则为真
35 <循环语句>   ::=  while ‘(’<条件>‘)’<语句>
36 <情况语句>  ::=  switch ‘(’<表达式>‘)’ ‘{’<情况表> ‘}’
37 <情况表>   ::=  <情况子语句>{<情况子语句>}
38 <情况子语句>  ::=  case<常量>:<语句>
39 <有返回值函数调用语句> ::= <标识符>‘(’<值参数表>‘)’
40 <无返回值函数调用语句> ::= <标识符>‘(’<值参数表>‘)’
41 <值参数表>   ::= <表达式>{,<表达式>}|<空>
42 <语句列>   ::= {<语句>}
43 <读语句>    ::=  scanf ‘(’<标识符>{,<标识符>}‘)’
44 <写语句>    ::= printf ‘(’ <字符串>,<表达式> ‘)’| printf ‘(’<字符串> ‘)’| printf ‘(’<表达式>‘)’
45 <返回语句>   ::=  return[‘(’<表达式>‘)’]
46
47
48   附加说明:
49
50 (1)char类型的表达式,用字符的ASCII码对应的整数参加运算,在写语句中输出字符
51
52 (2)标识符不区分大小写字母
53
54 (3)写语句中的字符串原样输出
55
56 (4)情况语句中,switch后面的表达式和case后面的常量只允许出现int和char类型;每个情况子语句执行完毕后,不继续执行后面的情况子语句
57
58 (5)数组的下标从0开始   

扩充C0文法

 二、符号表(Table)

  符号表是在编译过程中编译程序用来记录源程序中的各种名字(即标识符)的特性信息的表格。符号表的每一个符号表项将填入名字标识符以及与该名字相关联的信息,这些信息将全面地反映各个符号的属性及他们在编译过程中的特征,比如名字的种类(数组、变量、常量等)、类型(整形、字符型等)、值等与该名字的语义有关的其他信息等。

1、符号表结构

  符号表由符号表项(TableItem)构成,每个符号表项结构见下:

 1 class Table;
 2 class TableItem
 3 {
 4     public:
 5         string name;    // 符号表项名,如函数名、变量名等
 6         int kind;       // 标识符种类,如VAR、CONST、ARRAY、FUNCTION等
 7         int type;       // 标识符类型,如INT、CHAR等
 8         string value;   // 值或地址(例如常量的值、变量的地址)
 9         int dimension;  // 数组的上界、函数的参数个数
10         Table* pChildTable;     // 指向由该项引出的子表
11         Table* pParentTable;    // 指向该项所在的表
12
13         TableItem(string name, int kind, int type, string value, int dimension, Table* parentTable);
14         ~TableItem();
15 };

符号表项结构

2、符号表管理

  符号表由符号表管理类(TableManager)管理,如下:

 1 class Table;
 2 class TableItem;
 3 class TableManager
 4 {
 5     public:
 6         Table* pCurrentTable;       // 指向当前符号表
 7         Table* pTopTable;           // 指向最顶层符号表
 8         TableItem* pCurrentItem;    // 指向当前符号表项
 9
10         TableManager();
11         virtual ~TableManager();
12
13         // 检查当前符号表,是否存在名称为name的符号表项
14         int checkCurrent(string name, int isCaseSensitive);
15         // 检查所有的符号表,是否存在名称为name的符号表项
16         int checkAll(string name, int isCaseSensitive);
17         // 根据名称name返回对应的符号表项
18         TableItem* find(string name, int isCaseSensitive);
19         // 插入符号表项
20         void insert(string name, int kind, int type, string value, int dimension);
21         // 当前符号表项出栈
22         void pop();
23         // 将name对应的符号表项压栈
24         void push(string name);
25 };

符号表管理类

3、符号表管理算法

(1)压栈算法:符号表压栈操作,若当前符号表的最后一项为函数头部或过程头部,则为该项建立子符号表,并将当前符号表指针更新为此符号表

 1 void TableManager::push(string name)
 2 {
 3     if(pCurrentTable->itemNumber == 0)
 4     {
 5         ;// 如果当前没有符号表项,DONOTHING
 6     }
 7     // 如果名称叫name的符号表项有引出的表,则将该表压入栈顶
 8     else if(find(name, 1)->pChildTable != NULL)
 9     {
10         pCurrentTable = find(name, 1)->pChildTable;
11     }
12     else
13     {
14         ;//如果该符号表项没有引出的子表,DONOTHING
15     }
16 }

push(string name)

(2)出栈算法:符号表退栈操作,将当前符号表更新为次栈顶符号表

 1 void TableManager::pop()
 2 {
 3     // 如果当前符号表是由某个符号表项引出的,则更新当前符号表为该符号表项所在的符号表
 4     if(pCurrentTable->pParentItem != NULL)
 5     {
 6         pCurrentTable = pCurrentTable->pParentItem->pParentTable;
 7     }
 8     else
 9     {
10         ;// 如果为顶层符号表,DONOTING
11     }
12 }

pop()

(3)查询算法:修改自二分查找(符号表项按其名称的字母顺序,将其索引值存入一个数组,在该数组中二分查找),如果存在该符号表项,则返回索引值,否则返回该符号表项应该插入的位置

 1 int Table::find(string name, int left, int right, int isCaseSensitive)
 2 {
 3     int mid = (left+right)/2;
 4     if(left == right)
 5     {
 6         if(compare(name, itemList[itemIndex[left]]->name, isCaseSensitive) == 0)
 7         {
 8             itemExist = 1;
 9             return left;
10         }
11         else if(compare(name, itemList[itemIndex[left]]->name, isCaseSensitive) == 1)
12         {
13             itemExist = 0;
14             return left+1;
15         }
16         else
17         {
18             itemExist = 0;
19             return left;
20         }
21     }
22     else if(left+1 == right)
23     {
24         if(compare(name, itemList[itemIndex[left]]->name, isCaseSensitive) == 0)
25         {
26             itemExist = 1;
27             return left;
28         }
29         else if(compare(name, itemList[itemIndex[right]]->name, isCaseSensitive) == 0)
30         {
31             itemExist = 1;
32             return right;
33         }
34         else
35         {
36             itemExist = 0;          // newItem位置在left和right中间
37             return right;
38         }
39     }
40     else if(compare(name, itemList[itemIndex[mid]]->name, isCaseSensitive) == -1)
41     {
42         return find(name, left, mid, isCaseSensitive);
43     }
44     else if(compare(name, itemList[itemIndex[mid]]->name, isCaseSensitive) == 1)
45     {
46         return find(name, mid, right, isCaseSensitive);
47     }
48     else
49     {
50         itemExist = 1;
51         return mid;
52     }
53 }

find(string name, int left, int right, int isCaseSensitive)

(4)插入算法:将新的符号表项插入符号表中,并根据其名称的字母序建立索引,存入有序数组中,方便二分查找

 1 int Table::insert(string name, int kind, int type, string value, int dimension)
 2 {
 3     newItem = new TableItem(name, kind, type, value, dimension, this);
 4     if(itemNumber == 0)
 5     {
 6         itemIndex[0] = 0;
 7         itemList[itemNumber++] = newItem;
 8         return 0;
 9     }
10     else
11     {
12         if(name < itemList[itemIndex[0]]->name)
13         {
14             for(int i = itemNumber - 1; i >= 0; i--)
15                 itemIndex[i+1] = itemIndex[i];
16             itemIndex[0] = itemNumber;
17             itemList[itemNumber++] = newItem;
18         }
19         else if(name > itemList[itemIndex[itemNumber-1]]->name)
20         {
21             itemIndex[itemNumber] = itemNumber;
22             itemList[itemNumber++] = newItem;
23         }
24         else
25         {
26             int index = find(newItem->name, 0, itemNumber-1, 0);
27             if(itemExist == 1)
28             {
29                 //ERROR
30                 return -1;
31             }
32             else
33             {
34                 for(int i = itemNumber - 1; i >= index; i--)
35                     itemIndex[i+1] = itemIndex[i];
36                 itemIndex[index] = itemNumber;
37                 itemList[itemNumber++] = newItem;
38             }
39         }
40         return 0;
41     }
42 }

insert(string name, int kind, int type, string value, int dimension)

时间: 2024-12-24 23:13:20

扩充C0文法编译器开发笔记(一)符号表的相关文章

Android开发笔记(一百三十二)矢量图形与矢量动画

矢量图形VectorDrawable 与水波图形RippleDrawable一样,矢量图形VectorDrawable也是Android5.0之后新增的图形类.矢量图不同于一般的图形,它是由一系列几何曲线构成的图像,这些曲线以数学上定义的坐标点连接而成.具体到实现上,则需开发者提供一个xml格式的矢量图形定义,然后系统根据矢量定义自动计算该图形的绘制区域.因为绘图结果是动态计算得到,所以不管缩放到多少比例,矢量图形都会一样的清晰,不像位图那样拉大后会变模糊. 矢量图形的xml定义有点复杂,其结构

[置顶] Android开发笔记(成长轨迹)

分类: 开发学习笔记2013-06-21 09:44 26043人阅读 评论(5) 收藏 Android开发笔记 1.控制台输出:called unimplemented OpenGL ES API 调用了未实现的OpenGL ES API函数,一般由于导入的第三方库如地图库,里面有用到OpenGL,但是模拟器的硬件默认是没有这个的,所以需要我们编辑模拟器Emulation Options选项勾选 Use Host GPU 然后重启模拟器再尝试,如果还是这个错误,那么我们只好用真机测试了. 2.

web前端开发笔记(2)

web前端开发笔记(1) 一.HTML标签书写有哪些规范? 页面编码. 文档声明. 关键字与描述. 行内元素不能包含块级元素. a标签不能嵌套a标签. 标签名和属性必须用小写字母书写,属性必须加引号,标签必须闭合,单标签页必须闭合. 页面中不要用 进行缩进,如需缩进,用css控制. html标签使用必须语义化. 要为img标签填写alt和title属性. 二.HTML静态页面出现中文乱码如何解决? 引入<meta charset="UTF-8"> 三.通常情况下块属性标签和

PHP微信公众开发笔记(二)

PHP微信公众开发笔记系列 日期:2014.9.1 需求分析: 在成功的开启了微信开发者服务之后,我们便需要开始做响应用户操作的功能了.其实做微信公众平台,当初的目的我就是想做成一个服务平台,因为刚大学毕业,同学各奔东西.有的时候可能我们会到一个陌生的城市去,那时可能就会想啊,这个城市有班上的同学在么?这时掏出手机,点开服务号输入这个城市名,就会返回一串信息,假如有同学在这个城市,就会列出联系信息之类的.当然也许会说,既然是熟悉的同学,那么肯定会知道联系方式之类的,还需要这样多此一举么.而我的考

PHP微信公众开发笔记(五)

PHP微信公众开发笔记系列 日期:2014.9.3 今天做了身份验证的功能,然后完善了下搜索功能.其实主要的是将整个代码结构整理了一番,应该可以说是模块化设计吧. 模块化设计我们的公众号. 因为我们之前提的功能需求中有: 1.菜单--查询功能.我考虑到后期功能的扩展,就想将这些分模块来实现:菜单模块(这样,今后我们需要添加新的菜单功能,可以直接在这个模块里操作,这样修正和维护也简单,在考虑到后期可能会分工协作的时候各开发者之间不会产生冲突): 2.数据库模块(这里就主要是负责数据库相关的工作,如

Linux 驱动开发笔记(一)

1.查看printk函数日记输出 (1)使用字符终端:通常使用ctrl+alt+f1切换查看: (2)使用cat /proc/kmsg命令:(在Linux系统启动后,/proc/kmsg文件可以查看内核对外所用的符号表,可以用cat命令查看器内容.) (3)使用dmesg命令查看. linux/kernel.h文件定义的printk函数的Log Level: 常数定义语句 意义 #define KERN_EMERG "<0>"/*系统不运行*/ #define KERN_A

Linux及Arm-Linux程序开发笔记(零基础入门篇)

Linux及Arm-Linux程序开发笔记(零基础入门篇)  作者:一点一滴的Beer http://beer.cnblogs.com/ 本文地址:http://www.cnblogs.com/beer/archive/2011/05/05/2037449.html 目录 一.Arm-Linux程序开发平台简要介绍... 3 1.1程序开发所需系统及开发语言... 3 1.2系统平台搭建方式... 4 二.Linux开发平台搭建... 5 2.1安装虚拟工作站... 5 2.2安装Linux虚拟

python运维开发笔记4

1.函数如何被调用,通过return返回值来调用 2.生成器和return区别 yield 生成器返回对象,可以迭代 可以执行 glob模块 类似shell中的正则匹配 shlex模块  Popen 将命令参数直接分词 cmd = "ps ax -o pid,ppid,cmd" shlex.split(cmd) ['ps','ax','-o','pid,ppid,cmd'] ['mysql','-u','root','-p123','-e','show processlist'] p

PHP移动互联网开发笔记(6)——MySQL数据库基础回顾

最近看了一些架构方面的资料,但是发现基础知识都不怎么牢固,接下来的一段时间,我会定期总结基础知识. 一.数据类型 1.整型 数据类型 存储空间 说明 取值范围 TINYINT 1字节 非常小的整数 带符号值:-128~127 无符号值:0~255 SMALLINT 2字节 较小的整数 带符号值:-32768~32767 无符号值:0~65535 MEDIUMNT 3字节 中等大小的整数 带符号值:-8388608~8388607 无符号值:0~16777215 INT 4字节 标准整数 带符号值