编译原理学习笔记(五)语法制导定义
2017-04-12 21:06
429 查看
在初学编译原理时的第二章中就给了制导翻译程序的例子,在第五章中又再次提到,不过更加详细。
上次做的预测分析器还有不完善的地方——目前只能进行语法分析,不能产生语义动作。可以使用语法制导定义的方法来完成。
语法制导定义是上下文无关文法和属性以及规则的结合,属性与文法符号相关联,规则和产生式相关联。非终结符具有两种属性:综合属性和继承属性。分析树上的非终结符的综合属性是由产生式所关联的语义规则来定义的,其来源为自身属性以及其子结点的属性。继承属性是由父结点上所关联的语义规则定义,其属性值的来源是父结点、本身以及兄弟结点。
各个结点的属性值是存在依赖关系的,如3+2这样一个简单的表达式,以语法树的形式表示出来时,最终求出值的父结点的值依赖于两个子结点的值(先得到3、2,然后才计算得到5)。因此求值必须要按照一定的顺序。书中提到的具体求值顺序的算法涉及到拓扑排序,但因为我所要编的编译器的语法是比较简单的,只需要求综合属性即可,因此无需该算法。
如何将语义的内容附到之前的预测分析结构中去?我的思路是这样的:
建立一个语义单元结构,用以对应于某一个产生式,它关联一个语义动作,这个动作将在配置文件中定义。这个语义单元的对象在每一个非终结符的产生式展开时创建,创建后压入一个栈中,表示当前结点的父结点,当终结符匹配时,进行求值,并将结果通过栈返回给父结点,当父结点子结点均求值完毕时,弹出并将结果继续返回,直到栈空,求出最终值。这其实就是一个用栈模拟先序遍历的过程。代码如下:
目前面临的难题是如何来定义配置文件,使之可以表达出想要的语义动作,并且能够检查语义规范。
目前在语义单元结构中定义了一个映射表,将产生式与动作相关联,但smt_action还没有定义。目前只能将各个字符串连接并输出:
可以看出是一个深度遍历的过程。
上次做的预测分析器还有不完善的地方——目前只能进行语法分析,不能产生语义动作。可以使用语法制导定义的方法来完成。
语法制导定义是上下文无关文法和属性以及规则的结合,属性与文法符号相关联,规则和产生式相关联。非终结符具有两种属性:综合属性和继承属性。分析树上的非终结符的综合属性是由产生式所关联的语义规则来定义的,其来源为自身属性以及其子结点的属性。继承属性是由父结点上所关联的语义规则定义,其属性值的来源是父结点、本身以及兄弟结点。
各个结点的属性值是存在依赖关系的,如3+2这样一个简单的表达式,以语法树的形式表示出来时,最终求出值的父结点的值依赖于两个子结点的值(先得到3、2,然后才计算得到5)。因此求值必须要按照一定的顺序。书中提到的具体求值顺序的算法涉及到拓扑排序,但因为我所要编的编译器的语法是比较简单的,只需要求综合属性即可,因此无需该算法。
如何将语义的内容附到之前的预测分析结构中去?我的思路是这样的:
建立一个语义单元结构,用以对应于某一个产生式,它关联一个语义动作,这个动作将在配置文件中定义。这个语义单元的对象在每一个非终结符的产生式展开时创建,创建后压入一个栈中,表示当前结点的父结点,当终结符匹配时,进行求值,并将结果通过栈返回给父结点,当父结点子结点均求值完毕时,弹出并将结果继续返回,直到栈空,求出最终值。这其实就是一个用栈模拟先序遍历的过程。代码如下:
void nc_parser::translate(string code,string mode){//mode为起点的选择 通常为产生式的起始符 但由于NC程序的特殊,这里当默认为语句stmt(指令的翻译占大多数) syn_unit end(0); syn_unit start(mode, mesh_table[mode]->src.lex, 0, syn_unit::NONTERMINATOR); stack<syn_unit> stk; stack<smt_unit> smt_stk;//维护一个语义栈 当产生式展开时将其压入栈中(作为父节点存在) 用于获取匹配的值 stk.push(end); stk.push(start); int pos = 0; auto lx_unit = lex->getNextToken(code,pos); while (stk.top() != end){// && pos < code.length() auto&cur_sig = stk.top();//当前 //查表决定展开式: auto type = cur_sig.type; switch (cur_sig.type){//符号类型 case syn_unit::EMPTY://匹配空符前 先清算父结点 case syn_unit::LEX://终结符 if (cur_sig.type == syn_unit::EMPTY || lx_unit->compare(cur_sig.token)){//类型是否匹配 cur_sig.buf = lx_unit->get_result();//匹配语法单元 auto*sem = &smt_stk.top();//当前语义处理块 sem->calculate(&cur_sig);//计算属性值 while (!smt_stk.empty() && sem->is_calcu_over){ //如果该语义块计算完了 就输出/把值通过栈交给父结点 sem->output(); auto p = *sem;//临时存储当前弹出值 smt_stk.pop(); if (!smt_stk.empty()){ sem = &smt_stk.top(); sem->calculate(&p); } }//弹出栈顶所有计算完毕的父节点 stk.pop(); } else{//失配 尝试别的? report("不匹配的类型:"+lx_unit->token); } if (type!=syn_unit::EMPTY)//句子没扫描完才继续读token lx_unit = lex->getNextToken(code,pos);//匹配后才后移 break; case syn_unit::NONTERMINATOR: auto&prod = mesh_table[cur_sig.token];//获取产生式组 if (prod->drivetable.find(lx_unit) != prod->drivetable.end() || prod->drivetable.find(NULL) != prod->drivetable.end()){ //该单词在驱动表中 stk.pop(); int choice; if (prod->drivetable.find(lx_unit) != prod->drivetable.end()) choice = prod->drivetable[lx_unit]; else choice = prod->drivetable[NULL]; auto&dst = prod->dst[choice];//选择产生式 for (auto&var = dst.rbegin(); var != dst.rend(); var++) stk.push(*var); //展开并逆序压入栈 smt_stk.push(smt_unit(prod, choice)); //维护语义栈 } break; } } }
目前面临的难题是如何来定义配置文件,使之可以表达出想要的语义动作,并且能够检查语义规范。
struct smt_unit{ public: static map<production*,smt_action*>table; static void init(); private: production*pd;//产生式指针 int cho;//选择哪一个产生式 int cur;//当前计算完成数 string result;//计算结果 public: vector<string>value; void calculate(syn_unit*);//求值 传入语法单元 void calculate(smt_unit*);//求值 传入其他语义单元的结果 bool is_calcu_over; void output();//输出值 smt_unit(production*,int); };
目前在语义单元结构中定义了一个映射表,将产生式与动作相关联,但smt_action还没有定义。目前只能将各个字符串连接并输出:
可以看出是一个深度遍历的过程。
相关文章推荐
- 编译原理学习笔记(二)——高级语言及其语法描述
- 【编译原理龙书笔记】(二)一个简单的语法制导翻译器(仍未完成)
- 编译原理学习笔记(一)制导翻译器
- 编译原理学习笔记---语法
- 编译原理之学习 lua 1.1 笔记 (四) 多变量赋值和函数多返回值
- 编译原理学习笔记一(待续)
- 编译原理学习笔记01——(通过老外吃中餐—学最基本文法概念)——2014_1_11
- VC++学习笔记之程序编译原理
- 编译原理学习笔记06——(连连看—准备一下很多课件都演示的公式E → E+T | T )——2014_1_22
- Java菜鸟学习笔记--语法篇(四):BitOperator原理与详解
- 【学习笔记】编译原理:编译程序概述
- (转)Android开发学习笔记(二)——编译和运行原理(1)
- 编译原理——学习笔记
- 编译原理学习笔记03——(唐僧团队智过平顶山—学从上而下语法树)——2014_1_16
- 编译原理学习笔记09——(比蜡还要没有味道的——枯燥的LL)——2014_1_25
- 编译原理之学习 lua 1.1 笔记 (三) 表对象 array 及其相关指令
- Android开发学习笔记(二)——编译和运行原理(1)
- 编译原理学习笔记
- 韩顺平_轻松搞定网页设计(html+css+javascript)_第19讲_js运行原理_js开发工具介绍_js程序(hello)_js基本语法_学习笔记_源代码图解_PPT文档整理
- 编译原理学习笔记04——(孙悟空学72变之菩提老祖的阴谋—可怕的左递归)——2014_1_18