首先是课本最早出现的源码,可以运行
#include "pch.h"
#include <iostream>
#include<string>
#include<cctype>
#include<map>
#include<sstream>
using namespace std;
enum Token_value{
NAME,NUMBER,END,
PLUS='+',MINUS='-',MUL='*',DIV='/',
PRINT=';',ASSIGN='=',LP='(',RP=')'
};
Token_value curr_tok = PRINT;
int no_of_errors;
double term(bool get);
string string_value;
double number_value;
double error(const string&s)
{
no_of_errors++;
cout << "error" << s << '\n';
return 1;
}
Token_value get_token()
{
char ch = 0;
cin >> ch;
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;
default:
if (isalpha(ch)) {
string_value = ch;
while (cin.get(ch) && isalnum(ch));
string_value.push_back(ch);
return curr_tok = NAME;
}
error("bad token");
return curr_tok = PRINT;
return curr_tok = NUMBER;
}
}
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 prim(bool get) {
if (get) get_token();
switch (curr_tok)
{
case NUMBER:
{
double v = number_value;
get_token();
return v;
}
case NAME:
{
double&v = number_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(")needed");
get_token();
return e;
}
default:
return error("参数缺少");
}
}
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;
}
return error("divide by 0");
default:
return left;
}
}
istream* input;
int main(int argc,char* argv[] )
{
switch (argc)
{
case 1:
{
input = &cin;
break;
}
case 2:
{
input = new istringstream(argv[1]);
break;
}
default:
error("too many!");
return 1;
}
while (*input)
{
get_token();
if (curr_tok == END)break;
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
if (input != &cin)
delete input;
return no_of_errors;
}
加入命名空间以及异常处理内容后的终极版本
#include "pch.h"
#include <iostream>
#include<string>
#include<cctype>
#include<map>
#include<sstream>
using namespace std;
namespace Error {
struct Zero_divide
{
};
struct Syntax_error {
const char*p;
Syntax_error(const char*q) { p = q; }
};
struct Range_error {
int i;
Range_error(int ii) { i = ii; }
};
}
namespace Parser {
using namespace Error;
double expr(bool get);
double prim(bool get);
double term(bool get);
}
namespace Lexer {
enum Token_value {
NAME, NUMBER, END,
PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};
Token_value curr_tok = PRINT;
Token_value get_token();
string string_value;
double number_value;
};
double Parser::expr(bool get) {
using Lexer::curr_tok;
using Lexer::PLUS;
using Lexer::MINUS;
double left = term(get);
for (;;)
switch (curr_tok)
{
case PLUS:
left += term(true);
break;
case MINUS:
left -= term(true);
break;
default:
return left;
}
}
double Parser::prim(bool get) {
if (get) Lexer::get_token();
switch (Lexer::curr_tok)
{
case Lexer::NUMBER:
{
double v = Lexer::number_value;
Lexer::get_token();
return v;
}
case Lexer::NAME:
{
double&v = Lexer::number_value;
if (Lexer::get_token() == Lexer::ASSIGN)
v = expr(true);
return v;
}
case Lexer::MINUS:
return -prim(true);
case Lexer::LP:
{
double e = expr(true);
if (Lexer::curr_tok != Lexer::RP)
throw Error::Syntax_error("参数缺少");
Lexer::get_token();
return e;
}
default:
throw Error::Syntax_error("参数缺少");
}
}
double Parser::term(bool get) {
double left = prim(get);
for (;;)
switch (Lexer::curr_tok) {
case Lexer::MUL:
left *= prim(true);
break;
case Lexer::DIV:
if (double d = prim(true)) {
left /= d;
break;
}
throw Error::Zero_divide();
default:
return left;
}
}
Lexer::Token_value Lexer::get_token()
{
char ch = 0;
cin >> ch;
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:
if (isalpha(ch)) {
string_value = ch;
while (cin.get(ch) && isalnum(ch));
string_value.push_back(ch);
return curr_tok = NAME;
}
throw Error::Syntax_error("bad token");
return curr_tok = PRINT;
return curr_tok = NUMBER;
}
}
//驱动模块。
namespace Driver {
int no_of_errors;
istream* input;
void skip();
}
void Driver::skip() {
//skip函数将继续读取输入知道遇到换行或者分号时,返回。
no_of_errors++;
while (*input) {
char ch;
input->get(ch);
switch (ch) {
case'\n':
case';':
return;
}
}
}
int main(int argc, char* argv[])
{
try {
switch (argc)
{
case 1:
{
Driver::input = &cin;
break;
}
case 2:
{
Driver::input = new istringstream(argv[1]);
break;
}
default:
throw Error::Range_error(1);
}
}
catch (Error::Range_error) {
cout << "too many";
Lexer::curr_tok = Lexer::PRINT;
}
/*using namespace Lexer;
using namespace Parser;
while (*Driver::input)
try{
get_token();
if (curr_tok == END)break;
if (curr_tok == PRINT) continue;
cout << expr(false) << '\n';
}
catch(Error::Zero_divide){
cerr << "不可除以零。\n";
if (Lexer::curr_tok != Lexer::PRINT)Driver::skip();
//skip()将尝试把程序恢复到一个可以运行的情形。
}
catch(Error::Syntax_error e){
cerr << "格式错误。" << e.p << '\n';
if (Lexer::curr_tok != Lexer::PRINT)Driver::skip();
}
if (Driver::input != &cin)
delete Driver::input;
//释放空间。
return Driver::no_of_errors;*/
bool in_error = false;
//这种处理方式会导致错误的输入依然残留,所以还会报错,不够优秀。
while (*Driver::input) {
try {
Lexer::get_token();
if (Lexer::curr_tok == Lexer::END)break;
if (Lexer::curr_tok == Lexer::PRINT) {
in_error = false;
continue;
}
if (in_error == false)cout << Parser::expr(false) << '\n';
}
catch (Error::Zero_divide) {
cerr << "尝试除以零\n";
in_error = true;
}
catch (Error::Syntax_error e) {
cerr << "格式错误:" << e.p << '\n';
in_error = true;
cout << "error参数被顺利更改\n";
}
if (Driver::input != &cin)
delete Driver::input;
//释放空间。
return Driver::no_of_errors;
}
}