这种类型的错误是在类型检查期间还是在解析输入时产生的?应该在什么类型下解决错误?
4 回答
我认为这是一个语义错误,因为即使您使用的是以前未绑定的标识符,您的语言也能很好地解析——即句法分析只检查程序的格式是否正确。语义分析实际上检查您的程序是否具有有效的含义——例如绑定、作用域或类型。正如@pst 所说,您可以在解析期间进行范围检查,但这是一个实现细节。AFAIK 旧的编译器曾经这样做是为了节省一些时间和空间,但我认为今天这种方法是有问题的,如果你没有一些硬性能/内存限制。
该程序符合语言语法,因此在语法上是正确的。语言语法不包含诸如“必须声明标识符”之类的任何语句,并且确实没有任何方法可以这样做。在 Algol-68 项目中,按照这些思路构建两级语法的尝试失败了,据我所知,此后一直没有尝试过。
每一个的含义(如果有的话)是一个语义问题。Frank deRemer 将此类问题称为“静态语义”。
在我看来,这不是严格意义上的语法错误——也不是语义错误。如果我要为静态类型的编译语言(如 C 或 C++)实现此功能,那么我不会将检查放入解析器(因为解析器实际上无法检查此错误),而是放入代码生成器(编译器中遍历抽象语法树并将其转换为汇编代码的部分)。所以在我看来,它介于语法和语义错误之间:它是一个语法相关的错误,只能通过对代码进行语义分析来检查。
然而,如果我们考虑一种原始脚本语言,其中直接执行 AST(无需编译为字节码且没有 JIT),那么评估器/执行器函数本身会遍历 AST 并找到未声明的变量 - 在这种情况下,它将是运行时错误。不同之处在于“AST_walk()”例程位于程序生命周期的不同部分(编译时间和运行时),语言是脚本还是编译语言。
对于需要声明标识符的语言(有很多),具有未声明标识符的程序格式错误,因此缺少声明显然是语法错误。
处理这个问题的常用方法是将有关符号的信息合并到符号表中,以便解析可以使用这些信息。
以下是标识符类型如何影响解析的几个示例:
C / C++
一个经典案例:
(a)-b;
取决于a
,这是强制转换或减法:
#include <stdio.h>
#if TYPEDEF
typedef double a;
#else
double a = 3.0;
#endif
int main() {
int b = 3;
printf("%g\n", (a)-b);
return 0;
}
因此,如果a
根本没有声明,编译器必须将程序拒绝为语法错误(这正是标准使用的词。)
XML
这个很简单:
<block>Hello, world</blob>
这是格式不正确的 XML,但无法使用 CFG 检测到。(尽管如此,所有 XML 解析器都会正确地拒绝它,因为它是格式错误的。)对于 HTML/SGML,在某些明确定义的情况下可能会省略结束标记,解析比较棘手,但仍然具有确定性;同样,标签的精确声明将决定有效输入的解析,并且很容易提出根据声明进行不同解析的输入。
英语
好吧,不是编程语言。我有很多其他编程语言示例,但我认为这可能会触发其他一些直觉。
考虑两个语法正确的句子:
The sheep is in the meadow.
The sheep are in the meadow.
现在,怎么样:
The cow is in the meadow.
(*) The cow are in the meadow.
第二句话是可以理解的,尽管模棱两可(名词或动词是错的吗?)但在语法上肯定是不正确的。但是为了知道那个(和其他类似的例子),我们必须知道它sheep
有一个无标记的复数。确实,许多动物都有无标记的复数形式,所以我认为以下所有内容都是合乎语法的:
The caribou are in the meadow.
The antelope are in the meadow.
The buffalo are in the meadow.
但绝对不是:
(*) The mouse are in the meadow.
(*) The bird are in the meadow.
等等
似乎有一个普遍的误解,即由于句法分析器使用上下文无关语法分析器,因此语法分析仅限于解析上下文无关语法。这是不正确的。
在 C(和家族)的情况下,语法分析器使用符号表来帮助它解析。在 XML 的情况下,它使用标签堆栈,而在泛化 SGML(包括 HTML)的情况下,它也使用标签声明。因此,作为一个整体考虑的语法分析器比 CFG 更强大,而 CFG 只是分析的一部分。
给定程序通过语法分析的事实并不意味着它在语义上是正确的。例如,语法分析器需要知道是否是类型a
才能正确解析被减去,在它是一个变量的情况下。这些验证可以在构建解析树后的类型分析期间发生,但它们仍然是编译时错误。(a)-b
a
a
b
a