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

根据前缀表达式文法,实现statements() 和expression() 两个函数。

并且要求使得语义分析在完成分析前缀表达式并输出中间代码的同时,也能够将前缀表达式翻译为中缀表达式, 且要求翻译后的中缀表达式中尽可能少用括号

  1. statements -> expression SEMI
  2. | expression SEMI statements
  3.  
  4. expression -> PLUS expression expression
  5. | MINUS expression expression
  6. | TIMES expression expression
  7. | DIVISION expression expression
  8. | NUM_OR_ID

举例如下: 输入"+ a * b c;"时,应输出中缀式为" a + b * c", 而不是"a + (b * c)"或"(a) + (b * c)"等。

最后测试效果如下:

其中未实现河流命名算法故为阉割版。为方便读者阅读并理解后自行更改,这里只提供初版(low版),其代码如下(DDL后会更新):

  1. //retinf.c
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <stdbool.h>
  6.  
  7. #include "lex.h"
  8.  
  9. char err_id[] = "error";
  10. char * midexp;
  11. extern char * yytext;
  12.  
  13. struct YYLVAL {
  14. int last_op; /* last operation of expression
  15. for elimination of redundant parentheses */
  16.  
  17. char * val; /* 记录表达式中间临时变量 */
  18. char * expr; /* 记录表达式后缀式 */
  19. };
  20.  
  21. typedef struct YYLVAL Yylval;
  22.  
  23. Yylval * expression(void);
  24.  
  25. char *newname(void); /* 在name.c中定义 */
  26.  
  27. extern void freename(char *name);
  28.  
  29. void statements(void) {
  30. Yylval *temp;
  31. printf("Please input an infix expression and ending with \";\"\n");
  32. while (!match(EOI)) {
  33.  
  34. temp = expression();
  35.  
  36. printf("The Expression Is %s\n", temp->expr);
  37. freename(temp->val);
  38.  
  39. free(temp->expr);
  40. free(temp);
  41. if (match(SEMI)) {
  42. printf("Please input an infix expression and ending with \";\"\n");
  43. advance();
  44.  
  45. }
  46. else {
  47. fprintf(stderr, "%d: Inserting missing semicolon\n", yylineno);
  48. }
  49. }
  50. }
  51.  
  52. Yylval * expression(void) {
  53. Yylval *tempToReturn;
  54. tempToReturn = (Yylval *)malloc(sizeof(Yylval));
  55.  
  56. Yylval *temp0, *temp1;
  57. while (match(PLUS) || match(MINUS) || match(TIMES) || match(DIVISION)) {
  58.  
  59. char op = yytext[];
  60. advance();
  61. temp0 = expression();
  62.  
  63. temp1 = expression();
  64.  
  65. bool tempToReturnIsPro = op == '*' || op == '/';
  66. bool temp0IsLower = temp0->last_op == PLUS || temp0->last_op == MINUS;
  67. bool temp1IsLower = temp1->last_op == PLUS || temp1->last_op == MINUS;
  68.  
  69. if (tempToReturnIsPro) {
  70. if (temp0IsLower && temp1IsLower) {
  71. tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
  72. sprintf(tempToReturn->expr, "( %s ) %c ( %s )",
  73. temp0->expr, op, temp1->expr);
  74. }
  75. else if (temp0IsLower) {
  76. tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
  77. sprintf(tempToReturn->expr, "( %s ) %c %s",
  78. temp0->expr, op, temp1->expr);
  79. }
  80. else if (temp1IsLower) {
  81. tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
  82. sprintf(tempToReturn->expr, "%s %c ( %s )",
  83. temp0->expr, op, temp1->expr);
  84. }
  85. else {
  86. tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
  87. sprintf(tempToReturn->expr, "%s %c %s",
  88. temp0->expr, op, temp1->expr);
  89. }
  90. }
  91. else {
  92. tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + );
  93. sprintf(tempToReturn->expr, "%s %c %s",
  94. temp0->expr, op, temp1->expr);
  95. }
  96. switch (op)
  97. {
  98. case '+':tempToReturn->last_op = PLUS; break;
  99. case '-':tempToReturn->last_op = MINUS; break;
  100. case '*':tempToReturn->last_op = TIMES; break;
  101. case '/':tempToReturn->last_op = DIVISION; break;
  102. default:
  103. break;
  104. }
  105.  
  106. printf(" %s %c= %s\n", temp0->val, op, temp1->val);
  107. freename(temp1->val);
  108. tempToReturn->val = temp0->val;
  109. return tempToReturn;
  110.  
  111. }
  112.  
  113. if (match(NUM_OR_ID)) {
  114. printf(" %s = %0.*s\n", tempToReturn->val = newname(), yyleng, yytext);
  115. tempToReturn->expr = (char*)malloc(yyleng + );
  116. strncpy(tempToReturn->expr, yytext, yyleng);
  117. advance();
  118. tempToReturn->last_op = TIMES;
  119. return tempToReturn;
  120. }
  121. else if (match(SEMI)){
  122. printf("");
  123. return;
  124. }
  125. else {
  126. tempToReturn->val = newname();
  127. advance();
  128. fprintf(stderr, "%d: Number or identifier expected\n", yylineno);
  129. return;
  130. }
  131. }

