MiniPascal编译器-西工大编译原理实验

21/5/25更新

仔细想想,都过了快一年了,一年里真的经过了很多,因为考研不小心还错过了真爱。

去年没放代码上来,是因为查的严,怕出问题,最近好多来点赞关注的,就又想起这件事情了。

https://pan.baidu.com/s/1f1won95wqtUfYivXixBWDw

clhh

不过还是自己写一下更有感觉一点。

 


 

连续搞了三天的编译原理实验,从最开始啥都不会,到现在熟练地加文法、改bug,也算是小有心得,分享一下

我实现的这个相比要求的多了几个功能,比如:消除注释、FOR循环、多维数组、自动类型转换、类型检查、数组维数检查、还有一些错误提示之类的,画抽象语法树使用graphaz来画。

有几个关键点需要说一下:

环境

环境我用的codeblocks,网上下了个flex和bison的包,首先肯定是添加这两个的path路径,之后随便打开一个cmd,敲一个win_bison --help就会有下面这样的,当然具体时间win_bison还是Bison还是bison这取决于你下的包里究竟哪个exe文件叫啥。

之后打开codeblocks,选settings-》complier-》左拉到最后的other settings 的advanced opation,设置.l与.y文件的生成与编译语句:

编译:win_flex -L -o $file_dir\$file_name.c --header-file=$file_dir\$file_name.h $file_dir\$file_name.l

win_bison -v -d --output=$file_dir/$file_name.c --defines=$file_dir/$file_name.h $file_dir/$file_name.y

生成:$file_dir\$file_name.c
$file_dir\$file_name.h

$file_dir/$file_name.c
$file_dir/$file_name.h

之后创建对应的.l与.y文件就会自动.c和.h生成了,编译前需要先进行.l与.y的编译当前文件,之后才可以编译链接运行

文法

我是从网上下了一个有个大概框架的进行改造的,只说需要注意的:

.y文件里生命的union里最好都用struct,不然最后你想实现其他功能时就会发现规约时不能向上传递数据,很蛋疼。

网上下的那个里面符号表生成有点问题,临时变量不管啥都是int,所以你要在规约申请临时变量时就把类型给加上。

多维数组实现时,维度的定义与使用非常类似于原有的varlist的文法,简单改造,传递的参数改造一下文法加点东西就可以了。

注释消除用个状态机就行,非常简单。

FOR循环跟原有的while非常想,只要在开始加一个赋值语句,并在最后跳回前加一句自增运算就可以。

自动类型转换就是在进行算数运算时或进行赋值运算时,两个变量或常量不同类型,这时候只要判断一下类型,并且申请一个临时变量进行临时转换就可以。

类型检查同理,检查一下赋值或运算的时候是不是相似类型的int和real可以,但是real和array就不可以。

数组维数检查时,必须在定义的时候记录定义的维度与个维度长度,在使用时检查一下是否符合就可以。

错误提示建议直接输出提示字符,调用system(“pause”)暂停执行,之后直接exit(-1)结束运行,非常简单。

生成抽象语法树

可以写一个节点结构体,记录一些数据,造一棵树就可以了,数据结构的内容,非常简单。造的时候应该是规约结束时,将当前文法创建的创建,连接的连接,之后连在规约的那个节点上就好了。

画树

你有了一颗树之后,要把它画出来,下个graphaz的包出来,看看命令行能不能运行,建议直接放到工程目录下。因为c语言不能直接调用,所以你要先把树遍历一遍,边遍历边写一个描述文件,之后用来画图,类似这样:

然后在c里调用一个getcwd(NULL, 0)函数获得当前程序的目录,之前不是把画图包放着歌目录了么,你就可以找到里面的那个画图的dot.exe的路径了,当然你上面生成的这个文件也在这个下,使用system(“命令行”)来调用命令行,使用绝对路径来调用画图命令,就可以生成一个图片了,之后再system(“图片绝对路径”)就可以运行时自动打开这个图片了。

演示

我最后做出来的是这样的:

Program mini1;
Var a, b, c, d, e : Integer;
    arr1, arr2 : Array[10, 10] Of Integer;
    arr3 : Array[10, 10] Of Real;
Begin
    e := 1;
    For a := 0 To 9 Do
    Begin  
        For b := 0 To 9 Do
        Begin
            c := 1;
            While c <= 100 Do
            Begin
                If e <> 1 Then
                Begin
                    c := c * 10;
                End
                Else
                Begin
                    c := c * 20;
                    While d < (c + 2) Do
                    Begin
                        If (e <> 1) || !(e <> 1) Then
                        Begin
                            c := d * 10;
                        End
                    End
                End
            End;
            arr1[a][b] := c;
            arr1[b][a] := arr1[a][b];
            arr3[b][a] := (arr1[a][b] + 1.2) * d + 2;          
        End
    End
End

可以看到,非常复杂的也是可以的,比较完善的。

还有错误信息:

也算是能看了,感觉还行。

总结

这个实验还算有意思,我这大学就认真做过四次大作业,一次是C语言的,一次数据库的,几次计算机组成的(这个非常有意思),然后就是这个了。

确实学到了一些东西,以后也该学学命令行了。

这个东西说不定可以加到游戏里,感觉也是蛮有趣的。

顺便说一句,我爱西工大。

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值