一、实验目的

在实现词法、语法分析程序的基础上,编写相应的语义子程序,进行语义处理,加深对语法制导翻译原理的理解,进一步掌握将语法分析所识别的语法范畴变换为某种中间代码(四元式)的语义分析方法,并完成相关语义分析器的代码开发。

二、基本实验内容及要求

对文法 G2[<算术表达式>]中的产生式添加语义处理子程序,完成运算对象是简单变量(标识符)和无符号数的四则运算的计值处理,将输入的四则运算转换为四元式形式的中间代码。
输入:包含测试用例(由标识符、无符号数和+、−、*、/、(、)构成的算术表达式)的源程序文件。
输出:将源程序转换为中间代码形式表示,并将中间代码序列输出到文件中。若源程序中有错误,应指出错误信息。
要求:
1、结合实验一和实验二中的相关内容,完成语法制导翻译的程序设计。
2、对完成的编译系统进行全面测试,供测试的例子应包括符合语义规则的语句,以及分析程序能够判别的若干错例,并给出执行结果。

四、源程序

#include <iostream>
#include <string>
#include <iomanip>
#include <cstring>
#include <fstream>
#include <stdio.h>
#include <cassert>
#include <vector>
//#define _CRT_SECURE_NO_DEPRECATE
//#define _CRT_SECURE_NO_WARNINGS
using namespace std;
/*
begin   BEGIN   1
end     END     2
if      IF      3
then    THEN    4
else    ELSE    5
while   WHILE   6
do      DO      7
标识符 ID      8
浮点常数UCON    9
<        LT      10
<=      LE      11
==        EQ      12
<>        NE      13
>        GT      14
>=      GE      15
=      IS      16
+      PL      17
-       MI      18
*       MU      19
/       DI      20
(       LP      21
)       RP      22
*///词法分析部分
const char* table1[] = { " ","begin","end","if","then","else","while","do" };
const char* table2[] = { " ","BEGIN","END","IF","THEN","ELSE","WHILE","DO","ID","UCON","LT","LE","EQ","NE","GT","GE","IS","PL","MI","MU","DI","LP","RP" };
char TOKEN[20];//用来依次存放一个单词词文中的各个字符。
char str[50];//词法分析后的带有i的表达式
int len = 0;
//语法分析部分
string action[16][8] = { {"s4","null","null" ,"null" ,"null","null","s5" , "null" },{"null","null","s6","s7","null","null","null","acc"},{"null","r3","r3","r3","s8","s9","null","r3"} ,{"null","r6","r6","r6","r6","r6","null","r6"},{"s4","null","null","null","null","null","s5","null"},{"null","r8","r8","r8","r8","r8","null","r8"},{"s4","null","null","null","null","null","s5","null"},{"s4","null","null","null","null","null","s5","null"},{"s4","null","null","null","null","null","s5","null"},{"s4","null","null","null","null","null","s5","null"},{"null","s15","s6","s7","null","null","null","null"} ,{"null","r1","r1","r1","s8","s9","null","r1"},{"null","r2","r2","r2","s8","s9","null","r2"} ,{"null","r4","r4","r4","r4","r4","null","r4"} ,{"null","r5","r5","r5","r5","r5","null","r5"} ,{"null","r7","r7","r7","r7","r7","null","r7"} };
int go[16][3] = { {1 , 2 , 3 },{ -1 , -1 , -1 },{ -1 , -1 , -1 } ,{ -1 , -1 , -1 },{ 10 , 2 , 3 },{ -1 , -1 , -1 },{ -1 , 11 , 3 },{ -1 , 12 , 3 },{ -1 , -1 , 13 },{ -1 , -1 , 14 },{ -1 , -1 , -1 } ,{ -1 , -1 , -1 },{ -1 , -1 , -1 } ,{ -1 , -1 , -1 } ,{ -1 , -1 , -1 } ,{ -1 , -1 , -1 } };
//char vt[8] = { '(',')','+','-','*','/','i','#' };
//char vn[3] = { 'E','T','F' };
string grammar[9] = { "S->E","E->E+T","E->E-T","E->T","T->T*F","T->T/F","T->F","F->(E)","F->i" };
string gg[9] = { "S.PLACE=","生成四元式 ","生成四元式","E.PLACE=","生成四元式","生成四元式","T.PLACE=","F.PLACE= ","F.PLACE=" };
int grammarlength[9] = { 4,6,6,4,6,6,4,6,4 };
char grammarleft[9] = { 'S','E','E','E','T','T','T','F','F' };
string grammarright[9] = { "E","E+T","E-T","T","T*F","T/F","F","(E)","i" };
int grammarrightlength[9] = { 1,3,3,1,3,3,1,3,1 };//语义分析部分
#define PMAX 5 //定义产生式符号属性字符串的长度
int NXQ = 0;//指示下一个四元式编号
int NXTemp = 1;//指示临时变量的编号string eplace[10];//E的语义属性
string tplace[10];//T的语义属性
string fplace[10];//F的语义属性
int eindex = -1,tindex =-1,findex = -1;
char* NewTemp(void) /*产生一个临时变量*/
{char* TempID = (char*)malloc(PMAX);sprintf(TempID, "T%d", NXTemp++); /*整型变量 NXTemp 指示临时变量的编号*/return TempID;
}int lookup(char a[])/*每调用一次,就以 TOKEN 中的字符串查保留字表,若查到,就将相应关键字的类别码赋给整型变量 c;否则将 c 置为零。*/
{int i;for (i = 1; i <= 7; i++){if (strcmp(a, table1[i]) == 0)return i;}if (i == 8){return 0;}}
void out(int a, const char b[])
/*一般仅在进入终态时调用此函数,调用的形式为 OUT(c,VAL)。
其中,实参 c 为相应单词的类别码助记符;实参 VAL 为 TOKEN(即词文)或为空串。
函数 OUT 的功能是,在送出一个单词的内部表示之后,返回到调用该词法分析程序的那个程序。*/
{ofstream fout("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", fstream::app);char temp = ' ';if (a == 8 || a == 9){fout << "(" << table2[a] << " ," << b << ")" << endl;}else{fout << "(" << table2[a] << " ," << temp << ")" << endl;}fout.close();
}void report_error(void)//返回错误
{ofstream fout("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", fstream::app);fout << "输入不合规范!";fout.close();exit(0);
}
void scanner_example(FILE* fp)
{char ch;int i, c, flag = 0;;//ch = fgetc(fp);while ((ch = fgetc(fp)) != EOF){if (ch == ' ')ch = fgetc(fp);if (ch == '\n')ch = fgetc(fp);if (ch == '#')break;if (isalpha(ch)) //判断字符是否为字母,识别标识符和关键字{TOKEN[0] = ch; ch = fgetc(fp); i = 1;while (isalnum(ch))//检查所传的字符是否是字母和数字{TOKEN[i] = ch; i++;ch = fgetc(fp);}TOKEN[i] = '\0';//结束符fseek(fp, -1, 1); //从文件当前位置后退一个字符c = lookup(TOKEN);//查找在第二个表中的位置,如果是关键字返回下标,标识符返回0if (c == 0){out(8, TOKEN);//识别标识符str[len] = 'i';len++;}else out(c, TOKEN);//识别关键字}else if (isdigit(ch))//判断字符是否为数字字符{TOKEN[0] = ch; ch = fgetc(fp); i = 1;while (isdigit(ch) || ch == '.'){if (ch == '.'){if (flag == 0){flag = 1;TOKEN[i] = ch; i++;}else report_error();}else{TOKEN[i] = ch; i++;}ch = fgetc(fp);}TOKEN[i] = '\0';fseek(fp, -1, 1);out(9, TOKEN);//识别数字str[len] = 'i';len++;}elseswitch (ch){case '<': ch = fgetc(fp);if (ch == '=')out(11, TOKEN);//<=else if (ch == '>') out(13, TOKEN);//<>else{fseek(fp, -1, 1);out(10, TOKEN);//<}break;case '=': ch = fgetc(fp);if (ch == '=')out(12, TOKEN);//==else{fseek(fp, -1, 1);out(16, TOKEN);//=}break;case '>': ch = fgetc(fp);if (ch == '=')out(15, TOKEN);//>=else{fseek(fp, -1, 1);out(14, TOKEN);//>}break;case '+':{out(17, TOKEN);str[len] = '+';len++;break;}case '-':{out(18, TOKEN);str[len] = '-';len++;break;}case '*':{out(19, TOKEN);str[len] = '*';len++;break;}case '/':{out(20, TOKEN);str[len] = '/';len++;break;}case '(':{out(21, TOKEN);str[len] = '(';len++;break;}case ')':{out(22, TOKEN);str[len] = ')';len++;break;}default: report_error(); break;}}return;
}int main()
{cout << "请输入要分析的表达式(以#结束):" << endl;char strr[50];//输入的表达式int i = 0;ofstream out1("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\test.txt");out1.close();ofstream out("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\test.txt", ios::out);while (true){cin >> strr[i];out << strr[i];if (strr[i] == '#')break;i++;}out.close();FILE* fp1;FILE* fp2;fp2 = fopen("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", "w");fclose(fp2);fp1 = fopen("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\test.txt", "r");if (!fp1){printf("打开文件失败!");}scanner_example(fp1);string temp;cout << endl;cout << "词法分析结果为:" << endl;ifstream myfile2("C:\\Users\\Administrator\\Desktop\\编译原理\\实验代码\\result.txt", ios::in);if (!myfile2.is_open()){cout << "未成功打开文件" << endl;}while (getline(myfile2, temp)){cout << temp << endl;}myfile2.close();str[len] = '#';cout << endl;cout << "词法分析后表达式为:" << endl;for (int i = 0; i <= len; i++){cout << str[i];}cout << endl;cout << endl;cout << "语法分析结果为:" << endl;int count;//步骤int state[100], stateIndex;//状态串及下标state[0] = 0; stateIndex = 0;//初始化状态串char inSymbol[100], outSymbol[100];//栈中符号串  余留符号串inSymbol[0] = '#';//初始化int inSymbolIndex = 0, outSymbolIndex = 0;string analysis;//分析动作//string nextState;//下一状态for (int i = 0; i <= len; i++){outSymbol[i] = str[i];}cout << "字符串长度为:" << len << endl;cout << "步骤" << "\t" << "状态" << "\t\t";cout << "栈中符号" << "\t\t" << "余留符号串" << "\t\t";cout << "分析动作" << "\t\t" << "语义处理" << "\t\t" << "生成中间代码" << "\t\n";for (count = 1;;){cout << count << fixed << setprecision(3) << "\t";for (int i = 0; i <= stateIndex; i++){cout << state[i] << " " << fixed << setprecision(4);}cout << "\t\t";for (int i = 0; i <= inSymbolIndex; i++){cout << inSymbol[i] << " " << fixed << setprecision(4);}cout << "\t\t";for (int i = outSymbolIndex; i <= len; i++){cout << outSymbol[i] << " " << fixed << setprecision(4);}cout << "\t\t";int row = state[stateIndex], column;if (outSymbol[outSymbolIndex] == '(')column = 0;else if (outSymbol[outSymbolIndex] == ')')column = 1;else if (outSymbol[outSymbolIndex] == '+')column = 2;else if (outSymbol[outSymbolIndex] == '-')column = 3;else if (outSymbol[outSymbolIndex] == '*')column = 4;else if (outSymbol[outSymbolIndex] == '/')column = 5;else if (outSymbol[outSymbolIndex] == 'i')column = 6;else if (outSymbol[outSymbolIndex] == '#')column = 7;if (action[row][column] == "null"){cout << "error!" << endl;break;}else{analysis = action[row][column];cout << analysis << "\t";if (analysis[0] == 's'){cout << endl;stateIndex++;if (analysis.length() == 3){state[stateIndex] = ((int)(analysis[1]) - 48) * 10 + ((int)(analysis[2]) - 48);}else state[stateIndex] = (int)analysis[1] - 48;inSymbolIndex++;inSymbol[inSymbolIndex] = outSymbol[outSymbolIndex];outSymbolIndex++;count++;}else if (analysis[0] == 'r'){int temp = (int)analysis[1] - 48;cout << grammar[temp] << endl;stateIndex = stateIndex - grammarrightlength[temp];inSymbolIndex = inSymbolIndex + 1 - grammarrightlength[temp];inSymbol[inSymbolIndex] = grammarleft[temp];cout << " " << fixed << setprecision(3) << "\t";for (int i = 0; i <= stateIndex; i++){cout << state[i] << " " << fixed << setprecision(4);}cout << "\t\t";for (int i = 0; i <= inSymbolIndex; i++){cout << inSymbol[i] << " " << fixed << setprecision(4);}cout << "\t\t";for (int i = outSymbolIndex; i <= len; i++){cout << outSymbol[i] << " " << fixed << setprecision(4);}cout << "\t\t";int row2 = state[stateIndex], column2;if (inSymbol[inSymbolIndex] == 'E')column2 = 0;else if (inSymbol[inSymbolIndex] == 'T')column2 = 1;else if (inSymbol[inSymbolIndex] == 'F')column2 = 2;if (go[row2][column2] == -1){cout << "error!" << endl;break;}else{cout << "go[" << row2 << "," << column2 << "]=" << go[row2][column2] << "\t";stateIndex++;state[stateIndex] = go[row2][column2];count++;if (temp == 8){findex++;cout << gg[temp] << strr[outSymbolIndex - 1];fplace[findex] = strr[outSymbolIndex - 1];}else if(temp==6){tindex++;cout << gg[temp] << strr[outSymbolIndex - 1];tplace[tindex] = strr[outSymbolIndex - 1];findex--;}else if (temp == 3){eindex++;cout << gg[temp] << strr[outSymbolIndex - 1];eplace[eindex] = strr[outSymbolIndex - 1];tindex--;}else if (temp == 1){cout << gg[temp] ;const char* temp1 = eplace[eindex].c_str();const char* temp2 = tplace[tindex].c_str();                  tindex--;char* temp=NewTemp();//GEN("+", temp1, temp2, temp);cout << "( + , " << temp1 << " , " << temp2 << " , " << temp << " ) ";eplace[eindex] = NXTemp;}else if (temp == 2){cout << gg[temp] ;const char* temp1 = eplace[eindex].c_str();const char* temp2 = tplace[tindex].c_str();tindex--;char* temp = NewTemp();//GEN("-", temp1, temp2, temp);cout << "( - , " << temp1 << " , " << temp2 << " , " << temp << " ) ";eplace[eindex] = temp;}else if (temp == 4){cout << gg[temp] ;const char* temp1 = tplace[tindex].c_str();const char* temp2 = fplace[findex].c_str();findex--;char* temp = NewTemp();//GEN("*", temp1, temp2, temp);cout << "( * , " << temp1 << " , " << temp2 << " , " << temp << " ) ";tplace[tindex] = temp;}else if (temp == 5){cout << gg[temp] ;const char* temp1 = tplace[tindex].c_str();const char* temp2 = fplace[findex].c_str();findex--;char* temp = NewTemp();//GEN("/", temp1, temp2, temp);cout << "( / , " << temp1 << " , " << temp2 << " , " << temp << " ) ";tplace[tindex] = temp;}else if (temp == 7){findex++;fplace[findex] = eplace[eindex];eindex--;}cout << endl;}}else if (analysis == "acc"){cout << endl << "分析成功!";break;}}}fclose(fp1);fclose(fp2);return 0;
}

