我想做的是
有关。例如 输入
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}
;
答案 0 :(得分:4)
我的想法是专注于解析功能而忽略其他一切(即将其倾倒)本身存在缺陷吗?
它本身并没有缺陷。实际上,这是一种常见的方法[注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
非终端旁边;这可能会导致减少 - 减少冲突。)
说到自动分号插入,建议您不要在转换后的程序中依赖它。您应该在插入的console.log(...)
语句后添加一个显式分号。
这可能是对这个基本想法最严重的反对意见。如果您不想解决它,则需要对要转换的程序中的正则表达式进行以下限制:
function
。第二个限制相对简单,因为您可以将function
替换为完全等效的[f]unction
。第一个更麻烦;您需要将/(/
替换为/\x28/
。
在您提出的语法中,由于对any
所代表的内容存在疑惑,因此存在错误。 any
的第三个作品不应与fun
作品重复;相反,它应该允许fun
添加到any
序列。 (也许你只是从那个作品中遗漏了any
。但即便如此,当你可以使用非终端时,也没有必要重复fun
制作。)