读龙书学编译原理 语法翻译(3)...

接着上节讲, 我们来看如何在分析中插入合适的代码来生成语法树...

对于抽象语法树的总结 :

下面是作业 :

【抽象语法树】

在这个题目中,你将完整的实现抽象语法树(包括数据结构的定义、语法树的生成等)。首先,请下载我们提供的代码包:

http://staff.ustc.edu.cn/~bjhua/mooc/ast.zip

代码的运行方式是:

首先生成语法分析器:

$ bison exp.y

然后生成编译器:

$ gcc main.c exp.tab.c ast.c

最后使用编译器编译某个源文件:

$ a.exe <test.txt

在提供的代码里,我们已经提供了抽象语法树的定义、若干操作、及由bison生成语法树的代码框架。你的任务是:

  1. 进一步完善该代码框架,使其能够分析减法、除法和括号表达式;(你需要修改语法树的定义,修改bison源文件及其它代码)
  2. 重新研究第一次作业中的从Sum编译到Stack的小型编译器代码,把他移植到目前的代码框架中,这样你的编译器能够从文本文件中读入程序,然后输出编译的结果。(注意,你必须扩展你的编译器,让他能够支持减法和除法。)

代码实现 :

 1 %{
 2 #include <stdio.h>
 3 #include "ast.h"
 4   int yylex(); // this function will be called in the parser
 5   void yyerror(char *);
 6
 7   Exp_t tree;
 8
 9   %}
10
11 %union{
12   Exp_t exp;
13  }
14
15 %type <exp> digit exp program
16
17
18 %left ‘+‘ ‘-‘
19 %left ‘*‘ ‘/‘
20
21 %start program
22
23 %%
24
25 program: exp ‘\n‘{tree = $1;}
26 ;
27
28 exp: digit     {$$ = $1;}
29 | exp ‘+‘ exp  {$$ = Exp_Add_new ($1, $3);}
30 | exp ‘-‘ exp  {$$ = Exp_Minus_new ($1, $3);}
31 | exp ‘*‘ exp  {$$ = Exp_Times_new ($1, $3);}
32 | exp ‘/‘ exp  {$$ = Exp_Divide_new ($1, $3);}
33 ;
34
35 digit: ‘0‘  {$$ = Exp_Int_new (0);}
36 | ‘1‘       {$$ = Exp_Int_new (1);}
37 | ‘2‘       {$$ = Exp_Int_new (2);}
38 | ‘3‘       {$$ = Exp_Int_new (3);}
39 | ‘4‘       {$$ = Exp_Int_new (4);}
40 | ‘5‘       {$$ = Exp_Int_new (5);}
41 | ‘6‘       {$$ = Exp_Int_new (6);}
42 | ‘7‘       {$$ = Exp_Int_new (7);}
43 | ‘8‘       {$$ = Exp_Int_new (8);}
44 | ‘9‘       {$$ = Exp_Int_new (9);}
45 | ‘(‘exp‘)‘ {$$ = $2;}
46 ;
47
48 %%
49
50 int yylex ()
51 {
52   int c = getchar();
53   return c;
54 }
55
56 // bison needs this function to report
57 // error message
58 void yyerror(char *err)
59 {
60   fprintf (stderr, "%s\n", err);
61   return;
62 }
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "ast.h"
 4
 5 // "constructors"
 6 Exp_t Exp_Int_new (int n)
 7 {
 8   Exp_Int p = malloc (sizeof (*p));
 9   p->kind = EXP_INT;
10   p->n = n;
11   return (Exp_t)p;
12 }
13
14 Exp_t Exp_Add_new (Exp_t left, Exp_t right)
15 {
16   Exp_Add p = malloc (sizeof (*p));
17   p->kind = EXP_ADD;
18   p->left = left;
19   p->right = right;
20   return (Exp_t)p;
21 }
22
23 Exp_t Exp_Minus_new (Exp_t left, Exp_t right)
24 {
25   Exp_Add p = malloc (sizeof (*p));
26   p->kind = EXP_MINUS;
27   p->left = left;
28   p->right = right;
29   return (Exp_t)p;
30 }
31
32 Exp_t Exp_Times_new (Exp_t left, Exp_t right)
33 {
34   Exp_Add p = malloc (sizeof (*p));
35   p->kind = EXP_TIMES;
36   p->left = left;
37   p->right = right;
38   return (Exp_t)p;
39 }
40
41 Exp_t Exp_Divide_new (Exp_t left, Exp_t right)
42 {
43   Exp_Add p = malloc (sizeof (*p));
44   p->kind = EXP_DIVIDE;
45   p->left = left;
46   p->right = right;
47   return (Exp_t)p;
48 }
49 // all operations on "Exp"
50 void Exp_print (Exp_t exp)
51 {
52   switch (exp->kind){
53   case EXP_INT:{
54     Exp_Int p = (Exp_Int)exp;
55     printf ("%d", p->n);
56     return;
57   }
58   case EXP_ADD:{
59     Exp_Add p = (Exp_Add)exp;
60     printf ("(");
61     Exp_print (p->left);
62     printf (") + (");
63     Exp_print (p->right);
64     printf (")");
65     return;
66   }
67   case EXP_MINUS:{
68     Exp_Minus p = (Exp_Minus)exp;
69     printf ("(");
70     Exp_print (p->left);
71     printf (") - (");
72     Exp_print (p->right);
73     printf (")");
74     return;
75   }
76   case EXP_TIMES:{
77     Exp_Times p = (Exp_Times)exp;
78     printf ("(");
79     Exp_print (p->left);
80     printf (") * (");
81     Exp_print (p->right);
82     printf (")");
83     return;
84   }
85   case EXP_DIVIDE:{
86     Exp_Divide p = (Exp_Divide)exp;
87     printf ("(");
88     Exp_print (p->left);
89     printf (") / (");
90     Exp_print (p->right);
91     printf (")");
92     return;
93   }
94   default:
95     return;
96   }
97 }

