Last active
August 29, 2015 14:03
-
-
Save Determinant/8b9e124dc245d9818fa4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <cassert> | |
#include <cctype> | |
#include <cstring> | |
#include <cstdlib> | |
#define SCAST_FLOAT(x) static_cast<Float*>(x) | |
#define SCAST_INT(x) static_cast<Int*>(x) | |
/* Abstract interface for numbers */ | |
class Num { | |
public: | |
enum { | |
INT = 0, | |
FLOAT = 1 | |
} type_level; | |
/* Note that type_level of b must be the same as type_level of ``this'' | |
* */ | |
virtual Num *add(Num *b) = 0; | |
virtual Num *sub(Num *b) = 0; | |
virtual Num *mul(Num *b) = 0; | |
virtual Num *div(Num *b) = 0; | |
/* Convert b from a lower level type to higher level type */ | |
virtual Num *convert(Num *b) = 0; | |
virtual void print() = 0; | |
virtual ~Num() {} | |
}; | |
class Int; | |
class Float: public Num { | |
public: | |
double x; | |
Float() { type_level = FLOAT; } | |
Float(double _x) : x(_x) { type_level = FLOAT; } | |
Num *convert(Num *b); | |
Num *add(Num *b) { return new Float(x + SCAST_FLOAT(b)->x); } | |
Num *sub(Num *b) { return new Float(x - SCAST_FLOAT(b)->x); } | |
Num *mul(Num *b) { return new Float(x * SCAST_FLOAT(b)->x); } | |
Num *div(Num *b) { return new Float(x / SCAST_FLOAT(b)->x); } | |
void print() { printf("%.6f\n", x); } | |
static Float *from_string(char *repr); | |
}; | |
class Int : public Num { | |
public: | |
int x; | |
Int() { type_level = INT; } | |
Int(int _x) : x(_x) { type_level = INT; } | |
Num *convert(Num *b) { | |
assert(b->type_level <= type_level); | |
Int *nobj = new Int(); | |
switch (b->type_level) | |
{ | |
case INT: nobj->x = SCAST_INT(b)->x; break; | |
default: assert(0 && "Type Not Implemented"); | |
} | |
return nobj; | |
} | |
Num *add(Num *b) { return new Int(x + SCAST_INT(b)->x); } | |
Num *sub(Num *b) { return new Int(x - SCAST_INT(b)->x); } | |
Num *mul(Num *b) { return new Int(x * SCAST_INT(b)->x); } | |
Num *div(Num *b) { return new Int(x / SCAST_INT(b)->x); } | |
void print() { printf("%d\n", x); } | |
static Int *from_string(char *repr); | |
}; | |
Num *Float::convert(Num *b) { | |
assert(b->type_level <= type_level); | |
Float *nobj = new Float(); | |
switch (b->type_level) | |
{ | |
case INT: nobj->x = SCAST_INT(b)->x; break; | |
case FLOAT: nobj->x = SCAST_FLOAT(b)->x; break; | |
default: assert(0 && "Type Not Implemented"); | |
} | |
return nobj; | |
} | |
struct Cons { | |
Num *car; | |
Cons *cdr; | |
Cons(Num *_car, Cons *_cdr) : car(_car), cdr(_cdr) {} | |
bool check_length(int len) { | |
int l = 0; | |
for (Cons *p = this; p; p = p->cdr) l++; | |
return l == len; | |
} | |
}; | |
class Opt { | |
public: | |
virtual Num *calc(Cons *con) = 0; | |
}; | |
class Add : public Opt { | |
/* Use the lowest level type */ | |
Num *calc(Cons *con) { | |
Num *res = new Int(0), *last; | |
for (; con; con = con->cdr) | |
{ | |
Num *opr = con->car, *conv; | |
last = res; | |
if (res->type_level > opr->type_level) | |
res = res->add(conv = res->convert(opr)); | |
else | |
res = (conv = opr->convert(res))->add(opr); | |
delete last; | |
delete conv; | |
} | |
return res; | |
} | |
}; | |
class Mul : public Opt { | |
/* Use the lowest level type */ | |
Num *calc(Cons *con) { | |
Num *res = new Int(1), *last; | |
for (; con; con = con->cdr) | |
{ | |
Num *opr = con->car, *conv; | |
last = res; | |
if (res->type_level > opr->type_level) | |
res = res->mul(conv = res->convert(opr)); | |
else | |
res = (conv = opr->convert(res))->mul(opr); | |
delete last; | |
delete conv; | |
} | |
return res; | |
} | |
}; | |
FILE *input = stdin; | |
const int MAX_BUFF = 1024; | |
char buff[MAX_BUFF], *bptr = buff; | |
char *next_token() { | |
char *res = NULL; | |
int ch; | |
while (!res) | |
{ | |
if (bptr > buff && (*buff == '(' || *buff == ')')) | |
{ | |
buff[1] = '\0'; | |
res = strdup(buff); | |
bptr = buff; | |
break; | |
} | |
if ((ch = fgetc(input)) == EOF) | |
break; | |
switch (ch) | |
{ | |
case '(': | |
case ')': | |
if (bptr > buff) | |
{ | |
*bptr = '\0'; | |
res = strdup(buff); | |
} | |
*buff = (char)ch; | |
bptr = buff + 1; | |
break; | |
default: | |
if (isspace(ch)) | |
{ | |
if (bptr > buff) | |
{ | |
*bptr = '\0'; | |
res = strdup(buff); | |
} | |
bptr = buff; | |
} | |
else | |
*bptr++ = (char)ch; | |
} | |
} | |
return res; | |
} | |
int str_to_int(char *repr, bool &flag) { | |
char *endptr; | |
int val = (int)strtol(repr, &endptr, 10); | |
if (endptr == repr || endptr != repr + strlen(repr)) | |
{ | |
flag = false; | |
return 0; | |
} | |
flag = true; | |
return val; | |
} | |
double str_to_double(char *repr, bool &flag) { | |
char *endptr; | |
double val = strtod(repr, &endptr); | |
if (endptr == repr || endptr != repr + strlen(repr)) | |
{ | |
flag = false; | |
return 0; | |
} | |
flag = true; | |
return val; | |
} | |
Int *Int::from_string(char *repr) { | |
bool flag; | |
int val = str_to_int(repr, flag); | |
if (!flag) return NULL; | |
return new Int(val); | |
} | |
Float *Float::from_string(char *repr) { | |
bool flag; | |
double val = str_to_double(repr, flag); | |
if (!flag) return NULL; | |
return new Float(val); | |
} | |
Num *calc_exp() { | |
char *tk0 = next_token(); | |
Num *res; | |
assert(tk0 && "Token expected"); | |
if (*tk0 == '(') | |
{ | |
/* Procedure call */ | |
char *tk1 = next_token(); | |
Opt *opt; | |
Cons *cons = new Cons(NULL, NULL), *tail = cons; | |
Num *val; | |
assert(tk1 && "Procedure requires at least one operator"); | |
switch (*tk1) | |
{ | |
case '+': opt = new Add(); break; | |
case '*': opt = new Mul(); break; | |
default: | |
assert(0 && "Procedure operator not found"); | |
} | |
while ((val = calc_exp())) | |
{ | |
tail->cdr = new Cons(val, NULL); | |
tail = tail->cdr; | |
} | |
res = opt->calc(cons->cdr); | |
for (Cons *np; cons; cons = np) | |
{ | |
np = cons->cdr; | |
delete cons; | |
} | |
} | |
else if (*tk0 == ')') | |
/* The end of upper level of calling */ | |
return NULL; | |
else | |
{ | |
/* Constant number */ | |
res = Int::from_string(tk0); | |
if (!res) res = Float::from_string(tk0); | |
assert(res && "Not a number"); | |
} | |
return res; | |
} | |
int main() { | |
/* void test_conversion(); | |
test_conversion(); | |
*/ | |
for (Num *res;;) | |
{ | |
assert((res = calc_exp()) && "Invalid expression"); | |
res->print(); | |
} | |
return 0; | |
} | |
/* | |
void test_conversion() { | |
Num *a = new Int(1), *b = new Float(1.0); | |
Opt *adder = new Add(); | |
Cons *cons[] = { | |
new Cons(a, new Cons(b, NULL)), | |
new Cons(b, new Cons(a, NULL)), | |
new Cons(a, new Cons(a, NULL)), | |
new Cons(b, new Cons(b, NULL)), | |
new Cons(a, new Cons(a, new Cons(a, NULL))), | |
new Cons(a, new Cons(a, new Cons(b, NULL))), | |
new Cons(a, new Cons(b, new Cons(a, NULL))), | |
new Cons(b, new Cons(a, new Cons(a, NULL))), | |
}; | |
const int cons_len = sizeof(cons) / sizeof(cons[0]); | |
for (int i = 0; i < cons_len; i++) | |
adder->calc(cons[i])->print(); | |
for (int i = 0; i < cons_len; i++) | |
for (int j = 0; j < cons_len; j++) | |
{ | |
Cons *t = new Cons(adder->calc(cons[i]), cons[j]); | |
adder->calc(t)->print(); | |
delete t; | |
} | |
for (int i = 0; i < cons_len; i++) | |
for (Cons *p = cons[i], *np; p; p = np) | |
{ | |
np = p->cdr; | |
delete p; | |
} | |
} | |
*/ |
先留名
喵~竟然被抢了沙发 -_____-#不开森
这里可以抢沙发诶
前排
后排兜售瓜子饮料╮(╯▽╰)╭
后排膜拜
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
棒棒哒>_<