另:

  1. /*main.c XL分析器 */
  2.  
  3. main()
  4. {
  5. statements();
  6. }
  1. /*lex.c XL分析器 */
  2.  
  3. #include "lex.h"
  4. #include <stdio.h>
  5. #include <ctype.h>
  6.  
  7. char *yytext = ""; /* 当前词形,注意由于是直接指向
  8. 行缓冲区input_buffer,因此不是以'\0'结尾,
  9. 因此使用时要小心, 设初值为0, 表示缓冲区为空,
  10. 需要重新读行 */
  11. int yyleng = ; /* 词形的长度 */
  12. int yylineno = ; /* 输入的行号 */
  13.  
  14. lex()
  15. {
  16. static char input_buffer[];
  17. char *current;
  18.  
  19. current = yytext + yyleng; /* 跳过以读过的词形 */
  20.  
  21. while () { /* 读下一个词形 */
  22. while (!*current) {
  23. /* 如果当前缓冲区已读完,重新从键盘读入新的一行.
  24. 并且跳过空格
  25. */
  26.  
  27. current = input_buffer;
  28. /* 如果读行有误,返回 EOI */
  29. if (!fgets(input_buffer, , stdin)) {
  30. *current = '\0';
  31. return EOI;
  32. }
  33.  
  34. ++yylineno;
  35.  
  36. while (isspace(*current))
  37. ++current;
  38. }
  39.  
  40. for (; *current; ++current) {
  41. /* Get the next token */
  42.  
  43. yytext = current;
  44. yyleng = ;
  45.  
  46. /* 返回不同的词汇代码 */
  47. switch (*current) {
  48. case ';': return SEMI;
  49. case '+': return PLUS;
  50. case '-': return MINUS;
  51. case '/': return DIVISION;
  52. case '*': return TIMES;
  53. case '(': return LP;
  54. case ')': return RP;
  55.  
  56. case '\n':
  57. case '\t':
  58. case ' ': break;
  59.  
  60. default:
  61. if (!isalnum(*current))
  62. fprintf(stderr, "Ignoring illegal input <%c>\n", *current);
  63. else {
  64. while (isalnum(*current))
  65. ++current;
  66.  
  67. yyleng = current - yytext;
  68. return NUM_OR_ID;
  69. }
  70.  
  71. break;
  72. }
  73. }
  74. }
  75. }
  76.  
  77. static int Lookahead = -; /* 向前查看的词汇,设初值为-1
  78. 表示第一次调用match函数时
  79. 必须要读取一个词汇 */
  80.  
  81. int match(int token)
  82. {
  83. /* 判断token是否和当前向前查看的词汇相同. */
  84.  
  85. if (Lookahead == -)
  86. Lookahead = lex();
  87.  
  88. return token == Lookahead;
  89. }
  90.  
  91. void advance()
  92. {
  93. /* 向前都一个词汇 */
  94. Lookahead = lex();
  95. }
  1. /* lex.h XL分析器*/
  2. #define EOI 0 /* end of input */
  3. #define SEMI 1 /* ; */
  4. #define PLUS 2 /* + */
  5. #define TIMES 3 /* * */
  6. #define LP 4 /* ( */
  7. #define RP 5 /* ) */
  8. #define NUM_OR_ID 6 /* decimal number or identifier */
  9. #define MINUS 7
  10. #define DIVISION 8
  11. extern char *yytext; /* in lex.c */
  12. extern int yyleng;
  13. extern int yylineno;
  1. /*name.c XL分析器 */
  2.  
  3. #include <stdio.h>
  4.  
  5. char *Names[] = { "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
  6. "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15" };
  7.  
  8. char **Namep = Names;
  9.  
  10. extern int yylineno;
  11.  
  12. char *newname()
  13. {
  14. if (Namep >= &Names[sizeof(Names) / sizeof(*Names)]) {
  15. fprintf(stderr, "%d: Expression too complex\n", yylineno);
  16. exit();
  17. }
  18.  
  19. return(*Namep++);
  20. }
  21.  
  22. freename(s)
  23. char *s;
  24. {
  25. if (Namep > Names)
  26. *--Namep = s;
  27. else
  28. fprintf(stderr, "%d: (Internal error) Name stack underflow\n",
  29. yylineno);
  30. }

