循环外的语句重复 c++

Statement outside of loop gets repeated c++

提问人:Redstonerayy 提问时间:11/18/2021 最后编辑:Redstonerayy 更新时间:11/18/2021 访问量:142

问:

我尝试从用户的输入中读取令牌,就像编译器一样。 标记化工作正常,但是在输出所有令牌时,我想在它们全部发出后换行。

这是我的代码:

#include <iostream>
#include <map>
#include <vector>
//import for using std::getline()
#include <string>

//DIGITs
const std::string DIGITS = "0123456789";
const std::string WHITESPACE = " \t\n\r";

//TOKENS
const std::string TT_INT = "INT";
const std::string TT_FLOAT = "FLOAT";
const std::string TT_PLUS = "PLUS";
const std::string TT_MINUS = "MINUS";
const std::string TT_MUL = "MUL";
const std::string TT_DIV = "DIV";
const std::string TT_LPAREN = "LPAREN";
const std::string TT_RPAREN = "RPAREN";

const std::string TT_INVALID_NUMBER = "INVALID_NUMBER_LITERAL";

class Token{
    public: 
        std::string type;
        std::string value;
    
    void repr(){
        std::cout << type << ":" << "value" << "\n";
    }
};

class Lexer{
    public:
        std::string text;
        int position = -1;
        std::string current_char;
    
    void advance(){
        this->position += 1;
        this->current_char = this->text[this->position];
    }

    void make_digit(std::string *type, std::string *value){
        //if its number or floating point
        std::string digit = "";
        int is_float = 0;
        while(DIGITS.find(this->current_char) != std::string::npos || this->current_char == "."){
            digit += this->current_char;
            if(this->current_char == "."){
                is_float += 1;
            }
            this->advance();
        }
        *value = digit;
        if(is_float == 0){
            *type = TT_INT;
        } else if((0 < is_float) && (is_float < 2)){
            *type = TT_FLOAT;
        } else {
            *type = TT_INVALID_NUMBER;
        }
    }    

    std::vector<std::string> make_tokens(){
        std::vector<std::string> tokens;
        this->advance();

        while (!(this->text.length() <= this->position))
        {
            if(WHITESPACE.find(this->current_char) != std::string::npos){
                //dont add a token
                this->advance();
            } else if(DIGITS.find(this->current_char) != std::string::npos){
                std::string type;
                std::string value;
                this->make_digit(&type, &value);
                tokens.push_back(type);
                tokens.push_back(value);
            } else if(this->current_char == "+"){
                tokens.push_back(TT_PLUS);
                tokens.push_back(this->current_char);
                this->advance();
            } else if(this->current_char == "-"){
                tokens.push_back(TT_MINUS);
                tokens.push_back(this->current_char);
                this->advance();
            } else if(this->current_char == "*"){
                tokens.push_back(TT_MUL);
                tokens.push_back(this->current_char);
                this->advance();
            } else if(this->current_char == "/"){
                tokens.push_back(TT_DIV);
                tokens.push_back(this->current_char);
                this->advance();
            } else if(this->current_char == "("){
                tokens.push_back(TT_LPAREN);
                tokens.push_back(this->current_char);
                this->advance();
            } else if(this->current_char == ")"){
                tokens.push_back(TT_RPAREN);
                tokens.push_back(this->current_char);
                this->advance();
            } else {
                //nothing
                this->advance();
            }
        }             
        return tokens;  
    }

};

int main(){
    //previous: true
    while(std::getline(std::cin, input)){
        std::string input;
        //previous: std::cin >> input;
        //fix
        std::getline(std::cin, input);
        Lexer mylexer;
        mylexer.text = input;
        int x = 0;
        std::vector<std::string> output = mylexer.make_tokens();
        for (int i = 0; i < output.size(); i += 2){
            std::cout << output.at(i) << ":" << output.at(i + 1) << std::endl;
        }
        std::cout << "\n";
    }
};

输入 1 + 2 时

我的期望

1 + 2
INT:1
PLUS:+
INT:2

here is the cursor

我得到了什么

1 + 2
INT:1

PLUS:+

INT:2

here is the cursor

当删除末尾的换行符时,我得到了这个,但是当输入第二个输入行时,它全部在一起,没有空行,这不是我想要的

