⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vc.h

📁 《编译方法》课程设计内容2.《编译方法》课程设计内容
💻 H
字号:
/******************************************************************************
******************************************************************************* 
 
                                     vc.h 

			            头文件
			     
   本头文件定义了VSL编译器所使用的重要数据结构和常数

   文件修改时间
   ============

   2005年5月6日:  Turbo C 版 (C) hfwang
  
*******************************************************************************
******************************************************************************/

/* 定义常数 */

#define TRUE        1			 
#define FALSE       0			 /* 布尔常数 */
#define EOS         0			 /* 字符串结束标志 */
#define HASHSIZE  997			 /* 符号(HASH)表大小 */
#define R_UNDEF    -1		 	 /* 无效寄存器标志 */

/* 定义VSL的数据类型, 注意: 由于函数在VSL中可以先使用后定义, 而VSL的语法分析将
   函数当变量统一处理. 从而在词法分析时可能出现不知类型的变量进符号表. 因此, 在
   处理这样的变量时使用T_UNDEF. */

#define  T_UNDEF  	0			 /* 未知类型 */
#define  T_VAR  	1			 /* 局部变量 */
#define  T_FUNC   	2			 /* 函数 */
#define  T_TEXT   	3			 /* 字符串常量 */
#define  T_INT    	4			 /* 整数常量 */
#define  T_LABEL  	5			 /* 三地址码标号 */


/* 定义三地址指令编码, 共有12个运算符, 为了方便程序处理,增加一个未定义运算
   TAC_UNDEF. */

#define  TAC_UNDEF    0		 	 /* 未定义运算 */
#define  TAC_ADD      1			 /* a := b + c */
#define  TAC_SUB      2			 /* a := b - c */
#define  TAC_MUL      3			 /* a := b * c */
#define  TAC_DIV      4			 /* a := b / c */
#define  TAC_NEG      5			 /* a := -b */
#define  TAC_COPY     6			 /* a := b */
#define  TAC_GOTO     7			 /* goto a */
#define  TAC_IFZ      8			 /* ifz b goto a */
#define  TAC_IFNZ     9			 /* ifnz b goto a */
#define  TAC_ARG     10			 /* arg a */
#define  TAC_CALL    11			 /* a := call b */
#define  TAC_RETURN  12			 /* return a */

/* 此外, 为了方便代码生成时对内存空间、代码标号和函数的处理, 我们另外增加一些
   “伪指令”(这样的指令不出现在目标代码中). TACLABEL用于标记下一条语句,供
   转向语句之用,TACLABEL的第一个参数是符号表中的一个类型为T_LABEL的变量,该
   变量名是唯一的。TAC_VAR将定义一个局部变量,在代码生成时,该语句将对所定义的
   变量分配一个在动态栈上的存储空间。TAC_BEGINFUNC和TAC_ENDFUNC标记函数的开始
   和结束 */

#define  TAC_LABEL       13		 /* 产生一个标号 */
#define  TAC_VAR         14		 /* 产生一个变量 */
#define  TAC_BEGINFUNC   15		 /* 函数开始标记 */
#define  TAC_ENDFUNC     16		 /* 函数结束标记 */

/* 库函数将由外部文件提供,VSL提供两个库函数,即打印数值PRINTN和打印字符串
   PRINTS,在此我们用一个数组记录外部函数的入口点,数组第0号元素记录PRINTN,第
   1号元素记录PRINTS,数组的长度为2。 

   此外,假定库函数文件“lib”和汇编语言的头文件“header”和编译器在相同的工作
   目录,当然,为了更方便,我们可用#define设定库文件目录 */

#define  LIB_PRINTN     0		
#define  LIB_PRINTS     1
#define  LIB_MAX        2

#define  LIB_DIR  ""  

/* 设定库文件目录,当前值为空串,表示和编译器的目录相同,你也可将之设置为一个别
   的目录,将lib和header文件拷贝到该目录下,如:#define LIB_DIR "D:\\lib\\",表
   示库文件在D:\LIB目录下,注意:LIB之后一定不能少\\。*/

/* 由于很多结构有复杂的共用体和子域,为了方便书写和阅读,在此,对常用的一些域名
   进行宏定义,如:符号表结构中有域val1,该域的数据类型是共用体,共用体的域有
   字符指针类型的text和整数类型的val,如果:#define VAL1 val1.val和#define 
   TEXT1 val1.text,设sp是指向符号表的指针, 则:sp->val1.val可用sp->VAL1代替,
   sp->val1,test可用sp->TEST1代替。 */ 
   
#define VAL1   val1.val			 /* 取val1的val */
#define TEXT1  val1.text		 /* 取val1的text */
#define VAL2   val2.val			 /* 取val2的val */
#define LABEL2 val2.label		 /* 取val1的label */
#define ADDR2  val2.val			 /* 取val1的val,但含义为地址偏移量 */
#define ETYPE  res->type		 /* 取表达式结果res的type */
#define EVAL1  res->val1.val             /* 取表达式结果res的值val */
#define VA     a.var			 /* 取三地址码中第一运算量a的值val */
#define LA     a.lab			 /* 取三地址码中第一运算量a的标号lab */
#define VB     b.var			 /* 取三地址码中第二运算量b的值val */
#define LB     b.lab			 /* 取三地址码中第二运算量b的标号lab */
#define VC     c.var			 /* 取三地址码中第三运算量c的值val */
#define LC     c.lab			 /* 取三地址码中第三运算量c的标号lab */

