【问题标题】:C++ program checking for tag validityC++ 程序检查标签有效性
【发布时间】:2012-09-27 02:57:11
【问题描述】:

我是 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
 }

【问题讨论】:

  • 您的代码堆栈的寿命太短。您应该在函数顶部附近声明它,以便它可以看到多个标签。可能还有其他问题,但如果没有程序的完整可编译文本,实际上不可能找到不太明显的东西。

标签: c++ debugging tokenize


【解决方案1】:

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

stack&lt;string&gt; 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。实际上如果文件末尾的标签堆栈上有任何 LEFT,则必须存在不平衡,因此会出现错误。将那个条件检查作为你整体评估的一部分,我保证你会开始看到错误的过滤。

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

【讨论】:

  • 我已将其更改为在整个循环之外,但它仍将所有内容返回为真。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
相关资源
最近更新 更多