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{}それが宣言されているブロックのスコープを終了するとすぐに、その状態は失われます。

状態マシンは、より堅牢にするためにいくつかの作業を使用できますが、それは別の問題です。最初にタグスタックの範囲を修正してください。

これはdebuggerの下で実行する必要があります。これに慣れる必要があります。私が知っているすべてのプロの C/C++ エンジニアは、生産的な生活の半分を 1 つのデバッガーで費やしているからです。それはビジネスに伴います。そうは言っても、常に true を返すことに関して、ここで回答するのではなく、デバッガーでもう一度調査するために、これらの質問をあなたに差し上げます。

  1. lexer が TAG のトークン タイプを返さない場合はどうなりますか?
  2. lexer が TAG 型のトークンを返すが、それが '/' で始まらない場合はどうなりますか?
  3. lexer が TAG のトークン タイプを返し、それが '/' で始まっているのに、'/' を切り落とすとどうなりますか?

コードのある場所で、トークンの最初の文字で「/」をチェックしているように見えますが、2 行後ではなく、開始要素マーカーと終了要素マーカー「<」と「>」を破棄しようとしているようです。 . 具体的には:

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

これらの 2 行のコードは、終了タグと一致しません。最初に先頭の '/' をチェックし、<> が既に削除されていることを示します。次の行では、両方の <> がまだ存在しいるかのように、先頭と末尾の文字を文字列から削除します。しかし、それらが存在しない場合はどうなりますか (そして、存在することはできません。そうでなければ、'/' のチェックは false になります。今、わかりますか? あなたは '/' を切り取っています。それは重要ですか? そうですね。コードをさらに下に見ると、次のことがわかります。

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
}

「/」のチェック内のコードは、切り取っただけなので実行されません。したがって、トークンがすべてエントリ トークンであると考えて、トークンを次々と追加してファイル全体を調べてから、行を使い果たし、すぐに true を返します。実際には、ファイルの末尾のタグスタックに何か残っている場合は、バランスが崩れている必要があるため、エラーが発生します。その条件付きチェック全体的な評価の一部として配置すると、これから誤ったフィルタリングが見られるようになることを保証します.

今、あなたをデバッガーに連れて行ってください。コードを熟読するだけで、これらすべてを見つけることができました。リアルタイムで変更を確認できるデバッガーで実際に行ごとに実行しているときに表示されるものを想像してみてください。

于 2012-09-27T03:24:21.033 に答える