为我们的解释器构造一个调试器

为我们的解释器构造一个调试器_第1张图片
图片发自App

说明

现在的debugger支持最基本的两个命令,next step和watch variable。

语言定义

上一节实现了简单的解释器,语言的定义:

程序:语句序列
语句:语句序列|赋值语句(语句;)
赋值语句:变量=表达式
表达式:包含变量的四则运算

源码示例:


{
  number=2;
  a=number;
  b=10*a+10;
  c=a--b
};
x=11;
y=x*10

调试器使用

package lsbasi;

public class TestDebug {
    public static void main(String[] args) throws Exception {
        Lexer lexer = new Lexer("{number=2;a=number;b=10*a+10;c=a--b};x=11;y=x*10");
        Parser p = new Parser(lexer);

        Interpreter i = new Interpreter(p);
        i.debugger();
        System.out.println(i.GLOBAL_SCOPE);

    }
}

调试器实现

package lsbasi;

import java.util.List;
import java.util.Map;
import java.util.Scanner;

import lsbasi.ast.StatementAST;
import lsbasi.visit.NodeVisitor;

public class Debugger {
    Scanner s = new Scanner(System.in);
    private Map scope;
    private List list;
    private int index;

    public Debugger(List list, Map scope) {
        this.list = list;
        this.scope = scope;
        this.index = 0;
    }

    public void help() {
        System.out.println("h:help");
        System.out.println("n:next");
        System.out.println("w:watch");
    }

    public String waitUser() {
        return s.next();
    }

    public void debugger() throws Exception {
        help();
        while (index < list.size() ) {
            switch (waitUser()) {
            case "n":
                NodeVisitor.visit(list.get(index), scope);
                index++;
                break;
            case "h":
                help();
                break;
            case "w":
                System.out.println(scope);
                break;
            default:
                break;
            }
        }

    }

}

完整的代码

值得改进的地方当然很多了,例如调试器功能不完整,这个要考虑的扩展性的话,需要拆分代码。让每种调试功能成为一个实例,在需要的时候进行注册,组合子对象模式真的好像不错。

后记

相信很多人对调试器没有任何兴趣,但是据我所知很多年轻人编程几乎离不开调试器,比如我,这当然是很受高手鄙视的。

我一直在想调试器的工作原理是什么样的,有什么好处和坏处,怎么可以摆脱调试器束缚,让我也成为高手一下,而不是遇到问题就下断点,以前觉得这是必选项。当我听说,仅仅是听说,有人可以一次将代码写对的时候,我彻底改变了以前的想法,觉得自己的做法太low了。我想要离开调试器的话,我们必须对语言很熟悉,对正在操作的数据很熟悉,有一些辅助日志帮助,把逻辑设计的天衣无缝,一口气全写对。如果有一口气全写对的,请联系我,让我见识一下。

调试器的哲学是让计算的世界停下来,慢下来,让我们仔细思考我们的代码,看到变量值和当初考虑不完全的地方,有时候这种错误很难捕捉,即使最好的调试器也经不起拙略程序员的莽撞行为。我想另一个方法是我们可以让自己慢下来,来应对程序的部分错误。

但是很多时候我们接手不熟悉的代码,甚至得在线定位,或者对完整的代码不熟悉,这时候就得用调试器碰碰运气了。当然终极杀招似乎还是类似alert print之类的输出。

对于初学者调试器是种逆天的功能,可以让人对代码每一步有直观了解,弥补了对细节掌控的不足。但是任何牛皮的工具都不会替猿类的懒惰和不思进取买单,如果你不明白你自己正在干什么,做的再好都是垃圾。

你可能感兴趣的:(为我们的解释器构造一个调试器)