Это взято прямо из "языка программирования 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 объявлен как символ, но что произойдет, если вы введете 123.4 + 5.432; (предполагая, что input - cin) cin теперь содержит «строку» 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 << вызывается снова. Разве следующий вызов (* input) >> number_value не поместит 2 в числовое значение с перезаписью 1 (при условии, что на входе все еще 123.4 + 5.432)? Что здесь происходит. Думаю, мне нужно лучше понять, как работают потоки. Если бы кто-то мог найти время, дать краткое объяснение и указать мне хороший ресурс, я был бы очень признателен.
Спасибо,
Мэтью Хогган
Для тех, у кого нет книги, код:
#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" );
}
}
}