上一节,我们的 解释器 已经实现了对数组元素的访问和读取,这让我们的解释器有了进一步完善,本节,我们将再接再厉,为解释器增添新的代码执行功能,这次我们要完成的解释功能是,让解释器能够解析并正确执行if else语句。
这次我们需要解释执行的C语言程序实例如下:
void f() {
int a;
int b;
a = 1;
if (a > 0) {
b = a + 2;
}
}
上面代码只有if条件判断,完成了上面代码的解析执行功能后,我们再进一步,增加else的解析执行功能,也就是我们会进一步让解释器执行如下代码:
void f() {
int a;
int b;
a = 1;
if (a > 1) {
b = a + 2;
}
else {
b = a + 3;
}
}
IF ELSE语句的代码执行树
我们先看看IF else语句对应的语法表达式:
if_statement->IF LP test RP statement
if_else_statement->if_statement
if_else_statement->if_else_statement ELSE statement
Statement ->if_else_statement
test->expr
根据上面的语法表达式,解析器构造的语法执行树如下:
接下来我们看看相关代码实现,首先是CodeTreeBuilder.java里面,增添了构造上面代码执行树的相关代码:
public ICodeNode buildCodeTree(int production, String text) {
ICodeNode node = null;
Symbol symbol = null;
switch (production) {
...
case CGrammarInitializer.Expr_TO_Test:
node = ICodeFactory.createICodeNode(CTokenType. Test );
node.addChild(codeNodeStack.pop());
break;
case CGrammarInitializer.If_Test_Statement_TO_IFStatement:
node = ICodeFactory.createICodeNode(CTokenType.IF_STATEMENT);
node.addChild(codeNodeStack.pop()); //Test
node.addChild(codeNodeStack.pop()); //Statement
break;
case CGrammarInitializer.IfElseStatemnt_Else_Statemenet_TO_IfElseStatement:
node = ICodeFactory.createICodeNode(CTokenType.IF_ELSE_STATEMENT);
node.addChild(codeNodeStack.pop()); //IfStatement
node.addChild(codeNodeStack.pop()); // statement
break;
...
}
如果当前解析执行的C代码只有if 没有else部分的话,那么解释器会依赖类IfStatementExecutor去解释执行对应代码,我们看看相关代码实现:
public class IfStatementExecutor extends BaseExecutor {
@ Override
public Object Execute(ICodeNode root) {
ICodeNode res = executeChild(root, 0);
Integer val = (Integer)res.getAttribute(ICodeKey.VALUE);
copy Child(root, res);
if (val != null && val != 0) {
executeChild(root, 1);
}
return root;
}
}
上面的代码逻辑是这样的,If 节点先执行它第一个孩子节点,它的第一个孩子节点是Test节点,也就是先执行if判断条件,如果判断条件成立,也就是返回值val的结果不是0,那么就执行If节点的第二个孩子,第二个孩子对应的是if语句接下来用大括号包着的代码块,对应于语法表达式就是Statement节点。
如果C语言中的条件判断形式是if else, 那么解释器会依赖类ElseStatementExecutor,来对相关的C语言代码进行解释执行,该类的代码如下:
package backend;
import java.util.Collections;
public class ElseStatementExecutor extends BaseExecutor {
@Override
public Object Execute(ICodeNode root) {
//先执行if 部分
ICodeNode res = executeChild(root, 0);
Object obj = res.getAttribute(ICodeKey.VALUE);
if ((Integer)obj == 0) {
//if 部分没有执行,所以执行else部分
res = executeChild(root, 1);
}
copyChild(root, res);
return root;
}
}
它先执行它的第一个孩子节点,根据语法表达式它的第一个孩子节点对应的是IF 节点,也就是他先执行if 部分的代码,如果if判断条件成立,那么该节点执行后的返回结果将不会是0,如果是0的话,表明if 判断条件不成立,因此该节点要执行它的二孩子,也就是else 部分对应的Statment节点。
If 部分的条件判断,也就是Test节点的执行,最终会落到 Binary Executor里面,我们看看相关代码:
public class BinaryExecutor extends BaseExecutor{
@Override
public Object Execute(ICodeNode root) {
executeChildren(root);
ICodeNode child;
int production = (int)root.getAttribute(ICodeKey.PRODUCTION);
switch (production) {
...
case CGrammarInitializer.Binary_RelOP_Binary_TO_Binray:
val1 = (Integer)root.getChildren().get(0).getAttribute(ICodeKey.VALUE);
String operator = (String)root.getChildren().get(1).getAttribute(ICodeKey.TEXT);
val2 = (Integer)root.getChildren().get(2).getAttribute(ICodeKey.VALUE);
switch (operator) {
case "==":
root.setAttribute(ICodeKey.VALUE, val1 == val2 ? 1 : 0);
break;
case "<":
root.setAttribute(ICodeKey.VALUE, val1 < val2? 1 : 0);
break;
case "<=":
root.setAttribute(ICodeKey.VALUE, val1 <= val2? 1 : 0);
break;
case ">":
root.setAttribute(ICodeKey.VALUE, val1 > val2? 1 : 0);
break;
case ">=":
root.setAttribute(ICodeKey.VALUE, val1 >= val2? 1 : 0);
break;
case "!=":
root.setAttribute(ICodeKey.VALUE, val1 != val2? 1 : 0);
break;
...
}
它会解析if条件判断语句,把判断结果返回给父节点,如果条件成立的话,返回整形数值1,如果条件不成立,返回整形数值0,If 节点根据这个返回值,觉得是否执行它对应的Statment的节点