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

根据前缀表达式文法,实现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. Unable to determine the device handle for GPU 0000:01:00.0: GPU is lost.问题排坑

    在运行maskrcnn时,会碰到训练不动的问题,就卡在这儿 UserWarning: Converting sparse IndexedSlices to a dense Tensor of unkn ...

  2. Hive中数据加载失败:root:supergroup:drwxr-xr-x

    Hive中数据加载失败:inode=:root:supergroup:drwxr-xr-x 在执行hive,数据加载的时候,遇到了一个错误,如下图: 在执行程序的过程中,遇到权限问题很正常,背后原理也 ...

  3. Redis基础入门

    学习redis之前,要了解NoSQL.. 一.NoSql概述 由于关系型数据库很难实现: 1.高并发读写 2.海量数据的高校率存储和访问 3.高可扩展性和高可用性 所以出现NoSql,(Not Onl ...

  4. Centos7搭建docker仓库

    一:安装启动registry 1.1:环境准备 yum install -y python-devel libevent-devel python-pip gcc xz-devel pip insta ...

  5. 一个C++右值引用的问题

    暂时先不更新前一篇文章了,感觉那个文章要写好久.累死. 今天说一说C++右值引用的一个问题. 这个问题的发现也是很偶然的. 来一段毫无意义但是能证明问题的代码: std::string &&a ...

  6. 每天一点Linux系列之—vim

  7. Python PIL

    Python PIL PIL (Python Image Library) 库是Python 语言的一个第三方库,PIL库支持图像存储.显示和处理,能够处理几乎所有格式的图片. 一.PIL库简介 1. ...

  8. C++面试笔记(3)

    20. 浅拷贝与深拷贝 如何理解C++中的浅拷贝与深拷贝 深拷贝和浅拷贝 在进行对象拷贝时,当对象包含对其他资源的引用,如果需要拷贝这个独享所引用的对象,那就是深拷贝,否则就是浅拷贝 *** 21.构 ...

  9. 《A Knowledge-Grounded Neural Conversation Model》

    abstract 现在的大多数模型都可以被应用在闲聊场景下,但是还没有证据表明他们可以应用在更有用的对话场景下.这篇论文提出了一个知识驱动的,带有背景知识的神经网络对话系统,目的是为了在对话中产生更有 ...

  10. Qt 文件的操作

    文件操作是应用程序必不可少的部分.Qt 作为一个通用开发库,提供了跨平台的文件操作能力.从本章开始,我们来了解下 Qt 的文件以及输入输出的功能,也就是 I/O 系统. Qt 通过QIODevice提 ...