假设我正在创建一个简单的 JavaScript 语言解析器,它只涉及解析函数。
我需要区分 function "declarations"/"statements"和 function expressions 。因为它们看起来几乎相同,所以我想我需要知道使用 function
的上下文。
我想我可以通过前面的标记来确定函数表达式。我认为以下算法可能有效:
- 如果 token 是“函数”,那么
- 如果之前的 token 是 operator ,
除了“结束”运算符,例如“]”、“}”或“)”,或者
如果前一个标记是“:”,那么- 函数是一个函数表达式。
- 其他
- 函数是函数声明。
- 如果之前的 token 是 operator ,
我可以期望该算法正确确定函数
是声明还是表达式吗?如果有缺陷,应该修复什么?或者,如果仅通过查看前一个标记无法区分表单,那么我怎样才能以最少的努力来区分表单?
(我知道 Esprima 和 co. 存在。我想用不同的语言实现 native 解析器。)
最佳答案
我也在写JavaScript parser - 对于 Java,使用 JavaCC。是“流行”吗? :)
我不是专家,所以我的术语可能有点家庭水平,请原谅。
如果我理解你的想法正确,似乎你想在词法级别上区分函数声明和表达式。我认为这是一个错误的方式。 JavaScript 有一个非常棘手的语法,这可能适用于函数声明,但你会一直遇到极端情况。其中最复杂的两个是自动分号插入和正则表达式与除法。
现在回答你的问题。
语法:
FunctionDeclaration :
function Identifier ( FormalParameterList_opt ) { FunctionBody }
FunctionExpression :
function Identifier_opt ( FormalParameterList_opt ) { FunctionBody }
一种情况函数(
很简单。没有标识符 - 不能是FunctionDeclaration
。但这并不能保证这个可以 FunctionExpression
:顶层的 function () {}
在语法上不正确。
FunctionExpression
可能出现在表达式可能出现的位置 except for ExpressionStatement
.
所以问题是,你能否可靠地找出是否可以在词法上的某个地方期待一个表达式(即仅查看前一个标记)。
我认为这可能相当困难。看看my analysis对于类似的问题(从词法上检测正则表达式)。
适合您的算法:
- 如果 token 是“函数”,那么
- 如果前一个标记是运算符,
除了“结束”运算符,例如“]”、“}”或“)”,或者
如果前一个标记是“:”,那么- 函数是一个函数表达式。
- 其他
- 函数是函数声明。
- 如果前一个标记是运算符,
除了“结束”运算符,例如“]”、“}”或“)”,或者
如果前一个标记是 /
怎么办?接下来是function
?您会认为这是一个函数表达式,但它可能是一个正则表达式文字。
另外 :
并不意味着这是一个函数表达式,这可能无效:
label: function() {}
我还认为 ASI 可能会带来进一步的并发症。考虑:
i++
function a() {}
++
是 function
之前的后缀运算符,但 function a() {}
是函数声明,插入了分号自动位于其前面。
所以我认为你的算法不正确。而且我不确定您是否可以仅仅查看之前的几个标记就可以逃脱惩罚。
关于JavaScript语言解析: Distinguish function expressions and declarations,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27217854/