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

根据前缀表达式文法,实现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. H5样式(个人使用)

    @*定义全局样式*@ <style> body, ul, li, p, h1, h2, h3, h4, h5, h6, hr, span, form, fieldset, table, t ...

  2. ORACLE数据库管理员的职责

    ORACLE数据库管理员的职责 一.概述 ORACLE数据库管理员应按如下方式对ORACLE数据库系统做定期监控: (1). 每天对ORACLE数据库的运行状态,日志文件,备份情况,数据库的空间使用情 ...

  3. GC 是什么? 为什么要有GC?

    C/C++中由程序员进行对象的回收像学校食堂中由学生收盘子,.Net 中由GC 进行垃圾回收像餐馆中店员 去回收. GC 是垃圾收集器(Garbage Collection).程序员不用担心内存管理, ...

  4. Asp .Net Core Spa (一) - 入门

    第一次写文章, 很久之前就想写来着了, 文章哪里不清楚的, 也请多多提出意见. 最近发现用 .net core + spa (single page application) 这个组合的人也变多了, ...

  5. URL 通过Get方式传递数组参数

    URL 通过Get方式传递数组参数 方法1: ?id=1&id=2&id=3 后台获取时,只需要reqeust.getParameterValues("id") 获 ...

  6. HTML中data-* 属性

    使用 data-* 属性来嵌入自定义数据: <ul><li data-animal-type="bird">Owl</li><li dat ...

  7. 为什么Python是最适合初创公司的编程语言?

    为什么Python是最适合初创公司的编程语言? 选自Medium 作者:Gleb Pushkov 京东云开发者社区编译 对于初创公司而言,要在众多编程语言中为公司选择一个正确.合适的语言绝非易事. 如 ...

  8. Codeforces Round #479 (Div. 3) F. Consecutive Subsequence (简单dp)

    题目:https://codeforces.com/problemset/problem/977/F 题意:一个序列,求最长单调递增子序列,但是有一个要求是中间差值都是1 思路:dp,O(n)复杂度, ...

  9. 微信小程序 拖动图片一边进行截取

    简单实现一个画布截取图片的功能 原始图片超出指定尺寸,会进行隐藏,利用短边的宽度截取长边的宽度,拖动生成指定内容的图片 横图 竖图 var box_width = 600; //截取框尺寸 var b ...

  10. Blinn-Phong模型

    最近在看基础光照模型,比较感兴趣的是高光反射模型,有下列两种: 1.Phong模型 R = 2*N(dot(N, L)) - L specular = lightColor * SpecularCol ...