java实现C编译器:for 循环语句的解析和执行

请参看视频以便得到更详细的代码讲解和演示流程:
用java开发C语言编译器java


你们或许发现,咱们当前的C语言解释器,存在一个问题,那就是,当变量声明的同时若是付初值的话,解析器会出错,也就是对于下面语句:node

int a = 0;微信

咱们当前的解析器是解析不了的,必须把上面的语句转换为:
int a;
a = 0;ide

要想使当前的解释器可以解析并执行变量声明同时付初值的功能,实现起来较为复杂,因此我决定先把这个功能放一放,把精力先使用在更为重要的实现上。oop

本节咱们要为解释器增长的功能是对for循环进行解析和执行,for循环的语法表达式以下:ui

STATEMENT -> FOR LP OPT_EXPR  TEST SEMI END_OPT_EXPR RP STATEMENT(84)

其对应的执行树结构以下:
spa

对于一个具体的循环语句:.net

for (i= 0; i < 3; i++) {
    a = a + 1;
}

i = 0 对应于节点OptExpr, i < 3 对应节点Test, i++ 对应节点EndOptExpr, a = a+ 1; 对应最后一个Statement节点。code

解释器在执行for 语句时,先执行OptExpr节点,而后执行Test节点,若是Test节点执行后返回的值大于0,则执行最下面的Statement节点,而后再执行EndOptExpr节点,也就是for 循环后面的i++语句。视频

整个流程执行完毕后,解释着再次执行Test节点,若是执行后返回值不等于0,则继续执行最下面的Statement节点和EndPotExpr节点,若是返回值等于0,则执行结束。

咱们看看相关代码,在CodeTreeBuilder.java中,作如下改动:

public ICodeNode buildCodeTree(int production, String text) {
        ICodeNode node = null;
        Symbol symbol = null;

        switch (production) {
        ...
         case CGrammarInitializer.FOR_OptExpr_Test_EndOptExpr_Statement_TO_Statement:
            node = ICodeFactory.createICodeNode(CTokenType.STATEMENT);
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
            node.addChild(codeNodeStack.pop());
            break;

            ....

case CGrammarInitializer.Expr_Semi_TO_OptExpr:
        case CGrammarInitializer.Semi_TO_OptExpr:
            node = ICodeFactory.createICodeNode(CTokenType.OPT_EXPR);
            if (production == CGrammarInitializer.Expr_Semi_TO_OptExpr) {
                node.addChild(codeNodeStack.pop());
            }
            break;

        case CGrammarInitializer.Expr_TO_EndOpt:
            node = ICodeFactory.createICodeNode(CTokenType.END_OPT_EXPR);
            node.addChild(codeNodeStack.pop());
            break;
        ...
        }

增长的代码就是用来构造前面所说的关于for循环执行树的几个节点。在StatementExecutor的实现中,咱们增长了对for循环的实现:

public class StatementExecutor extends BaseExecutor{
    private enum LoopType {
        FOR,
        WHILE,
        DO_WHILE
    };

     @Override 
     public Object Execute(ICodeNode root) {
         int production = (int)root.getAttribute(ICodeKey.PRODUCTION);

         switch (production) {
         case CGrammarInitializer.FOR_OptExpr_Test_EndOptExpr_Statement_TO_Statement:
             //execute OptExpr
             executeChild(root, 0);

             while( isLoopContinute(root, LoopType.FOR) ) {
                 //execute statment in for body
                 executeChild(root, 3);

                 //execute EndOptExpr
                 executeChild(root, 2); 
             }

             break;
         default:
             executeChildren(root);

             break;
         }

         return root;
     }

     private boolean isLoopContinute(ICodeNode root, LoopType type) {
         ICodeNode res = null;
         if (type == LoopType.FOR) {
             res = executeChild(root, 1);
             int result = (Integer)res.getAttribute(ICodeKey.VALUE);
             return result != 0;
         }

         return false;
     }
}

executeChild(root, 0); 对应于执行树中的OptExpr节点,也就是执行for语句中的变量初始化语句,也就是i = 0; isLoopContinute 执行的是执行树中第二个节点,也就是Test节点,对应的是for 语句中的 i < 3语句,若是返回的结果不等于0,也就是循环条件知足,那么执行循环体内部的语句代码,也就是经过调用
executeChild(root, 3);, 从而执行执最下面的Statement节点,对应于例子中,就是 a = a + 1; 最后经过调用executeChild(root, 2); 执行EndOptExpr节点,对应于for循环,就是语句i++;

咱们须要添加新的代码,以便解释器能正确执行i++语句,该语句对应的语法表达式是:
UNARY -> UNARY INCOP
因此咱们须要在UnaryNodeExecutor中,添加相应的实现代码,具体改动以下:

public class UnaryNodeExecutor extends BaseExecutor{

    @Override
    public Object Execute(ICodeNode root) {
        executeChildren(root);
        ....
        switch (production) {
        ....
         case CGrammarInitializer.Unary_Incop_TO_Unary:
            symbol = (Symbol)root.getChildren().get(0).getAttribute(ICodeKey.SYMBOL);
            Integer val = (Integer)symbol.getValue();
            IValueSetter setter;
            setter = (IValueSetter)symbol;
            try {
                setter.setValue(val + 1);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                System.err.println("Runtime Error: Assign Value Error");
            }
            break;
        }
        }
    }

咱们先拿到变量i所对应的Symbol对象,经过该对象的ValueSetter接口,使得变量的值自加1.

经过上面的代码改进,咱们的解释器对C语言的执行能力能够获得进一步增强,能够正确解析和执行下面的C语言代码:

void f() {
int i;
int a;

i = 0;
a = 0;

for (i = 0; i < 3; i++) {
    a = a + 1;
}

}


本文分享自微信公众号 - Coding迪斯尼(gh_c9f933e7765d)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索