首先,ghord 是完全正确的。这是由解析器的递归性质引起的,所以给他点赞吧。但是需要有证据,OP希望我将其作为单独的答案发布。
火狐
那么,在哪里可以找到它是如何完成的呢?问一些从事发动机制造的人。所以我走到#jsapi
频道上irc://irc.mozilla.org
问他们:
< bhackett> zirak: well, with a recursive descent parser all the productions will roughly correspond to a frame on the C stack
< bhackett> zirak: the parser is at js/src/frontent/Parser.cpp
< Waldo> zirak: Parser<ParseHandler>::statement(bool canHaveDirectives) and Parser<ParseHandler>::statements() pretty much
< bhackett> zirak: in this case, the recursion will be Parser::blockStatement ->Parser::statements -> Parser::statement -> Parser::blockStatement
这几乎是答案。转到 Mozilla 中央存储库并进行挖掘,我们有我们的嫌疑人:
所以,我们所拥有的是:
statements
它调用blockStatement
,它解析块,找到另一个块,调用
statements
它调用blockStatement
,它解析块,找到另一个块,调用
statements
它调用blockStatement
,它解析块,找到另一个块,调用
直到堆栈崩溃,我猜这里。
所以我们有 Firefox 的源代码。
基于 v8 的 Chrome/Chromium/其他任何东西
从 Firefox 中吸取教训,我去了 v8 项目并寻找一个名为parser
. 果然,它就在那里!
接下来的事情是在解析块时寻找,所以我天真地搜索statements
,到达有希望的ParseStatement。
这是我们的幸运日,一个巨人switch
!第一个案例是我们关心的,一个电话,ParseBlock
另一个有前途的名字!
确实,在内部ParseBlock
,我们找到了对 的调用ParseStatement
。所以,要清楚,我们有两个功能:
他们互相调用,就像我们在 Firefox 中看到的那样:
ParseStatement
它调用ParseBlock
,它解析块,找到另一个块,调用
ParseStatement
它调用ParseBlock
,它解析块,找到另一个块,调用
ParseStatement
它调用ParseBlock
,它解析块,找到另一个块,调用
直到kaboom进入堆栈。
苹果浏览器
(很抱歉在上次编辑中称它为封闭源代码!) Safari 的 js 引擎是JavaScriptCore,它位于 WebKit 项目中。查找函数与为 Chrome 查找函数几乎相同,所以让我们跳到有趣的部分:
我们中间多了一个函数,但是原理是一样的:
parseSourceElements
which calls parseStatement
which callsparseBlockStatement
解析块,找到另一个块,调用
parseSourceElements
which calls parseStatement
which callsparseBlockStatement
解析块,找到另一个块,调用
parseSourceElements
which calls parseStatement
which callsparseBlockStatement
解析块,找到另一个块,调用
繁荣
IE(以及所有其他封闭源代码,如 Opera)
......将仍然是一个谜,除非他们突然有想要公开他们的资源的冲动,或者如果一位有进取心的员工与我们分享了内部信息。上面两个伟大的引擎以同样的方式做这件事,所以我们可以假设其他浏览器也做同样的事情。
如果浏览器没有崩溃,那是一个有趣的问题,但这个答案不能指望咳嗽答案。