编译原理作业(第一次)-完成retinf.c(阉割版)
首先,作业要求概括如下:
根据前缀表达式文法,实现statements() 和expression() 两个函数。
并且要求使得语义分析在完成分析前缀表达式并输出中间代码的同时,也能够将前缀表达式翻译为中缀表达式, 且要求翻译后的中缀表达式中尽可能少用括号。
statements -> expression SEMI
| expression SEMI statements expression -> PLUS expression expression
| MINUS expression expression
| TIMES expression expression
| DIVISION expression expression
| NUM_OR_ID
举例如下: 输入"+ a * b c;"时,应输出中缀式为" a + b * c", 而不是"a + (b * c)"或"(a) + (b * c)"等。
最后测试效果如下:

其中未实现河流命名算法故为阉割版。为方便读者阅读并理解后自行更改,这里只提供初版(low版),其代码如下(DDL后会更新):
//retinf.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h> #include "lex.h" char err_id[] = "error";
char * midexp;
extern char * yytext; struct YYLVAL {
int last_op; /* last operation of expression
for elimination of redundant parentheses */ char * val; /* 记录表达式中间临时变量 */
char * expr; /* 记录表达式后缀式 */
}; typedef struct YYLVAL Yylval; Yylval * expression(void); char *newname(void); /* 在name.c中定义 */ extern void freename(char *name); void statements(void) {
Yylval *temp;
printf("Please input an infix expression and ending with \";\"\n");
while (!match(EOI)) { temp = expression(); printf("The Expression Is %s\n", temp->expr);
freename(temp->val); free(temp->expr);
free(temp);
if (match(SEMI)) {
printf("Please input an infix expression and ending with \";\"\n");
advance(); }
else {
fprintf(stderr, "%d: Inserting missing semicolon\n", yylineno);
}
}
} Yylval * expression(void) {
Yylval *tempToReturn;
tempToReturn = (Yylval *)malloc(sizeof(Yylval)); Yylval *temp0, *temp1;
while (match(PLUS) || match(MINUS) || match(TIMES) || match(DIVISION)) { char op = yytext[];
advance();
temp0 = expression(); temp1 = expression(); bool tempToReturnIsPro = op == '*' || op == '/';
bool temp0IsLower = temp0->last_op == PLUS || temp0->last_op == MINUS;
bool temp1IsLower = temp1->last_op == PLUS || temp1->last_op == MINUS; if (tempToReturnIsPro) {
if (temp0IsLower && temp1IsLower) {
tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
sprintf(tempToReturn->expr, "( %s ) %c ( %s )",
temp0->expr, op, temp1->expr);
}
else if (temp0IsLower) {
tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
sprintf(tempToReturn->expr, "( %s ) %c %s",
temp0->expr, op, temp1->expr);
}
else if (temp1IsLower) {
tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
sprintf(tempToReturn->expr, "%s %c ( %s )",
temp0->expr, op, temp1->expr);
}
else {
tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
sprintf(tempToReturn->expr, "%s %c %s",
temp0->expr, op, temp1->expr);
}
}
else {
tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
sprintf(tempToReturn->expr, "%s %c %s",
temp0->expr, op, temp1->expr);
}
switch (op)
{
case '+':tempToReturn->last_op = PLUS; break;
case '-':tempToReturn->last_op = MINUS; break;
case '*':tempToReturn->last_op = TIMES; break;
case '/':tempToReturn->last_op = DIVISION; break;
default:
break;
} printf(" %s %c= %s\n", temp0->val, op, temp1->val);
freename(temp1->val);
tempToReturn->val = temp0->val;
return tempToReturn; } if (match(NUM_OR_ID)) {
printf(" %s = %0.*s\n", tempToReturn->val = newname(), yyleng, yytext);
tempToReturn->expr = (char*)malloc(yyleng + );
strncpy(tempToReturn->expr, yytext, yyleng);
advance();
tempToReturn->last_op = TIMES;
return tempToReturn;
}
else if (match(SEMI)){
printf("");
return;
}
else {
tempToReturn->val = newname();
advance();
fprintf(stderr, "%d: Number or identifier expected\n", yylineno);
return;
}
}
另:
/*main.c XL分析器 */ main()
{
statements();
}
/*lex.c XL分析器 */ #include "lex.h"
#include <stdio.h>
#include <ctype.h> char *yytext = ""; /* 当前词形,注意由于是直接指向
行缓冲区input_buffer,因此不是以'\0'结尾,
因此使用时要小心, 设初值为0, 表示缓冲区为空,
需要重新读行 */
int yyleng = ; /* 词形的长度 */
int yylineno = ; /* 输入的行号 */ lex()
{
static char input_buffer[];
char *current; current = yytext + yyleng; /* 跳过以读过的词形 */ while () { /* 读下一个词形 */
while (!*current) {
/* 如果当前缓冲区已读完,重新从键盘读入新的一行.
并且跳过空格
*/ current = input_buffer;
/* 如果读行有误,返回 EOI */
if (!fgets(input_buffer, , stdin)) {
*current = '\0';
return EOI;
} ++yylineno; while (isspace(*current))
++current;
} for (; *current; ++current) {
/* Get the next token */ yytext = current;
yyleng = ; /* 返回不同的词汇代码 */
switch (*current) {
case ';': return SEMI;
case '+': return PLUS;
case '-': return MINUS;
case '/': return DIVISION;
case '*': return TIMES;
case '(': return LP;
case ')': return RP; case '\n':
case '\t':
case ' ': break; default:
if (!isalnum(*current))
fprintf(stderr, "Ignoring illegal input <%c>\n", *current);
else {
while (isalnum(*current))
++current; yyleng = current - yytext;
return NUM_OR_ID;
} break;
}
}
}
} static int Lookahead = -; /* 向前查看的词汇,设初值为-1
表示第一次调用match函数时
必须要读取一个词汇 */ int match(int token)
{
/* 判断token是否和当前向前查看的词汇相同. */ if (Lookahead == -)
Lookahead = lex(); return token == Lookahead;
} void advance()
{
/* 向前都一个词汇 */
Lookahead = lex();
}
/* lex.h XL分析器*/
#define EOI 0 /* end of input */
#define SEMI 1 /* ; */
#define PLUS 2 /* + */
#define TIMES 3 /* * */
#define LP 4 /* ( */
#define RP 5 /* ) */
#define NUM_OR_ID 6 /* decimal number or identifier */
#define MINUS 7
#define DIVISION 8
extern char *yytext; /* in lex.c */
extern int yyleng;
extern int yylineno;
/*name.c XL分析器 */
#include <stdio.h>
char *Names[] = { "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15" };
char **Namep = Names;
extern int yylineno;
char *newname()
{
if (Namep >= &Names[sizeof(Names) / sizeof(*Names)]) {
fprintf(stderr, "%d: Expression too complex\n", yylineno);
exit();
}
return(*Namep++);
}
freename(s)
char *s;
{
if (Namep > Names)
*--Namep = s;
else
fprintf(stderr, "%d: (Internal error) Name stack underflow\n",
yylineno);
}
具体生成方法不一,使用makefile方式最好。
这里只提供基本的gcc 方式(部分linux中没有自带,自行安装)。
gcc -c lex.c gcc -c retinf.c gcc -c name.c gcc -c main.c gcc -o namebalabala lex.o retinf.o name.o main.o
//gcc -o namebalabala *.o ./namebalabala
注意,如果非要在win下vs中直接运行此程序的话,你会发现:


