免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2076 | 回复: 6
打印 上一主题 下一主题

中间代码生成疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-05-17 12:08 |只看该作者 |倒序浏览
在语法制导翻译阶段,当使用某个产生式进行如归约时,就执行相应的语义动作,如:
S->id:=E {p=lookup(id.name);if(p!=nil)emit(p':='E.place);else error();}
花括号即语义动作,我的问题是,这段代码是写在文法定义文件中的,那么,当我们的编译器在使用该产生式进行处理时,是如何调用这段代码的,关键的问题是这段代码并不是在编译器中的。
一种做法是读取这段代码,然后根据代码的不同,在编译器中编写相同处理的代码进行执行,例如在编译器中编写emit()函数,而在翻译过程中发现动作也有emit,就调用编译器中编写的函数,这样虽然可以,但效率不好,而且动作中的其他语句如if也要进行处理,相当于又要对动作中的语句进行解析执行
另一种做法像YACC,将其作为代码段复制到某个源文件如.c中,然后使用C编译器编译执行

如果像YACC的做法,难道说所有的编译器都将语法动作复制到另外的源文件后编译执行以生成中间代码。
若不是,又无法直接执行动作代码。

请教高手们,此问题应如何解决呢????

论坛徽章:
2
摩羯座
日期:2013-10-10 14:29:04天蝎座
日期:2014-01-03 09:14:49
2 [报告]
发表于 2012-05-17 14:43 |只看该作者
> 关键的问题是这段代码并不是在编译器中的。

这是什么意思?编译器里不实现这个产生式?

论坛徽章:
0
3 [报告]
发表于 2012-05-17 14:56 |只看该作者
回复 2# EricFisher

假设有一个产生式S->A {x},其中的x部分为语义动作,当我们使用yacc时,它根据S->A的规则帮我们生成一个.c的源文件,即编译器源代码文件,并且将x的代码复制其中,这样,我们用c的编译器编译该文件时,则x代码与生成的代码作为整体被合并与编译,在生成的编译器源代码中可以直接执行x的代码段
但如果我们自已写了一个编译器,根据S规则进行语法分析,那么当OK了之后,我们写的编译器要执行x的代码,但此时x的代码对我们写的编译器来说只是一个代码段,只是一段文本,问题就是如何让这段代码被执行

这有点类似在SQL中,我们可以写一个语句SELECT * FROM XX,然后执行,但在SQL中,我们也可以定义一个变量v,并置v为:
v = "SELECT * FROM XX",然后通过 exec(v)来执行
   

论坛徽章:
2
摩羯座
日期:2013-10-10 14:29:04天蝎座
日期:2014-01-03 09:14:49
4 [报告]
发表于 2012-05-17 16:34 |只看该作者
前端语法分析部分,如果是手工编写,需要为文法的非终结符编写相应的语法分析函数,根据输入的下一个待处理的单词选择恰当的产生式。在编写这些分析函数的时候,将动作语句嵌入到分析过程中就可以了。比如gcc中,之前是用yacc写的,现在已经改成手写。下面的代码是while语句的分析函数。
  1. /* Parse a while statement (C90 6.6.5, C99 6.8.5).

  2.    while-statement:
  3.       while (expression) statement
  4. */

  5. static void
  6. c_parser_while_statement (c_parser *parser)
  7. {
  8.   tree block, cond, body, save_break, save_cont;
  9.   location_t loc;
  10.   gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
  11.   c_parser_consume_token (parser);
  12.   block = c_begin_compound_stmt (flag_isoc99);
  13.   loc = c_parser_peek_token (parser)->location;
  14.   cond = c_parser_paren_condition (parser);
  15.   save_break = c_break_label;
  16.   c_break_label = NULL_TREE;
  17.   save_cont = c_cont_label;
  18.   c_cont_label = NULL_TREE;
  19.   body = c_parser_c99_block_statement (parser);
  20.   c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
  21.   add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
  22.   c_break_label = save_break;
  23.   c_cont_label = save_cont;
  24. }
复制代码
这里的c_finish_loop就是执行一个动作。

论坛徽章:
0
5 [报告]
发表于 2012-05-19 14:32 |只看该作者
回复 4# EricFisher


    使用函数的方式没YACC那么灵活
   昨天下载了WINDOWS版的LEX与YACC工具Parser Generator,安装后里面包含了源码,有两个版本C与JAVA,C的代码量异常多,而JAVA相对少了很多,不知是什么原因,而且C版本的似乎非常复杂

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
6 [报告]
发表于 2012-05-22 17:34 |只看该作者
shecx 发表于 2012-05-17 14:56
回复 2# EricFisher

假设有一个产生式S->A {x},其中的x部分为语义动作,当我们使用yacc时,它根据S->A ...

那还不是一样吗?
自己手写的话
parse()
{
    if(....) {
   ....
    else if(S(now)==OK) {
        ....//你要执行的代码
    }

}

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
7 [报告]
发表于 2012-05-22 17:37 |只看该作者
cjaizss 发表于 2012-05-22 17:34
那还不是一样吗?
自己手写的话
parse()

一般来说,手写状态机还是:
parse()
{
     while(READ_WORD/*词法分析*/()) {
           cal(now_stat);
           switch(now_stat) {
                case S:
                        //做什么?
                ....
                default:
                       .....
           }
     }
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP