flex/bison 中的表达式出现次数
Expression occurrences in flex/bison
假设我有一个这样的 Bison 表达式:
multiply: T_FIGURE { $$ = ; }
| multiply T_ASTERISK multiply { $$ = * ; }
;
它应该 return 一些数字相乘的结果,或者如果只提供一个数字则返回输入。如果我想将提供的数字限制为最多 3 个,我将重写表达式如下:
multiply: T_FIGURE { $$ = ; }
| T_FIGURE T_MULTIPLY T_FIGURE { $$ = * ; }
| T_FIGURE T_MULTIPLY T_FIGURE T_MULTIPLY T_FIGURE { $$ = * * ; }
;
我的问题:有没有办法重写这个表达式,这样我就不必手动指定出现次数,而是使用某种参数能够轻松地将上限更改为例如 30出现次数?
一句话,"No"。这不是野牛的特征(也不是我所知道的任何 yacc 衍生物)。
解决此类问题的最简单方法是使用代码生成器。要么使用像 m4
这样可用的宏处理器,要么用任何你觉得舒服的脚本语言编写你自己的脚本table。
您还可以通过对语义操作中的参数进行计数来动态解决问题(这意味着修改语义类型以同时包含值和计数。)如果超出计数,则可能会抛出语法错误。 (同样,在你的语义动作中。)这种方法的主要优点是避免破坏解析器的状态 table。如果您的限制很大并且相互影响,您可能会发现您正在生成一个非常大的状态机。
作为一个非常简单的例子(只有一个运算符):
%{
typedef struct ExprNode {
int count;
double value;
} ExprNode;
%}
%union {
ExprNode expr;
double value;
}
%token <value> T_FIGURE
%type <expr> expr multiply
%%
expr: T_FIGURE { $$.count = 0; $$.value = ; }
multiply: expr
| multiply '*' expr { if (.count >= LIMIT) {
yyerror("Too many products");
YYABORT;
}
else {
$$.count = .count + 1;
$$.value = .value * .value;
}
}
假设我有一个这样的 Bison 表达式:
multiply: T_FIGURE { $$ = ; }
| multiply T_ASTERISK multiply { $$ = * ; }
;
它应该 return 一些数字相乘的结果,或者如果只提供一个数字则返回输入。如果我想将提供的数字限制为最多 3 个,我将重写表达式如下:
multiply: T_FIGURE { $$ = ; }
| T_FIGURE T_MULTIPLY T_FIGURE { $$ = * ; }
| T_FIGURE T_MULTIPLY T_FIGURE T_MULTIPLY T_FIGURE { $$ = * * ; }
;
我的问题:有没有办法重写这个表达式,这样我就不必手动指定出现次数,而是使用某种参数能够轻松地将上限更改为例如 30出现次数?
一句话,"No"。这不是野牛的特征(也不是我所知道的任何 yacc 衍生物)。
解决此类问题的最简单方法是使用代码生成器。要么使用像 m4
这样可用的宏处理器,要么用任何你觉得舒服的脚本语言编写你自己的脚本table。
您还可以通过对语义操作中的参数进行计数来动态解决问题(这意味着修改语义类型以同时包含值和计数。)如果超出计数,则可能会抛出语法错误。 (同样,在你的语义动作中。)这种方法的主要优点是避免破坏解析器的状态 table。如果您的限制很大并且相互影响,您可能会发现您正在生成一个非常大的状态机。
作为一个非常简单的例子(只有一个运算符):
%{
typedef struct ExprNode {
int count;
double value;
} ExprNode;
%}
%union {
ExprNode expr;
double value;
}
%token <value> T_FIGURE
%type <expr> expr multiply
%%
expr: T_FIGURE { $$.count = 0; $$.value = ; }
multiply: expr
| multiply '*' expr { if (.count >= LIMIT) {
yyerror("Too many products");
YYABORT;
}
else {
$$.count = .count + 1;
$$.value = .value * .value;
}
}