编译原理的大作业――关于TINY+的编译器

2014-11-24 03:09:10 · 作者: · 浏览: 1

(1)词法分析器的构造

工作流程:

1)首先跳过所有空白字符和注释,直到出现一个不是空白字符且不属于注释的字符,记为ch;


2)如果ch
=非法字符,则报错,转步骤一
=数字,则进行整型常量分析
=英文字母,则进行标识符分析
=单引号,则进行字符串常量分析
=其他(特殊符号),则进行操作符分析

3)返回分析结果(Kind,Value)值。

(2)语法分析器的构造

实现TINY+语言的语法分析、语义分析、汇编代码生成。

具体流程分析:

所需要的数据结构定义(包括Token结构体,Sym结构体,用来存储符号的各种属性,TreeNode结构体用来定义语法树的节点):

#ifndef STRUCT
#define STRUCT
#pragma once  
#include 
  
   
using namespace std;
enum ObjType
{
	OT_FUN = 0,		// 函数
	OT_VAR,			// 变量
	OT_CONST,		// 常量
};

enum ValType
{
	VT_INT = 100,		// 整型数类型
	VT_BOOL,			// 布尔类型
	VT_STRING,	      // 字符串类型
};

enum NodeType
{
	PROGRAM = 200,		// 程序(开始符号)节点
	STMT_SEQUENCE,		// 语句列表节点
	IF_STMT,			// 条件语句节点
	REPEAT_STMT,		// repeat语句节点
	ASSIGN_STMT,		// 赋值语句节点
	READ_STMT,			// read语句节点
	WRITE_STMT,			// write语句节点
	WHILE_STMT,			// while语句节点
	GTR_EXP,			// 大于表达式节点
	GEQ_EXP,			// 大于等于表达式节点
	LSS_EXP,			// 小于表达式节点
	LEQ_EXP,			// 小于等于表达式节点
	EQU_EXP,            // 等于表达式节点
	LOG_OR_EXP,			// 逻辑或表达式节点
	LOG_AND_EXP,		// 逻辑与表达式节点
	LOG_NOT_EXP,		// 逻辑非表达式节点
	ADD_EXP,			// 加法表达式节点
	SUB_EXP,			// 减法表达式节点
	MUL_EXP,			// 乘法表达式节点
	DIV_EXP,			// 除法表达式节点
	FACTOR				// 原子节点			( )
};

enum kind_set
{
	TK_INT = 300,
	TK_BOOL,
	TK_STRING,
	TK_TRUE,
	TK_FALSE,
	TK_OR,
	TK_AND,
	TK_NOT,
	TK_WHILE,
	TK_DO,
	TK_IF,
	TK_THEN,
	TK_ELSE,
	TK_END,
	TK_REPEAT,
	TK_UNTIL,
	TK_READ,
	TK_WRITE,
	TK_ID,

	TK_GTR = 400,
	TK_LEQ,
	TK_GEQ,
	TK_COMMA,
	TK_SEMICOLON,
	TK_ASSIGN,
	TK_ADD,
	TK_SUB,
	TK_MUL,
	TK_DIV,
	TK_LP,
	TK_RP,
	TK_LSS,
	TK_EQU,
	NUM
};

typedef struct 
{
	int kind;		// 符号的Kind值,如TK_IF等
	int ival;		// 若符号是整型常量,则ival记录该常量的值
	string sval;		// 若符号是标识符或字符串常量,则sval记录标识符的名字或字符串
}Token;

typedef struct 
{
	Token tk;			// 符号(词法分析器的返回值)
	ObjType objtype;	// 符号对象类型
	ValType valtype;	// 值类型
	//int	addr;			// 地址
	//int	size;			// 字节数
	//int	level;			// 层次
}Sym;

typedef struct _TreeNode
{
	NodeType nodetype;		// 节点类型
	ValType valtype;		// 节点值类型
	_TreeNode *child[3];	// 子节点的指针

	Token tk;				// 当节点是FACTOR类型时该成员才有效
} TreeNode;

#endif
  


然后就是构造词法分析器来获得TOKEN,(词法分析器代码略去,代码有200多行)

定义符号表来存储标识符:

#pragma once  
#include "Struct.h"
#include
  
   
using namespace std;
/**
 * 符号表
 */
static int num=0;

class SymTable
{
public:
	Sym* insertSym(string name)
	{
		Sym *sym=new Sym();
		Token tk={NULL,NULL,name};
		sym->tk=tk;
		s[num]=sym;
		num++;
		return sym;
	}
	Sym* findSym(string name)
	{
		for(int j=0;j
   
    tk.sval) return s[j]; } return NULL; } void delSym(string name) { int temp; for(int j=0;j
    
     tk.sval) { temp=j; break; } } for(int j=temp;j
      
      


然后就是定义各种节点的分析函数(代码略去,理由同上);

最后就是中间代码的生成。

所遇到的问题:

(1)Token结构体中的sval最初是用char *来存储,问题截图如下:

\

执行完match之后sval的值就发生改变了。

问题原因:Token temp=_token,temp的sval域是char*的指针,temp = _token后,它与_token的sval的地址是一样的。这样调用match会通过getToken修改_token的值,所以temp的sval的内容也跟着改变了。

解决办法(1):strcpy(temp.sval,_token.sval),这样通过字符串复制就可以了!不过感觉修改的比较多,很冗余。

解决办法(2):将sval的char*类型转换成string类型,这样不用指针就可以的!代码也很简洁。

希望解决的问题:既然temp的sval域和_token的sval的地址是一样的,那么为什么修改_token的值后,两者的值为什么不一样?