bool check_exp(const node* p, int rr_level) { if (!p || p->t == nt_num) return true; // rrlvl1: 交换率,以下两个判断保证了A+B+C+...+Z这种形式下,只选择A>B>C>...>Z这一种组合 if (rr_level >= 1) { if (commulative(p->op)) { double v1 = p->l_child->val(); double v2 = p->r_child->val(); if (v1 < v2) return false; if (double_equ(v1, v2) && shape_less(p->l_child, p->r_child)) return false; } if (p->l_child->t == nt_op && p->l_child->op == p->op && associative(p->op)) { double v1 = p->l_child->r_child->val(); double v2 = p->r_child->val(); if (v1 < v2) return false; if (double_equ(v1, v2) && shape_less(p->l_child->r_child, p->r_child)) return false; } } // rrlvl2: 去除/1和-0。/1可以用*1替换,-0可以用+0替换。 if (rr_level >= 2) { if (p->op == L'/' && double_equ(p->r_child->val(), 1)) return false; if (p->op == L'-' && double_equ(p->r_child->val(), 0)) return false; } if (!check_exp(p->l_child, rr_level)) return false; if (!check_exp(p->r_child, rr_level)) return false; return true; }
bool check_bone(const node* p, int rr_level) { if (!p || p->t == nt_num) return true; // '_'是连字符,要求右孩子是数,左孩子是数或者也是个'_' if (p->op == L'_') { if (p->r_child->t == nt_op) return false; if (p->l_child->t == nt_op && p->l_child->op != L'_') return false; } if (rr_level >= 1) { // 交换率:规定两个分支的顺序 if (commulative(p->op)) { // 不可以在这里判断,在check_exp时对满足交换率的左右子树采用了求值的方法:大值在左 // if (shape_less(p->l_child, p->r_child, false)) return false; } // 不能出现 A-B+C A/B*C,应该是A+C-B, A*C/B if (p->l_child->t == nt_op && get_pred(p->op) == get_pred(p->l_child->op)) { if (p->op < p->l_child->op) return false; } // 结合率 // 不能出现 A+(B+C), A+(B-C), A-(B+C), A-(B-C)这样的情况,乘除类似 if (p->r_child->t == nt_op && associative(p->op) && get_pred(p->op) == get_pred(p->r_child->op)) return false; } if (!check_bone(p->l_child, rr_level)) return false; if (!check_bone(p->r_child, rr_level)) return false; return true; }
string DocCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2, int priority) { string s; int thisPriority = gBinOpLateqTable[opcode]->fPriority; /* Priority parenthesis handling. */ string lpar = ""; string rpar = ""; if((thisPriority < priority) || ((thisPriority == priority) && !associative(opcode))) { // (a+b)*c or (a/b)/c need parenthesis lpar = " \\left("; rpar = "\\right) "; } Type t1 = getCertifiedSigType(arg1); Type t2 = getCertifiedSigType(arg2); bool intOpDetected = false; if((t1->nature() == kInt) && (t2->nature() == kInt)) { intOpDetected = true; } string op; if(!intOpDetected) { op = gBinOpLateqTable[opcode]->fName; } else { switch(opcode) { case kAdd: op = "\\oplus"; gDocNoticeFlagMap["intplus"] = true; break; case kSub: op = "\\ominus"; gDocNoticeFlagMap["intminus"] = true; break; case kMul: op = "\\odot"; gDocNoticeFlagMap["intmult"] = true; break; case kDiv: op = "\\oslash"; gDocNoticeFlagMap["intdiv"] = true; gDocNoticeFlagMap["intcast"] = true; // "$normalize(int(i/j))$" in the notice. break; default: op = gBinOpLateqTable[opcode]->fName; break; } } /* LaTeX frac{}{} handling VS general case. */ if((opcode == kDiv) && (!intOpDetected)) { s = subst("$0\\frac{$1}{$2}$3", lpar, CS(arg1, 0), CS(arg2, 0), rpar); } else { s = subst("$0$1 $2 $3$4", lpar, CS(arg1, thisPriority), op, CS(arg2, thisPriority), rpar); } // if (opcode == kMul) { // gDocNoticeFlagMap["cdot"] = true; // } return generateCacheCode(sig, s); }