剩下的两个文件改动不大就不贴代码了...

时间: 2024-10-13 12:38:01

读龙书学编译原理 语法翻译(3)...的相关文章

读龙书学编译原理 语法翻译(1)...

完成了语法分析, 那么这一阶段最后要讨论的就是如何生成抽象语法树了...这一阶段称之为语法翻译 : 那么我们来看看翻译的基本思想 : 其实现如下 : 下面是具体实例 :

读龙书学编译原理 代码生成(1)...

这两天把编译器撸到了抽象语法树环节, 准备看完第八单元一口气撸完编译器...至于翻译成什么语言, 先看看再说... 之前讨论完语法检查和符号表, 那么前端就算全部结束了, 那么我们可以把视角转移到中后端... 其结构大概是这样的... 这个阶段就是所谓的代码生成, 那么代码生成具体要完成任务是这样的... 这里提到了2个重要的任务, 那么我们首先来看第一个 : 然后是第二个 : 为了讲解这些任务的解决方案, 这是接下来要讲解的两种ISA...

读龙书学编译原理 语法分析(1)...

首先我们来分析一下语法分析器的任务 : 将由词法分析器返回的Tokens(记号流)经过检查和处理生成根据规定的语法规则来生成抽象语法树... 最终大概是这样 (两个输入 一个输出): 然后是语法树, 大概是这样 : 那么接下来看看在这一阶段所需要学习的内容 : 大概就是这样...

读龙书学编译原理 手撸编译器(1)...

从上海回来这两天一口气看完了语义分析, 前段也就差不多了, 本来准备看代码生成的, 人突然就不想看了, 老毛病又犯了 : 很久没不敲代码, 手痒的不行, 所以决定边往前推进边实现前面的部分... 想到终于可以开始实现编译器心里就激动的不行, 那么就这么愉快的开始了... 首先当然是规定语言的词法语法, 由于第一次写编译器, 也不想搞得太过复杂, 我准备写的是一个简化版本的C语言, 大部分词法和语法都将才采用C语言标准... 首先是基本类型 : int, string,bool (这两个C语言里面

读龙书学编译原理 手撸编译器(2)...

经过一天的实践, 勉强写完了语法分析部分和词法分析的抽象语法树的生成部分... 但是也发现也昨天规定的词法和文法中出现的一些问题, 同时我根据情况进行了一些改动... prog -> func funcs | func -> type id () block block -> { stmts } stmts -> stmt stmts | stmt -> type id; | type id = judge; | id = judge; | if(judge) block |

读龙书学编译原理 语法分析(15)...

到这里词法分析模块就接近尾声了, 下面对词法分析模块进行总结 : 递归下降本质上也算是自顶向下的分析算法, 适合手工编码, 它相对来说更加灵活, 能够对于特定的DSL进行更加灵活的处理优化, 但是相对来说比较慢.而自动生成器则恰好相反, 接下来是一个LR(1)语法生成器的实例 -- YACC. 首先这是yacc所需的源文件的结构, 通过输入这个文件yacc能为我们生成实际的语法分析器的代码... 由图中可以看出该文件分为三个部分, 下面是实例代码 : 1 %{ 2 #include <stdio

读龙书学编译原理 语法分析(12)...

那么最后我就来看看这个所谓的lr(0)分析表生成算法 : 这个算法乍一看好像又和前面脱节了, 但是如果仔细看之前的讲解, 比如下图, 仔细比较, 感受一下 ... 你会发现 : 每次产生的D其实就相当于是一个新的状态, 那么再看一下closure 和 goto的具体实现 : 不难发现closure其实就是把所有原推导式左侧点的右侧的非终结符(也就是即将探索的第一个非终结符)的推导式全部加入这个集合, 那么为什么要这样做呢 ? 因为这个算法是并行的, 比如上图, 在执行推导式0的时候, 他需要先完

读龙书学编译原理 手撸词法生成器(3)...

今天撸了一个晚上终于完成了, 感觉还是要说一下体会吧... 其实之前课程本身已经提供了相关的算法伪代码, 那么在思路上应该没有问题, 那么最后我却用了一个晚上才完成最后的hopcroft 算法呢... 其实难点在于数据结构的运用, 这边图论算法熟悉的话应该会感觉轻松一些...(不幸的是我还没有系统的学过算法...) 就具体代码实现本身来讲, 第一个难点在于如何对已存在的状态进行切分, 比较说起来就是split而已, 但实际操作起来切得却是一串dfa的状态, 我刚开始准备只用一个State(用于第

读龙书学编译原理 手撸词法生成器(2)...

今天AI考的还算顺利, 没有不会做的, 目前也没发现错的, 在这里顺便也谈谈AI吧, 我之所以不选AI, 总感觉理论性太强, 学起来不来劲, 经历了大二这一个学期的理论学习, 这AI简直是神课啊, 真是怕了, 大三到英国肯定不选AI... 其实就算在今天下午在考试我也是一直惦记着我的词法生成器... 6点考完, 休息了一波8点左右就开始继续写我的词法生成器的第二部分(从NFA到DFA)了, 过程的还算是顺利, 2个小时左右也就写完了, 之后刷知乎刷到了现在, 真是浪费时间啊... 明天再写一下最