五、实验结果及分析
1、正确表达式


2、错误表达式

编译原理实验三 语义分析程序设计与实现相关推荐

  1. 合工大 编译原理 实验三

    合工大 编译原理 实验三 LR(1) 分析法 本项目使用c++实现,利用Windows API制作了简易的UI界面. 具体功能如下: 支持查看文法,项目族,LR(1) 分析表,句子归约过程. 可使用包 ...

  2. 编译原理实验一 词法分析程序设计与实现

    一.实验目的 通过编写和调试一个词法分析程序,掌握在对程序设计语言的源程序进行扫描的过程中,将字符流形式的源程序转化为一个由各类单词构成的序列的词法分析方法. 二.基本实验内容与要求 假定一种高级程序 ...

  3. java编程实现算符优先分析法,编译原理实验三-算符优先分析法

    编译原理实验3-算符优先分析法 #include #include #include #include #define SIZE 128 char priority[6][6]; //算符优先关系表数 ...

  4. 笔记-编译原理-实验四-语义分析与中间代码生成

    实验四. 语义分析及中间代码生成 设计思想 根据对属性文法及语义分析.中间代码生成的学习,可以将实验二.三的两种语法分析器进行一定的改造,以达到进行语法分析的同时进行语义分析并生成中间代码.根据PL0 ...

  5. 编译原理实验一、 程序设计语言认知实验报告

    一.实验目的 了解程序设计语言的发展历史,了解不同程序设计语言的各自特点:感受编译执行和解释执行两种不同的执行方式,初步体验语言对编译器设计的影响,为后续编译程序的设计和开发奠定良好的基础. 二.实验 ...

  6. 编译原理实验三:对完整程序进行词法分析并输出对应的二元组

    实验要求 [任务介绍]根据给定源语言的构词规则,从任意字符串中识别出该语言所有的合法的单词符号,并以等长的二元组形式输出. [输入]字符串形式的源程序. [输出]单词符号所构成的串(流),单词以等长的 ...

  7. 编译原理实验三 LR(1)分析法

    实验三 LR(1)分析法 构造 LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文 法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的 语法分析方法. 二.实验内 ...

  8. 编译原理实验三【中间代码生成程序设计】

    基本要求: ①掌握中间代码生成的基本方法. ②掌握语法制导翻译模式. ③完成算术表达式的中间代码生成程序. 重点及难点:掌握语法制导翻译模式的核心思想和工作原理,在此基础上完成基于算数表达式的中间代码 ...

  9. 编译原理 - 实验三 - 递归下降语法分析器的调试及扩展

    一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任 ...

