我想做的是
通过语法阅读我的JavaScript代码
在每个函数的主体内编写特定的行。
对于。例如
输入
function(){
console.log('this is some function');
}
function somefunc (args){
console.log('this is some other function');
function(){
console.log('function inside a function');
}
}
输出
function(){
//auto generated debug log
debug('some text');
console.log('this is some function');
}
function somefunc (args){
//auto generated debug log
debug('some text');
console.log('this is some other function');
function(){
//auto generated debug log
debug('some text');
console.log('function inside a function');
}
}
我能够识别该功能,但无法将所有内容都放在一起。我需要一些面包屑来朝着正确的书写语法方向移动,以实现所需的输出。
我的想法是只专注于解析函数,而忽略固有缺陷的其他所有内容(即将其转回)。
到目前为止,我所做的是
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
"(" return '('
")" return ')'
<<EOF>> return 'EOF'
"function" return 'FUNCTION'
"{" return '{'
"}" return '}'
. return 'ANYTHING'
/lex
/* operator associations and precedence */
%start expr
%% /* language grammar */
expr: any EOF
{typeof console !== 'undefined' ? console.log($1) : print($1);
return $1;}
;
fun: FUNCTION '(' any ')' '{' any '}'
{$$=$1+$2+$3+$4+$5+'console.log(something)'+$6+$7}
;
any: ANYTHING
{$$=$1;}
| any ANYTHING
{$$=$1+$2}
| FUNCTION '(' any ')' '{' any '}'
{$$=$1+$2+$3+$4+$5+'console.log(something)'+$6+$7}
;
最佳答案
我的想法是仅专注于解析函数并忽略其他所有内容(即将它们转回)固有存在缺陷吗?
它不是天生的缺陷。实际上,这是一种常见的方法[注1]。但是,您的解决方案需要更多的工作。
首先,您需要使词法分析器更强大。它应该正确标识注释和字符串文字。否则,您可能会冒充匹配误报的风险:这些文字中隐藏着明显的标记。理想情况下,您还可以识别正则表达式,但这要复杂得多,因为它需要解析器的配合,而诸如您建议的那种简单化的解析器没有足够的上下文来区分正则表达式的开头和除法运算符。 [笔记2]
您还需要识别标识符。否则,碰巧包含字符function
(例如compare_function
)的标识符也将是错误的匹配项。
出现问题是因为any
不能包含FUNCTION
令牌。因此,如果您的扫描仪产生一个杂散的FUNCTION
令牌,则解析将失败。
另外,请记住,括号和括号不是ANYTHING
标记。由于程序通常会有许多括号和花括号,而这些括号和括号不是函数文字的一部分,因此您需要将它们添加到any
规则中。请注意,您不想将它们添加为单个令牌。而是需要添加括号平衡的序列(例如,'(' any ')'
)。否则,您将在'}'
上出现shift-reduce冲突。 (function(){ var a = { };...
:解析器如何知道}
不会关闭函数体?)
具有两个非终端可能会更简单,例如[注3]:
any: /* empty */ { $$ = ""; }
| any any_object { $$ = $1 + $2; }
;
any_object
: ANYTHING
| fun
| '(' any ')' { $$ = $1 + $2 + $3; }
| '{' any '}' { $$ = $1 + $2 + $3; }
;
您遇到的另一个问题是扫描仪会跳过空格,因此解析器将永远不会看到它。这意味着它不会出现在语义值中,因此您的转换会删除它。这将破坏任何依赖于自动分号插入的程序,以及某些其他构造(例如,
return 42;
; return42;
完全不同。)。您可能希望将空格识别为单独的标记,然后将其添加您的any
规则(或上面的any_object
规则),以及fun
规则中function
和(
之间以及)
和{
之间的可选元素。 (由于空格将包含在any
中,因此您不得在any
非终结符旁边添加空格;这可能会导致reduce-reduce冲突。)谈到自动分号插入,建议您不要在转换后的程序中依赖它。您应该在插入的
console.log(...)
语句后放置一个明确的分号。笔记
正如艾拉·巴克斯特(Ira Baxter)在评论中指出的那样,这种方法通常被称为“孤岛解析器”,因为这样的想法是,您试图在没有其他趣味性文字的海洋中寻找“孤岛”。我相信该术语广为流传的有用论文是Leon Moonen 2001年对WCRE的贡献,即“使用岛语法生成健壮的解析器”。 (Google会为您找到全文PDF。)Google也会为您找到有关此范例的其他信息,包括Ira Baxter自己更为悲观的答案here on SO
这可能是对该基本概念的最严重的反对。如果您不想解决该问题,则需要对要转换的程序中的正则表达式施加以下限制:
括号和花括号必须保持平衡
正则表达式不能包含字符串
function
。第二个限制相对简单,因为您可以用完全等效的
function
替换[f]unction
。第一个比较麻烦。您需要将/(/
替换为/\x28/
。在您提出的语法中,由于对
any
表示的混淆而出错。 any
的第三次生产不应与fun
生产重复。相反,它应允许将fun
添加到any
序列中。 (也许您只是从该生产中遗漏了any
。但是即使如此,当您仅可以使用非终端时,也无需重复fun
生产。)关于javascript - 编写野牛语法以识别javascript函数并忽略其他所有内容,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37209419/