📄 fprase.cpp
字号:
unsigned index = ByteCode[++IP];
Data::VarMap_t::const_iterator iter =
data->FuncParserNames.begin();
while(iter->second != index) ++iter;
dest << "call\t" << iter->first << endl;
break;
}
default:
if(opcode < VarBegin)
{
string n;
switch(opcode)
{
case cNeg: n = "neg"; break;
case cAdd: n = "add"; break;
case cSub: n = "sub"; break;
case cMul: n = "mul"; break;
case cDiv: n = "div"; break;
case cMod: n = "mod"; break;
case cPow: n = "pow"; break;
case cEqual: n = "eq"; break;
case cLess: n = "lt"; break;
case cGreater: n = "gt"; break;
case cAnd: n = "and"; break;
case cOr: n = "or"; break;
case cDeg: n = "deg"; break;
case cRad: n = "rad"; break;
#ifndef DISABLE_EVAL
case cEval: n = "call\t0"; break;
#endif
#ifdef SUPPORT_OPTIMIZER
case cVar: n = "(var)"; break;
case cDup: n = "dup"; break;
case cInv: n = "inv"; break;
#endif
default: n = Functions[opcode-cAbs].name;
}
dest << n << endl;
}
else
{
dest << "push\tVar" << opcode-VarBegin << endl;
}
}
}
}
#endif
//========================================================================
// Optimization code was contributed by Bisqwit (http://iki.fi/bisqwit/)
//========================================================================
#ifdef SUPPORT_OPTIMIZER
#include <list>
#include <utility>
#define CONSTANT_E 2.71828182845904509080 // exp(1)
#define CONSTANT_PI M_PI // atan2(0,-1)
#define CONSTANT_L10 2.30258509299404590109 // log(10)
#define CONSTANT_L10I 0.43429448190325176116 // 1/log(10)
#define CONSTANT_L10E CONSTANT_L10I // log10(e)
#define CONSTANT_L10EI CONSTANT_L10 // 1/log10(e)
#define CONSTANT_DR (180.0 / M_PI) // 180/pi
#define CONSTANT_RD (M_PI / 180.0) // pi/180
namespace {
class compres
{
// states: 0=false, 1=true, 2=unknown
public:
compres(bool b) : state(b) {}
compres(char v) : state(v) {}
// is it?
operator bool() const { return state != 0; }
// is it not?
bool operator! () const { return state != 1; }
bool operator==(bool b) const { return state != !b; }
bool operator!=(bool b) const { return state != b; }
private:
char state;
};
const compres maybe = (char)2;
struct CodeTree;
class SubTree
{
CodeTree *tree;
bool sign; // Only possible when parent is cAdd or cMul
inline void flipsign() { sign = !sign; }
public:
SubTree();
SubTree(double value);
SubTree(const SubTree &b);
SubTree(const CodeTree &b);
~SubTree();
const SubTree &operator= (const SubTree &b);
const SubTree &operator= (const CodeTree &b);
bool getsign() const { return sign; }
const CodeTree* operator-> () const { return tree; }
const CodeTree& operator* () const { return *tree; }
struct CodeTree* operator-> () { return tree; }
struct CodeTree& operator* () { return *tree; }
bool operator< (const SubTree& b) const;
bool operator== (const SubTree& b) const;
void Negate(); // Note: Parent must be cAdd
void Invert(); // Note: Parent must be cMul
void CheckConstNeg();
void CheckConstInv();
};
bool IsNegate(const SubTree &p1, const SubTree &p2);
bool IsInverse(const SubTree &p1, const SubTree &p2);
typedef list<SubTree> paramlist;
struct CodeTreeData
{
paramlist args;
private:
unsigned op; // Operation
double value; // In case of cImmed
unsigned var; // In case of cVar
unsigned funcno; // In case of cFCall, cPCall
public:
CodeTreeData() : op(cAdd) {}
~CodeTreeData() {}
void SetOp(unsigned newop) { op=newop; }
void SetFuncNo(unsigned newno) { funcno=newno; }
unsigned GetFuncNo() const { return funcno; }
bool IsFunc() const { return op == cFCall || op == cPCall; }
bool IsImmed() const { return op == cImmed; }
bool IsVar() const { return op == cVar; }
inline unsigned GetOp() const { return op; }
inline double GetImmed() const
{
return value;
}
inline unsigned GetVar() const
{
return var;
}
void AddParam(const SubTree &p)
{
args.push_back(p);
}
void SetVar(unsigned v)
{
args.clear();
op = cVar;
var = v;
}
void SetImmed(double v)
{
args.clear();
op = cImmed;
value = orig = v;
inverted = negated = false;
}
void NegateImmed()
{
negated = !negated;
UpdateValue();
}
void InvertImmed()
{
inverted = !inverted;
UpdateValue();
}
bool IsOriginal() const { return !(IsInverted() || IsNegated()); }
bool IsInverted() const { return inverted; }
bool IsNegated() const { return negated; }
bool IsInvertedOriginal() const { return IsInverted() && !IsNegated(); }
bool IsNegatedOriginal() const { return !IsInverted() && IsNegated(); }
private:
void UpdateValue()
{
value = orig;
if(IsInverted()) { value = 1.0 / value;
// FIXME: potential divide by zero.
}
if(IsNegated()) value = -value;
}
double orig;
bool inverted;
bool negated;
protected:
// Ensure we don't accidentally copy this
void operator=(const CodeTreeData &b);
};
class CodeTreeDataPtr
{
typedef pair<CodeTreeData, unsigned> p_t;
typedef p_t* pp;
mutable pp p;
void Alloc() const { ++p->second; }
void Dealloc() const { if(!--p->second) delete p; p = 0; }
void PrepareForWrite()
{
// We're ready if we're the only owner.
if(p->second == 1) return;
// Then make a clone.
p_t *newtree = new p_t(p->first, 1);
// Forget the old
Dealloc();
// Keep the new
p = newtree;
}
public:
CodeTreeDataPtr() : p(new p_t) { p->second = 1; }
CodeTreeDataPtr(const CodeTreeDataPtr &b): p(b.p) { Alloc(); }
~CodeTreeDataPtr() { Dealloc(); }
const CodeTreeDataPtr &operator= (const CodeTreeDataPtr &b)
{
b.Alloc();
Dealloc();
p = b.p;
return *this;
}
const CodeTreeData *operator-> () const { return &p->first; }
const CodeTreeData &operator* () const { return p->first; }
CodeTreeData *operator-> () { PrepareForWrite(); return &p->first; }
CodeTreeData &operator* () { PrepareForWrite(); return p->first; }
void Shock();
};
#define CHECKCONSTNEG(item, op) \
((op)==cMul) \
? (item).CheckConstInv() \
: (item).CheckConstNeg()
struct CodeTree
{
CodeTreeDataPtr data;
private:
typedef paramlist::iterator pit;
typedef paramlist::const_iterator pcit;
/*
template<unsigned v> inline void chk() const
{
}
*/
public:
const pcit GetBegin() const { return data->args.begin(); }
const pcit GetEnd() const { return data->args.end(); }
const pit GetBegin() { return data->args.begin(); }
const pit GetEnd() { return data->args.end(); }
const SubTree& getp0() const { /*chk<1>();*/pcit tmp=GetBegin(); return *tmp; }
const SubTree& getp1() const { /*chk<2>();*/pcit tmp=GetBegin(); ++tmp; return *tmp; }
const SubTree& getp2() const { /*chk<3>();*/pcit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
unsigned GetArgCount() const { return data->args.size(); }
void Erase(const pit p) { data->args.erase(p); }
SubTree& getp0() { /*chk<1>();*/pit tmp=GetBegin(); return *tmp; }
SubTree& getp1() { /*chk<2>();*/pit tmp=GetBegin(); ++tmp; return *tmp; }
SubTree& getp2() { /*chk<3>();*/pit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
// set
void SetImmed(double v) { data->SetImmed(v); }
void SetOp(unsigned op) { data->SetOp(op); }
void SetVar(unsigned v) { data->SetVar(v); }
// get
double GetImmed() const { return data->GetImmed(); }
unsigned GetVar() const { return data->GetVar(); }
unsigned GetOp() const { return data->GetOp(); }
// test
bool IsImmed() const { return data->IsImmed(); }
bool IsVar() const { return data->IsVar(); }
// act
void AddParam(const SubTree &p) { data->AddParam(p); }
void NegateImmed() { data->NegateImmed(); } // don't use when op!=cImmed
void InvertImmed() { data->InvertImmed(); } // don't use when op!=cImmed
compres NonZero() const { if(!IsImmed()) return maybe;
return GetImmed() != 0.0; }
compres IsPositive() const { if(!IsImmed()) return maybe;
return GetImmed() > 0.0; }
private:
struct ConstList
{
double voidvalue;
list<pit> cp;
double value;
unsigned size() const { return cp.size(); }
};
struct ConstList BuildConstList();
void KillConst(const ConstList &cl)
{
for(list<pit>::const_iterator i=cl.cp.begin(); i!=cl.cp.end(); ++i)
Erase(*i);
}
void FinishConst(const ConstList &cl)
{
if(cl.value != cl.voidvalue && cl.size() > 1) AddParam(cl.value);
if(cl.value == cl.voidvalue || cl.size() > 1) KillConst(cl);
}
public:
CodeTree() {}
CodeTree(double v) { SetImmed(v); }
CodeTree(unsigned op, const SubTree &p)
{
SetOp(op);
AddParam(p);
}
CodeTree(unsigned op, const SubTree &p1, const SubTree &p2)
{
SetOp(op);
AddParam(p1);
AddParam(p2);
}
bool operator== (const CodeTree& b) const;
bool operator< (const CodeTree& b) const;
private:
bool IsSortable() const
{
switch(GetOp())
{
case cAdd: case cMul:
case cEqual:
case cAnd: case cOr:
case cMax: case cMin:
return true;
default:
return false;
}
}
void SortIfPossible()
{
if(IsSortable())
{
data->args.sort();
}
}
void ReplaceWithConst(double value)
{
SetImmed(value);
/* REMEMBER TO CALL CheckConstInv / CheckConstNeg
* FOR PARENT SubTree, OR MAYHEM HAPPENS
*/
}
void ReplaceWith(const CodeTree &b)
{
// If b is child of *this, mayhem
// happens. So we first make a clone
// and then proceed with copy.
CodeTreeDataPtr tmp = b.data;
tmp.Shock();
data = tmp;
}
void ReplaceWith(unsigned op, const SubTree &p)
{
ReplaceWith(CodeTree(op, p));
}
void ReplaceWith(unsigned op, const SubTree &p1, const SubTree &p2)
{
ReplaceWith(CodeTree(op, p1, p2));
}
void OptimizeConflict()
{
// This optimization does this: x-x = 0, x/x = 1, a+b-a = b.
if(GetOp() == cAdd || GetOp() == cMul)
{
Redo:
pit a, b;
for(a=GetBegin(); a!=GetEnd(); ++a)
{
for(b=GetBegin(); ++b != GetEnd(); )
{
const SubTree &p1 = *a;
const SubTree &p2 = *b;
if(GetOp() == cMul ? IsInverse(p1,p2)
: IsNegate(p1,p2))
{
// These parameters complement each others out
Erase(b);
Erase(a);
goto Redo;
}
}
}
}
OptimizeRedundant();
}
void OptimizeRedundant()
{
// This optimization does this: min()=0, max()=0, add()=0, mul()=1
if(!GetArgCount())
{
if(GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
ReplaceWithConst(0);
else if(GetOp() == cMul)
ReplaceWithConst(1);
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -