Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#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;
}
}
*/
@CodePothunter

This comment has been minimized.

Copy link

CodePothunter commented Jul 5, 2014

棒棒哒>_<

@hydorah

This comment has been minimized.

Copy link

hydorah commented Jul 5, 2014

先留名

@Phonicavi

This comment has been minimized.

Copy link

Phonicavi commented Jul 5, 2014

喵~竟然被抢了沙发 -_____-#不开森

@lemonbirdy

This comment has been minimized.

Copy link

lemonbirdy commented Jul 6, 2014

这里可以抢沙发诶
前排

@octopusszzy

This comment has been minimized.

Copy link

octopusszzy commented Jul 6, 2014

后排兜售瓜子饮料╮(╯▽╰)╭

@OptimusT

This comment has been minimized.

Copy link

OptimusT commented Jul 7, 2014

后排膜拜

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.