Reader类实现中的文件读取错误

时间:2019-10-27 14:05:41

标签: c++

我正在尝试为自己正在使用的业余编程语言实现Reader类。读取者的工作非常简单,即读取源文件并删除注释。

这是Reader类的定义:

// reader.hh
// Contains Reader Class specifications

#ifndef PHI_SRC_FRONTEND_READER_HH
#define PHI_SRC_FRONTEND_READER_HH

#include "errhandler.hh"

class Reader
{
public:
    Reader() = default;

    auto val() const -> String const & { return val_; }

    void read(String const &filename);

    explicit operator bool() const { return success; }
    auto operator!() const -> bool { return !success; }

    friend auto operator==(Reader const &lhs, Reader const &rhs) -> bool
    {
        return lhs.val_ == rhs.val_;
    }

    friend auto operator!=(Reader const &lhs, Reader const &rhs) -> bool
    {
        return lhs.val_ != rhs.val_;
    }

    friend auto operator<<(std::ostream &stream, Reader const &read) -> std::ostream &
    {
        return stream << read.val_;
    }

private:
    String val_;
    bool success;
};

#endif

以前,我为Reader的{​​{1}}函数使用了一个非常简单的占位符。基本上,它使用istreambuf_iterator复制了文件中的所有内容

read

这很好,它通过了单元测试,我也手动检查了输出,也很好。

