循环外的语句重复c++

2022-09-05 iostream c++ getline cin

我尝试像编译器一样从用户的输入中读取令牌。 标记化运行良好,但在输出所有标记时,我希望在它们全部发出后换行。

以下是我的代码:

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

//DIGITs
const std::string DIGITS = "0123456789";
const std::string WHITESPACE = " 	
";

//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" << "
";
    }
};

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 << "
";
    }
};

输入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++.exe编译时,Throw_Bad_ARRAY_NEW_LENGTHV错误意味着什么


解决方案

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

operator>>一次仅读取一个单词。遇到空格时停止读取。

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

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


附注:您不应该使用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...
}

相关文章