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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索