You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bison中获取产生式值及跨产生式类型赋值的方案咨询

问题1:判断二元运算符类别

你当前代码的核心问题是if(T_LT || T_GT || ...)这类判断永远为真,因为T_LT/T_GT都是Bison定义的非零整数常量,和你当前匹配到的运算符没有任何关系。最优实现方案如下:

  1. 扩展%union定义,新增字段存储运算符类型:
%union 
{
  char* text;
  TYPE_INFO typeInfo;
  int op_type; // 新增:存储运算符对应的token值
};
  1. 为运算符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
  1. 补全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; }
        ;
  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的语义值传递机制,把下层非终结符的属性向上层传递,方案如下:

  1. 给N_FUNCT_NAME、N_LAMBDA_EXPR、N_PROGN_OR_USERFUNCTCALL指定绑定typeInfo字段:
%type <typeInfo> N_FUNCT_NAME N_LAMBDA_EXPR N_PROGN_OR_USERFUNCTCALL
  1. 在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的分支也同理给$$赋值
            ;
  1. 在上层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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 14:06:02