您的位置:首页 > 编程语言 > C语言/C++

C++ 一个简单的解释器 - 四则运算

2016-08-01 00:00 351 查看
#include <list>
using namespace std;

/*
─────────────────────────────
│ 10 │  + │  20 │  *  |  5  |
─────────────────────────────

(run interpret)
===>>>
Token[Digits]   : 10
Token[Operator] : +
Token[Digits]   : 20
Token[Operator] : *
Token[Digits]   : 5

===>>>
10 + 20 * 5

优先级:
x÷ > +-
===>>>
10 + 100

===>>>
110

*/

//
// 配置
//
const char CounterDigits[]    = "1234567890";
const char CounterOperators[] = "*/+-";
const char CounterNils[]      = " ";

enum TokensTypes
{
Nil,
Operator,
Digits,
Eof,
Err
};

//
// common
//
inline bool isinchars( const char* str, char s ) {
int len = strlen( str );
for( int i = 0; i < len; i++ )
if( s == str[i] )
return true;
return false;
}
inline bool isDigit( char s ) {
return isinchars( CounterDigits, s );
}
inline bool isOperator( char s ) {
return isinchars( CounterOperators, s );
}
inline bool isNil( char s ) {
return isinchars( CounterNils, s );
}

//
// 类实现
//
class Token
{
public:
Token( TokensTypes tts ) {
this->type = tts;
for( char &ch : raw )
ch = 0;
}

Token( TokensTypes tts, char* rawstr, int startpos, int endpos ) {
this->type = tts;
char tmpch = rawstr[endpos];
rawstr[endpos] = 0;
strcpy( this->raw, rawstr + startpos );
rawstr[endpos] = tmpch;
}

TokensTypes type;
char raw[11];
};

class CounterInterpreter
{
public:
CounterInterpreter( char* linestr ) : rawstring( linestr ), pos( 0 ) {}
~CounterInterpreter() { tokens.clear(); }

//每个Token分析
Token readtoken() {
int startpos = this->pos;
while( 1 )
{
//空格时startpos和pos同时递增
if( isNil( rawstring[this->pos] ) ) {
startpos = ++this->pos;
continue;
}
//只有startpos处就是Operator时才判断为操作符
else if( isOperator( rawstring[startpos] ) ) {
return Token( TokensTypes::Operator, rawstring, startpos, ++this->pos );
}
//前方不是数字的数字处为Digits的结束处
else if( isDigit( rawstring[this->pos] ) ) {
if( !isDigit( rawstring[this->pos + 1] ) )
return Token( TokensTypes::Digits, rawstring, startpos, ++this->pos );
}
//EOF
else if( rawstring[this->pos] == 0 ) {
return Token( TokensTypes::Eof );
}
//ERROR
else {
this->pos++;
return Token( TokensTypes::Err );
}

this->pos++;
}
}

//Token分解
bool analysis() {
while( 1 ) {
Token t = readtoken();
tokens.push_back( t );
if( t.type == Eof )
break;
if( t.type == Err )
return false;
}
return true;
}

//正确性验证
bool verify() {
TokensTypes nextstatus = TokensTypes::Digits;
for( auto t : tokens ) {
//d+o+d
if( t.type != nextstatus && t.type != TokensTypes::Eof )
return false;
//数字可以放在最前最后  但操作符不行
if( t.type == TokensTypes::Eof && nextstatus == TokensTypes::Digits )
return false;

if( nextstatus == TokensTypes::Digits )
nextstatus = TokensTypes::Operator;
else if( nextstatus == TokensTypes::Operator )
nextstatus = TokensTypes::Digits;
}
return true;
}

//最终计算
int execute() {
//优先计算*/
//遇到*/时,将自己+身边的2个Token进行重新计算后,
//删除右边的2个,并将结果写入最左边Token
for( auto t = tokens.begin(); t != tokens.end(); t++ ) {
if( (*t).type == TokensTypes::Operator ) {
if( (*t).raw[0] == '*' ) {
t--;
int tmp = strtol( (*t).raw, 0, 10 );
t++; t++;
tmp *= strtol( (*t).raw, 0, 10 );
t--; t--;
sprintf( (*t).raw, "%d", tmp );
t++;
tokens.erase( t++ );
tokens.erase( t++ );
t--;
}
else if( (*t).raw[0] == '/' ) {
t--;
int tmp = strtol( (*t).raw, 0, 10 );
t++; t++;
tmp /= strtol( (*t).raw, 0, 10 );
t--; t--;
sprintf( (*t).raw, "%d", tmp );
t++;
tokens.erase( t++ );
tokens.erase( t++ );
t--;
}
}
}

//最后得出总数:计算+-
int total = 0;
for( auto t = tokens.begin(); t != tokens.end(); t++ ) {
if( (*t).type == TokensTypes::Digits ) {
total = strtol( (*t).raw, 0, 10 );
}
else if( (*t).type == TokensTypes::Operator ) {
switch( (*t).raw[0] ) {
case '+':
t++;
total += strtol( (*t).raw, 0, 10 );
break;
case '-':
t++;
total -= strtol( (*t).raw, 0, 10 );
break;
}
}
}

return total;
}

//将token按顺序装起来
list tokens;
char* rawstring;
int pos;
};

简单测试一下:

void main() {
string str;
while( 1 ) {
//cin >> str;        //bug: cin会处理空格为结束符
getline( cin, str );

CounterInterpreter ci( (char*)(str.data()) );
cout << "analysis : " << ci.analysis() << endl;
cout << "verify   : " << ci.verify() << endl;
cout << "result   : " << ci.execute() << endl;
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