最新文章

  1. 法院判决:优步无罪,无人车安全员可能面临过失杀人控诉
  2. CTFshow 反序列化 web258
  3. 检索数据_22_根据数据项的值排序
  4. jdbc oracle 连接串
  5. MSP430G2553需要注意的一些参数
  6. 开源数据访问组件Smark.Data 1.7新增功能
  7. python约瑟夫环单向循环链表_约瑟夫环的单向循环链表的实现代码
  8. zabbix监控 openstack 的实例的资源使用情况
  9. Matlab--获取300dpi或600dpi图形插入word2010中
  10. python print sys.stdout
  11. Eclpise 和 MyEclipse 的区别
  12. Eclipse、IntelliJ IDEA、TortoiseSVN清除svn帐号
  13. 【转】如何理解NPV与IRR的区别??
  14. Mac视频下载转换器MovieSherlock使用教程
  15. 使用激光可调湿蚀刻曲面实现无间隙微透镜阵列的通用
  16. 面试官:内存耗尽后Redis会发生什么 ?
  17. [转] vagrant学习笔记 - provision
  18. 在线gif压缩文件大小_如何在不损失图像质量的情况下压缩动画GIF文件
  19. week9 day4 CSS网页布局
  20. 没有美术基础学游戏建模怎么样?

热门文章

  1. 618狂欢过后,冷静揭秘亚马逊和淘宝如何用算法让你剁手
  2. Euraka服务端简单配置
  3. FreeBSD 更新
  4. marlin源码gcode解析与算法插补执行框架
  5. 南京邮电大学matlab实验报告,南邮通信原理 实验二 BPSK_BDPSK 传输系统综合实验 (1)...
  6. 空间域与频率域与图像变换
  7. c语言在数组输出字母,c语言字符数组与字符串的使用详解
  8. 记录:element UI table 表格 固定列单元格上下错位
  9. 关于老式打印机驱动安装 惠普,普通安装与驱动下载
  10. 数字孪生白皮书_透过数字孪生白皮书2020,看平行世界的当下与未来