打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C语言解释器的实现

C语言解释器的实现--序(零)

    在写CuteC文本编辑器的同时,为了使之有脚本执行能力。特意实现了一个简易的C语言解释器,所谓的解释器,就是它是解析执行脚本文件的,并不产生可执行的目标代码。它具备了C语言的几乎全部的语法。随着时间的推移,我打算把它作为一个独立的项目来开发了。在这个过程中,自己也学到了不少的知识,所以也打算跟大家分享。写这些东西,虽然是重复发明轮子的事,但也不至于是在浪费生命。程序员嘛,我总觉得应该是要理解我们每天所编译出来的程序是怎么被执行,应该明白我们敲打的每行代码的实际意义。
    我打算写一个系列的文章来说明这个解释器的实现过程,其中对于编译原理的理论知识不做太多的讲解,一是不容易提高大家的积极性,二是自己水平有限。所以我觉得大部分从例子出发,讲解一个个目标的实现过程,大家慢慢体会,估计收获会比较大。
   
    通过这一系列的文章,大家应该可以学到以下的知识。
    1.更深入的理解C的内部细节,对以后的开发总是有好处的。例如,你能很清楚C语言的类型定义,通过基本的类型为何能够定义出无穷的各种类型。
    2.了解表达式的解析,中间代码的产生。这点非常有意思,了解了这点,可以用同样的方法做很多事情,包括设计个计算器,解析复杂的配置文件,在软件中解析命令等等。
    3.对编译器有一个感性的认识,虽然离写出编译器还比较遥远,但对于语法解析,预编译,理解的就比较深入了。现在很多软件都有预编译的模块在里面,比如Pro*C, GSoap等等。
    4.我们产生的中间代码其实已经非常接近汇编代码,这对理解C的执行过程总是有好处的。
   
    总之,晒晒自己的成果,怎么说也是我亲亲苦苦写出来的,希望大家能找到点可以借鉴的东西吧~代码我还在努力的编写,过一段时间再放出来一个初级的版本。如果工作忙,那估计就要再等一段时间了。

    以前我发过上一个版本的解释器,可以在这篇文章中下载,不过我现在已经重写了解释器,所以要看结果可以先下载下来看看:)。

posted @ 2011-12-16 17:18 linxr 阅读(1672) 评论(8) 编辑 收藏
评论列表
  
#1楼 2011-12-17 09:31 对镜弹箜篌  
lz继续啊
  
#2楼 2011-12-17 10:38 ayanmw  
原来如此,如果做出来,其实很强大的,其实你在写一个C虚拟机,和什么Java虚拟机,Python虚拟机,.net虚拟机 差不多了...
无非就是 编译原理 中的语法解析,然后再动态的实现.说到容易,做时难.
如果有成品了,我愿意去测试,去尝试,去推广.
  
#3楼 2011-12-17 19:31 troubadeur  
Hi, I found you!
  
#4楼[楼主] 2011-12-18 00:46 linxr  
@troubadeur
你吓我一跳
  
#5楼 2012-01-17 16:19 吕子熏  
不太建议将一个脚本类的语言设计成类C 那样,如果硬将C的设计方式硬套到解释型的脚本上,很诡异的。毕竟没有人关心我声明的变量是int,double,还是char* ; C之所以那样具有强类型声明,以及指针等,是因为他是经典意义上的编译语言。其实你想要的是类似C那样的语法规则而已。不太清楚你语法分析生成的那个中间语言描述是什么样子的,瞅着不太像类汇编型的(没发现描述操作数的地方,一个exp,stm,看着太抽象)。个人建议,对于语法特性上做些选择性的实现吧,对变量的声明采用弱类型,添加string的操作,以及提供些基础的数据结构等。 当你实现到这步时,你就会发现对申请的变量很难做控制,此时加上GC 跟 VM 吧。其实你要做的东西很多~~ 不过想法蛮赞的哦,毕竟这年头能想着造轮子的人挺少的,尤其是像解释器/编译器这样的高级轮子。

PS: 不明白你内部怎么执行那段中间代码的,但是解释执行的速度确实太慢了。刚才做了测试对5000个数据进行选择排序我跑了2分半都没跑完! 贴下我以前做过测试的语言速度:
C 16MS
LUA 890MS
PERL 4281MS
ALEX 12672MS
(cpu:inter pentium 双核E5400 @ 2.70ghz)。
  
#6楼[楼主] 2012-01-18 20:51 linxr  
@吕子熏
呵呵,你说的很有道理。因为重新设计一门语言对我来说估计会比较困难,所以就直接用C的语法了,呵呵,是蛮诡异的。

执行速度是很慢的,现在我放上去的是我得初级版本,没有中间代码。我写得文章是对应我得新版本的,不过还没有全部写完。所以也就没放上来。

新版本的效率应该速度会比较快,老版本的因为没有中间代码,所以是边解析语法,边运算,一层一层递归下去。所以很慢。新版本的中间代码的执行就快多了,也模拟了C语言的函数调用过程。所以效率应该会提高不少,因为执行的时候不用再去解析语法了。

等我写完了,我再把代码发布上来,到时大家一起讨论。
  
#7楼[楼主] 2012-01-18 21:10 linxr  
@吕子熏
呵呵,我刚才测试了下我得新版本的。下面是我的选择排序的代码。排序我自己数了数,6s差不多就跑完了。我得cpu比较好,i7 2.0GHz, 4核双线程的。
int select( int *a, int len )
{
int i, j, x, tmp;
for( i=0; i<len; i++)
{
int min = i;
for( j=i+1; j<len; j++ )
{
if( a[j] < a[min] )
min = j;
}

tmp = a[min];
a[min] = a[i];
a[i] = tmp;
}
}

int show( int *a, int len )
{
int i;
for (int i=0; i<len; i++)
{
printf( "%d ", a[i] );
}
printf( "\n" );
}

int main()
{
int i;
int a[5000];
for( i=0; i<5000; i++ ){
a[i] = rand()%5000;
}

show(a, 5000);
select(a, 5000);
show(a, 5000);
return 0;
}
  
#8楼 2012-01-18 22:56 吕子熏  
其实你模拟函数调用的过程,解释中间代码这些,是在做vm的工作。既然本身就是托管类型的语言,你就要捕获在vm中出现的异常;同时,当异常出现后要明确的显示出当前异常是什么类型,以及出现在源代码的第几行。对于堆上申请的内存,不建议抛给程序员去管理,毕竟这不是像c那样的编译型语言,面向的直接是cpu。托管类型的语言直接面对的vm,vm面向的才是真正的cpu,所以对内存的管理应该放到vm上来做。此时你就需要添加gc...... 怎么说那:vm,gc,中间指令集这些都没法跑掉。除非你做的是个DSL一个轻量级的描述性语言,过程仅仅就只有lex跟parse。

解析中间代码执行指令这块,最重要的任务就是怎么快,怎么来。代码的可读性为了性能完全可以牺牲!对于被频繁调用的指令(例如: pop,push,mov等),如果解析指令代码比较少的话,都用宏展开。大面积的产生函数调用,你会发现此处的开销是惊人的。中间指令的设计尽量增加其描述性,同样的一段代码被翻译成的中间指令越少越好。 其实你做到最后就会发现,你大部分的工作都会耗在对vm和中间指令进行优化上了。 这也可能是为什么一个编译器/解释器优化部分最难做的原因吧, 呵呵
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
手把手教你做一个 C 语言编译器(1):设计
虚拟机
解释型和编译型程序设计语言
JVM 专题十五:执行引擎
C,Java和Python三门编程语言性能比较
Lisp 的永恒之道
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服