为什么`try`是一个明确的关键字? [英] Why is `try` an explicit keyword?

查看:159
本文介绍了为什么`try`是一个明确的关键字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在所有异常感知语言中,我知道(C ++,Java,C#,Python,Delphi-Pascal,PHP),捕获异常需要一个显式的 try code> catch 块。我经常想知道这是什么技术原因。为什么我们不能将 catch 子句附加到一个其他普通的代码块?作为一个C ++示例,为什么我们必须这样写:

In all exception-aware languages I know (C++, Java, C#, Python, Delphi-Pascal, PHP), catching exceptions requires an explicit try block followed by catch blocks. I was often wondering what the technical reason for that is. Why couldn't we just append catch clauses to an otherwise ordinary block of code? As a C++ example, why do we have to write this:

int main()
{
  int i = 0;
  try {
    i = foo();
  }
  catch (std::exception& e)
  {
    i = -1;
  }
}

而不是这样:

int main()
{
  int i = 0;
  {
    i = foo();
  }
  catch (std::exception& e)
  {
    i = -1;
  }
}

是否有实现原因,或者是只是有人首先设计了这样的方式,现在每个人都熟悉它并复制它?

Is there an implementation reason for this, or is it just "somebody first designed it that way and now everyone is just familiar with it and copies it?"

我看到的方式,编译语言没有意义 - 在生成任何代码之前,编译器会看到整个源代码树,因此在$ code>之前,可以轻松地在块前插入 try 跟踪该块(如果需要为尝试块生成特殊代码)。我可以想象一些使用解释型语言的语言,它们不提前解析,同时需要在尝试块开始时采取一些措施,但是我不知道是否有这样的语言存在。

The way I see it, it makes no sense for compiled languages - the compiler sees the entire source code tree before generating any code, so it could easily insert the try keyword in front of a block on the fly when a catch clause follows that block (if it needs to generate special code for try blocks in the first place). I could imagine some use in interpreted languages which do no parsing in advance and at the same time need to take some action at the start of a try block, but I don't know if any such languages exists.

让我们放弃语言,没有明确的方式声明任意的块(如Python)。在所有其他人中,是否有技术原因要求尝试关键字(或等效)?

Let's leave aside languages without an explicit way to declare arbitrary blocks (such as Python). In all the others, is there a technical reason for requiring a try keyword (or equivalent)?

推荐答案

这个问题有几种答案,所有这些都可能是相关的。

There are several kinds of answers to this question, all of which might be relevant.

第一个问题是关于效率和区别编译和解释语言。基本的直觉是正确的,语法的细节不影响生成的代码。解析器通常会生成抽象语法树(明确或隐含地),无论是编译器还是解释器。一旦AST到位,用于生成AST的语法的细节是无关紧要的。

The first question is about efficiency and a distinction between compiled and interpreted languages. The basic intuition is correct, that the details of syntax don't affect generated code. Parsers usually generate an abstract syntax tree (be that explicitly or implicitly), be it for compilers or interpreters. Once the AST is in place, the details of syntax used to generate the AST are irrelevant.

下一个问题是是否需要明确的关键字来协助解析。简单的答案是没有必要,但可以帮助你。为了理解为什么没有必要,你必须知道一个解析器的前瞻集。前瞻集是每个解析状态的一组令牌,如果要在令牌流中显示下一个语法,这将是正确的语法。解析器生成器(例如 bison )明确设置此前瞻性设置。递归下降解析器也有一个前瞻集,但它们通常不会在表中明确显示。

The next question is whether requiring an explicit keyword assists in parsing or not. The simple answer is that it's not necessary, but can be helpful. To understand why it's not necessary, you have to know what a "lookahead set" is for a parser. The lookahead set is a set of tokens for each parsing state that would be correct grammar if they were to appear next in the token stream. Parser generators such as bison model this lookahead set explicitly. Recursive descent parsers also have a lookahead set, but they are often do not appear explicitly in a table.

现在考虑一个语言,如在问题中提出的,使用以下语法进行例外:

Now consider a language that, as proposed in the question, uses the following syntax for exceptions:

block: "{" statement_list "}" ;
statement: block ;
statement: block "catch" block ;
statement: //... other kinds of statements

使用这种语法,一个块可以装饰一个异常块。关于歧义的问题是,在看到之后,是否 catch 关键字是不明确的。假设 catch 关键字是唯一的,解析器将会识别异常装饰语句是完全明确的。

With this syntax, a block can either be adorned with an exception block or not. The question about ambiguity is whether, after having seen a block, whether the catch keyword is ambiguous. Assuming that the catch keyword is unique, it's completely unambiguous that the parser is going to recognize an exception-adorned statement.

现在我说,为解析器必须有一个明确的 try 关键字是很有帮助的。以什么方式有帮助?它限制了某些解析器状态的前瞻设置。 尝试之后设置的前瞻是单个令牌 {。匹配关闭大括号后面的前瞻设置是单个关键字 catch 。一个表驱动的解析器并不在意这一点,但它使手写递归下降解析器更容易编写。更重要的是,它改进了解析器中的错误处理。如果在第一个块中出现语法错误,则使用 try 关键字意味着错误恢复可以查找 catch 令牌作为重新建立已知解析器状态的栅栏,可能是因为它是一个前瞻集的单个成员。

Now I said that it's helpful to have to have an explicit try keyword for the parser. In what way is it helpful? It constrains the lookahead set for certain parser states. The lookahead set after try itself is the single token {. The lookahead set after the matching close brace is the single keyword catch. A table-driven parser doesn't care about this, but it makes a hand-written recursive descent parser a bit easier to write. More importantly, though, it improves error handling in the parser. If a syntax error occurs in the first block, having a try keyword means that error recovery can look for a catch token as a fence post at which to re-establish a known parser state, possible exactly because it's the single member of a lookahead set.

关于 try 关键字与语言设计有关。简单地说,在块前面有明确的关键字使得代码更容易阅读。人类仍然需要解析代码,即使他们不使用计算机算法来执行。减少正式语法中设置的前瞻性的大小也可以减少第一次看到的代码段可能意味着什么的可能性。这提高了代码的清晰度。

The last question about a try keyword have to do with language design. Simply put, having explicit keywords in front of blocks makes the code easier to read. Humans still have to parse the code by eye, even if they don't use computer algorithms to do it. Reducing the size of the lookahead set in the formal grammar also reduces the possibilities of what a section of code might mean when first glanced at. This improves the clarity of the code.

这篇关于为什么`try`是一个明确的关键字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