但这只是一个占位符,实际的void Reader::read(String const &filename) { val_.clear(); success = true; // success flag, true by default auto file = std::ifstream{filename}; if(!file) { log_error(Error{Error::Type::ReadError, "Could not open file"}); success = false; } val_.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); // Read entire file into val_ } 需要删除注释。这使我得以实现:

Reader

但是,这很奇怪地导致单元测试失败。。我已经比较了// reader.cc // Contains Reader Class Implementation // Work In Progress, placeholders being used for now #include <fstream> #include <sstream> #include "reader.hh" void Reader::read(String const &filename) { val_.clear(); success = true; // success flag, true by default auto inStringLiteral = false; // Variable to determine if the reader is currently reading a string literal // (enclosed in double quotes) // In order to not mistake '//' inside literals as comments" auto file = std::ifstream{filename}; if(!file) { log_error(Error{Error::Type::ReadError, "Cannot open file: " + filename}); success = false; return; } for (unsigned char c; file >> c; ) { // ASCII characters only use 7 bits, which is up to 127 // So value of an ascii char must be lesser than 128 if (c < 128) { if(c == '"') { inStringLiteral = !inStringLiteral; // flip the value of the boolean } if(!inStringLiteral && c == '/') { // If we're not inside a string literal enclosed in quotes, and find a backslash // Peek at the next character to check if it is a backslash // In case two consecutive backslashes are found, treat it as a comment and // ignore everything until the end of line if(file >> c) { if(c == '/') { // keep reading until a newline is found while(file >> c && c != '\n') { } } else { c = '/'; file.unget(); } } else { c = '/'; } } val_ += c; } else { log_error(Error{Error::Type::ReadError, "Unrecognized character(s) found in file: " + filename}); success = false; return; } } } 函数的两个版本的输出,(显然)它们的输出完全相同。注意,我实际上没有检查字符串的相等性,但是它们确实 look 相同。我已经尝试找到很多错误的原因,但是失败了。...

这是我用于阅读器的单元测试(使用GoogleTest):

read

正如我之前提到的,它在第一个占位符版本中工作得很好,但是实际的#include <gtest/gtest.h> #include "frontend/reader.hh" TEST(ReaderTest, BaseTestCase) { auto TestReader = Reader{}; auto const ExpectedOutput = String{ R"delim(Int test = 0; String test2 = "abcdefgh"; Float test3 = 0.9876; )delim"}; TestReader.read("TestFiles/ReaderTest_BaseTestCase.phi"); ASSERT_FALSE(!TestReader); ASSERT_EQ(TestReader.val(), ExpectedOutput); // If Reader Base Test Case fails, no need to continue next tests } TEST(ReaderTest, Should_Fail_When_FileDoesNotExist) { auto TestReader = Reader{}; TestReader.read("Non_existent_test_file.txt"); EXPECT_TRUE(!TestReader); } 函数似乎没有通过测试。...奇怪的是,示例文件没有通过甚至有任何评论,这是读者阅读的示例文件:

read

(是的,从字面上看是正确的。正如我之前提到的,读者正在阅读的语言不是C ++,而是我正在研究的一种自制语言,但这可能与这个问题无关。)

哦,如果您需要编译它,则需要实现和定义errhandler(errhandler.hh和errhandler.cc),我也将它们放在这里:

声明(errhandler.hh):

Int test = 0;
String test2 = "abcdefgh";
Float test3 = 0.9876;

定义(errhandler.cc):

    // errhandler.hh
    // Contains Phi Error Handling specifications
    // Mostly complete, minor changes still might be made though

    #ifndef PHI_SRC_FRONTEND_ERRHANDLER_HH
    #define PHI_SRC_FRONTEND_ERRHANDLER_HH

    #include <iostream>
    #include "utils.hh"

    class Error
    {
    public:
        enum class Type : unsigned char
        {
            ReadError, LexError, ParseError, SemanticError, InterpretError
        };

        Error() = delete;
        Error(Type type__, String const &val__) : type_(type__), val_(val__) {}

        auto type() const -> Type { return type_;  }
        auto val() const -> String { return val_; }

        friend auto operator<<(std::ostream &stream, Error const &error) -> std::ostream&
        {
            return stream << error.val();
        }

    private:
        Type type_;
        String val_;
    };

    class ErrorLog
    {
    public:
        using iterator = Vector<Error>::iterator;
        using const_iterator = Vector<Error>::const_iterator;
        using reverse_iterator = Vector<Error>::reverse_iterator;
        using const_reverse_iterator = Vector<Error>::const_reverse_iterator;

        void push(Error const &error) { errors.push_back(error); }
        void pop() { errors.pop_back(); }

        auto size() const -> Size { return errors.size(); }

        auto operator[](Size index) -> Error& { return errors[index]; }
        auto operator[](Size index) const -> Error const& { return errors[index]; }

        auto begin() -> iterator { return errors.begin(); }
        auto end() -> iterator { return errors.end(); }

        auto cbegin() const -> const_iterator { return errors.cbegin(); }
        auto cend() const -> const_iterator { return errors.cend(); }

        auto rbegin() -> reverse_iterator { return errors.rbegin(); }
        auto rend() -> reverse_iterator { return errors.rend(); }

        auto crbegin() -> const_reverse_iterator { return errors.crbegin(); }
        auto crend() -> const_reverse_iterator { return errors.crend(); }

        friend auto operator<<(std::ostream &stream, ErrorLog const &error_log) -> std::ostream&
        {
            for (Size i = 0; i < error_log.size(); i++)
                stream << error_log[i];

            return stream;
        }

    private:
        Vector<Error> errors;
    };

    void log_error(Error const &error);
    void show_errors(std::ostream& stream);

    extern ErrorLog errlog;
    // The global error log to be used by every part of the Phi system
    // To be declared in main()

    #endif

最后,您还需要包含实用程序的utils标头

// errhandler.cc
// Contains Phi Error Handling implementation
// Work In Progress, placeholders are temporarily being used

#include "errhandler.hh"

void log_error(Error const& error)
{
    errlog.push(error);
}

void show_errors(std::ostream& stream)
{
    stream << errlog;
}

这个问题确实使我在该项目上的进展停了下来。帮助我解决问题真的很有帮助

1 个答案:

答案 0 :(得分:0)

因此,评论中的人确实为我提供了帮助,建议我使用>>而不是eof()和get()as eof() is unreliable来读取流中的字符。但是即使那样也解决不了问题。在我通过一些谷歌搜索自己弄清楚之前,我不得不使用std :: noskipws,以便使>>运算符不跳过空格,然后它起作用。感谢您的所有帮助,我非常感谢