这是从Bjarne Stroustrup的“C ++编程语言”中获得的。我想澄清他如何将数字累积到变量(int number_value)中。请不要扯掉代码,我没有写它(完整的代码来自帖子底部的第6章)。
特别是当解析器调用词法分析器时,词法分析器如何使用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现在包含其流中包含的“string”123.4 + 5.432。然后我们转到词法分析器中的switch语句(get_token())。我假设:
ch == 1?
此时?接下来在switch语句中,我们将“通过”到'。'。案件。在这里我们将'1'放回流中并将其写入number_value?
(*input).putback( ch );
(*input) >> number_value;
现在number_value = 1,我们返回解析器。由于我们找到了NUMBER,因此再次调用get_token()。和cin运算符<<再次被召唤。不会下次调用(*输入)>> number_value将2放入数值覆盖1(假设输入仍然是123.4 + 5.432)?这里发生了什么。我想我需要更好地理解流如何工作。如果有人可以花时间,并给出一个简短的解释并指出我的资源,我将不胜感激。
谢谢,
Matthew 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" );
}
}
}
答案 0 :(得分:2)
现在number_value = 1,我们返回解析器。
没有。 (*input) >> number_value;
读入整个double,即123.4,因为number_value是double类型。除此之外,你是对的。
答案 1 :(得分:2)
'技巧'是由以下三行的不同行为引起的:
char ch; std::cin >> ch;
std::string string_value; std::cin >> string_value;
double number_value; std::cin >> number_value;
第一个只获取一个字符,第二个和第三个获取多个字符以构建正确类型的变量。
字符串重载全局operator>>
函数以提供字符串版本,此版本使用空格作为分隔符(如果需要使用字符串输入空格,则应查看getline
)。
双版本使用istream& operator>> (double& val);
成员函数,只有在形成双值时才会读取字符。
所以,假设您输入abc
。代码cin >> ch
将使用字符ch
填充'a'
,并将其从输入流中删除。然后,您将在默认情况下使用isapha
检测到此情况,因为它与其他任何情况都不匹配。
此时,您将该字符'a'
重新推送到输入流,以便您可以重新读取它,并执行获取整个字符串cin >> string_value
的{{1}},不单个角色。
同样,如果您输入abc
,它将被3.14159
检查捕获,该字符将被推回到输入流,然后case '3'
将获得整个值。