关于std :: cin的澄清:
这是从Bjarne Stroustrup的“C++编程语言”我只想澄清一下他如何将数字累加到变量(int number_value)中。请不要撕毁代码,我没有写(完整的代码从第6章的底部帖子)。关于std :: cin的澄清:
特别是当解析器调用词法分析器时,词法分析器如何通过使用cin来构建数字。我相信答案是在这八行中,但我想解释它是如何工作的。
if(isalpha(ch)) {
(*input).putback(ch);
(*input) >> string_value;
return curr_tok=NAME;
} else {
error("bad token ");
return curr_tok=PRINT;
}
这在我看来,get_token中第一次()被调用时,它把全expression_list为CIN或任何输入流点(内部的get_token())。
(*input) >> ch;
我知道ch声明为char,但如果您键入123.4 + 5.432,会发生什么情况; (假设输入是cin),cin现在包含其流中包含的“字符串”123.4 + 5.432。然后我们转到lexer中的switch语句(get_token())。我假设::
ch == 1?
在这一点上?接下来在switch语句中,我们将“通过”到“。”案件。在这里,我们将'1'放回到流中并将其写入number_value?
(*input).putback(ch);
(*input) >> number_value;
现在number_value = 1,我们返回解析器。由于我们找到了一个NUMBER,它再次调用get_token()。再次调用cin运算符< <。下一次调用(* input)>> number_value将2置入数值,覆盖1(假设输入仍然是123.4 + 5.432)?这里发生了什么。我想我需要更好地理解流如何工作。如果有人可以花时间,并给出一个简短的解释,并指出我一个很好的资源,我将不胜感激。
谢谢
马修Hoggan
对于那些没有书,代码:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <map>
#include <cctype>
std::istream *input;
double number_value;
int no_of_errors;
std::string string_value;
std::map<std::string,double> table;
enum Token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*', DIV='/',
PRINT=';', ASSIGN='=', LP='(', RP=')'
};
Token_value curr_tok=PRINT;
double expr(bool);
double term(bool);
double prim(bool);
Token_value get_token();
double error(std::string s) {
no_of_errors++;
std::cerr << "error: " << s << std::endl;
return 1.0;
}
Token_value get_token() {
char ch = 0;
(*input) >> ch;
switch(ch) {
case 0: {
return curr_tok=END;
}
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=': {
return curr_tok = static_cast<Token_value>(ch);
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.': {
(*input).putback(ch);
(*input) >> number_value;
return curr_tok=NUMBER;
}
default: {
if(isalpha(ch)) {
(*input).putback(ch);
(*input) >> string_value;
return curr_tok=NAME;
} else {
error("bad token ");
return curr_tok=PRINT;
}
}
}
}
int main(int argc, char *argv[ ]) {
switch(argc) {
case 1: {
input = &std::cin;
break;
}
case 2: {
input = new std::istringstream(argv[1]);
break;
}
default: {
error(" To many arguments");
return 1;
}
}
table["pi"] = 3.1415926535897932385;
table["e"] = 2.7182818284590452354;
while((*input)) {
get_token();
if(curr_tok == END) {
break;
}
if(curr_tok == PRINT) {
continue;
}
std::cout << expr(false) << std::endl;
}
if(input != &std::cin) {
delete input;
}
return 0;
}
double expr(bool get) {
double left = term(get);
for(; ;) {
switch(curr_tok) {
case PLUS: {
left += term(true);
break;
}
case MINUS: {
left -= term(true);
break;
}
default: {
return left;
}
}
}
}
double term(bool get) {
double left = prim(get);
for(; ;) {
switch(curr_tok) {
case MUL: {
left *= prim(true);
break;
}
case DIV: {
if(double d = prim(true)) {
left /= d;
break;
}
else {
return error("divide by 0");
}
}
default: {
return left;
}
}
}
}
double prim(bool get) {
if(get) {
get_token();
}
switch(curr_tok) {
case NUMBER: {
double v = number_value;
get_token();
return v;
}
case NAME: {
double &v = table[string_value];
if(get_token() == ASSIGN) {
v = expr(true);
return v;
}
}
case MINUS: {
return -prim(true);
}
case LP: {
double e = expr(true);
if(curr_tok != RP) {
return error("')' expected");
}
get_token();
return e;
}
default: {
return error("primary expected");
}
}
}
“特技”是由以下三行的不同行为引起正确的类型。
字符串超载全局operator>>
函数为字符串提供版本,并且此版本使用空格作为分隔符(如果需要在字符串中输入空格,则应查看getline
)。
该双重版本使用istream& operator>> (double& val);
成员函数,只读取字符,但它们在形成双精度值时有意义。
因此,假设您输入abc
。代码cin >> ch
将使用字符'a'
填充ch
,将其从输入流中移除。您将在默认情况下使用isapha
来检测此情况,因为它与任何其他情况都不匹配。
在这一点上,你把这个角色'a'
回输入流,因此您可以重新读取它,并执行cin >> string_value
它得到整个字符串abc
,不单个字符。
同样,如果您输入3.14159
,这将是由case '3'
支票夹,字符将被上推回输入流,然后cin >> number_value
将获得全部价值。
现在NUMBER_VALUE = 1,我们回到解析器。
第(*input) >> number_value;
读入整个double,即123.4,因为number_value是double类型的。除此之外,你是对的。
char ch; std::cin >> ch;
std::string string_value; std::cin >> string_value;
double number_value; std::cin >> number_value;
第一只是得到一个字符,第二和第三个获得多个人物打造的一个变量:
所以它读取,直到它找到空白?我记得阅读>>阅读,直到它发现空白在哪里(cin.get(ch)&&!isalpha(ch)){;}会读直到找到第一个非数字? –
@Mthethew;否。流操作符将读取不符合正在读取的类型的第一个字符。 –