首先,作业要求概括如下:

根据前缀表达式文法,实现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(阉割版)的更多相关文章

  1. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  2. Java编译原理

    http://wenku.baidu.com/view/f9b1734b87c24028915fc3a3.html Java编译原理 1. 关于动态加载机制 学习Java比C++更容易理解OOP的思想 ...

  3. python实现算术表达式的词法语法语义分析(编译原理应用)

    本学期编译原理的一个大作业,我的选题是算术表达式的词法语法语义分析,当时由于学得比较渣,只用了递归下降的方法进行了分析. 首先,用户输入算术表达式,其中算术表达式可以包含基本运算符,括号,数字,以及用 ...

  4. 学了编译原理能否用 Java 写一个编译器或解释器?

    16 个回答 默认排序​ RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...

  5. .net 编译原理

    这听起来像是个非常高大上的名字,上学的时候我们学过的编译原理或者编译技术实际上是在讲如何将高级程序语言如C++编译为计算机可以理解的汇编语言,这里说的编译原理只是想说明在.NET的世界里编译这件事儿和 ...

  6. 编译原理实验之SLR1文法分析

    ---内容开始--- 这是一份编译原理实验报告,分析表是手动造的,可以作为借鉴. 基于  SLR(1) 分析法的语法制导翻译及中间代码生成程序设计原理与实现1 .理论传授语法制导的基本概念,目标代码结 ...

  7. 揭秘autoit3的运行机制和反编译原理

    今天发这个帖子的目的在于和论坛里面的朋友交流一下学习心得,主要内容是围绕着autoit3的编译原理.先开门见山的说一下结果,我不知道如何反编译au3,但相信论坛有很多高手,能解开我心中的疑团.我没有想 ...

  8. 编译原理_P1004

    龙书相关知识点总结 //*************************引论***********************************// 1. 编译器(compiler):从一中语言( ...

  9. 编译原理-词法分析05-正则表达式到DFA-01

    编译原理-词法分析05-正则表达式到DFA 要经历 正则表达式 --> NFA --> DFA 的过程. 0. 术语 Thompson构造Thompson Construction 利用ε ...

随机推荐

  1. vmware克隆虚拟机后进行网络配置

    1.首先将虚拟机网络模式选为NAT模式 2.点击高级,查看MAC地址 然后编辑:/etc/udev/rules.d/70-persistent-net.rules 其中teh是网卡的名称,每一次克隆新 ...

  2. GCP 谷歌云平台申请教程

    最近为了学个国外的课程,想要用谷歌云平台的GPU,谷歌云平台,新注册,赠送300美金,免费用一年.注册的时候发现,必须要有国外的信用卡,网上搜索,并试了几个解决方案. 1.不用信用卡,能不能申请成功? ...

  3. 【webpack学习笔记】a04-建立开发环境

    开发环境就是在开发过程中为了方便配置的环境,生产环境就是开发完成即将上线的情况. 好了,说了句废话,切入正题. 在开发时,打包后的文件压缩成一团,报错调试的时候傻眼了有木有?每次做出修改需要到浏览器查 ...

  4. 201671010142 2017-2 《java第十二十三章学习感悟》

    Swing编程第一步,需要导入Swing相关包,即javax.swing.*. 接下里需要设置界面外观风格,使用到UIManager类. 设置完外观之后一定要调用 SwingUtilities.upd ...

  5. JAVAEE 第六周

    JSF 生命周期: FacesServlet 充当用户和 JSF 应用程序之间的纽带.它在明确限定的 JSF 生命周期(规定了用户请求之间的整个事件流)的范围内工作. 1.   当JSF页面上的一个事 ...

  6. PostgreSQL 问题总结

    一.postgresql  - server don't listen(服务器未监听) 1)检测是否开启PostgreSQL服务,没开启的话,需要自己手动建立PostgreSQL服务. 2)查看543 ...

  7. scrapy splash 之一二

    scrapy splash 用来爬取动态网页,其效果和scrapy selenium phantomjs一样,都是通过渲染js得到动态网页然后实现网页解析, selenium + phantomjs ...

  8. Excel修改证件照图片背景色

    在实际生活中,我们常常需要把白底证件照更改为蓝底或红底.操作步骤只需4步!   工具/原料   Excel 方法/步骤     第1步:插入白底证件照 单击[插入]---[图片],选择图片保存的位置, ...

  9. Maven中遇到Unsupported major.minor version 51.0错误

    将错误复制到某度上,查询出结果显示JDK版本不匹配. 我按着步骤执行结束后还是有以下错误: 配置: Tomcat: 最终解决: 我在Initialize的时候使用的版本是JDK1.8的,导致的这个错误 ...

  10. 小程序 map组件问题 cover-view问题

    使用小程序的组件map时 在开发者工具上一切顺利 但是在真机预览时 发现地图的层级是最高的 任何标签都覆盖不了它 调整z-index值并没有什么效果 原因是 微信小程序的map.video.canva ...