我最近不得不为比特币的脚本语言编写解释器代码;其中一部分涉及提出一种算法来检查给定脚本中的控制流是否有意义(即每个OP_IF
都匹配OP_ENDIF
,每OP_ELSE
和OP_ENDIF
有一个匹配的OP_IF
,等等。
这就是我提出的:
public class if_else_checker {
public static boolean search(String[] commands, String[] tracker, int if_index) {
boolean seenElse = false;
for (int i = if_index; i < commands.length; i++) {
if (commands[i].equals("OP_ELSE")) {
if (seenElse == true && tracker[i] == null) return false;
if (tracker[i] == null) {
tracker[i] = "OP_ELSE";
seenElse = true;
}
}
else if (commands[i].equals("OP_ENDIF")) {
if (tracker[i] != null && tracker[i].equals("OP_ENDIF"))
{
continue;
}
tracker[i] = "OP_ENDIF";
return true;
}
else if (commands[i].equals("OP_IF")) {
if (tracker[i] != null && tracker[i].equals("OP_IF")) {
continue;
}
tracker[i] = "OP_IF";
if (search(commands, tracker, i + 1) == false) return false;
}
}
return false;
}
public static boolean validate(String[] args)
{
String[] tracker = new String[args.length];
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("OP_IF"))
{
if (tracker[i] == null || !tracker[i].equals("OP_IF"))
{
tracker[i] = "OP_IF";
if (search(args, tracker, i + 1) == false) return false;
}
else continue;
}
else if (args[i].equals("OP_ELSE"))
{
if (tracker[i] == null || !tracker[i].equals("OP_ELSE")) return false;
}
else if (args[i].equals("OP_ENDIF"))
{
if (tracker[i] == null || !tracker[i].equals("OP_ENDIF")) return false;
}
}
return true;
}
public static void main(String[] args)
{
System.out.println(validate(args));
}
}
它有效,但我想知道是否有一种方法可以优化它/是否有标准方法可以做到这一点? (一个优化是让validate()
返回它找到的OP_ENDIF
的索引,而不是布尔值;这会将运行时从二次时间改为线性)。
答案 0 :(得分:0)
解决此问题的最佳方法是使用Stack数据结构。每个新的打开指令(例如OP_IF)都被推入堆栈。当您找到结束指令(例如OP_ENDIF)时,弹出堆栈的顶部元素并检查它是否是该结束指令的相应打开指令。如果是,那么它有效,然后继续下一步。最后,如果堆栈为空,那么您检查的控制流程是正确的。否则,它不是。