/* 以下是编译器的核心数据结构,符号表元素的数据类型SYMB是一个结构类型,有4个域:
   next指向符号表元素的指针,type为该节点的类型,val1是一共用体,对常整数取
   其值val,对变量取其形text, val2也是一样,在表示内存偏移量等时取整数val,在
   表示三地址码标号时,取指向三地址码结构的指针label。指针next将不再使用的符号
   表元素链结在一起,再次申请符号元素的内存单元时,直接从该链表中提取,从而避免
   了对内存的频繁申请。

   为了简化编译处理,整个VSL程序共享一个符号表,与此同时,我们将常数,标号、函
   数和临时变量一并放入符号表统一处理,这样大大地简化了三地址码的数据结构 */
   
typedef struct symb			 /* 符号表节点的数据结构 */
{
	struct symb *next ;		 /* 下一个节点 */
	int          type ;		 /* 符号的数据类型 */
	union				 /* 变量的第一个值 */
	{
		int         val ;	 /* 对整数常数取其值 */
		char       *text ;	 /* 对变量取其形,为字符指针 */
	} val1 ;
	union				 /* 变量的第一个值 */
	{
		int         val ;	 /* 对变量取偏移量等 */
		struct tac *label ;	 /* 对标号取三地址码指针 */
	} val2 ;
} SYMB ;

/* 三地址码结构TAC是一个有4个域的双向链表,next指针指向下一个三地址码,prev指针
   指向前一个三地址码,该指针供在代码生成处理时,返回第一个三地址码之用。域op
   是操作码,域a是第一操作数,域b和c分别是第二和第三操作数,其数据类型均为共用体,
   其成员或者是符号表指针var,或者是TAC指针。这4个域记录如下形式的三地址指令:

     a := b op c  */

typedef struct tac			 /* 三地址码双向链表的节点的数据类型 */
{
	struct tac  *next ;		 /* 向前指针 */
	struct tac  *prev ;		 /* 向后指针 */
	int          op ;		 /* 操作码 */
	union				 /* 第一操作数 */
	{
		SYMB        *var ;	 /* 变量名 */
		struct tac  *lab ;	 /* 三地址 */
	} a ;
	union		 		 /* 第二操作数 */
	{
		SYMB        *var ;
		struct tac  *lab ;
	} b ;
	union				 /* 第三操作数 */
	{
		SYMB        *var ;
		struct tac  *lab ;
	} c ;
} TAC ;

/* 在语法处理时,对表达式的翻译,我们不仅需要将表达式翻译成三地址码,还需要记录
   中间临时变量的内存地址,为此,增加一个结构ENODE, 记录临时变量,此外,为了处
   理函数调用时参数列表,我们在ENODE中增加一个域next,使得中间临时变量形成一个单
   向链表。 */

typedef struct enode			 /* 表达式链表 */
{
	struct enode *next ;		 /* 链表指针 */
	TAC          *tac ;		 /* 表达式的三地址指令 */
	SYMB         *res ;		 /* 临时变量在符号表的指针 */
} ENODE ;

/* 以下是编译器所需的全局变量, 它们在main.c模块中定义,在其他的模块中引用。符号表
   symbtab是一个哈西表,其元素的数据类型是指向符号单向链表的节点的指针。library
   是一个数组,其元素是三地址码指针,该指针指向库函数的三地址码链表的头节点。

   在翻译表达式时产生的中间临时变量,我们按正常的变量等同处理,对每个临时变量,
   用“Tnnn”的形式表示,其中nnn是区别其他临时变量的唯一的整数,我们用next_tmp
   表示该整数,每次产生临时变量时,该整数自动加1,同样,用“Lnnn”处理标号,并
   用next_label作为标号的计数器 */

extern SYMB *symbtab[HASHSIZE] ;	 /* 符号表 */
extern TAC  *library[LIB_MAX] ;		 /* 函数库数组 */
extern int   next_tmp ;			 /* 临时变量计数器 */
extern int   next_label ;		 /* 标号计数器 */

/* 以下是编译器的全局函数,其函数定义大部份在main.c模块,通过下面的引用说明这
   些函数在其他模块中使用 */

extern SYMB  *mkconst( int  n ) ;	 /* 在main.c中定义 */
extern SYMB  *mklabel( int  l ) ;
extern SYMB  *mktmp( void ) ;
extern TAC   *mktac( int   op,
		     SYMB *a,
		     SYMB *b,
		     SYMB *c ) ;
extern TAC   *join_tac( TAC *c1,
		        TAC *c2 ) ;
extern void   insert( SYMB *s ) ;
extern SYMB  *lookup( char *s ) ;
extern SYMB  *get_symb( void ) ;
extern void   free_symb( SYMB *s ) ;
extern ENODE *get_enode( void ) ;
extern void   free_enode( ENODE *expr ) ;
extern void  *safe_malloc( int  n ) ;
extern void   error( char *str ) ;
extern void   print_instr( TAC *i ) ;

extern void   cg( TAC *tl ) ;	 	 /* 在cg.c中定义 */

/* extern void  *malloc( int  size ) ;*/	 /* External routines */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -