/* * Free an entire expression recursively. */ void freeExp(Exp *exp) { switch(exp->type) { case T_App: freeExp(exp->value->app->fun); freeExp(exp->value->app->arg); free(exp->value->app); free(exp->value); break; case T_Abs: freeExp(exp->value->abs->body); free(exp->value->abs); free(exp->value); break; case T_Var: free(exp->value->var); free(exp->value); break; case T_Con: free(exp->value->con); free(exp->value); break; case T_Opn: free(exp->value->opn); free(exp->value); break; } free(exp); }
static exp_node *expression(void){ exp_node *expn = newExpNode(); if(match(TOKEN_LBRA, NO_CONSUME) || match(TOKEN_IDENTIFIER, NO_CONSUME) || match(TOKEN_LITERAL, NO_CONSUME)) if((expn->termn = term()) != NULL) if((expn->termtln = term_tail()) != error) return expn; freeExp(expn); return NULL; }
/* * Perform reduction on a template until it reaches its normal form (when no * reduction rules are applicable). */ Exp *reduceTemplateNorm(Exp *exp) { Exp *initExp = copyExp(exp); bool normalForm = false; while(!normalForm) { Exp *redExp = reduceTemplate(initExp); normalForm = expEqual(initExp, redExp); freeExp(initExp); initExp = redExp; } return initExp; }
/* * Perform at least one reduction step on the given template. */ Exp *reduceTemplate(Exp *exp) { // Conditionals if(isApp(exp) && isApp(appFun(exp)) && isApp(appFun(appFun(exp))) && isOpn(appFun(appFun(appFun(exp)))) && (opnType(appFun(appFun(appFun(exp)))) == O_Cond)) { Exp *guard = appArg(appFun(appFun(exp))); Exp *truExp = appArg(appFun(exp)); Exp *falExp = appArg(exp); // If the guard is true, return the true expression. if(isCon(guard) && (conVal(guard) == true)) { return copyExp(truExp); } // If the guard is false, return the false expression. else if(isCon(guard) && (conVal(guard) == false)) { return copyExp(falExp); } // If the guard is not reduced, reduce it. else { return newApp(newApp(newApp( newOpn(O_Cond), reduceTemplate(guard)), copyExp(truExp)), copyExp(falExp)); } } // End of conditional case // Binary operations else if(isApp(exp) && isApp(appFun(exp)) && isBinaryOpn(appFun(appFun(exp)))) { OpTy opn = opnType(appFun(appFun(exp))); Exp *arg1 = appArg(appFun(exp)); Exp *arg2 = appArg(exp); // Handle equality differently because it is polymorphic. if(opn == O_Equ) { Exp *redA1 = reduceTemplateNorm(arg1); Exp *redA2 = reduceTemplateNorm(arg2); bool same = expEqual(redA1, redA2); freeExp(redA1); freeExp(redA2); return newCon(C_Bool, same); } else if(isApp(arg1) || isAbs(arg1) || isVar(arg1) || isOpn(arg1)) { return newApp( newApp( newOpn(opn), reduceTemplate(arg1)), copyExp(arg2)); } else if(isApp(arg2) || isAbs(arg2) || isVar(arg2) || isOpn(arg2)) { return newApp( newApp( newOpn(opn), copyExp(arg1)), reduceTemplate(arg2)); } else { assert(isCon(arg1)); assert(isCon(arg2)); if(opn == O_Add) { return newCon(C_Int, conVal(arg1) + conVal(arg2)); } else if(opn == O_Sub) { return newCon(C_Int, conVal(arg1) - conVal(arg2)); } else if(opn == O_Mul) { return newCon(C_Int, conVal(arg1) * conVal(arg2)); } else if(opn == O_Div) { return newCon(C_Int, conVal(arg1) / conVal(arg2)); } else if(opn == O_Mod) { return newCon(C_Int, conVal(arg1) % conVal(arg2)); } else if(opn == O_Lss) { return newCon(C_Bool, conVal(arg1) < conVal(arg2)); } else if(opn == O_LsE) { return newCon(C_Bool, conVal(arg1) <= conVal(arg2)); } else if(opn == O_NEq) { return newCon(C_Bool, conVal(arg1) != conVal(arg2)); } else if(opn == O_Gtr) { return newCon(C_Bool, conVal(arg1) > conVal(arg2)); } else if(opn == O_GtE) { return newCon(C_Bool, conVal(arg1) >= conVal(arg2)); } else if(opn == O_Xor) { return newCon(C_Bool, (!conVal(arg1)) != (!conVal(arg2))); } else if(opn == O_And) { return newCon(C_Bool, conVal(arg1) && conVal(arg2)); } else if(opn == O_Or ) { return newCon(C_Bool, conVal(arg1) || conVal(arg2)); } else { printf("Error reducing binary operation - unrecognised " "operation\n"); assert(false); } } } // End of binary operations case // iszero & not unary operations else if(isApp(exp) && isOpn(appFun(exp)) && (opnType(appFun(exp)) == O_Not || opnType(appFun(exp)) == O_IsZ)) { OpTy opn = opnType(appFun(exp)); Exp *arg = appArg(exp); if(isApp(arg) || isAbs(arg) || isVar(arg) || isOpn(arg)) { return newApp(newOpn(opn), reduceTemplate(arg)); } else { if(opn == O_Not) { return newCon(C_Bool, !(conVal(arg))); } else { assert(opn == O_IsZ); return newCon(C_Bool, conVal(arg) == 0); } } } // End iszero & not unary operations case // Polymorphic unary operations // Null else if(isApp(exp) && isOpn(appFun(exp)) && (opnType(appFun(exp)) == O_Null)) { Exp *arg = appArg(exp); Exp *reducedArg = reduceTemplateNorm(arg); if(isOpn(reducedArg) && (opnType(reducedArg) == O_Empty)) { freeExp(reducedArg); return newCon(C_Bool, true); } else { freeExp(reducedArg); return newCon(C_Bool, false); } } // End Null // Head and Tail else if(isApp(exp) && isOpn(appFun(exp)) && ((opnType(appFun(exp)) == O_Head) || (opnType(appFun(exp)) == O_Tail))) { OpTy opn = opnType(appFun(exp)); Exp *arg = appArg(exp); if(isApp(arg) && isApp(appFun(arg)) && isOpn(appFun(appFun(arg))) && (opnType(appFun(appFun(arg)))) == O_Cons) { Exp *head = appArg(appFun(arg)); Exp *tail = appArg(arg); if(opn == O_Head) { return copyExp(head); } else { assert(opn == O_Tail); return copyExp(tail); } } else { return newApp(newOpn(opn), reduceTemplate(arg)); } } // End Head and Tail // Cons else if(isApp(exp) && isOpn(appFun(exp)) && (opnType(appFun(exp)) == O_Cons)) { Exp *consArg = appArg(exp); return newApp(newOpn(O_Cons), reduceTemplate(consArg)); } // End Cons // Sum operations else if(isApp(exp) && isOpn(appFun(exp)) && ((opnType(appFun(exp)) == O_RemL) || (opnType(appFun(exp)) == O_RemR))) { OpTy opn = opnType(appFun(exp)); Exp *arg = appArg(exp); if(isApp(arg) && isOpn(appFun(arg)) && ((opnType(appFun(arg)) == O_InjL) || (opnType(appFun(arg)) == O_InjR))) { OpTy innerOpn = opnType(appFun(arg)); Exp *innerArg = appArg(arg); if(((opn == O_RemL) && (innerOpn == O_InjL)) || ((opn == O_RemR) && (innerOpn == O_InjR))) { return copyExp(innerArg); } else { printf("Error - removed value from a non-sum expression or " "wrong side of sum expression\n"); assert(false); } } else { return newApp(newOpn(opn), reduceTemplate(arg)); } } else if(isApp(exp) && isOpn(appFun(exp)) && ((opnType(appFun(exp)) == O_InjL) || (opnType(appFun(exp)) == O_InjR))) { OpTy opn = opnType(appFun(exp)); Exp *arg = appArg(exp); return newApp(newOpn(opn), reduceTemplate(arg)); } else if(isApp(exp) && isOpn(appFun(exp)) && (opnType(appFun(exp)) == O_IsLeft)) { Exp *arg = appArg(exp); if(isApp(arg) && isOpn(appFun(arg)) && ((opnType(appFun(arg)) == O_InjL) || (opnType(appFun(arg)) == O_InjR))) { OpTy injOpn = opnType(appFun(arg)); return newCon(C_Bool, injOpn == O_InjL); } else { return newApp(newOpn(O_IsLeft), reduceTemplate(arg)); } } // End sum operations // Tuple operations else if(isApp(exp) && isOpn(appFun(exp)) && ((opnType(appFun(exp)) == O_Fst) || (opnType(appFun(exp)) == O_Snd))) { OpTy opn = opnType(appFun(exp)); Exp *arg = appArg(exp); if(isApp(arg) && isApp(appFun(arg)) && isOpn(appFun(appFun(arg))) && (opnType(appFun(appFun(arg))) == O_Tuple)) { Exp *fst = appArg(appFun(arg)); Exp *snd = appArg(arg); return copyExp((opn == O_Fst) ? fst : snd); } else { return newApp(newOpn(opn), reduceTemplate(arg)); } } else if(isApp(exp) && isOpn(appFun(exp)) && (opnType(appFun(exp)) == O_Tuple)) { Exp *arg = appArg(exp); return newApp(newOpn(O_Tuple), reduceTemplate(arg)); } // End Tuple operations // Fixed point combinator else if(isApp(exp) && isOpn(appFun(exp)) && (opnType(appFun(exp)) == O_Fix)) { return newApp(copyExp(appArg(exp)), copyExp(exp)); } // End fixed point combinator // End polymorphic unary operations // Lambda abstractions else if(isApp(exp) && isAbs(appFun(exp))) { Exp *abs = appFun(exp); Exp *arg = appArg(exp); return replace(absBody(abs), 0, arg); } // End lambda abstractions // Function calls else if(isApp(exp) && isVar(appFun(exp))) { Exp *var = appFun(exp); Exp *arg = appArg(exp); int bind = varBind(var); if(hasFunc(bind)) { return newApp(instantiate(bind), copyExp(arg)); } else { return newApp(copyExp(var), reduceTemplate(arg)); } } else if(isVar(exp) && hasFunc(varBind(exp))) { return instantiate(varBind(exp)); } // End function calls // Catch-all application case else if(isApp(exp)) { Exp *fun = appFun(exp); Exp *arg = appArg(exp); return newApp(reduceTemplate(fun), reduceTemplate(arg)); } // End catch-all application case // If there are no reductions to make, return a copy of the given template. else { return copyExp(exp); } }