第七章 习题答案
前言
这一章的习题是有连贯性的,我就不放分开来的代码了,直接上最终版本
Calculator
/*
本程序实现了一个简单的表达式计算器,支持变量操作
从cin读入,输出到cout。
输入文法如下:
Calculation:
Statement
Print
Quit
Calculation Statement
Print:
';'
Quit:
'q'
"quit"
Statement:
Declaration
Expression
Declaration:
"let" name '=' Expression
"const" name '=' Expression
Expression:
Term
Expression '+' Term
Expression '-' Term
Term:
Primary
Term * Primary
Term / Primary
Term % Primary
Primary:
Number
'(' Expression ')'
- Primary //处理负数
Assignment
Number:
floating-point-literal
Assignment:
name '=' Expression
*/
#include "../../std_lib_facilities.h"
struct Token {
char kind;
double value;
string name;
Token(char ch) :kind(ch), value(0) { }
Token(char ch, double val) :kind(ch), value(val) { }
Token(char ch, string n) :kind(ch), name(n) { }
};
class Token_stream {
private:
bool full;
Token buffer;
public:
Token_stream() :full(false), buffer(0) { } // The constructor just sets full to indicate that the buffer is empty:
Token get();
void putback(Token t);
void ignore(char);
};
const string declkey = "let";
const char let = 'L';
const string quitkey = "quit";
const char quit = 'q';
const string helpkey = "help";
const char help = 'h';
const char print = ';';
const char number = '8';
const char name = 'a';
const char assign = '=';
const char con = 'C';
const string constkey = "const";
Token Token_stream::get()
{
if (full)
{
full = false;
return buffer;
}
char ch;
//cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.)
while (isspace((ch = cin.get())) && ch != '\n')
continue;
switch (ch) {
case '(': case ')':
case '+': case '-':
case '*': case '/': case '%':
case '=':
case quit:
case print:
return Token{ ch }; // let each character represent itself
case '\n':
return Token{ print };
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch); // put digit back into the input stream
//cin.unget(); // same as putback(char), except no parameter
double val;
cin >> val; // read a floating-point number
return Token{ number, val };
}
default:
if (isalpha(ch)) {
string s;
s += ch;
//名字为字母开头的,带字母数字和下划线的字符串
while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_'))
s += ch;
cin.putback(ch);
if (s == declkey) return Token{ let }; // 声明变量关键字
if (s == constkey) return Token{ con }; // 声明常量关键字
if (s == helpkey || (s.size() == 1 && s[0] == help)) return Token{ help };
if (s == quitkey) return Token{ quit };
return Token{ name, s };
}
error("Bad token");
}
}
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
if (full)
error("putback() into a full buffer.");
buffer = t;
full = true;
}
void Token_stream::ignore(char c)
{
if (full && c == buffer.kind) {
full = false;
return;
}
full = false;
char ch;
while (cin >> ch)
if (ch == c) return;
}
//---------------------------------------------------------
// set Variable
class Variable {
public:
string name;
double value;
bool is_const;
Variable(string n, double v, bool b) :name(n), value(v), is_const(b) { }
};
class Symbol_table {
public:
Symbol_table() {}
double get(string var);
void set(string var, double d);
bool is_declared(string var);
double define(string var, double val, bool is_const);
private:
vector<Variable> var_table;
};
double Symbol_table::get(string s)
{
for (const Variable& v : var_table)
if (v.name == s)
return v.value;
error("get: undefined name ", s);
}
void Symbol_table::set(string s, double d)
{
for (Variable& v : var_table)
if (v.name == s)
{
if (v.is_const)
error("set: can not assign to a const ", s);
v.value = d;
return;
}
error("set: undefined name ", s);
}
bool Symbol_table::is_declared(string var)
{
//判断var是否已经在var_table中了
for (const Variable& v : var_table)
if (v.name == var)
return true;
return false;
}
double Symbol_table::define(string var, double val, bool is_const)
{
//将(var, val)加入var_table中
if (is_declared(var))
error(var, " declared twice");
var_table.push_back(Variable{ var, val, is_const });
return val;
}
Token_stream ts;
Symbol_table st;
//--------Expression---------------
double expression();
double assignment(string var)
{
// 函数假设已经读入了赋值语句的左值和赋值符号
double right = expression();
st.set(var, right);
return right;
}
double primary()
{
Token t = ts.get();
switch (t.kind) {
case '(':
{
double d = expression();
t = ts.get();
if (t.kind != ')')
error("'(' expected");
return d;
}
case '-':
return -primary();
case number:
return t.value;
case name:
{
Token t2 = ts.get();
if (t2.kind != assign)
{
ts.putback(t2);
return st.get(t.name); // if next char is not a assignment operator, then return variable value
}
else
return assignment(t.name);
}
default:
error("primary expected");
}
}
double term()
{
double left = primary();
while (true) {
Token t = ts.get();
switch (t.kind) {
case '*':
left *= primary();
break;
case '/':
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
break;
}
case '%':
{
double d = primary();
if (d == 0) error("divide by zero");
left = fmod(left, d);
break;
}
default:
ts.putback(t);
return left;
}
}
}
double expression()
{
double left = term();
while (true) {
Token t = ts.get();
switch (t.kind) {
case '+':
left += term();
break;
case '-':
left -= term();
break;
default:
ts.putback(t);
return left;
}
}
}
double declaration(char kind)
{
Token t = ts.get();
if (t.kind != name)
error("name expected in declaration");
string var_name = t.name;
Token t2 = ts.get();
if (t2.kind != '=')
error("= missing in declaration of ", var_name);
double d = expression();
bool is_const = kind == con;
st.define(var_name, d, is_const);
return d;
}
double statement()
{
Token t = ts.get();
switch (t.kind) {
case let:
case con:
return declaration(t.kind);
default:
ts.putback(t);
return expression();
}
}
void clean_up_mess()
{
ts.ignore(print);
}
const string prompt = "> ";
const string result = "= ";
void help_message()
{
cout << "Please enter expressions using floating-point numbers.\n";
cout << "You can use \"+ - * / %\" operators, ';' to output result, 'h' to help, and 'q' to quit.\n";
cout << "You can also define variables and constant by using let and const" << endl;
cout << "For example: let a = 1 define a variable a, const b = a * 3 define a constant b" << endl;
}
void calculate()
{
while (true)
try {
cout << prompt;
Token t = ts.get();
while (t.kind == print) t = ts.get(); // 丢弃之前的所有打印字符
if (t.kind == quit) return;
if (t.kind == help)
{
help_message();
continue;
}
ts.putback(t);
cout << result << statement() << endl;
}
catch (runtime_error& e) {
cerr << e.what() << endl;
clean_up_mess();
}
}
int main()
try {
cout << "Welcome to our simple calculator.\n";
cout << "Please enter expressions using floating-point numbers.\n";
cout << "You can use \"+ - * / %\" operators, ';' to output result, 'h' to help, and 'q' to quit.\n";
cout << "You can also define variables and constant by using let and const" << endl;
cout << "For example: let a = 1 define a variable a, const b = a * 3 define a constant b" << endl;
calculate();
return 0;
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
char c;
while (cin >> c && c != ';');
return 1;
}
catch (...) {
cerr << "exception\n";
char c;
while (cin >> c && c != ';');
return 2;
}