具体生成方法不一,使用makefile方式最好。

这里只提供基本的gcc 方式(部分linux中没有自带,自行安装)。

  1. gcc -c lex.c
  2.  
  3. gcc -c retinf.c
  4.  
  5. gcc -c name.c
  6.  
  7. gcc -c main.c
  8.  
  9. gcc -o namebalabala lex.o retinf.o name.o main.o
  10. //gcc -o namebalabala *.o
  11.  
  12. ./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. https://www.cnblogs.com/h2zZhou/p/5440271.html

    https://www.cnblogs.com/h2zZhou/p/5440271.html

  2. Forth 编译程序

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  3. nginx + gunicorn + flask项目发布

    程序安装(linux mint) gunicorn安装:pip install gunicorn nginx安装:sudo apt-get install nginx 配置 nginx默认配置信息在/ ...

  4. js 原型原型链

    个人的理解,有什么不正确的请指教,共同学习 //声明一个构造函数Personfunction Person(name,age){ this.name = name; this.age = age;} ...

  5. pgmpy安装

    1.anaconda安装,可能在cmd中输入conda会报错,是因为在安装的时候没有配置好环境变量,在安装的时候有一个框框没选(当时是not recommand), 解决办法:需要在系统环境变量中添加 ...

  6. Python 字符串String相关知识

    test.capitalize( )     |首字母大写 test.lower( )             |全部变成小写(只能处理英文字母) test.casefold( )         | ...

  7. python builtin列表

    Python Builtin function获得通过 python3 -c "import builtins;ff=open('test.txt','w');strlist=[(i+'\n ...

  8. jmeter之headers中的Content-Type.

    jmeter在发送http post请求时,会把body  里的数据格式给携带上(最好携带上),一般在信息头里增加.另因一篇文章.感觉写的非常好.https://imququ.com/post/fou ...

  9. selenium的定位方式

    1.selenium的定位方式 selenium有18种定位方式,8种单数,8种复数,2种父类 2.8种单数定位方式 from selenium import webdriverimport time ...

  10. AIX下core文件的分析

    笔者曾在AIX系统下使用C语言开发多个应用系统.众所周知,C语言编写程序时容易出现内存使用不当的BUG,例如内存越界.使用野指针.内存未初始化等等.在程序运行时,这些BUG很可能造成程序崩溃,但在测试 ...