http://acdream.info/problem?pid=1232
手写了一个词法分析引擎。肯定是写麻烦了。
词法分析器Lexer将字符串解析为词法单元。
词法单元Token,储存词法单元的属性和值。
语法分析器Parser,读取词法单元,构建语法树。
表达式结点Expr。
define操作用并查集搞。
print操作用Parser读取一个Expr,然后执行Expr求值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
const int maxn=411111;
int _Cnt;
map<string,int>idmap;
map<int,int>conmap;
int _Pa[maxn];
int _Val[maxn];
void makeset(int i){
_Pa[i]=i;
_Val[i]=0;
}
int findset(int x){
if (x!=_Pa[x]) _Pa[x]=findset(_Pa[x]);
return _Pa[x];
}
void Define(int x,int y){
if (x!=_Pa[x]) return;
x=findset(x);
y=findset(y);
if (x!=y) _Pa[x]=y;
//printf("Pa[%d]=%d\n",x,y);
}
void SetValue(int x,int v){
_Val[x]=v;
}
int GetValue(int x){
//printf("GetValue(%d) ",x);
//printf("Pa[%d]=%d ",x,_Pa[x]);
x=findset(x);
//printf("findSet=%d Value=%d\n",x,_Val[x]);
return _Val[x];
}
int RegistInt(int v){
//printf("Regist Int %d\n",v);
map<int,int>::iterator it;
it=conmap.find(v);
if (it!=conmap.end()){
return it->second;
}
else{
conmap[v]=++_Cnt;
makeset(_Cnt);
SetValue(_Cnt,v);
return _Cnt;
}
}
int RegistStr(string str){
//printf("Regist Str %s\n",str.c_str());
map<string,int>::iterator it;
it=idmap.find(str);
if (it!=idmap.end()){
//printf("Find %d\n",it->second);
return it->second;
}
else{
idmap[str]=++_Cnt;
makeset(_Cnt);
SetValue(_Cnt,0);
//printf("Not Fine %d\n",_Cnt);
return _Cnt;
}
}
int power(int a,int b){
int ans=1;
while(b){
if(b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
class Token {
public:
enum Tag {
Int,Id,Add,Sub,Mul,Div,Mod,Pow,Lp,Rp,Eof
};
Token() {
type=Eof;
}
Token(int v) {
type=Int;
num=v;
}
Token(char c) {
switch (c) {
case '+':
type=Add;
break;
case '-':
type=Sub;
break;
case '*':
type=Mul;
break;
case '/':
type=Div;
break;
case '%':
type=Mod;
break;
case '^':
type=Pow;
break;
case '(':
type=Lp;
break;
case ')':
type=Rp;
break;
default:
type=Eof;
break;
}
op=c;
}
Token(char *p) {
type=Id;
id=p;
}
Tag type;
char op;
int num;
char *id;
};
class Expr {
public:
Expr() {}
virtual int Eval() {
return 0;
}
virtual ~Expr() {}
};
class Constant : public Expr {
public:
Constant(int v) {
value=v;
}
virtual ~Constant() {}
virtual int Eval() {
int s=RegistInt(value);
int v=GetValue(s);
//printf("const %d = %d inset num=%d\n",value,v,s);
return v;
}
int value;
};
class Id : public Expr {
public:
Id(string i) : id(i) {}
virtual ~Id() {}
virtual int Eval() {
int s=RegistStr(id);
int v=GetValue(s);
//printf("Id %s = %d\n",id.c_str(),v);
return v;// TODO
}
string id;
};
class Arith : public Expr {
public:
Arith(char o,Expr* x1,Expr* x2) {
op=o;
expr1=x1;
expr2=x2;
}
virtual ~Arith() {
delete expr1;
delete expr2;
}
virtual int Eval() {
int v1=expr1->Eval();
int v2=expr2->Eval();
//printf("Eval %d %c %d\n",v1,op,v2);
int ans=0;
int ng=0;
switch (op) {
case '+':
return v1+v2;
case '-':
return v1-v2;
case '*':
return v1*v2;
case '/':
ng=0;
if (v1<0) {
ng^=1;
v1=-v1;
}
if (v2<0){
ng^=1;
v2=-v2;
}
if (ng) return -(v1/v2);
else return v1/v2;
case '%':
ng=0;
if (v1<0) {
ng^=1;
v1=-v1;
}
if (v2<0){
ng^=1;
v2=-v2;
}
if (ng) return -(v1%v2);
else return v1%v2;
case '^':
//ans=1;
//for (int i=0;i<v2;i++) ans*=v1;
//ans=(int)pow(v1,v2);
ans=power(v1,v2);
return ans;
default:
return 0;
}
}
char op;
Expr* expr1;
Expr* expr2;
};
class Unary : public Expr {
public:
Unary(char o,Expr* x) {
op=o;
expr=x;
}
virtual ~Unary() {
delete expr;
}
virtual int Eval() {
int v=expr->Eval();
//printf("Eval %c %d\n",op,v);
switch (op) {
case '-':
return -v;
default:
return 0;
}
}
char op;
Expr* expr;
};
class Lexer {
public:
void init(char *s) {
buf=s;
pos=0;
len=strlen(buf);
peek=' ';
//printf("len = %d\n",len);
}
void Readch() {
if (pos<len) {
peek=buf[pos++];
} else {
peek=0;
}
}
Token Scan() {
for (;; Readch()) {
if (peek==' '||peek=='\t') continue;
else if (peek==0) return Token();
else break;
}
//printf("peek = %c\n",peek);
if (isdigit(peek)) {
int v=0;
do {
v=10*v+peek-'0';
Readch();
} while (isdigit(peek));
return Token(v);
}
if (isalpha(peek)) {
int cnt=0;
do {
if (peek>='A'&&peek<='Z') peek=peek-'A'+'a';
idt[cnt++]=peek;
Readch();
} while (isalnum(peek));
idt[cnt]=0;
return Token(idt);
}
char tp=peek;
peek=' ';
return Token(tp);
}
private:
char idt[20];
char *buf;
int pos;
int len;
char peek;
} lexer;
class Parser {
public:
void init(Lexer *l) {
lex=l;
Read();
}
void Read() {
look=lex->Scan();
//printf("Get Token type=%d value=",look.type);
//if (look.type==Token::Int) printf("%d\n",look.num);
//else if (look.type==Token::Id) printf("%s\n",look.id);
//else printf("%c\n",look.op);
}
Expr* expr() {
Expr* x=term();
while (look.type==Token::Add||look.type==Token::Sub) {
char op=look.op;
Read();
x=new Arith(op,x,term());
}
return x;
}
Expr* term() {
Expr* x=powpow();
while (look.type==Token::Mul||look.type==Token::Div||look.type==Token::Mod) {
char op=look.op;
Read();
x=new Arith(op,x,powpow());
}
return x;
}
Expr* powpow() {
Expr* x=unary();
if (look.type!=look.Pow) return x;
char op=look.op;
vector<Expr*>v;
v.push_back(x);
while (look.type==look.Pow) {
Read();
Expr* ex=unary();
v.push_back(ex);
}
x=v.back();
v.pop_back();
for (vector<Expr*>::reverse_iterator it=v.rbegin(); it!=v.rend(); it++) {
Expr* ex=(*it);
x=new Arith(op,ex,x);
}
return x;
}
Expr* unary() {
if (look.type==Token::Sub) {
Read();
return new Unary('-',unary());
} else return factor();
}
Expr* factor() {
if (look.type==Token::Lp) {
Read();
Expr* x=expr();
if (look.type==Token::Rp) {
Read();
}
return x;
} else if (look.type==Token::Int) {
int v=look.num;
Read();
return new Constant(v);
} else if (look.type==Token::Id) {
string str(look.id);
Read();
return new Id(str);
} else {
return new Expr();
}
}
private:
Lexer* lex;
Token look;
} parser;
char cmd[20];
char expr[2222];
int main() {
_Cnt=0;
idmap.clear();
conmap.clear();
while (~scanf("%s",cmd)) {
if (cmd[0]=='p') {
gets(expr);
lexer.init(expr);
/*
for (;;){
Token tok=lexer.Scan();
if (tok.type==Token::Eof) break;
printf("%d ",tok.type);
if (tok.type==Token::Int) printf("%d\n",tok.num);
else if (tok.type==Token::Id) printf("%s\n",tok.id);
else printf("%c\n",tok.op);
}
*/
parser.init(&lexer);
Expr* p=parser.expr();
int res=p->Eval();
printf("%d\n",res);
delete p;
}
else if (cmd[0]=='d') {
gets(expr);
lexer.init(expr);
Token tok1=lexer.Scan();
int s1,s2;
if (tok1.type==Token::Int){
s1=RegistInt(tok1.num);
}
else if (tok1.type==Token::Id){
s1=RegistStr(tok1.id);
}
Token tok2=lexer.Scan();
if (tok2.type==Token::Int){
s2=RegistInt(tok2.num);
}
else if (tok2.type==Token::Id){
s2=RegistStr(tok2.id);
}
Define(s1,s2);
}
}
return 0;
}
/*
define x y
print x+x
define y 2
print x+x
print y
print x
*/