posts - 57,  comments - 191,  trackbacks - 21

这个基于LL分析器的计算器是大三时上编译原理的一个作业。感觉是自己做过相对比较有深度的一个程序。第一次放出来跟大家分享。希望多多指教。

这个计算器支持带括号的四则运算和乘方运算。具体实现过程如下:

词法分析器:

        相关正则定义:

            DIGIT     [0-9]

            NUMBER  {DIGIT}((.{DIGIT}+)|{DIGIT}*)

            DELIM    [ \t\n]

            OPERATOR [+|-|*|/|^|(|)|=]

        识别数值的DFA的状态转换图:

            

        

 

词法分析器的构造:

            因为要识别表达式中的负数(形如1+ -1),这个工作有两个做法,一个是在词法分析的过程中使得词法分析器可以识别负数。一个是词法分析器只识别正数,让语法分析器去识别负数还是减法运算符。前一种方法不是一个标准的词法分析程序可以完成的,因为它要引用上下文。至少向前看一个字符。这就是LL文法或LR1)文法的范围了。所以使用第二种方案。这也是大多数情况下所采用的方案。

    文法分析器:

        计算器的功能:计划包括含括号的实数四则运算和乘方运算。同时还可以识别出负号。

        初期文法:

 

        

 

将上述文法消除左递归可得出下面的文法:注意乘方运算是具有右结合性的。而四则运算是左结合的。由于LL分析法本身的限制,要将一个非二义也非左递归的一个产生式:进行转化(因为它有公共的左因子),使其可以用LL分析法进行分析。

           

       

 

计算出上述文法的FIRST集和FOLLOW集,如下:

 

         

 

 

  

 

 分析表的建立:因为空间原因,表项中只给出产生式的右部

 

id

+

-

*

/

^

(

)

$

E

TE’

 

TE’

 

 

 

TE’

 

 

E’

 

+TE’

-TE’

 

 

 

 

T

FT’

 

FT’

 

 

 

FT’

 

 

T’

 

*FT’

/FT’

 

 

F

N

 

-N

 

 

 

N

 

 

N

MN’

 

 

 

 

 

MN’

 

 

N’

 

^N

 

M

Id

 

 

 

 

 

(E)

 

 

文法的分析表

   

 

文法分析表建立完成之后,就可以开始写程序了。代码如下:

 

 

Code

 

可以看到,一个简单的计算器就有如此多的步骤。一个复杂的编译器的建立过程,即使有Yacc和Lex等的帮助,也是不容易的。

 

posted on 2008-11-20 20:20 南柯之石 阅读(1408) 评论(9)  编辑 收藏 网摘

FeedBack:
2008-11-20 20:56 | 怪怪      
和书上差不多 :)

LZ要是能就一些细节展开,想必能吸引更多读者。如:

“LL分析法本身的限制”

给大家分析一下这个限制,等等 :)

  回复  引用  查看    
#2楼[楼主]
2008-11-20 21:05 | 南柯之石      
@怪怪

谢谢你的建议。

这个例子的确是和书上差不多。书上是二则运算,我只是变成了四则+乘方。

也许当时来写“LL分析法本身的限制”能有不少要写的。不过现在距写这个程序也已经过去很久了。只是因为最近在看SharpDevelop里对BOO的Code Completion的支持,想起了这个曾经的小东西。放硬盘里还不去挂上来,也许还能给刚入门读者一些参考。:)

  回复  引用  查看    
2008-11-20 21:06 | 包建强      
递归向下虽然速度慢,但是翻译的时候就简单了.
自下而上真的是太繁了

  回复  引用  查看    
2008-11-20 21:07 | 包建强      
我记得SharpDevelop 1.1中是递归向下的文法分析器
  回复  引用  查看    
2008-11-20 21:20 | JimLiu      
我也在写Yacc,现在用的是LR(0),留了抽象类做接口,以后再尝试LR(1)等方法。
  回复  引用  查看    
#6楼[楼主]
2008-11-20 21:38 | 南柯之石      
@包建强

LR只能算是耳闻了。

现在SharpDevelop里Boo的确是用LL的,因为是动态语言,所以支持得不太好。C#和BOO用的好像不是一个方法。

  回复  引用  查看    
2008-11-21 02:29 | 怪怪      
@包建强
自顶向下也不代表一定要递归下降,比如还有预测分析法。而递归下降也并不是慢的代名词,最终还要看你支持的文法和实现的细节。

至于自底向上的规约,手工去写确实繁琐,不过工具很多,就是自己写可能也是先写一个CC了。就LR来说,它的优点并不在于效率,而是在至少相同的效率下,可以兼顾更广泛的文法。

不过最近的潮流,用Strustroup的一句话概括,很多时髦编译器都是递归下降打造的。据说好懂、改起来自在,代码也好维护~

  回复  引用  查看    
2008-11-21 08:19 | 装配脑袋      
LL或者递归下降等都不能算是慢,实际上LL型递归下降Parser速度就很快。LL表驱动Parser完全可以做得和LR一样(前提是LR生成器生成的足够好:)。递归下降的Parser非常好写,可以算是想到哪写到哪,而且整个过程能够提供足够的代码支持。不使用YACC和Lex,也可以写出LL递归下降Parser。但LR文法支持更多的写法。大部分语言都有LR文法,而且就算有LL文法通常也不如LR直观。
  回复  引用  查看    
2008-11-21 08:27 | 装配脑袋      
如果学过一点语言和自动机理论,了解使用集合来表示状态的思想,那么理解LR(k)的建立过程是非常容易的。而且是一个十分适合机器生成的机械算法。有些旧的编译原理试图用手工建立的方式获得LR状态转换表,实在是缺乏实用价值。就连一个小小的四则运算,手工生成的也未必能保证正确。
  回复  引用  查看    
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1337930




相关文章:

相关链接:
<2008年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

本人保留本博客所有文章版权,未经得本人同意的转载,必须在明显位置注明文章出处及作者,否则视为侵权。

与我联系

搜索

 

常用链接

留言簿

我的标签

随笔档案(55)

文章档案(3)

积分与排名

  • 积分 - 38558
  • 排名 - 1568

最新评论

阅读排行榜

评论排行榜

60天内阅读排行