例如(在 C 中):
int break = 1;
int for = 2;
为什么编译器在推导它时会有任何问题,break
并且for
这里是变量?
所以,我们需要关键字,因为
- 我们希望程序是可读的
- 我们不想使今天已经很复杂的编译器的工作过于复杂
- 但最重要的是,如果为某些特殊操作保留一些“关键字”,则语言会更强大。然后,该语言可以考虑在更高级别上有用,而不是在尝试以明确的方式实现 for 循环时死去。
例如(在 C 中):
int break = 1;
int for = 2;
为什么编译器在推导它时会有任何问题,break
并且for
这里是变量?
所以,我们需要关键字,因为
没有必要——Fortran 没有保留任何字词,所以像:
if if .eq. then then if = else else then = if endif
是完全合法的。这不仅使编译器难以解析该语言,而且人们通常几乎不可能阅读或发现错误。例如,考虑经典的 Fortran(比如说,一直到 Fortran 77 ——我最近没有使用它,但至少希望他们在最近的标准中修复了一些类似的东西)。Fortran DO 循环如下所示:
DO 10 I = 1,10
如果没有它们并排,您可能会看到您会如何想念它的不同之处:
DO 10 I = 1.10
不幸的是,后者根本不是 DO 循环——它是将值简单地分配1.10
给一个名为的变量DO 10 I
(是的,它还允许名称中有空格)。由于 Fortran 还支持隐式(未声明的)变量,所以这(或曾经)完全合法,一些编译器甚至会在没有警告的情况下接受它!
那么当计算机遇到如下语句时会做什么:
while(1) {
...
if (condition)
break;
}
它真的应该打破吗?还是应该将其视为1;
?
该语言在某些情况下会变得模棱两可,或者您必须创建一个非常智能的解析器来推断微妙的语法,而这只是不必要的额外工作。
他们没有。众所周知,PL/1 没有关键字;每个“关键字”(BEGIN、DO、...)也可以用作变量名。但允许这意味着你可以编写真正晦涩难懂的代码: IF DO>BEGIN THEN PRINT:=CALL-GOTO; 如果那组名称是适度的(因为它在我见过的所有语言中都是如此,除了 PL/1 :-)。
APL 也以没有关键字着称。但它有一组大约 200 个令人惊叹的标志性符号,可用于编写复杂的运算符。(“多米诺”运算符 [不要问!] 是一个中间有一个计算器分隔符号的方框)在这种情况下,语言设计者只是使用图标而不是关键字。结果是 APL 享有“只写”语言的美誉。
底线:不是必需的,但如果关键字是程序员已知的一小部分保留标识符,它往往会使程序更具可读性。(一些语言坚持“关键字”以“.”之类的特殊标点符号开头,以允许使用所有可能的标识符,但这不值得额外的打字麻烦或页面上的混乱;它很容易当关键字集较小时,远离与关键字匹配的“标识符”)。
由于它被标记为 C,因此原始 C 语言默认情况下任何变量都定义为 type int
。
这意味着foo;
将声明一个类型为 的变量int
。
假设你这样做break;
。那么编译器是如何知道你是要声明一个名为的变量break
还是使用关键字break
呢?
几个原因:
您的示例中的关键字可能看起来很明确。但这不是您使用变量“break”或变量“for”的唯一地方。
编写解析器会更加困难并且容易出错,而且收益甚微。
在库中使用关键字作为函数或过程名称可能会产生不希望的、可能与安全相关的副作用。
正如其他人所说,这使编译器更容易解析您的源代码。但我还想说一点:它还可以让你的源代码更具可读性;考虑这个例子:
if (if > 0) then then = 10 end if
第二个“if”和第二个“then”是变量,而其他不是。我认为这种代码不可读。:)
如果你写这样的东西,编译器会出现问题:
while(*s++);
return(5);
这是一个循环还是对名为 的函数的调用while
?您是想从当前函数返回值 5,还是要调用一个名为 的函数return
?
如果具有特殊含义的结构仅具有可用于明确引用它们的特殊名称,它通常会简化事情。
如果我们说的是 C++——它已经有非常复杂的语法。例如,允许使用关键字作为变量名会使它变得更加复杂。
因为我们想保留我们所拥有的一些理智点:
void myfunction(bool) { .. };
funcp while = &myfunction;
while(true);
我想编写解析器看起来很奇怪,如果不是不可能的话。例如
int break = 1;
while (true) {
// code to change break
if (!break) break; // not very readable code.
}
根据语言定义,编译器可能需要也可能不需要关键字。当它不知道该做什么时,它可以尝试应用优先规则或失败。
一个例子:
void return(int i){printf("%d",i);}
public int foo(int a)
{
if(a > 2)return (a+1)*2;
return a + 3;
}
如果 a 大于 2 会发生什么?
您可以定义一种不使用关键字的语言。您甚至可以定义一种允许您替换所有符号的语言(因为它们本身只是非常短的关键字)。
问题不在于编译器,如果您的规范完整且没有错误,它将起作用。问题是 PEBCAD,使用该语言特性的程序将难以阅读,因为您必须跟踪符号定义。
FWIW,Tcl 没有任何保留字。您可以拥有名为“if”、“break”等的变量和函数。令牌的解释完全取决于上下文。同一个标记可以在一个上下文中表示一个命令,在另一个上下文中表示一个变量,或者在另一个上下文中表示一个文字字符串。
在许多情况下,编译器可以将关键字解释为普通标识符,例如您的示例:
int break = 1;
int for = 2;
事实上,我只是为一种简单的类似汇编的玩具语言编写了一个编译器,它可以做到这一点,但在这种情况下会警告用户。
但有时语法以关键字和标识符不明确的方式定义:
int break;
while(...)
{
break; // <-- treat this as expression or statement?
}
最明显的原因是编辑器会强调关键字,这样代码对人类来说更具可读性。允许将关键字视为标识符会使代码高亮变得更加困难,并且还会导致代码的可读性差。