编译器/解释器中的符号前瞻

Phr*_*dge -2 c compiler-construction interpreter

在为简单的编程语言构建某种解释器时,我偶然发现了一个有趣的问题。我称之为“符号前瞻”问题。

我这是什么意思?例如,在 C/C++ 编译器中,您将要使用的符号必须始终已在代码上方的某处声明。像这样:

struct int_pair;

struct rectangle {
    int_pair position;
    int_pair size;
};

struct int_pair {
    int x, y;
};
Run Code Online (Sandbox Code Playgroud)

而不是这样的:

struct rectangle {
    int_pair position;
    int_pair size;
};

struct int_pair {
    int x, y;
};
Run Code Online (Sandbox Code Playgroud)

在 C# 或 Java 中,可以在文件中的任意位置使用任何符号:

public class Rectangle {
    private IntPair position, size; // using IntPair before declaring it
}

public class IntPair {
    public int Sum() { // using x and y before declaring it
        return x + y;
    }

    public int x, y;
}
Run Code Online (Sandbox Code Playgroud)

那么我的问题是什么?

我发现,在构建 AST 时,了解代码中的 Symbol 是否引用函数、变量或其他内容很有用,这样解释器就可以决定以下代码应该是什么样子,这可以改进很多事情。这要求这个符号已经在我的程序中的某个地方声明,但我真的不喜欢这种“C”风格的编程。我想要的是像 Java 或 C# 那样的编程风格:声明可以位于代码中的任何位置,不受特定顺序的限制 - 并且解释器在构建 AST 时可以依赖于符号含义。

解决这个问题的一种方法可能是构建某种先行算法,该算法会飞过程序并捕获所有相关符号,而不是其他任何东西。但对我来说,这似乎相当混乱并且类似于解决方法。

所以我的问题是,需要使用 C# 和 Java 方式来声明内容(请参阅上面的代码片段),但我自己弄清楚如何在解释器中实现此功能。所以我要求一个想法/代码片段/算法/策略,让我可以预见符号及其含义。

非常感谢您的帮助。:)

ric*_*ici 5

Java 和 C# 的语法设计方式使得即使您不知道子表达式(包括标识符)的类型,表达式(例如函数调用)也是明确的。C 不是这样设计的。

明确语法的优点之一是您可以在不进行任何类型分析的情况下创建 AST,这意味着不需要预先声明。一旦你有了 AST,你就可以做任何你想做的分析,比如通过遍历解析树来检查函数原型和调用点。

并且无需同时进行所有分析;您可以根据需要多次行走这棵树。这使得组织代码变得更加容易,并且不会产生任何重大开销。