输入函数
读输入的部分通常都是程序里最麻烦的部分,这是因为程序必须与人交流,它必须处理人们的奇思怪想、各种习惯和看起来像是随机的错误。试图强求人按照某种更适合机器的方式活动通常被(正确地)认为是很令人讨厌的。低级输入例程的工作是读入字符,并由它们组合出高级的单词,这些单词随之成为高级例程的输入单位。在这里的低级输入由get_token()完成。写低级输入例程并不是每天都要做的工作,许多系统中提供了完成这些事情的标准函数。
我将分两个阶段完成get_token()。首先我将提供一个不太靠得住的简单版本,它给用户强加了很大负担。而后,我要把它决定需要去组合的哪种单词,而后返回表示被读单词的Token_value值。
初始化语句将第一个非空白字符读入ch,并检查该读入操作的成功完成:
Token_value get_token()
{
char ch = 0;
cin >> ch;
switch(ch)
case 0:
return curr_tok = END; // 赋值和返回
}
按默认方式,运算符 >> 将跳过空白(即空格、制表符、换行符等),如果操作失败还将保持ch不变。因此,ch==0的情况就表示了输入的结束。
赋值也是一个运算符,赋值表达式的结果就是赋给变量那个值。这使我能在同一个语句里将值END赋给curr_tok,并且返回它。在一个语句中做两件事对于维护很有帮助。如果赋值和返回在代码中分开做,程序员就可能会修改了一个而忘记另一个。
在考虑整个函数之前,让我们先分开来看一些情况。表达式结束符';',括号和运算符的处理都很简单,只需要返回它们的值:
case ';':
caes '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok = Token_value(ch);
数可以按如下方式处理:
case '0': case '1': case '2': case '3': case '4:'
case '5': case '6': case '7': case '8': case '9':
case '.':
cin.putback(ch);
cin >> number_value;
return curr_tok = NUMBER;
按水平方式将case标号堆在一起而不是垂直地放置并不是什么好主意,因为这种安排更难阅读。然而,在每行中放一个数字也很令人生厌。由于运算符 >> 已经有针对将浮点常数读入double的定义,这里的代码就非常简单:首先把第一个字符(数字或者圆点)放回cin,而后将常数读到number_value里。
名字的处理也与此类似:
default: // NAME, NAME =, 或者错误
if(isalpha(ch))
{
cin.putback(ch);
cin >> string_value;
return curr_tok = NAME;
}
error("bad_token");
return curr_tok = PRINT;
这里用了标准库函数isalpha()(20.4.2节),以避免将每个字母列为一个case标号。运算符 >> 用于字符串(这里是string_value)的结果是不断读入字符,直到遇到空白为止。这样,用户要想把某个名字作为运算符的运算对象,就必须用空白表示名字的结束。这一情况当然不太理想,我们将6.1.3节重新回到这个问题。
这里是最后的完整的输入函数:
Token_value get_token()
{
char ch = 0;
cin >> cin;
switch(ch)
{
case 0:
return curr_tok = END;
case ';':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return curr_tok = Token_value(ch);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
cin.putback(ch);
cin >> number_value;
return curr_tok = NUMBER;
default: // NAME, NAME=, 或者错误
if(isalpha(ch))
{
cin.putback(ch);
cin >> string_value;
return curr_tok = NAME;
}
error("bad token");
return curr_tok = PRINT;
}
}
由于前面将运算符的Token_value值定义成该运算符的整数值(4.8节),从运算符到对应的单词值的转换就非常简单了。
🔚