0

我是 C++ 的初学者,并试图使检查按预期工作。但几乎所有测试都返回 true。在这种情况下,它只假设返回 true:

<red> Red blank <dim> I'm now dim and red. </dim> </red>

但这在现在也返回 true:

<red> Blah I'm red.<dim> Im dim now </red> </dim>

或这个 :

 <red> blah <im dim now

所以我想知道我的代码中是否有一些我忽略的东西。

bool is_well_formed(ifstream& ifs, string& error_msg) {

string fname,line;
Token tok;
Lexer lexer;
tags.insert("blue");
tags.insert("red");
tags.insert("cyan");
tags.insert("white");
tags.insert("yellow");
tags.insert("magenta");
tags.insert("dim");
tags.insert("underline");
tags.insert("bold");

stack<string> tagstack;
while (getline(ifs, fname)) { 
    // tries to open the file whose name is in string fname

    if (ifs.fail()) {
        cerr << "ERROR: Failed to open file " << fname << endl;
        ifs.clear();
    } else {
        while (getline(ifs, line)) {
            lexer.set_input(line);
            while (lexer.has_more_token()) {
                tok = lexer.next_token();
                string tmpTok = tok.value;
                switch (tok.type) {
                case TAG:

                    // If it has /, remove / from tmpTok
                if (tok.value[0] == '/') {
                    // If it's a closing t
                        tmpTok = tmpTok.substr(1,tmpTok.length()-1);
                    }
                    if(tags.find(tmpTok) == tags.end()) {
                    // Check whether the encountered tag is valid
                    error_return("Tag " + tmpTok + " is invalid!");
                    return false;
                     } else {
                     // Valid Tag encountered

                     tagstack.push(tmpTok);
                     // Check if the tags are formed properly
                            if (tmpTok.find('/')) {
                             // Remove / from tmpTok
                            string closingTag =  tmpTok;
                                string openingTag = tagstack.top();
                                tagstack.pop();
                    if(closingTag.compare(openingTag) != 0) {
                        error_return(closingTag+"doesn't match" +openingTag);
                        return false;
                      } //else 
                                  //  return true; // if the file is well formed
                 }/**else{
                    tagstack.push(tmpTok);
                 }*/
                     }// else end    

                    break;
               case IDENT:
                   // cout << "IDENT: " << tok.value << endl;
                    break; 
                case ERRTOK:
                    error_return("Syntax error on this line\n");
                    return false;
                    //cout << "Syntax error on this line\n";
                    break;
                case ENDTOK:
                    break;
                }
            }
        }
    }
}
return true; // if the file is well-formed
 }
4

1 回答 1

1

对于这么简单的事情(这一定很简单,因为这不可能解析现实世界中的谁知道你将要得到的 XML)有几件事可能会有所不同,但你的直接问题是直截了当的:

stack<string> tagstack声明移到每行循环之外,或者更好的是,移到整个处理循环之外。一旦您将标签压入堆栈并退出else{}声明它的块的范围,它现在所在的位置,该状态就会丢失。

您的状态机可以使用一些工作来提高健壮性,但这是另一个问题,请先修复标签堆栈的范围。

你需要在调试器下运行它,你应该习惯这一点,因为我认识的每一位专业 C/C++ 工程师都将他们一半的生产生活都花在了一个人身上。它伴随着业务而来。话虽如此,关于始终返回 true,我会将这些问题提供给您,而不是在这里回答,而是再次在调试器中进行调查

  1. 如果词法分析器从不返回标记类型的 TAG 会发生什么?
  2. 如果词法分析器返回一个 TAG 类型的标记,但它从不以“/”开头,会发生什么?
  3. 如果词法分析器返回一个标记类型的 TAG 会发生什么情况,它以“/”开头,但您随后继续砍掉“/”?

在您的代码中的一个地方,您似乎正在检查令牌的第一个字符是否有“/”,而不是两行之后,您似乎试图丢弃开始和结束元素标记“<”和“>” . 具体来说:

if (tok.value[0] == '/') {
   // If it's a closing t
   tmpTok = tmpTok.substr(1,tmpTok.length()-1);
}

这两行代码对于结束标签是不一致的。首先你检查一个前导'/',表明 <> 已经被剥离,下一行你继续从字符串中剥离前导和尾字符,就好像它仍然存在两个 <>。但是如果它们不存在怎么办(而且它们不可能存在,否则您对“/”的检查将是错误的。您现在看到了吗?您正在切掉“/”。这重要吗?好吧。再往下看代码,我们发现:

if (tmpTok.find('/')) {
   // Remove / from tmpTok
   string closingTag =  tmpTok;
   string openingTag = tagstack.top();
   tagstack.pop();
   if(closingTag.compare(openingTag) != 0) {
      error_return(closingTag+"doesn't match" +openingTag);
      return false;
   } //else
}

'/' 检查中的任何代码都不会执行,因为您只是将其切断。因此,您将遍历整个文件,在令牌认为它们都是条目令牌之后添加令牌,然后用完行,然后presto,返回true。实际上,如果文件末尾的 tagstack 上有任何 LEFT ,则必须存在不平衡,因此会出现错误。将该条件检查作为整体评估的一部分,我保证您会开始看到错误的过滤。

现在让你去调试器。我设法找到所有这些只是仔细阅读代码。想象一下在调试器中逐行运行时您会看到的内容,您可以在其中实时查看更改。

于 2012-09-27T03:24:21.033 回答