Javascript 递归布尔和/或到数组jison解析器
我对jison非常陌生,并且已经设法拼凑出一个有用的查询解析器。我现在尝试创建一个解析器,它可以将“a==1、b==1和c==1”这样的字符串解析为Javascript 递归布尔和/或到数组jison解析器,javascript,parsing,jison,Javascript,Parsing,Jison,我对jison非常陌生,并且已经设法拼凑出一个有用的查询解析器。我现在尝试创建一个解析器,它可以将“a==1、b==1和c==1”这样的字符串解析为 {and: [ {a: {eq: 1}}, {b: {eq: 1}}, {c: {eq: 2}} ]} {or: [ {a: {eq: 1}}, {and: [ {b: {eq: 1}}, {c: {eq: 1}} ]} ]} 而像“a==1或b==1和c==1”这样的字符串应该解析为 {and: [
{and: [
{a: {eq: 1}},
{b: {eq: 1}},
{c: {eq: 2}}
]}
{or: [
{a: {eq: 1}},
{and: [
{b: {eq: 1}},
{c: {eq: 1}}
]}
]}
而像“a==1或b==1和c==1”这样的字符串应该解析为
{and: [
{a: {eq: 1}},
{b: {eq: 1}},
{c: {eq: 2}}
]}
{or: [
{a: {eq: 1}},
{and: [
{b: {eq: 1}},
{c: {eq: 1}}
]}
]}
到目前为止,我的语法是这样的:
%lex
%%
\s+ /*skip whitespace*/
\"(\\.|[^"])*\" yytext = yytext.substr(1, yyleng-2); return 'STRING';
"==" return '==';
and[^\w] return 'and';
or[^\w] return 'or';
[0-9]+(?:\.[0-9]+)?\b return 'NUMBER';
[a-zA-Z][\.a-zA-Z0-9_]* return 'SYMBOL';
<<EOF>> return 'EOF';
/lex
%left 'or'
%left 'and'
%left '=='
%start expressions
%%
expressions
: e EOF
{$$ = $1;}
;
e
: property '==' value
{ $$ = {}; $[$1] = {eq: $3}; }
| boolAnd
{ $$ = {and: $1}}
| boolOr
{ $$ = {or: $1}}
;
boolAnd
: boolAnd 'and' e
{$$ = $1; $1.push($3);}
| e 'and' e
{$$ = [$1, $3];}
;
boolOr
: boolOr 'or' e
{$$ = $1; $1.push($3);}
| e 'or' e
{$$ = [$1, $3];}
;
property
: SYMBOL
{$$ = $1;}
;
value
: NUMBER
{$$ = Number(yytext);}
| STRING
{$$ = yytext; }
;
有人能就我做错了什么提出建议吗?非常感谢
e : boolAnd
不可能在以下两者之间作出决定:
boolAnd: e 'and' e
| boolAnd 'and' e
这正是jison所抱怨的。(值得注意的是,将boolAnd
减少到e
似乎并不是您想要的。这实际上是一个类型错误,或者如果JS有类型的话也会是这样。)
就我个人而言,我只会使用二叉树;根据我的经验,他们更容易合作。您可以使用单个非终结符和优先级声明轻松实现这一点
%left 'or'
%left 'and'
%%
e
: property '==' value
{ $$ = {eq: [$1, $3]}; /* This seems better to me. YMMV. }
| e 'and' e
{ $$ = {and: [$1, $3]}}
| e 'or' e
{ $$ = {or: [$1, $3]}}
| '(' e ')'
{ $$ = $2 /* You didn't have this one, but it seems useful */ }
;
可以制作一个处理可变运算符的语法(即,将
xopyopz
简化为{OP:[x,y,z]}
),但要正确处理它实际上需要相当多的工作,而且它不容易产生基于优先级声明的解决方案。除非您真的想区分x OP y OP z
和x OP(y OP z)
,这在布尔运算符的情况下是不必要的,否则在第二次遍历解析树时折叠多个类似的二元运算符,或者在创建二元节点时直接折叠多个类似的二元运算符通常更容易、更一般,通过检查子表达式的运算符类型。这很有帮助。我没有考虑过第二次通过这棵树来折叠同一个操作符。最后,我编写了一个递归,将我的二进制布尔运算符数组展平,效果很好。尽管我很好奇,考虑到你的警告,这种东西的弹性会是什么。非常感谢!