很正常,这是因为执行的标准不一样。为了防止溢出,微软要求用sprintf_s() 和strncpy_s() 函数(其中_s代表safe)代替sprintf() 和strncpy()。
也就多了一个目标串长度的参数,百度一下就好了。
但实际过程中应该还是会有一些问题的,特别是地址方面的。这个时候就自己debug吧~
编译原理作业(第一次)-完成retinf.c(阉割版)的更多相关文章
- Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用
catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...
- Java编译原理
http://wenku.baidu.com/view/f9b1734b87c24028915fc3a3.html Java编译原理 1. 关于动态加载机制 学习Java比C++更容易理解OOP的思想 ...
- python实现算术表达式的词法语法语义分析(编译原理应用)
本学期编译原理的一个大作业,我的选题是算术表达式的词法语法语义分析,当时由于学得比较渣,只用了递归下降的方法进行了分析. 首先,用户输入算术表达式,其中算术表达式可以包含基本运算符,括号,数字,以及用 ...
- 学了编译原理能否用 Java 写一个编译器或解释器?
16 个回答 默认排序 RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...
- .net 编译原理
这听起来像是个非常高大上的名字,上学的时候我们学过的编译原理或者编译技术实际上是在讲如何将高级程序语言如C++编译为计算机可以理解的汇编语言,这里说的编译原理只是想说明在.NET的世界里编译这件事儿和 ...
- 编译原理实验之SLR1文法分析
---内容开始--- 这是一份编译原理实验报告,分析表是手动造的,可以作为借鉴. 基于 SLR(1) 分析法的语法制导翻译及中间代码生成程序设计原理与实现1 .理论传授语法制导的基本概念,目标代码结 ...
- 揭秘autoit3的运行机制和反编译原理
今天发这个帖子的目的在于和论坛里面的朋友交流一下学习心得,主要内容是围绕着autoit3的编译原理.先开门见山的说一下结果,我不知道如何反编译au3,但相信论坛有很多高手,能解开我心中的疑团.我没有想 ...
- 编译原理_P1004
龙书相关知识点总结 //*************************引论***********************************// 1. 编译器(compiler):从一中语言( ...
- 编译原理-词法分析05-正则表达式到DFA-01
编译原理-词法分析05-正则表达式到DFA 要经历 正则表达式 --> NFA --> DFA 的过程. 0. 术语 Thompson构造Thompson Construction 利用ε ...
随机推荐
- js-notebook
注意DOM和BOM的区别,ECMAScript只针对js的语法核心,实际大部分浏览器里的js = ECMAScript + DOM + BOM, 而nodejs里就只包括core js 隐性的toSt ...
- mysql5.7.20 windows 解压缩版安装
1.下载 文件下载路径:https://dev.mysql.com/downloads/mysql/ 2.配置文件 在解压的文件夹内新建my.ini文件,并加入以下内容: [mysql] # 设置my ...
- 分享我编写的powershell脚本:ssh-copy-id.ps1
问:通过[字符串界面].如何从win,通过ssh,连接到sshd?答:在任意版本win中,通过cmd.exe,powershell.exe中调用ssh.exe,连接sshd. 问:通过[pow ...
- tfs增加用户
1.windows上添加用户 2.tfs对应项目添加该用户 3.注意: 要设置服务器对应的本地安全策略 从网络上允许该用户访问
- 接口自动化测试遭遇问题,excel中取出来的json串,无法使用requests去请求解决办法
最近遭遇了一个问题,问题不大不小,想半天没想明白是哪里有问题,今天终于解决了 用python读取了excel用例中,body json字符串内容,然后requests去请求内容,结果一直报错,一直不明 ...
- [2003_p1]乒乓球
一道因为输出不一样疯狂超时的题目(是我太菜,但是我jio得代码是ok的) 题目描述 国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及.其中11分制改革引起了很大的 ...
- 剖析一个用C++写的行情交易系统
最近hen ci hen ci用C++写完了一整套证券行情系统,但是不是服务沪深交易所的,是给文交所用的.整个系统涵盖了从DBF文件解析开始到客户端展现这一整条逻辑.想来一年多没有更新博客了,所以趁这 ...
- Docker容器的管理
创建容器的工作原理: 当利用docker run来创建容器时,Docker在后台运行的标准操作包括:检查本地是否存在指定的镜像,不存在就从公有仓库下载,利用镜像创建并启动一个容器分配一个文件系统,并在 ...
- 获取百度地图POI数据三(模拟关键词搜索)
上一篇博文中讲到如何获取用于搜索的关键词,并且已经准备好了一百五十万的关键词 这其中有门牌号码,餐馆酒店名称,公司名称,道路名称等.有了这些数据,我们就可以通过代码,模拟我们在百度地图的搜索框中搜 ...
- 酷学习笔记——ASP.NET Core 简介
ASP.NET Core 简介 其实就是说酷好,不好好学,不学好,没饭吃. 新词汇:IoT,Internet of Things,网联网,微软物联网英文网站.微软物联网中文网站