1 + 2
INT:1
PLUS:+
INT:2
here is the cursor

但我希望它看起来像这样

1 + 2
INT:1
PLUS:+
INT:2

3 + 4
INT:3
PLUS:+
INT:4

谁能解释一下这种奇怪的行为是什么? 我错过了什么吗?请注意,我没有太多的C++经验。 我在Windows上使用clang-cl.exe进行编译。我也想知道使用 MSYS2 g++ 编译时throw_bad_array_new_lengthv错误是什么意思.exe

C++ IOSTREAM CIN GetLine

评论

1赞 user4581301 11/18/2021
建议:如果循环有问题,请从程序中删除除循环以外的所有内容。一旦所有的噪音都消失了,问题的根源往往是显而易见的。使用最小的可重复示例来获得灵感。
3赞 Joe 11/18/2021
您正在输出两行新行。首先,你转储,它放了一行新行。然后你输出哪个输出另一个。摆脱std::endl\n\n
0赞 Redstonerayy 11/18/2021
@joe但我不明白的是为什么它甚至会重复 3 次,因为我想它不在循环中。另请参阅我的编辑
0赞 Remy Lebeau 11/18/2021
当我按原样运行代码时,出现运行时错误。所以某处的逻辑存在错误。
0赞 Redstonerayy 11/18/2021
@RemyLebeau哪个错误消息?编辑:是因为用 g++ 编译吗?

答:

3赞 Remy Lebeau 11/18/2021 #1

输出中出现额外换行符的原因是,您正在使用 .operator>>input

operator>>一次只能阅读 1 个单词。当遇到空格时,它会停止读取。

因此,当您输入作为输入时,您最终只使用第一个单词作为 ,然后循环打印出来,然后换行符,然后在循环退出后打印出另一个换行符。然后,您阅读下一个单词,对其进行标记化,然后打印出来,然后是 2 个换行符。然后你读下一个单词,标记它,并打印出来,然后是 2 个换行符。1 + 2make_tokens()1mylexer.textINT:1+PLUS:+2INT:2

请改用。然后,您将在一次调用中标记整个输入,然后您将打印出您期望的输出类型 - 所有 3 个标记,它们之间有 1 个换行符,然后在结束后再换行 1 个换行符。std::getline(std::cin, input);1 + 2make_tokens()


顺便说一句:你不应该使用循环,特别是因为你忽略了阅读是否成功。您正在导致一个无限循环,可能会使代码崩溃。while(true)std::cin

当没有更多输入要读取时,您应该使用 的错误状态来停止循环,例如:std::cin

std::string input;
while (std::cin >> input){
    // use input as needed...
}

或者,在以下情况下:std::getline()

std::string input;
while (std::getline(std::cin, input)){
    // use input as needed...
}

评论

0赞 Redstonerayy 11/18/2021
这解决了它。据我了解。是不是 std::cin 有点像一堆词,所以每次我都称它为 1。queque 中的单词将被设置到变量中,因此 for 循环将始终只执行一次,而 while 循环将执行 3 次?
0赞 Remy Lebeau 11/18/2021
不,不是单词队列。但这就是你的代码处理的方式。该行为是由于如何从任何 ,行为本身不是。这就是解决此问题的原因,因为在从 .从同一流中读取的不同方式。std::cinstd::cinoperator>>istreamstd::cinstd::getline()std::cin
0赞 Redstonerayy 11/18/2021
因此,IOTream 库(现在名称有意义)以某种方式处理此控制台输入,并且 std::cin 和 std::getline() 只是访问它的函数。
0赞 Remy Lebeau 11/18/2021
它比这更复杂一些。 只是一个标准对象,没什么特别的。 并且可以从任何对象读取(其他对象包括 、 等)。对象具有从中读取的关联对象。默认情况下,分配了一个知道如何从控制台的输入中读取的。所以。与 w/ 和 w/ 类似。std::cinstd::istreamoperator>>std::getline()std::istreamstd::ifstreamstd::istringstreamstd::istreamstd::stream_bufstd::cinstd::stream_bufSTDINoperator>>/getline <- cin <- stream_buf <- STDINstd::coutSTDOUTstd::cerrSTDERR