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

Bison代码无法正确打印数组值问题求助

解决Bison数组语法仅打印第一个元素的问题

你的问题主要出在两个核心点:语法规则没处理元素间的逗号分隔,以及没有正确聚合array_vals的语义值,导致只能拿到第一个元素。下面一步步帮你修正:

1. 先补全语法:处理逗号分隔

你的输入是[10, 20, 30, 40],但原语法完全没匹配元素间的逗号——这会直接导致解析错误(除非你的Lexer把逗号当成空白符忽略了,但这不符合常规数组语法)。首先给逗号声明token,再修改array_vals规则:

%token ','  // 把逗号声明为合法token

然后调整array_vals,支持空数组、单个元素、逗号分隔的多个元素:

array_vals: /* 空数组,匹配[]的情况 */
          | vals                // 单个元素,比如[10]
          | array_vals ',' vals // 多个元素,逗号分隔,比如[10,20]

2. 声明语义类型,实现元素累积

原代码没给非终结符指定语义类型,Bison默认无法把多个元素的值攒起来。我们用std::vector存储数组元素,用std::variant兼容int、float、string三种值类型,先在Bison定义段添加必要的代码:

%{
#include <iostream>
#include <vector>
#include <variant>
#include <string>

// 定义能容纳三种类型值的变体
using Value = std::variant<int, float, std::string>;
// 用vector存储整个数组的元素列表
using ValueList = std::vector<Value>;
%}

// 定义语义值联合体,绑定终结符和非终结符的类型
%union {
    int ival;
    float fval;
    std::string* sval;
    ValueList* list;
    Value* val;
}

// 给终结符绑定对应的语义类型
%token <ival> INT
%token <fval> FLOAT
%token <sval> STRING
%token ','

// 给非终结符绑定语义类型
%type <list> array_vals
%type <val> vals

3. 给规则加语义动作,累积所有元素

先修改vals规则,把每个token的值包装成Value对象:

vals: INT     { $$ = new Value($1); }
    | FLOAT   { $$ = new Value($1); }
    | STRING  { $$ = new Value(*$1); delete $1; } // 注意Lexer中STRING是new出来的,要释放内存

再修改array_vals规则,用vector把所有元素攒起来(推荐左递归,Bison处理左递归效率更高):

array_vals: /* 空数组 */       { $$ = new ValueList(); }
          | vals                { $$ = new ValueList(); $$->push_back(*$1); delete $1; }
          | array_vals ',' vals { $1->push_back(*$3); $$ = $1; delete $3; }

4. 修改array规则,打印全部元素

现在$2是存储了所有元素的ValueList*,我们可以遍历它打印每个值:

array: '[' array_vals ']' { 
    std::cout << "数组元素:";
    // 用std::visit访问variant里的不同类型值
    for (const auto& val : *$2) {
        std::visit([](auto&& arg) {
            std::cout << arg << " ";
        }, val);
    }
    std::cout << std::endl;
    delete $2; // 释放内存
}

关键问题解释

  • 原代码里array_vals没有语义值聚合逻辑,Bison只会保留第一个vals的语义值,后续递归的元素直接被丢弃了。
  • 必须显式声明语义类型,让Bison知道如何传递和累积多个元素的值。
  • 逗号是数组语法的必要部分,必须在规则中匹配,否则根本无法正确解析带逗号的输入。

如果不想手动管理内存,可以用std::unique_ptr代替裸指针,比如把ValueList*改成std::unique_ptr<ValueList>,这样就不用手动delete了。

内容的提问来源于stack exchange,提问作者user9362751

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:57:37