Интерпретатор

#include <string.h>

#include <ctype.h>

enum token_value {

NAME, NUMBER, END,

PLUS = '+', MINUS = '-', MUL='*', DIV='/',

PRINT=';', ASSIGN='=', LP='(', RP=')'

};

token_value curr_tok;

struct name {

char* string;

name* next;

double value;

};

const TBLSZ = 23;

name* table[TBLSZ];

int no_of_errors;

double error(char* s) {

cerr << "error: " << s << "\n";

no_of_errors++;

return 1;

}

name* look(char* p, int ins = 0)

{

int ii= 0;

char *pp = p;

while (*pp) ii = ii<<1 ^ *pp++;

if (ii < 0) ii = -ii;

ii %= TBLSZ;

for (name* n=table [ii]; n; n=n->next)

if (strcmp(p,n->string) == 0) return n;

if (ins == 0) error("name not found");

name* nn = new name;

nn->string = new char[strlen(p) + 1];

strcpy(nn->string,p);

nn->value = 1;

nn->next = table[ii];

table[ii] = nn;

return nn;

}

inline name* insert(char* s) { return look (s,1); }

token_value get_token();

double term();

double expr()

{

double left = term();

for (;;)

switch (curr_tok) {

case PLUS:

get_token();

left += term();

break;

case MINUS:

get_token();

left -= term();

break;

default :

return left;

}

}

double prim();

double term()

{

double left = prim();

for (;;)

switch (curr_tok) {

case MUL:

get_token();

left *= prim();

break;

case DIV:

get_token();

double d = prim();

if (d == 0) return error("divide by o");

left /= d;

break;

default:

return left;

}

}

int number_value;

char name_string[80];

double prim()

{

switch (curr_tok) {

case NUMBER:

get_token();

return number_value;

case NAME:

if (get_token() == ASSIGN) {

name* n = insert(name_string);

get_token();

n->value = expr();

return n->value;

}

return look(name_string)->value;

case MINUS:

get_token();

return -prim();

case LP:

get_token();

double e = expr();

if (curr_tok != RP) return error(") expected");

get_token();

return e;

case END:

return 1;

default:

return error ("primary expected");

}

}

token_value get_token()

{

char ch = 0;

do {

if(!cin.get(ch)) return curr_tok = END;

} while (ch!='\n' && isspace(ch));

switch (ch) {

case ';':

case '\n':

cin >> WS;

return curr_tok=PRINT;

case '*':

case '/':

case '+':

case '-':

case '(':

case ')':

case '=':

return curr_tok=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)) {

char* p = name_string;

*p++ = ch;

while (cin.get(ch) && isalnum(ch)) *p++ = ch;

cin.putback(ch);

*p = 0;

return curr_tok=NAME;

}

error ("bad token");

return curr_tok=PRINT;

}

}

int main(int argc, char* argv[])

{

switch (argc) {

case 1:

break;

case 2:

cin = *new istream(strlen(argv[1]),argv[1]);

break;

default:

error("too many arguments");

return 1;

}

// insert predefined names:

insert("pi")->value = 3.1415926535897932385;

insert("e")->value = 2.7182818284590452354;

while (1) {

get_token();

if( curr_tok == END) break;

if (curr_tok == PRINT) continue;

cout << expr() << "\n";

}

return no_of_errors;

}


Страница: