自己动手写编译器:符号表及其实现

本节我们要完成一个任务,给定如下一段代码:

{int x; char y; {bool y; x; y;} x; y;}

解析上面代码后输出结果为:

{
  {x:int; y:bool} x:int; y:char}

大家如果对c, c++, java有所了解,那么就会知道作用域这个概念。所谓作用域就是变量在一个范围内起作用,一旦出了既定范围,那么它就会失效。c,c++,java用{表示作用域的起始,用}表示作用域的结束。内层作用域的变量会覆盖上一层作用域的变量。例如在上面代码中最外层定义了两个变量,分别是int类型的x,和char类型的y,在内层作用域又定义了一个bool类型的同名变量y,它会覆盖外出的char类型y,在内层作用域访问y时,我们访问的是类型为bool的y,但由于内层作用域没有定义x,因此访问x时,它对应外层作用域的x,因此我们的任务是识别作用域,同时解析出变量在不同作用域中对应的类型。

在编译原理中,使用一种叫符号表的特殊结构来记录变量的信息,例如变量的类型,名称,在内存中的地址等。在使用IDE开发代码时,我们调试时,将鼠标挪到某个变量名称上,IDE就会显示出变量的值等信息,这些信息就得依靠符号表来存储,没有符号表就不能实现断点或是单步调试。

在代码解析过程中,一旦发现有变量定义出现时,编译器就跟构造一条符号记录,然后将其插入到符号表。当编译器发现代码进入新的作用域时,它会创建一个新的符号表用于记录新作用域下的变量信息,于是每个作用域都会对应一个符号表,在该作用域下变量的相关信息就从对应符号表查询。内部作用域对应的符号表会有一个指针指向它上一层作用域的符号表,在解析内部作用域的变量时,如果发现某个变量没有出现在其符号表中,那么就顺着指针在上一层符号表查找,如果还是查找不到那么继续往上查找,如果到达最外层作用域,其符号表还是没有对应变量,那么就产生了语法错误,也就是代码使用了未声明的变量,其基本逻辑如下图所示:
请添加图片描述

从上图看到,前面代码中最内层的作用域访问了变量x,但是x并没有在当前作用域里定义,于是编译器从当前作用域对应的符号表指针出发,找到上一层作用域的符号表,在那里查询到了x的定义,因此在内存作用域中使用的x,对应为外层作用域定义的x。理论说的太多容易糊涂,我们看看具体的代码实现,在Parser目录下新增symbol.go,添加如下代码:

package parser

type Symbol struct {
	VariableName string 
	Type   string 
}

func NewSymbol (name , var_type string) *Symbol {
	return &Symbol {
		VariableName: name, 
		Type:  var_type,
	}
}

这里定义的Symbol对象比较简单,它只记录了当前变量名称和类型&#x

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值