编译实验三--生成中间代码

一.实验目的

通过语法制导或翻译模式生成中间代码。

二.实验环境

①开发语言:java
②开发环境:jdk1.8

三.功能描述

理解并应用课本的语法制导定义。
在自底向上语法分析基础上设计语义规则(语法制导翻译),将源程序翻译为四元式输出,若有错误将错误信息输出。

四.文法和分析表

文法:
program → block
block → { stmts }
stmts → stmt stmts | e
stmt → id= expr ;
| if ( bool ) stmt
| if ( bool) stmt else stmt
| while (bool) stmt
| do stmt while (bool ) ;
| break ;
| block
bool → expr < expr
| expr <= expr
| expr > expr
| expr >= expr
| expr
expr → expr + term
| expr - term
| term
term → term * factor
| term / factor
| factor
factor → ( expr ) | id| num

语义规则SDD

产生式语义规则
program → block
block → { stmts }block.addr=stmt.addr block.code=stmt.code
stmts → stmt stmts1stmts.addr=new Temp() stmts.code=stmt.code//stmts1.code
stmts → stmtstmts.addr=stmt.addr stmts.code=stmt.code
stmt → id= expr ;stmt.code=expr.code//gen(top.get(id.lexeme)'='id.addr)
stmt → if ( bool ) stmt1stmt.addr=new Temp() stmt.code=bool.code//label//L1//stmt1.code//Label//L2
stmt → if ( bool) stmt1 else stmt2stmt.addr=new Temp() stmt.code=bool.code//label//L1//bool.code//label//L2//stmt1.code//goto L3//label//L2//stmt2.code//lable//L3
stmt → while (bool) stmt1stmt.addr=new Temp() stmt.code=label//L1//bool.code//label//L2//stmt1.code
stmt → do stmt1 while (bool );stmt.addr=new Temp() stmt.code=label//L1//bool.code//label//L2
stmt → break ;goto next
stmt → blockstmt.addr=new Temp() stmt.code=block.code
bool → expr1 < expr2bool.addr=new Temp() bool.code=expr1.code//expr2.code//gen(bool.addr'='expr1.addr'<'expr2.addr)
bool → expr1 <= expr2bool.addr=new Temp() bool.code=expr1.code//expr2.code//gen(bool.addr'='expr1.addr'<='expr2.addr)
bool → expr1 > expr2bool.addr=new Temp() bool.code=expr1.code//expr2.code//gen(bool.addr'='expr1.addr'>'expr2.addr)
bool → expr1 >= expr2bool.addr=new Temp() bool.code=expr1.code//expr2.code//gen(bool.addr'='expr1.addr'>='expr2.addr)
bool → exprbool.addr=expr.addr bool.code=expr.code
expr → expr1 + termexpr.addr=new Temp() expr.code=expr1.code//expr2.code//gen(expr.addr'='expr1.addr'+'term.addr)
expr → expr1 - termexpr.addr=new Temp() expr.code=expr1.code//expr2.code//gen(expr.addr'='expr1.addr'-'term.addr)
expr → termexpr.addr=term.addr expr.code=term.code
term → term1 * factorterm.addr= new Temp() term.code=term1.code//factor.code//gen(term.addr'='term1.addr'*'factor.addr
term → term1 / factorterm.addr= new Temp() term.code=term1.code
term → factorterm.addr=factor.addr term.code=factor.code
factor → ( expr )factor.addr=expr.addr factor.code=expr.code
factor → idfactor.addr=top.get(id.lexeme) factor.code=''
factor → numfactor.addr=top.get(num.lexeme) factor.code=''

五.程序设计思路

规约式子标号(前项,后项,弹出数,标号)

1475969-20190101213341386-916317565.png

在实验二的代码上改进,设计语义规则,在规约时执行相应的语义动作。因为该文法是S-SDD所以可以用自底向上的语法分析。
规约的思路具体见实验二
新增全局变量
int num:保存节点的数目
Stack<Integer> stacknum:数值栈
List<String> listop:临时保存四元式集合,用于后期合并
Stack<List> bool:保存各个模块的四元式
语义动作分为3种,一种是识别id,num,创建id,num节点,将他们压入数值栈中。

