【问题标题】:JavaScript Language Parsing: Distinguish function expressions and declarationsJavaScript 语言解析:区分函数表达式和声明
【发布时间】:2014-11-30 20:25:57
【问题描述】:

假设我正在创建一个仅涉及解析函数的简单 JavaScript 语言解析器。

我需要区分function "declarations"/"statements"function expressions。因为它们看起来几乎相同,所以我想我需要知道使用 function 的上下文。

我想我可以通过前面的记号来确定一个函数表达式。我认为以下算法可能有效:

  • 如果令牌是“函数”,那么
    • 如果之前的令牌是operator
      除了“关闭”运算符,如“]”、“}”或“)”,OR
      如果前一个标记是“:”,那么
      • Function 是一个函数表达式。
    • 其他
      • Function 是一个函数声明。

我能否期望该算法能够正确确定 function 是声明还是表达式?如果它有缺陷,应该修复什么?或者,如果不能仅通过查看前一个标记来区分形式,我还能如何以最少的努力来区分形式?

(我知道 Esprima 和 co. 存在。我想用不同的语言实现 native 解析器。)

【问题讨论】:

  • 解析器是用哪种语言实现的?
  • @AndersonGreen Emacs Lisp。
  • 已经用 Emacs Lisp 编写了几个解析器生成器。请参阅此处的讨论:stackoverflow.com/questions/2228477/parsing-in-emacs-lisp
  • 无论我是否使用解析器生成器,我仍然需要确定我的问题中算法的准确性。
  • 你在写什么样的解析器?仅检查前一个标记可能会在某些边缘情况下给出错误的结果。你不能只看周围的上下文,不管它期望一个表达式还是一个语句,来更紧密地遵循 ES5 语法?

标签: javascript parsing expression declaration abstract-syntax-tree


【解决方案1】:

我也在写一个JavaScript parser - 用于Java,带有JavaCC。是“时尚”吗? :)

我不是专家,所以我的术语可能有些家喻户晓,请原谅。

如果我理解你的想法是正确的,你似乎想在词法层面区分函数声明和表达式。我认为这是一种错误的方式。 JavaScript 有一个非常棘手的语法,这可能适用于函数声明,但你会一直遇到极端情况。其中最复杂的两个是自动分号插入和正则表达式与除法。

现在回答你的问题。

语法:

FunctionDeclaration :
    function Identifier ( FormalParameterList_opt ) { FunctionBody }

FunctionExpression :
    function Identifier_opt ( FormalParameterList_opt ) { FunctionBody }

一个案例function ( 很简单。无标识符 - 不能是 FunctionDeclaration。然而,这并不能保证这个 canFunctionExpression: function () {} 在顶层是语法错误的。

FunctionExpression 可能出现在表达式可能出现except for ExpressionStatement 的地方。

所以问题是,您能否可靠地确定您是否可以在词法的某个地方期待一个表达式(即仅查看前一个标记)。

我认为这可能相当困难。看看my analysis 是否有类似的问题(从词法上检测正则表达式)。

为你算法:

  • 如果令牌是“函数”,那么
    • 如果前一个令牌是运算符, 除了“关闭”运算符,如“]”、“}”或“)”,OR
      如果前一个标记是“:”,那么
      • Function 是一个函数表达式。
    • 其他
      • Function 是一个函数声明。

如果之前的令牌是/ 怎么办?接下来是function?你会认为这是一个函数表达式,但这可能是一个正则表达式文字。

还有:不代表这是一个函数表达式,这可能是无效

label: function() {}

我还认为 ASI 可能会出现更多并发症。考虑:

i++
function a() {}

++function前面的后缀运算符,而function a() {}是函数声明,前面自动插入了一个分号。

所以我认为你的算法不正确。而且我不确定您是否可以仅仅查看几个以前的令牌就可以逃脱。

【讨论】:

  • @PiotrDabkowski — 在您发布的代码中,; 是一个空语句,function f() {} 是一个函数声明(关键字 function 在语句的开头), + 1 是一个解析为正值的表达式。
  • 嗯,这很奇怪,谢谢。但是 * 不会解决 :) 我认为它是实现中的一个错误,因为它应该尽可能地在没有 ; 的情况下解析。插入。并且 +1 不被视为数字文字(文字没有符号)。
  • @PiotrDabkowski ;function f() {} * 1 无效。 ; 是空语句,function f() {} 是函数声明,* 1 不能出现。
  • 这很奇怪,因为 1*function f() {} 有效。而且我在规范中找不到任何可以解释函数 f() {} * 1 错误的内容。 function f() {} 在这两种情况下都应被视为命名函数表达式,因为它是表达式的一部分。似乎 JS 实现并不关心以下标记。
  • @PiotrDabkowski function f() {} 是一个源元素的函数声明。解析程序时,它匹配顶级源元素。所以下面的* 1 也必须是一个源元素,它不是。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多