第一章 概述
1.1 设计内容:
题目 第19题
对文法 G: E→E+T|T
T→T*F|F
F→(E)|i
采用教材P.98表5.3
| + | * | ( | ) | i | # |
+ | > | < | < | > | < | > |
* | > | > | < | > | < | > |
( | < | < | < | = | < | e1 |
) | > | > | e2 | > | e2 | > |
i | > | > | e2 | > | e2 | > |
# | < | < | < | e3 | < | e1 |
实现P.93描述的算符优先分析算法。
。
1.2设计要求
程序显示输出“移进-归约”的步骤要编制各出错处理子程序
第二章 设计的基本原理
算符优先优先分析算法:
k:=1; S[k]:=’#’;
REPEAT
把下一个输入符号读进a中;
IF S[k]是终结符 then j:=k else j:=k-1;
WHILE S[j]>a DO
BEGIN
REPEAT
Q:=S[j];
IF S[j-1]属于终结符 then j:=j-1; else j:=j-2;
UNTIL S[j]<Q;
把S[j+1]…..S[k]归约为某个N;
k:=j+1;
S[k]:=N;
END OF WHILE;
IF S[j] <a OR S[j]=a then
BEGIN k:=k+1;S[k]:=a END
ELSE ERROR
UNTIL a=’#’;
出错处理子程序:
1.如果+或*被归约,则检查其两端是否出现非终结符.否则打印错:”却表达式”
2.如i被归约,则检查其左端或右端是否有非终结符.如果有,则给出信息:”
达式间无运算符联接”.
3.如果()被规约,则检查是否在括号内有一非终结符.如果没有,则给出信息:”括号间无表达式”.
对应的如下
e1 当表达式以(结尾时,调用此程序
将(从栈顶移去 给出出错信息:非法左括号.
e2 当i或)后跟i或(时,调用此程序
在输入端插入+ 给出错误信息:缺少运算符
e3 当表达式以(开始时,调用此程序 从输入端删除)
给出错误信息:非法左括号.
e4 (1)若栈顶有非终结符E,则表达式分析完毕.
(2) 若为空,则在输入端插入i
给出错误信息:缺少表达式
第三章 程序设计
1总体方案设计
输入表达式→算符分析→选择是移进还是归约(同时判断是否有错,调用相应的出错处理子程序)→完成(表达式的分析成功与失败)
2 各模块设计
首先是优先关系表的存储以及终结符的表示:
char functor[5]={'+','*','(',')','#'};
char table[6][6]={
// + * ( ) i # // 程序涉及到的算符
{'>','<','<','>','<','>'},
{'>','>','<','>','<','>'},
{'<','<','<','=','<','1'},
{'>','>','2','>','2','>'},
{'>','>','2','>','2','>'},
{'<','<','<','3','<','4'},
};
char VTchar[6]={'+','*','(',')','i','#'}; //终结符数组
//存储产生式:E→E+T|T, T→T*F|F , F→(E)|i;
char suanfu[5]={'+','*','(',')','#'};
char guiyuechar[5][3]={{'+','E','T'},{'*','T','F'},{'(',NULL,'E'},{')','E',NULL},{'#',NULL,'E'}};
char produce[2][2]= {{'E','+'},{'T','*'}};
归约栈的定义以及一些方法的定义
class stack
{
public:
stack(){top=0;sarray[0]='#';}
char poptop(){return array[top];}
void push(char a){top++;sarray[top]=a;}
CString sPrint(){
CString change;
for(int i=0;i<=top;i++)
change+=sarray[i];
return change;
}
char gets(int i){return sarray[i];}
int point(){return top;}
void puts(int i,char a){ sarray[i]=a;}
void changetop(int i){ top=i;}
private:
char sarray[100];
int top;
};
终结符的判断函数
bool judgeSuanfu(char b)
{
for(int i=0;i<5;i++)
if(functor[i]==b)
return true;
return false;
}
bool judgeVT(char a)//判断输入符号a是不是终结符
{
for(int i=0;i<6;i++)
if(VTchar[i]==a)
return true;
return false;
}
优先级的判断
char precedence(char a,char b)
{//判断优先级
int i=0;
for(;i<6;i++)
if(VTchar[i]==a)
break;
int j=0;
for(;j<6;j++)
if(VTchar[j]==b)
break;
return table[i][j];
}
进入实现模块
char Q;
int hang=0;
int count=1;
stack s;
int k=0;
//s.sPrint();
UpdateData(true);
m_list.InsertItem(hang,s.sPrint());
m_list.SetItemText(hang,1,m_input);
m_list.SetItemText(hang,2,"...........");
hang++;
CString expression=m_input;
CString viewexpression;
CString chanshengshi;
char a;
char b;
int exadr=0;
do{
a=expression[exadr];
int j;
if(judgeVT(s.gets(k)))
j=k;
else j=k-1;
if(precedence(s.gets(j),a)=='>')
{
while(precedence(s.gets(j),a)=='>'||precedence(s.gets(j),Q)=='=')
{
do{
Q=s.gets(j);
if(judgeVT(s.gets(j-1)))
j--;
else j=j-2;
}while (precedence(s.gets(j),Q)=='>');
if(s.gets(j+1)=='i')
{
s.puts(j+1,'F');
chanshengshi="F→i";
}
else if(precedence(s.gets(j),Q)=='=')
{
s.puts(j,'F');
chanshengshi="F→(E)";
if(a=='#')
{k=j;j--;}
else k=j;
s.changetop(k);
}
else
{
if(Q=='+')
{
s.puts(j+1,'E');
k=j+1;s.changetop(k);
chanshengshi="E→E+T";
}
if(Q=='*')
{
s.puts(j+1,'T');
k=j+1;s.changetop(k);
chanshengshi="T→T*F"; }
}
m_list.InsertItem(hang,s.sPrint());
m_list.SetItemText(hang,1,viewexpression);
m_list.SetItemText(hang,2,chanshengshi);
hang++;
}
}
else
if(precedence(s.gets(j),a)=='<'||precedence(s.gets(j),a)=='=')
{
k++; exadr++;
viewexpression=expression;
viewexpression.Delete(0,count);
count++;
s.push(a);
m_list.InsertItem(hang,s.sPrint());
m_list.SetItemText(hang,1,viewexpression);
m_list.SetItemText(hang,2,"移进");
hang++;
}
else {
switch(precedence(s.gets(j),a))
{
case '1':///当表达式以左括号结尾时,将'('从栈顶移出 给出错误信息:非法左括号
{
int change=s.point();
change--;
s.changetop(change);
MessageBox( "非法左括号:'(' 默认删除 '(' ", MB_OK );
expression.Delete(exadr,1);
if(judgeSuanfu(s.poptop()))
{
int xxx=s.point();
xxx--;
s.changetop(xxx);
}
m_list.InsertItem(hang,s.sPrint());
m_list.SetItemText(hang,1,viewexpression);
m_list.SetItemText(hang,2,"删除");
hang++;
break;
}
case '2':
{
//if(expression[exadr+1]=='i')
{
// 当i或(后跟i或)时 在输入端插入'+' 给出错误信息:缺少运算符/
expression.Insert(exadr,"+");
MessageBox( "缺少运算符 默认在此之后
加上算符+", MB_OK );
}
break;
}
case '3':{
// 当表达式以右括号开始,调用此程序 从输入端删除')' 给出错信息:非法右括号/
MessageBox( "从输入端删除')'", MB_OK );
expression.Delete(0,1);
break;
}
case '4':{
// 1 若栈顶有非终结符E时,则表达式分析结束 2 若为空则在输入端插入i
if(s.poptop()=='E') a='#';
if(s.poptop()=='#') expression.Insert(exadr,"i");
{
s.puts(j+1,'F');
s.changetop(j+1);
chanshengshi="F→i";
m_list.InsertItem(hang,s.sPrint());
m_list.SetItemText(hang,1,viewexpression);
m_list.SetItemText(hang,2,chanshengshi);
hang++;
}
break;
}
}
/出错处理子程序调入
}
}while(a!='#');
第四章 程序测试
1.程序测试:
2.出错处理的测试:
第五章 结论
参考文献
程序设计语言编译原理(第3版)陈火旺
编译原理及编译程序构造 秦振松