实验四. 语义分析及中间代码生成
1. 实验目的
(1) 通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析 所识别的语法范畴变换为某种中间代码的语义翻译方法。
(2) 掌握目前普遍采用的语义分析方法──语法制导翻译技术。
(3) 给出 PL/0 文法规范,要求在语法分析程序中添加语义处理,对于语 法正确的表达式,输出其中间代码;对于语法正确的算术表达式, 输出其计算值。
2. 实验准备
微机安装好 C 语言,或 C++,或 Visual C++,或自己需要用的语言.
3. 实验内容
已给 PL/0 语言文法,在实验二或实验三的表达式语法分析程序里,添 加语义处理部分,输出表达式的中间代码,用四元式序列表示。
4. 实验要求
(1) 语义分析对象重点考虑经过语法分析后已是正确的语法范畴,本实 验重点是语义子程序。
(2) 在实验二或实验三“语法分析器”的里面添加 PL/0 语言“表达式” 部分的语义处理,输出表达式的中间代码,计算表达式的语义值。
(3) 中间代码用四元式序列表示。
5. 设计思想
(1)递归下降分析方法
当一个文法满足LL(1)条件时,就可以为它构造一个不带回溯的自上而下分析程序,这个程序是由一组递归程序组成的,每个过程对应文法的一个非终结符。
(2)语义分析:对于因子,如果在识别为无符号整数是需要强制类型转换将string转换为int,并赋值arg(若是字母直接赋值给arg);对于项,遇到因子则赋值arg,将乘法/除法运算符赋值给op,若为算数表达式,则需要newtemp(),计算出相应的值,否则输出四元式;对于表达式,遇到项则赋值arg,将加法/减法运算符赋值给op,若为算数表达式,则需要newtemp(),计算出相应的值,否则输出四元式。
(3)G(<表达式>):
<表达式> ::= [+|-]<项>{<加法运算符> <项>}
<项> ::= <因子>{<乘法运算符> <因子>}
<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
<加法运算符> ::= +|-
<乘法运算符> ::= |/
<关系运算符> ::= =|#|<|<=|>|>=
常见的文法表示方式:
G(E):
E-> +TK|-TK|TK
K-> AT|ε
T-> FN
N-> MF|ε
A -> +|-
M -> |/
R -> =|#|<|<=|>|>=
D -> 0|1|2|3|4|5|6|7|8|9
Z -> a|b|c|d|e|f|…|x|y|z
T -> DT|D
F -> Z|ZF|FD
a.此文法无公共左因子,也无需消除左递归
b.FIRST集合:
FIRST(<表达式>)={+,-,<标识符>,<无符号整数>,(}
FIRST(<项>)={<标识符>,<无符号整数>,(}
FIRST(<因子>)={<标识符>,<无符号整数>,(}
FIRST(<加法运算符>)={+,-}
FIRST(<乘法运算符>)={,/}
FIRST(<关系运算符>)={=,#,<,<=,>,>=}
c.FOLLOW集合:
FOLLOW(<表达式>)={#,)}
FOLLOW(<项>)={+,-,#,)}
FOLLOW(<因子>)={,/,+,-,#,)}
FOLLOW(<加法运算符>)={<标识符>,<无符号整数>,(}
FOLLOW(<乘法运算符>)={<标识符>,<无符号整数>,(}
FOLLOW(<关系运算符>)={}
由非终结符分项的FIRST集两两不相交,且一个非终结符的FIRST集和FOLLOW集不相交,所以此文法为LL(1)文法,可以用递归下降分析法。
(4)子程序算法:(本算法没有细致的划分标识符和无符号整数,直接用上一次实验的词法分析所得结果提取单词编码进行输出判断)
PROCEDURE <表达式>:
BEGIN
IF SYM=’+’ OR SYM=’-’ THEN
BEGIN
ADVANCE;
ARG=<项>;
WHINE OP=<加法运算符> DO
BEGIN
ADVANCE;
ARG=<项>;
NEWTEMP();
END
END
ELSE ERROR
END
PROCEDURE <项>:
BEGIN
ARG=<因子>
WHINE op=<乘法运算符> DO
BEGIN
ADVANCE;
ARG=<因子>;
END
END
PROCEDURE <因子>:
BEGIN
IF SYM=‘标识符’ OR ARG=‘无符号整数’
BEGIN
ADVANCE;
END
ELSE IF SYM=’(’
BEGIN
ADVANCE;
<表达式>
IF SYM=’)’
BEGIN
ADVANCE;
END
ELSE ERROR
END
ELSE ERROR
END
PRODUCE <加法运算符>:
BEGIN
IF SYM=’+’ OR ‘-’
BEGIN
FLAG=TURE
END
ELSE
BEGIN
FLAG=FLASE
END
END
PRODUCE <乘法运算符>:
BEGIN
IF SYM=’*’ OR ‘/’
BEGIN
FLAG=TURE
END
ELSE
BEGIN
FLAG=FLASE
END
END
PRODUCE <关系运算符>:
BEGIN
IF SYM=’=’ OR ‘#’ OR ‘<’ OR ‘<=’ OR ‘>’ OR ‘>=’
BEGIN
FLAG=TURE
END
ELSE
BEGIN
FLAG=FLASE
END
END
PROGRAM PAESER
BEGIN
ADVANCE;
<表达式>
IF SYM<>’#’ THEN ERROR
END
(5)算法流程图
(6)输入输出源程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
map<string,string> Word;//使用map数据结构实现key-value对应
std::map<string,string>::iterator it;//用来遍历key-value对应关系的迭代器
string str;//词法分析string变量进行字符识别
string str1;//语法分析中的string变量字符的识别
string pointer; //指针
string pointer1;//记录除去pointer的
void map_init();//key-value(单词-编码)对应关系进行初始化
void lexicalAnalysis();//词法分析过程
string expression();//表达式算法过程--字母
int expression1();//表达式算法过程--数字
string term();//项算法过程--字母
int term1();//项算法过程--数字
string factor();//因子算法过程--字母
int factor1();//因子算法过程--数字
int additionOperator();//加法运算符算法过程
int MultiplicationExpression();//乘法运算符算法过程
int relationshipOperator();//关系运算符算法过程
int advance();
int AllisNum(string strg);
//全局变量
int error=0;//记录错误的个数
int lparenum=0;//记录左括号的个数
int found;//提取字符串中指针的位置
int flag=0;//记录往后移动一个指针是否正确
int n=0;//记录输入的行数
int k=0;
int ccount=0;//记录输出四元式的数目
int rresult;//算数表达式结果
ifstream file("./2.txt");
struct Quaternion{//四元式
string op;
string arg1;
string arg2;
string result;
};
struct Quaternion Quaternion[100];
int Staletters(string s){//输入的表达式当中字母的个数
int ccount=0;
for(std::size_t i = 0; i < s.size(); i++){
if(isalpha(s[i]))//判断是否为字母
{
//cout<
ccount++;
}
}
return ccount;
}
int main(){
map_init();//key-value(单词-编码)对应关系进行初始化
//lexicalAnalysis();//下面是词法分析
string word;//识别单词
string str;//识别字符
ofstream outfile("./2.txt");
cin>>str;
for(std::size_t i=0;i<str.size();i++){//对整个字符串进行遍历
while(str[i]==' '||str[i]=='\n') i++;//若最开始为空格或换行符,则将指针的位置往后移
if(isalpha(str[i])){//对标识符和基本字进行识别,调用库函数isalpha()
word=str[i++];
while(isalpha(str[i])||isdigit(str[i])){
word+=str[i++];
}
it=Word.find(word);//返回word在Word中的迭代器
if(it!=Word.end()){//判断是不是基本字,若为基本字则进行输出
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}
else{//否则为标识符直接输出
outfile<<"(ident"<<","<<word<<")"<<endl;
}
i--;
}
else if(isdigit(str[i])){//判断是不是常数,调用库函数isdigit()
word=str[i++];
while(isdigit(str[i])){
word+=str[i++];
}
if(isalpha(str[i])){
outfile<<"error!"<<endl;
break;
}
else{
outfile<<"(number"<<","<<word<<")"<<endl;
}
i--;
}else if(str[i]=='<'){//对<,<=,<>分别进行判断
word=str[i++];
if(str[i]=='>'){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else if(str[i]=='='){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
i--;
}else{
outfile<<"error!"<<endl;
break;
}
}else if(str[i]=='>'){//对>,>=分别进行判断
word=str[i++];
if(str[i]=='='){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
i--;
}else{
outfile<<"error!"<<endl;
break;
}
}else if(str[i]==':'){//对:=进行判断
word=str[i++];
if(str[i]=='='){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else{
outfile<<"error!"<<endl;
break;
}
}else{//对其他的基本字依次进行判断
word=str[i];
it=Word.find(word);
if(it!=Word.end()){
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else{
break;
}
}
}
outfile.close();//词法分析结束
flag=advance();//指针移动到下一个词法分析输出
//cout<
if(Staletters(str)>0){//若表达式中没有字母则表示为算数表达式可以直接得出结果否则需要输出四元式
if(flag){//当识别出编码时开始识别表达式
expression();
}
if(flag!=-1&&!error){//当没有出现错误时就表示自上而下语法分析正确
for(int i=0;i<ccount;i++){//输出四元式
cout<<'('<<Quaternion[i].op<<','<<Quaternion[i].arg1<<','<<Quaternion[i].arg2<<','<<Quaternion[i].result<<')'<<endl;
}
}
}
else if(Staletters(str)==0){//算数表达式
if(flag){//当识别出编码时开始识别表达式
rresult=expression1();
}
if(flag!=-1&&!error){//当没有出现错误时就表示自上而下语法分析正确
cout<<"17"<<endl;
}
}
else{
cout<<"error!!!"<<endl;
return 0;
}
file.close();
return 0;
}
/*int AllisNum(string strg)
{
for (int i = 0; i < strg.size(); i++)
{
int tmp = (int)strg[i];
if (tmp >= 48 && tmp <= 57)
{
continue;
}
else
{
return 0;
}
}
return 1;
}*/
int advance(){//表示指针的移动
if(!getline(file,str1)){
return 0;//到文件末尾结束
}
found=str1.find(',',0);//查找字符‘,’,返回索引值
if(found==-1){//没有找到时表示识别错误
error++;
cout<<"Syntax error : recognition character error "<<endl;
return -1;//表示程序错误
}
pointer=str1.substr(1,found-1);//指定位置复制子字符串,比如(lparen,() --pointer为lparen
pointer1=str1.substr(found+1,str1.size()-found-2);//指定位置复制子字符串,比如(lparen,() --pointer1为()
//cout<
return 1;//返回全局变量str
}
string newtemp(){//产生变量名
char *p;
char m[12];
p=(char*)malloc(12);
k++;
snprintf(m, sizeof(m), "%d", k);
/*第一个参数是要写入转换结果的目标字符串,
第二个参数是要写入转换结果的目标字符串的字节数,
第三个参数是转移数字类型。
第四个参数是要转换的数字t1 t2 t3 ......
*/
strcpy(p+1,m);
p[0]='t';
string s;
s=p;
return s;
}
void emit(string op,string arg1,string arg2,string result){//产生四元式用于显示
Quaternion[ccount].op=op;
Quaternion[ccount].arg1=arg1;
Quaternion[ccount].arg2=arg2;
Quaternion[ccount].result=result;
ccount++;
return;
}
string expression(){//按字母的表达式
string op,arg1,arg2,result;
if(error){//有错误项显示error
return NULL;
}
arg1=term();//b
if(error){//有错误项显示error
return NULL;
}
/*if((pointer=="plus")||(pointer=="minus")){//当指向'+'或'-'的时候
flag=advance();//指向下一个单词编码
if(!error){
return;
}
if(flag==0){
cout<<"Syntax error : add operator last missing item"<
while(additionOperator()){//循环过程:当识别单词编码为plus或minus时,trem()
op=pointer1;//+
flag=advance();
if(error){
return NULL;
}
if(flag==0){//语法错误
cout<<"Syntax error : add operator last missing item"<<endl;
error++;
return NULL;
}
arg2=term();//第二个arg2c
if(error){
return NULL;
}
/*if(AllisNum(arg1)&&AllisNum(arg2)){//判断字符串是否全部为数字
int result;
if(op=="+"){
result=atoi(arg1.c_str())+atoi(arg2.c_str());//string->int
arg1 = result;
}
else{
result=atoi(arg1.c_str())-atoi(arg2.c_str());
arg1=result;
}
}
else{
string result;*/
result=newtemp();//产生新的变量t1
emit(op,arg1,arg2,result);//输出四元式(+,b,c,t1)
arg1=result;//将结果存放于下一个四元式的第一个值
}
return arg1;
}
int expression1(){//算数表达式
int arg1,arg2,result;
string op;
if(error){//有错误项显示error
return 0;
}
arg1=term1();//2
if(error){//有错误项显示error
return 0;
}
while(additionOperator()){//循环过程:当识别单词编码为plus或minus时,trem()
op=pointer1;//+
flag=advance();
if(error){
return 0;
}
if(flag==0){//语法错误
cout<<"Syntax error : add operator last missing item"<<endl;
error++;
return 0;
}
arg2=term1();//3*5=15
if(error){
return 0;
}
if(op=="+"){//int 类型直接相加减
result=arg1+arg2;//17
arg1=result;
}
else{
result=arg1-arg2;
arg1=result;
}
}
rresult=arg1;
return rresult;//输出17
}
string term(){//带字母的表达式的项
string op,arg1,arg2,result;
arg1=factor();//b
if(error){
return NULL;
}
while(MultiplicationExpression()){//循环:当指向单词编码为times或则slash时,factor()
op=pointer1;//*
flag=advance();
if(error){
return NULL;
}
if(flag==0){//语法错误
error++;
cout<<"Syntax error : multiplication operator missing factor"<<endl;
return NULL;
}
if(error){
return NULL;
}
arg2=factor();//c
if(error){
return NULL;
}
/*if(AllisNum(arg1)&&AllisNum(arg2)){
int result;
if(op=="*"){
result=atoi(arg1.c_str())*atoi(arg2.c_str());
arg1 = result;
}
else{
result=atoi(arg1.c_str())/atoi(arg2.c_str());
arg1=result;
}
}
else{*/
//string result;
result=newtemp();//产生t2
emit(op,arg1,arg2,result);//(*,a,t1,t2)
arg1=result;//将t2存放在下一个产生式的arg1
}
return arg1;
}
int term1(){//算数表达式的项
string op;//*
int arg1,arg2,result;
arg1=factor1();//3
if(error){
return 0;
}
while(MultiplicationExpression()){//循环:当指向单词编码为times或则slash时,factor()
op=pointer1;//*
flag=advance();
if(error){
return 0;
}
if(flag==0){
error++;
cout<<"Syntax error : multiplication operator missing factor"<<endl;
return 0;
}
if(error){
return 0;
}
arg2=factor1();//5
if(error){
return 0;
}
if (op=="*"){
result=arg1*arg2;//15
arg1=result;//将本四元式的值作为下一个四元式的arg1
}
else{
if(arg2==0){
error++;
cout<<"Divisor cannot be 0!!!"<<endl;
return 0;
}
result=arg1/arg2;
arg1=result;
}
}
return arg1;
}
string factor(){//带字母表达式因子
string arg;//值
if(pointer=="ident"||pointer=="number"){//如果识别的是标识符和整数时,指针往后移动,识别单词编码
arg=pointer1;//a b c
flag=advance();
if(error){
return NULL;//强制break
}
if(lparenum==0&&pointer=="rparen"){
error++;
cout<<"Syntax error : ')' does not match"<<endl;
return NULL;
}
}
else if(pointer=="lparen"){//如果识别左括号成功,则判断是否为表达式、右括号
lparenum++;
flag=advance();
if(error){
return NULL;
}
if(flag==0){//error : 已到文件末尾,只剩左括号,没有右括号与之匹配
error++;
cout<<" Syntax error : '(' followed by missing expression, no ')' matches it"<<endl;
return NULL;
}
arg=expression();
if(error){
return NULL;
}
if(flag==0||pointer!="rparen"){
error++;
cout<<"Syntax error : no ')' matches opening bracket"<<endl;
return NULL;
}else{
lparenum--;//有右括号与左括号匹配,左括号数减1
flag=advance();
if(error){
return NULL;
}
if(flag==0){
return arg;
}
}
}else{
cout<<"Syntax error :factor header is not < identifier > | < unsigned integer > | '(' "<<endl;
error++;
return NULL;
}
return arg;
}
int factor1(){//算数表达式因子
int arg;//存放数值
if(pointer=="ident"){//如果识别的是标识符时,算数表达式报错
error++;
cout<<"error"<<endl;
return 0;
}
else if(pointer=="number"){//如果识别的是整数时,指针往后移动,识别单词编码,并且返回整数
stringstream ss;
ss<<pointer1;
ss>>arg;
//arg=std::atoi(pointer1.c_str());//2 3 5
//cout<
flag=advance();
if(error){
return 0;//强制break
}
if(lparenum==0&&pointer=="rparen"){
error++;
cout<<"Syntax error : ')' does not match"<<endl;
return 0;
}
}
else if(pointer=="lparen"){//如果识别左括号成功,则判断是否为表达式、右括号
lparenum++;
flag=advance();
if(error){
return 0;
}
if(flag==0){//error : 已到文件末尾,只剩左括号,没有右括号与之匹配
error++;
cout<<" Syntax error : '(' followed by missing expression, no ')' matches it"<<endl;
return 0;
}
arg=expression1();
if(error){
return 0;
}
if(flag==0||pointer!="rparen"){
error++;
cout<<"Syntax error : no ')' matches opening bracket"<<endl;
return 0;
}else{
lparenum--;//有右括号与左括号匹配,左括号数减1
flag=advance();
if(error){
return 0;
}
if(flag==0){
return arg;
}
}
}else{
cout<<"Syntax error :factor header is not < identifier > | < unsigned integer > | '(' "<<endl;
error++;
return 0;
}
return arg;
}
int additionOperator(){
if((pointer=="plus")||(pointer=="minus"))//如果识别的是'+'和'-'时,识别正确
return 1;
else
return 0;
}
int MultiplicationExpression(){
if((pointer=="times")||(pointer=="slash"))//如果识别的是'*'和'/'时,指针往后移动,识别单词编码
return 1;
else
return 0;
}
int relationshipOperator(){//=|#|<|<=|>|>=
if((pointer=="eql")||(pointer=="#")||(pointer=="lss")||(pointer=="leq")||(pointer=="gtr")||(pointer=="geq"))//如果识别的是=|#|<|<=|>|>=时,指针往后移动,识别单词编码
return 1;
else
return 0;
}
void map_init(){//key-value(单词-编码)对应关系进行初始化
Word["begin"]="beginsym";
Word["call"]="callsym";
Word["const"]="constsym";
Word["do"]="dosym";
Word["end"]="endsym";
Word["if"]="ifsym";
Word["odd"]="oddsym";
Word["procedure"]="proceduresym";
Word["read"]="readsym";
Word["then"]="thensym";
Word["var"]="varsym";
Word["while"]="whilesym";
Word["write"]="writesym";
Word["+"]="plus";
Word["-"]="minus";
Word["*"]="times";
Word["/"]="slash";
Word["="]="eql";
Word["<>"]="neq";
Word["<"]="lss";
Word["<="]="leq";
Word[">"]="gtr";
Word[">="]="geq";
Word[":="]="becomes";
Word["("]="lparen";
Word[")"]="rparen";
Word[","]="comma";
Word[";"]="semicolon";
Word["."]="period";
Word["#"]="#";
}
void lexicalAnalysis(){
string word;//识别单词
string str;//识别字符
//ifstream infile("./1.txt");
ofstream outfile("./2.txt");
//ostringstream buf;
//char ch;
//while(buf&&infile.get(ch)) buf.put(ch);//将文件中的字符读出来
//str=buf.str();
cin>>str;
for(std::size_t i=0;i<str.size();i++){//对整个字符串进行遍历
while(str[i]==' '||str[i]=='\n') i++;//若最开始为空格或换行符,则将指针的位置往后移
if(isalpha(str[i])){//对标识符和基本字进行识别,调用库函数isalpha()
word=str[i++];
while(isalpha(str[i])||isdigit(str[i])){
word+=str[i++];
}
it=Word.find(word);//返回word在Word中的迭代器
if(it!=Word.end()){//判断是不是基本字,若为基本字则进行输出
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}
else{//否则为标识符直接输出
outfile<<"(ident"<<","<<word<<")"<<endl;
}
i--;
}
else if(isdigit(str[i])){//判断是不是常数,调用库函数isdigit()
word=str[i++];
while(isdigit(str[i])){
word+=str[i++];
}
if(isalpha(str[i])){
outfile<<"error!"<<endl;
break;
}
else{
outfile<<"(number"<<","<<word<<")"<<endl;
}
i--;
}else if(str[i]=='<'){//对<,<=,<>分别进行判断
word=str[i++];
if(str[i]=='>'){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else if(str[i]=='='){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
i--;
}else{
outfile<<"error!"<<endl;
break;
}
}else if(str[i]=='>'){//对>,>=分别进行判断
word=str[i++];
if(str[i]=='='){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
i--;
}else{
outfile<<"error!"<<endl;
break;
}
}else if(str[i]==':'){//对:=进行判断
word=str[i++];
if(str[i]=='='){
word+=str[i];
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else{
outfile<<"error!"<<endl;
break;
}
}else{//对其他的基本字依次进行判断
word=str[i];
it=Word.find(word);
if(it!=Word.end()){
outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
}else{
break;
}
}
}
//infile.close();
outfile.close();
}