递归下降解析器(Recursive Descent Parser, RDP)是一种用于解析表达式的编程技术。尽管它的概念可能在初次接触时显得有些难以理解,但通过本文的介绍,希望能够帮助逐步揭开RDP的神秘面纱。本文将通过一个简单的程序演示RDP的工作原理,帮助更好地理解这一技术。
为了简化演示,使用Windows控制台项目。在编写本文时,作者使用的是24英寸的ASUS显示器,并将控制台窗口的宽度和高度分别设置为150和60。当然,可以根据个人喜好和显示器的不同,调整以下代码中的参数:
private const int ScreenWidth = 150;
private const int ScreenHeight = 60;
...
Console.SetBufferSize(ScreenWidth, ScreenHeight);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.BackgroundColor = ConsoleColor.Black;
首先,下载并解压项目,然后使用Visual Studio打开RDPInst.sln文件。该项目包含两个子项目:
对RDP的主要修改是增加了一个List<MyStackFrame> MyStackFrameList。MyStackFrame类(为了避免与System.Diagnostics.StackFrame混淆,给它起了这个名字)包含了在RDP评估表达式时感兴趣的项目:
public class MyStackFrame {
public DateTime Timestamp { get; set; }
public int StackLevel { get; set; }
public String Op { get; set; }
public String Method { get; set; }
public String Token { get; set; }
public RecursiveDescentParserInstrumented.TokenType TokenType { get; set; }
public Double SaveResult { get; set; }
public Double PartialResult { get; set; }
public Double Result { get; set; }
public int ExprNdx { get; set; }
}
递归下降解析器使用递归,将值推入栈中。在此过程中,会创建一个MyStackFrame对象并将其添加到myStackFrameList中。当RDP完成表达式的评估后,TestParserProgram会遍历这个列表,实际上是在“回放”方法和值。
解析器的核心是其语法,这里以EBNF(扩展巴科斯-诺尔范式)表示法展示:
构建程序后,按CTRL+F5以“不调试方式启动”。应该会出现一个控制台窗口,提示"Enter Expression For Instrumented Parser (Enter to quit)>"(确保将控制台的高度和宽度设置为适当的大小)。输入要解析的表达式,然后连续按Enter键,直到表达式完成。当按Enter键时,程序会遍历myStackFrameList。在左侧,可以观察到方法调用以及操作的结果(加法、减法、指数等等)。右侧是栈;可以观察到数字如何被推入栈中,然后在遇到操作符如+,^或*时被弹出,显示当前结果。注意如何在左下角显示表达式,光标指向当前正在处理的标记。