📄 util.cpp
字号:
/****************************************************/
/* 文件 util.cpp */
/* 说明 类PASCAL语言编译器功能函数的实现 */
/* 主题 编译器结构:原理和实例 */
/****************************************************/
/* 头文件globals.h定义了全局类型与变量 */
#include "globals.h"
#include "stdio.h"
#include "string.h"
#include "symbTable.h"
#include "code.h"
#include "cgen.h"
int fp_num=0; /*输出时记录token个数的变量*/
/*****************************************************************/
/* 函数名 printTokenlist */
/* 功 能 将文件tokenlist中的信息作为返回值 */
/* 一般,listing指向标准输出。 */
/* 说 明 用于显示词法分析结果 */
/*****************************************************************/
void printTokenlist()
{
TokenType token;
int m;
fp=fopen("c:\\Tokenlist","rb"); /*打开文件*/
if(fp==NULL)
{
printf("can not open the file:Tokenlist!\n");
Error = TRUE;
//exit(0);
}
for (m=1;m<=Tokennum;m++)
{
fread(&token,TOKENLEN,1,fp);
fprintf(listing,"\t%d: ",token.lineshow);/*打印行号*/
/* 对函数参数Lex给定单词进行分类处理 */
switch (token.Lex)
{
/* 单词token为保留字,将保留字词元以指定格式写入列表文件listing */
case PROGRAM:
case PROCEDURE:
case TYPE:
case VAR:
case IF:
case THEN:
case ELSE:
case FI:
case INTEGER:
case CHAR:
case WHILE:
case DO:
case ENDWH:
case BEGIN:
case END:
case READ:
case WRITE:
case ARRAY:
case OF:
case RECORD:
case RETURN:
fprintf(listing, /*打印保留字*/
"reserved word: %s\n",token.Sem);
break;
/* 单词token为特殊符号:ASSIGN (赋值),将":="写入文件listing */
case ASSIGN: fprintf(listing,":=\n"); break;
/* 单词token为特殊符号:LT (小于),将"<"写入文件listing */
case LT: fprintf(listing,"<\n"); break;
/* 单词token为特殊符号:EQ (等于),将"="写入文件listing */
case EQ: fprintf(listing,"=\n"); break;
/* 单词token为特殊符号:LPAREN (左括号),将"("写入文件listing */
case LPAREN: fprintf(listing,"(\n"); break;
/* 单词token为特殊符号:RPAREN (右括号),将")"写入文件listing */
case RPAREN: fprintf(listing,")\n"); break;
/* 单词token为特殊符号:SEMI (分号),将";"写入文件listing */
case SEMI: fprintf(listing,";\n"); break;
/* 单词token为特殊符号:PLUS (加号),将"+"写入文件listing */
case PLUS: fprintf(listing,"+\n"); break;
/* 单词token为特殊符号;MINUS (减号),将"-"写入文件listing */
case MINUS: fprintf(listing,"-\n"); break;
/* 单词token为特殊符号:TIMES (乘号),将"*"写入文件listing */
case TIMES: fprintf(listing,"*\n"); break;
/* 单词token为特殊符号:OVER (除号),将"/"写入文件listing */
case OVER: fprintf(listing,"/\n"); break;
case DOT: fprintf(listing,".\n"); break;
case COMMA: fprintf(listing,",\n"); break;
case LMIDPAREN: fprintf(listing,"[\n"); break;
case RMIDPAREN: fprintf(listing,"]\n"); break;
case UNDERANGE: fprintf(listing,"..\n"); break;
/* 单词token为簿记单词符号:ENDFILE (文件结尾),将EOF写入文件listing */
case ENDFILE: fprintf(listing,"EOF\n"); break;
/* 单词token为多字符单词符号:NUM (数字),将数值写入文件listing */
case INTC:
fprintf(listing,
"NUM, val= %s\n",token.Sem);
break;
case CHARC:
fprintf(listing,
"INCHAR, char=%c\n",token.Sem);
break;
/* 单词token为多字符单词符号:ID (标识符),将标识符名写入文件listing */
case ID:
fprintf(listing,
"ID, name= %s\n",token.Sem);
break;
/* 单词token为簿记单词符号:ERROR (错误),将错误信息写入文件listing */
case ERROR:
fprintf(listing,
"ERROR: %s\n",token.Sem);
break;
/* 单词token为其他未知单词,未知信息写入文件listing,此种情况不应发生 */
default:
fprintf(listing,"Unknown token: %d\n",token.Lex);
break;
}
fseek(fp,m*TOKENLEN,0);
}
fprintf(listing,"\n");
fclose(fp);
}
/*****************************************************************/
/* 函数名 ReadNextToken */
/* 功 能 将文件tokenlist中的信息作为返回值 */
/* 一般,listing指向标准输出。 */
/* 说 明 返回值为TokenType类型,用于语法分析中 */
/*****************************************************************/
void ReadNextToken(TokenType *p)
{
FILE *fp2;
/*按只读方式打开文件*/
fp2=fopen("c:\\Tokenlist","rb");
if (fp==NULL)
{
printf("cannot create file Tokenlist!\n");
Error = TRUE;
//exit(0);
}
fseek(fp2,fp_num*sizeof(TokenType),0);
fread(p,sizeof(TokenType),1,fp2);
fp_num++;
fclose(fp2);
}
/********************************************************/
/* 函数名 copyString */
/* 功 能 字符串复制函数 */
/* 说 明 该函数为已存在的字串分配内存单元,并将其复制 */
/********************************************************/
char * copyString(char * s)
{ int n;
char * t;
/* 函数参数s所给字串为NULL(空), 函数返回NULL */
if (s==NULL) return NULL;
/* 函数参数s所给字串非空,计算字串s长度+1赋给临时变量n */
n = strlen(s)+1;
/* 动态分配内存单元,指定单元长度为n,t为指向该单元的指针 */
t = (char *)malloc(n);
/* 单元指针t为NULL(空),未能成功分配 *
* 将出错信息及行号lineno写入列表文件listing */
if (t==NULL)
{
fprintf(listing,"Out of memory error at line %d\n",lineno);
Error = TRUE;
}
/* 调用库函数string.h,复制给定字串s到新字串单元t */
else strcpy(t,s);
/* 函数返回复制得到的新字串指针t */
return t;
}
/*****************************************************************/
/* 函数名 ChainToFile */
/* 功 能 将链表中的Token结点依次存入文件中 */
/* 说 明 参数p是指针变量,指向Token链表的表头 */
/*****************************************************************/
void ChainToFile (ChainNodeType *Chainhead)
{
int num=1;
ChainNodeType *currentP=Chainhead;
/*创建一个新的文件"Tokenlist",以存储Token序列*/
fp=fopen("c:\\Tokenlist","wb+");
if (fp==NULL)
{ printf("cannot create file Tokenlist!\n");
Error = TRUE;
//exit(0);
}
fp=fopen("c:\\Tokenlist","ab"); /*按追加方式打开文件*/
if (fp==NULL)
{ printf("cannot open file Tokenlist!\n");
Error = TRUE;
//exit(0);
}
/*从表头到表尾,依次将所有的Token写入文件*/
do
{ fwrite(currentP,TOKENLEN,1,fp);
currentP=currentP->nextToken;
num++;
}
while (currentP!=NULL);
fclose(fp); /*关闭文件*/
}
/********************************************************
*********以下是LL1语法分析方法所用到的栈操作************
********************************************************/
/*用链表实现栈操作,栈中存放的是终极符和非终极符,上面的两个枚举
类型*/
void Push(int i,int j)
{ StackNode *p;
p=(StackNode *)malloc(sizeof(StackNode));
if (i==1)
(*p).var.Ntmlvar=(NontmlType)j;
else if (i==2)
(*p).var.tmlvar=(TmlType)j;
p->flag=i;
p->underNode=StackTop;
StackTop=p;
STACKEMPTY=false;
}
void Pop()
{ StackNode *p;
p=StackTop;
StackTop=(*StackTop).underNode;
free(p);
if (StackTop==NULL)
STACKEMPTY=true;
}
/*读栈顶标志,看是终极符还是非终极符*/
int readStackflag()
{ int j;
j=StackTop->flag ;
return(j);
}
/*非终极符时*/
NontmlType readstackN()
{
return ((*StackTop).var.Ntmlvar);
}
/*终极符*/
TmlType readstackT()
{
return ((*StackTop).var.tmlvar);
}
/*压栈的实现过程,压入的是指向树节点的指针的地址*/
void PushPA(TreeNode **t)
{
StackNodePA *p=NULL;
p=(StackNodePA *)malloc (sizeof(StackNodePA));
p->pointer= t ;
p->underNode =StackTopPA;
StackTopPA=p;
paSTACKEMPTY=false;
}
/*弹栈的实现过程*/
TreeNode ** PopPA()
{
StackNodePA *p=NULL;
TreeNode **backpointer;
p = StackTopPA;
backpointer=p ->pointer;
StackTopPA=StackTopPA->underNode;
free(p);
if (StackTopPA==NULL)
paSTACKEMPTY=true;
return backpointer;
}
/*操作符栈的压栈实现过程,压入的是指向树节点的指针*/
void PushOp(TreeNode *t)
{
StackNodeP *p=NULL;
p=(StackNodeP *)malloc (sizeof(StackNodeP));
p->pointer= t ;
p->underNode =OpStackTop;
OpStackTop=p;
OpSTACKEMPTY=FALSE;
}
/*操作符栈的弹栈实现过程*/
TreeNode * PopOp()
{
StackNodeP *p=NULL;
TreeNode *backpointer;
p=OpStackTop;
backpointer=p->pointer;
OpStackTop=OpStackTop->underNode;
free(p);
if (OpStackTop==NULL)
OpSTACKEMPTY= TRUE;
return backpointer;
}
LexType ReadOpStack()
{
TreeNode *t1;
t1=OpStackTop->pointer;
return (t1->attr.ExpAttr.op);
}
/*操作数栈的压栈实现过程,压入的是指向树节点的指针*/
void PushNum(TreeNode *t)
{
StackNodeP *p=NULL;
p =(StackNodeP *)malloc (sizeof(StackNodeP));
p->pointer= t ;
p->underNode =NumStackTop;
NumStackTop=p;
NumSTACKEMPTY=false;
}
/*操作数栈的弹栈实现过程*/
TreeNode * PopNum()
{
StackNodeP *p=NULL;
TreeNode *backpointer;
p =NumStackTop;
backpointer=p->pointer;
NumStackTop=NumStackTop->underNode;
free(p);
if (NumStackTop==NULL)
NumSTACKEMPTY=true;
return backpointer;
}
/********************************************************
*********以下是创建语法树所用的各类节点的申请***********
********************************************************/
/********************************************************/
/* 函数名 newRootNode */
/* 功 能 创建语法树根节点函数 */
/* 说 明 该函数为语法树创建一个新的根结点 */
/* 并将语法树节点成员初始化 */
/********************************************************/
TreeNode * newRootNode(void)
{
/* 在内存中动态申请分配单元,返回指向该单元的语法树结点类型指针t */
TreeNode * t = (TreeNode *) malloc(sizeof(TreeNode));
int i;
/* 语法树节点指针t为NULL,未能成功分配内存单元 *
* 将出错信息及行号lineno写入列表文件listing */
if (t==NULL)
{
fprintf(listing,"Out of memory error at line %d\n",lineno);
Error = TRUE;
}
/* 语法树节点指针t不是NULL,成功分配内存单元 */
else {
/* 初始化新语法树节点t各子节点child[i]为NULL */
for (i=0;i<MAXCHILDREN;i++) t->child[i] = NULL;
/* 初始化新语法树节点t兄弟节点sibling为NULL */
t->sibling = NULL;
/* 指定新语法树节点t成员:结点类型nodekind为语句类型ProK */
t->nodekind = ProK;
/* 指定新语法树节点t成员:源代码行号lineno为全局变量lineno */
t->lineno = lineno;
for(i=0;i<10;i++)
{
strcpy(t->name[i],"\0");
t->table[i] = NULL;
}
}
/* 函数返回语法树根节点指针t */
return t;
}
/********************************************************/
/* 函数名 newPheadNode */
/* 功 能 创建程序头类型语法树节点函数 */
/* 说 明 该函数为语法树创建一个新的程序头类型结点 */
/* 并将语法树节点成员初始化 */
/********************************************************/
TreeNode * newPheadNode(void)
{
/* 在内存中动态申请分配单元,返回指向该单元的语法树结点类型指针t */
TreeNode * t = (TreeNode *) malloc(sizeof(TreeNode));
int i;
/* 语法树节点指针t为NULL,未能成功分配内存单元 *
* 将出错信息及行号lineno写入列表文件listing */
if (t==NULL)
{
fprintf(listing,"Out of memory error at line %d\n",lineno);
Error = TRUE;
}
/* 语法树节点指针t不是NULL,成功分配内存单元 */
else {
/* 初始化新语法树节点t各子节点child[i]为NULL */
for (i=0;i<MAXCHILDREN;i++) t->child[i] = NULL;
/* 初始化新语法树节点t兄弟节点sibling为NULL */
t->sibling = NULL;
/* 指定新语法树节点t成员:结点类型nodekind为语句类型PheadK */
t->nodekind = PheadK;
/* 指定新语法树节点t成员:源代码行号lineno为全局变量lineno */
t->lineno = lineno;
t->idnum = 0;
for(i=0;i<10;i++)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -