一、实验目的
通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法成分变换为中间代码的语义翻译方法.
二、实验内容
采用递归下降语法制导翻译法,对算术表达式、赋值语句进行语义分析并生成四元式序列。
三实验要求
- 实验要求
- 文法:
- statement→begin expr end
expr → expr + term
| expr - term
| term
term → term * factor
| term / factor
| factor
factor → ( expr ) | id | num
- 实现一遍扫描翻译
3、实验的输入和输出:
输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。
例如:对于语句串
begin a:=2+3*4;x:=(a+b)/c end#
输出的三地址指令如下:
t1=3*4
t2=2+t1
a=t2
t3=a+b
t4=t3/c
x=t4
四、实验步骤
算法思想
1设置语义过程
emit(char *result,char *arg1,char *op,char *ag2)
该函数功能是生成一个三地址语句送到四元式表中。
四元式表的结构如下:
struct {char result[8];
char ag1[8];
char op[8];
char ag2[8];
}quad[20];
(2) char *newtemp()
该函数回送一个新的临时变量名,临时变量名产生的顺序为T1,T2,….
Char *newtemp(void)
{
char *p;
char m[8];
p=(char *)malloc(8);
k++;
itoa(k,m,10);
strcpy(p+1,m);
p[0]=’t’;
return(p);
}
2.主程序示意图如图c.10所示。
3.函数lrparser在原来语法分析的基础上插入相应的语义动作:将输入串翻译成四元式序列。在实验中我们只对表达式、赋值语句进行翻译。
四、实验过程原始记录(数据、图表、计算等)
实验的输入和输出:
输入是语法分析提供的正确的单词串,输出为三地址指令形式的四元式序列。
例如:对于语句串
begin a:=2+3*4;x:=(a+b)/c end#
输出的三地址指令如下:
t1=3*4
t2=2+t1
a=t2
t3=a+b
t4=t3/c
x=t4
五、实验过程和思路
思路:
编译器包含了词法分析、语法分析和代码生成三个阶段。
在词法分析阶段,通过读入字符并识别其类型,将输入的代码划分成一个个单词,并将每个单词的类型(关键字、标识符、数字等)保存在变量中。
在语法分析阶段,根据对应的文法规则,递归地调用各个函数进行语法分析。这里的文法规则包含了赋值语句、条件语句和循环语句。在语法分析过程中,还会借助生成四元式的方法,逐步构建出目标程序的中间代码。
在代码生成阶段,将语法分析阶段得到的四元式转换成目标程序的汇编代码。
主要是将输入的代码分析成语法树,然后生成对应的目标程序。
实验代码:
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include <conio.h>
char prog[80], token[6];
int count = 0;
char ch; /*当前读入单词*/
int syn, p, m, n, sum, kk = 0, k = 0; //p/*输入缓冲区指针*/
int length = 0; //输入字符长度
int mark = 0; /*标记注释//*/
int mark2;// 用于/* */ 注释
char* rwtab[6] = { "begin","if","then","while","do","end" };
char* expression(void);
struct {
char result[8];
char ag1[8];
char op[8];
char ag2[8];
}quad[20];
void emit(char* result, char* ag1, char* op, char* ag2)
{
strcpy(quad[count].result, result);
strcpy(quad[count].ag1, ag1);
strcpy(quad[count].op, op);
strcpy(quad[count].ag2, ag2);
count++;
return;
}
/*词法扫描程序:*/
void scaner()
{
for (n = 0; n < 8; n++)
token[n] = NULL;
m = 0;
ch = prog[p++];
while (ch == ' ')ch = prog[p++];
if ((ch <= 'z' && ch >= 'a') || (ch <= 'Z' && ch >= 'A'))
{
while ((ch <= 'z' && ch >= 'a') || (ch <= 'Z' && ch >= 'A') || (ch <= '9' && ch >= '0'))
{
token[m++] = ch;
ch = prog[p++];
}
token[m++] = '\0';
ch = prog[--p];
syn = 10;
for (n = 0; n < 6; n++)
if (strcmp(token, rwtab[n]) == 0)
{
syn = n + 1;
break;
}
//break;
}
else
if ((ch <= '9' && ch >= '0'))
{
sum = 0;
while ((ch <= '9' && ch >= '0'))
{
sum = sum * 10 + ch - '0';
ch = prog[p++];
}
ch = prog[--p];
syn = 11;
}
else
switch (ch)
{
case '<':m = 0; token[m++] = ch;
ch = prog[p++];
if (ch == '>')
{
syn = 21;
token[m++] = ch;
}
else
if (ch == '=')
{
syn = 22;
token[m++] = ch;
}
else
{
syn = 20;
ch = prog[--p];
}
break;
case '>':token[m++] = ch;
ch = prog[p++];
if (ch == '=')
{
syn = 24;
token[m++] = ch;
}
else
{
syn = 23;
ch = prog[--p];
}
break;
case ':':token[m++] = ch;
ch = prog[p++];
if (ch == '=')
{
syn = 18;
token[m++] = ch;
}
else
{
syn = 17;
ch = prog[--p];
}
break;
case '+':syn = 13; token[0] = ch; break;
case '-':syn = 14; token[0] = ch; break;
case '*':
syn = 15;
token[m++] = ch;
ch = prog[p++];
if (ch == '/')
{
mark2 = 1;
return scaner();
}
ch = prog[--p];
break;
case '/':
syn = 16;
token[m++] = ch;
ch = prog[p++];
if (ch == '/')
{
mark = 0;
while (mark == 0)
{
scaner();
}
p++;
//mark=0;
}
else if (ch == '*')
{
mark = 1;
syn = 30; ///**/
token[m++] = '*';
mark2 = 0;
while (mark2 == 0)
{
scaner();
}
p++;
//mark2=0;
}
ch = prog[--p];
break;
case ':=':syn = 18; token[0] = ch; break;
case '<>':syn = 21; token[0] = ch; break;
case '<=':syn = 22; token[0] = ch; break;
case '>=':syn = 24; token[0] = ch; break;
case '=':syn = 25; token[0] = ch; break;
case ';':syn = 26; token[0] = ch; break;
case '(':syn = 27; token[0] = ch; break;
case ')':syn = 28; token[0] = ch; break;
case '\n':
syn = 29;
token[0] = ch;
mark = 1;
return scaner();
break;
case '#':syn = 0; token[0] = ch; break;
case '\0':syn = 1000; token[0] = '\0'; break;
default:syn = -1;
}
}
char* newtemp(void)
{
char* p;
char m[8];
p = (char*)malloc(8);
k++;
itoa(k, m, 10);
strcpy(p + 1, m);
p[0] = 't';
return(p);
}
//factor分析函数
char* factor()
{
char* fplace;
fplace = (char*)malloc(12);
strcpy(fplace, " ");
if (syn == 10)
{
strcpy(fplace, token);
scaner();
}
else if (syn == 11)
{
itoa(sum, fplace, 10);
scaner();
}
else
if (syn == 27) //( 27
{
scaner();
fplace = expression();
if (syn == 28)scaner();
else
{
printf("缺少')' 出错!\n");
kk = 1;
}
}
else
{
printf("表达式错误!\n");
kk = 1;
}
return (fplace);
}
//term分析函数
char* term(void)
{
char* tp, * ep2, * eplace, * tt;
tp = (char*)malloc(12);/*分配空间*/
ep2 = (char*)malloc(12);
eplace = (char*)malloc(12);
tt = (char*)malloc(12);
strcpy(eplace, factor());
while (syn == 15 || syn == 16)
{
if (syn == 15)
{
tt[0] = '*';
tt[1] = '\0';
}
else if (syn == 16)
{
tt[0] = '/';
tt[1] = '\0';
}
scaner();
strcpy(ep2, factor());
strcpy(tp, newtemp()); //tp为临时变量
emit(tp, eplace, tt, ep2); //将三地址代码送到四元式表
strcpy(eplace, tp);
//factor();
}
return (eplace);
}
//expression表达式分析函数
char* expression()
{
char* tp, * ep2, * eplace, * tt;
tp = (char*)malloc(12);/*分配空间*/
ep2 = (char*)malloc(12);
eplace = (char*)malloc(12);
tt = (char*)malloc(12);
strcpy(eplace, term());/*调用term分析产生表达式计算的第一项eplace*/
while (syn == 13 || syn == 14)
{
if (syn == 13)
{
tt[0] = '+';
tt[1] = '\0';
}
else if (syn == 14)
{
tt[0] = '-';
tt[1] = '\0';
}
scaner();
strcpy(ep2, term());/*/调用term分析产生表达式计算的第二项ep2/*/
strcpy(tp, newtemp());/*/调用newtemp产生临时变量tp存储计算结果/*/
emit(tp, eplace, tt, ep2);/*/生成四元式送入四元式表/*/
strcpy(eplace, tp);
}
return (eplace);
}
//statement语句分析函数
int statement()
{
//scaner();
int schain = 0;
char tt[8], eplace[8];
if (syn == 10)
{
strcpy(tt, token);
scaner();
if (syn == 18) //:= 18
{
scaner();
strcpy(eplace, expression());
emit(tt, eplace," "," ");
schain = 0;
//expression();
}
else
{
printf("赋号值错误!\n");
kk = 1;
}
}
else
{
printf("语句错误\n");
//kk=1;
}
return (schain);
}
//语句串分析
int yucu()
{
int schain = 0;
schain = statement();
while (syn != 6 && p != length - 1 && syn != 0)
{
if (syn != 26)
scaner();
while (syn == 26) //26==;
{
scaner();
if (syn != 0 && syn != 6)
{
schain = statement();
}
}
}
return (schain);
}
//递归下降分析程序
int lrparser()
{
int schain = 0;
scaner();
if (syn != 1)
{
printf("begin错误\n");
kk = 1;
}
else
scaner();
schain = yucu();
if (syn == 6)
{
scaner();
if (kk == 0)
printf("sucess");
}
else {
if (kk != 1)
kk = 1;
printf("缺少end\n");
}
return (schain);
}
void readFile() {
int i = 0;
char temp[255];
/*ifstream fin("data.txt");*/
FILE* fp = fopen("data.txt", "r");
while ((temp[i] = fgetc(fp)) != EOF)
{
prog[i++] = temp[i];
}
length = i;
}
int main()
{
int i;
p = 0;
readFile();
printf("\nplease intput string:");
do
{
ch = getchar();
prog[p++] = ch;
} while (ch != '#');
length = p;
//将程序保存在prog字符数组中
p = 0;
printf("词法分析:\n");
do
{
scaner();
if (syn < 1000/*&&syn!=100&&syn!=101*/)
{
printf("(%d,%s)\n", syn, token);
}
} while (syn < 1000);
printf("\n\n");
printf("语法分析:\n");
p = 0;
//scaner();
lrparser();
printf("\n");
printf("\n三地址指令如下:\n");
for (i = 0; i < count; i++)
{
printf("%s=", quad[i].result); //t1= //x=
printf("%s", quad[i].ag1); //a //t1
printf("%s", quad[i].op); //+
printf("%s ", quad[i].ag2); //b
printf("\n");
}
getch();
}
如有帮助,求三连