Bison中获取产生式值及跨产生式类型赋值的方案咨询
问题1:判断二元运算符类别
你当前代码的核心问题是if(T_LT || T_GT || ...)这类判断永远为真,因为T_LT/T_GT都是Bison定义的非零整数常量,和你当前匹配到的运算符没有任何关系。最优实现方案如下:
- 扩展
%union定义,新增字段存储运算符类型:
%union { char* text; TYPE_INFO typeInfo; int op_type; // 新增:存储运算符对应的token值 };
- 为运算符token和运算符非终结符指定类型:
// 给所有运算符token指定绑定op_type字段 %token <op_type> T_ADD T_SUB T_MULT T_DIV T_LT T_GT T_LE T_GE T_EQ T_NE T_NOT T_AND T_OR // 给N_BIN_OP非终结符指定绑定op_type字段 %type <op_type> N_BIN_OP
- 补全
N_BIN_OP的产生式,将匹配到的运算符token值向上传递:
N_BIN_OP: T_ADD { $$ = $1; } | T_SUB { $$ = $1; } | T_MULT { $$ = $1; } | T_DIV { $$ = $1; } | T_LT { $$ = $1; } | T_GT { $$ = $1; } | T_LE { $$ = $1; } | T_GE { $$ = $1; } | T_EQ { $$ = $1; } | T_NE { $$ = $1; } | T_NOT { $$ = $1; } | T_AND { $$ = $1; } | T_OR { $$ = $1; } ;
- 修改
N_ARITHLOGIC_EXPR的判断逻辑,读取传递上来的运算符值:
N_ARITHLOGIC_EXPR : N_UN_OP N_EXPR { if($2.type == FUNCTION){ yyerror("Arg 1 cannot be function"); } $$.type = BOOL; $$.numParams = NOT_APPLICABLE; $$.returnType = NOT_APPLICABLE; } | N_BIN_OP N_EXPR N_EXPR { // 读取当前匹配的运算符值$1做判断 if($1 == T_LT || $1 == T_GT || $1 == T_LE || $1 == T_GE || $1 == T_EQ || $1 == T_NE || $1 == T_NOT){ if(!(($2.type == INT && $3.type == INT) || ($2.type == STR && $3.type == STR))){ yyerror("Arg n must be integer or string"); } else{ $$.type = BOOL; $$.numParams = NOT_APPLICABLE; $$.returnType = NOT_APPLICABLE; } } else if($1 == T_AND || $1 == T_OR){ if(($2.type == INT && $3.type == FUNCTION) || ($2.type == STR && $3.type == FUNCTION) || ($2.type == BOOL && $3.type == FUNCTION) || ($2.type == FUNCTION && $3.type == FUNCTION)){ yyerror("Arg n cannot be a function"); } else{ $$.type = BOOL; $$.numParams = NOT_APPLICABLE; $$.returnType = NOT_APPLICABLE; } } else if ($1 == T_ADD || $1 == T_SUB || $1 == T_MULT || $1 == T_DIV){ if(!($2.type == INT && $3.type == INT)){ yyerror("Arg n must be integer"); } else{ $$.type = INT; $$.numParams = NOT_APPLICABLE; $$.returnType = NOT_APPLICABLE; } } } ;
如果想要代码更简洁,可以封装辅助判断函数,比如:
static int is_relational_op(int op) { return op == T_LT || op == T_GT || op == T_LE || op == T_GE || op == T_EQ || op == T_NE; }
后续判断直接调用函数即可。
问题2:跨产生式传递函数返回类型
核心是利用Bison的语义值传递机制,把下层非终结符的属性向上层传递,方案如下:
- 给
N_FUNCT_NAME、N_LAMBDA_EXPR、N_PROGN_OR_USERFUNCTCALL指定绑定typeInfo字段:
%type <typeInfo> N_FUNCT_NAME N_LAMBDA_EXPR N_PROGN_OR_USERFUNCTCALL
- 在
N_FUNCT_NAME的产生式中给语义值赋值:
N_FUNCT_NAME : T_PROGN { // 这里给$$赋值为T_PROGN对应的返回类型,固定返回类型直接写,动态返回从函数签名存储结构中读取 $$.type = PROGN_RETURN_TYPE; $$.numParams = PROGN_PARAM_NUM; $$.returnType = PROGN_RETURN_TYPE; } // 其他N_FUNCT_NAME的分支也同理给$$赋值 ;
- 在上层
N_PROGN_OR_USERFUNCTCALL的产生式中读取下层传递的语义值:
N_PROGN_OR_USERFUNCTCALL : N_FUNCT_NAME N_ACTUAL_PARAMS { // 直接读取$1也就是N_FUNCT_NAME的语义值赋值给当前节点 $$.type = $1.type; $$.numParams = $1.numParams; $$.returnType = $1.returnType; // 此处可新增参数数量、类型校验逻辑 } | T_LPAREN N_LAMBDA_EXPR T_RPAREN N_ACTUAL_PARAMS { // lambda分支同理读取N_LAMBDA_EXPR的语义值 $$.type = $2.type; $$.numParams = $2.numParams; $$.returnType = $2.returnType; } ;
内容的提问来源于stack exchange,提问作者MaddieP
相关产品推荐
相关产品推荐