1475969-20190101213206509-536573283.png

第二种是二操作符的操作。将数值栈中的节点两个弹出,计算后将新的节点压入数值栈。将语句保存起来,加入临时list中。

1475969-20190101213231474-460787569.png

第三种是合并的操作。将list的语句合并成一个,放入模块栈中。

1475969-20190101213253771-794716217.png

六.函数

程序结构描述:函数调用格式、参数含义、返回值描述、函数功能
一系列规约后操作函数如
public static void print24()
参数:无
返回值:无
功能:使用24号式子规约时执行,初始化一个新num节点。(图在上面)

七.程序结构描写(部分,其他的在实验二)

就是规约的时候的操作,print后面的数字对应表达式
1475969-20190101222129429-2014638736.png
1475969-20190101222220187-1915509524.png
1475969-20190101222302063-679565074.png
1475969-20190101222331126-1630753907.png
在规约时进行

if(s2.charAt(0)=='r')//规约
            {
                String s3=s2.substring(1);
                int i=Integer.parseInt(s3);//按照第几条规则规约
                if(i==24)print24();
                if(i==19)print19();
                if(i==15)print15();
                if(i==5)print5();
                if(i==4)print4();
                if(i==7)print7();
                if(i==13)print13();
                if(i==11)print11();
                if(i==12)print12();
                if(i==14)print14();
                if(i==16)print16();
                if(i==17)print17();
                if(i==20)print20();
                if(i==23)print23();
                if(i==9)print9();
                if(i==8)print8();
                type type=new type();
                type=rule.get(i);
                int popnum=type.pop;//要弹出几条
                print(step,stack.toString(),stack1.toString(),s1,"按照"+type.right+"->"+type.left+"的规则进行规约",0);
                for(int flag=0;flag<popnum;flag++)
                {
                stack.pop();//状态栈弹出
                stack1.pop();//符号栈弹出
                }
                top=stack.peek();//顶端
                stack1.push(type.right);
                Map<String,String> map2=new HashMap<>();
                map2=Mgoto.get(top);//非终结符用goto
                if(map2.containsKey(type.right))
                {
                    stack.push(Integer.parseInt(map2.get(type.right)));
                    top=Integer.parseInt(map2.get(type.right));
                    
                }
                else
                {
                    System.out.println("error sen!");
                    p.write(("\r\n语法错误!\r\n当前状态 :"+top+"\r\n无法解析符号 :"+s1).getBytes());
                    break;
                }
            }

八.流程图(实验二上新增)

新增在规约时执行语义动作
1475969-20190101213852209-1892264695.png

总流程图

1475969-20190101213946239-882322003.jpg

九.函数调用(实验二上新增)

1475969-20190101214547991-1877715442.jpg

十.测试数据(同实验二)

(1)

  • 输入
    1475969-20190101220515870-1069530648.png
  • 输出
    1475969-20190101220402265-2057297885.png
    (2)
  • 输入
    1475969-20190101220700603-1842233509.png
  • 输出
    1475969-20190101220641750-1913887698.png
    (3)
  • 输入
    1475969-20190101220718423-846548273.png
  • 输出
    1475969-20190101221150218-1233247054.png
    (4)错误输入
  • 输入
    1475969-20190101221452550-786230971.png
  • 输出
    1475969-20190101221442552-1406955626.png

十一.总结

这次实验因为是S-SDD的文法总体不算难,就是在实验二的基础上改下就可以了。但是如果是L-SDD的话就会很麻烦。通过这次实验,知道了如何进行语法翻译。通过三次实验下来,对于一个简易编译器的实现已经有了一个整体的构架了,相信在通过自己以后的深入学习,一定能写出属于自己的编译器。

转载于:https://www.cnblogs.com/zzc2018/p/10205986.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值