Skip to content

Instantly share code, notes, and snippets.

@Determinant
Last active August 29, 2015 14:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Determinant/8b9e124dc245d9818fa4 to your computer and use it in GitHub Desktop.
Save Determinant/8b9e124dc245d9818fa4 to your computer and use it in GitHub Desktop.
#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
Copy link

棒棒哒>_<

@hydorah
Copy link

hydorah commented Jul 5, 2014

先留名

@Phonicavi
Copy link

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

@lemonbirdy
Copy link

这里可以抢沙发诶
前排

@octopusszzy
Copy link

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

@OptimusT
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