1

所以我有一个 Node 对象的抽象语法树。每个节点都有任意数量的子节点以及任意数量的标签,这些标签是通过 std::map 结构附加到节点的信息花絮。现在我想以类似 XML 的格式打印整个语法树。为此,我使用此功能:

int __ostreamNode_indent = 0;
std::ostream & operator << ( std::ostream & ss, Node* n )
{   
    for( int i = 0 ; i < __ostreamNode_indent ; ++i )
        ss << "  ";

    ss << "<" << n->getSymbolType() << " ";
    for( std::map<std::string,std::string>::iterator itr = n->getTags().begin() ; itr != n->getTags().end() ; ++itr )
    {   
        ss << itr->first << "=\"" << itr->second << "\" ";
    }
    ss << "numtags=" << n->getTags().size() << " ";

    if( n->getChildren().size() == 0 )
        ss << "/";

    ss << ">" << std::endl;

    __ostreamNode_indent++;
    for( unsigned int i = 0 ; i != n->getChildren().size() ; ++i )
    {   
        ss <<  n->getChildren().at(i);
    }
    __ostreamNode_indent--;

    if( n->getChildren().size() != 0 )
    {
        for( int i = 0 ; i < __ostreamNode_indent ; ++i )
            ss << "  ";

        ss << "</" << n->getSymbolType() << ">" << std::endl;
    }

    return ss;
}

结构正是我想要的方式:XML-tag 类型是节点的类型,并且节点的标签嵌入在同一个 XML 开始标签中。子节点放置在开始标签和结束标签之间。这是一个例子:

<block line="0" numtags=2 >
  <funcdef line="0" numtags=2 >
    <identifier line="0" col="13" value="main" numtags=3 />
    <expressionunion line="0" numtags=2 >
      <identifier line="0" col="16" value="a" numtags=3 />
      <identifier line="0" col="19" value="b" numtags=3 />
    </expressionunion>
    <assignment line="1" numtags=2 >
      <identifier line="1" col="5" value="c" numtags=3 />
      <numel line="1" numtags=2 >
        <solveunder line="1" numtags=2 >
          <identifier line="1" col="11" value="a" numtags=3 />
          <identifier line="1" col="16" value="b" numtags=3 />
        </solveunder>
      </numel>
    </assignment>
    <return line="2" numtags=2 >
      <power line="2" numtags=2 >
        <identifier line="2" col="12" value="c" numtags=3 />
        <identifier line="2" col="14" value="b" numtags=3 />
      </power>
    </return>
  </funcdef>
</block>

这个例子也说明了这个问题。我用线条遍历所有标签

    for( std::map<std::string,std::string>::iterator itr = n->getTags().begin() ; itr != n->getTags().end() ; ++itr )
    {   
        ss << itr->first << "=\"" << itr->second << "\" ";
    }

并将它们输出为 key="value"。但是,有时此循环会跳过最后一个元素。请注意紧跟在此循环之后的行如何输出标签的数量。当存在两个标签时,实际上只显示第一个。为什么不显示第二个?

编辑:马克 B 回答了这个问题;阅读他的答案以了解问题的确切解释。他在心里猜到这是getTags()的定义:

std::map<std::string,std::string> getTags()
{   
    return tags;
};

将其更改为此(添加&符号)就可以了:

std::map<std::string,std::string> & getTags()
{   
    return tags;
};
4

2 回答 2

6

我将使用我的心理调试技能并建议getTags()按值返回容器(而不是对实际容器的引用),因此beginandend节点指的是不同的临时容器。在那一点上,迭代发生的任何事情都是公平的,因为原始的临时容器已经消失了。

于 2013-01-30T14:29:59.177 回答
0

马克可能是对的。

另一种可能性是您损坏了该地图。通过在地图中编辑一个键来表示。

于 2013-01-30T14:43:03.003 回答