void Parser::FNSyntax_DeleteExpression(ExprNode *node) { ExprNode *temp = NULL; for(ExprNode *i = node; i != NULL; i = i->next) { if(temp != NULL) { POV_FREE(temp); } FNSyntax_DeleteExpression(i->child); if((i->op == OP_VARIABLE) || (i->op == OP_MEMBER)) { POV_FREE(i->variable); } else if(i->op == OP_CALL) { if((i->call.token == FUNCT_ID_TOKEN) || (i->call.token == VECTFUNCT_ID_TOKEN)) dynamic_cast<FunctionVM*>(sceneData->functionContextFactory)->RemoveFunction(i->call.fn); POV_FREE(i->call.name); } temp = i; } if(temp != NULL) { POV_FREE(temp); } }
void FNSyntax_DeleteExpression(ExprNode *node) { ExprNode *temp = NULL; for(ExprNode *i = node; i != NULL; i = i->next) { if(temp != NULL) { POV_FREE(temp); } FNSyntax_DeleteExpression(i->child); if((i->op == OP_VARIABLE) || (i->op == OP_MEMBER)) { POV_FREE(i->variable); } else if(i->op == OP_CALL) { if((i->call.token == FUNCT_ID_TOKEN) || (i->call.token == VECTFUNCT_ID_TOKEN)) POVFPU_RemoveFunction(i->call.fn); POV_FREE(i->call.name); } temp = i; } if(temp != NULL) { POV_FREE(temp); } }
FUNCTION_PTR Parser::Parse_FunctionContent(void) { FUNCTION_PTR ptr = (FUNCTION_PTR)POV_MALLOC(sizeof(FUNCTION), "Function ID"); ExprNode *expression = NULL; FunctionCode function; FNCode f(this, &function, false, NULL); expression = FNSyntax_ParseExpression(); f.Compile(expression); FNSyntax_DeleteExpression(expression); *ptr = sceneData->functionVM->AddFunction(&function); return ptr; }
void Parser::optimise_expr(ExprNode *node) { ExprNode *left,*right,*ptr,*temp; DBL result; bool have_result; int op,cnt; if(node == NULL) return; if(node->op == OP_CALL) { if(node->call.token == POW_TOKEN) { node->op = OP_FIRST; POV_FREE(node->call.name); if(node->child != NULL) { node->child->op = OP_LEFTMOST; if(node->child->next != NULL) { node->child->next->op = OP_POW; node->child->next->prev = node->child; } } } } if(node->op < OP_FIRST) // using switch statement might be better [trf] { ptr = node->next; if(ptr != NULL) { if(ptr->op == OP_NEG) { op = ptr->op; cnt = 0; for(ptr = node->next; ptr != NULL; ptr = ptr->next) { cnt++; if(ptr->child != NULL) break; } if(ptr != NULL) { optimise_expr(ptr->child); if(ptr->child != NULL) { left = ptr->child; if(left->op == OP_CONSTANT) { ptr->child = NULL; if(node->next != NULL) FNSyntax_DeleteExpression(node->next); if(op == OP_NEG) { if((cnt % 2) == 0) node->number = (left->number); else node->number = -(left->number); } POV_FREE(left); node->op = OP_CONSTANT; node->child = NULL; node->prev = NULL; node->next = NULL; return; // early exit } } } } } optimise_expr(node->child); for(ptr = node->next; ptr != NULL; ptr = ptr->next) { left = ptr->prev->child; right = ptr->child; if((right != NULL) && (ptr->op == OP_SUB)) { if(right->op == OP_CONSTANT) { ptr->op = OP_ADD; right->number = -right->number; } } optimise_expr(right); if((left != NULL) && (right != NULL) && (((ptr->op != OP_MUL) && (ptr->op != OP_DIV)) || !left_subtree_has_variable_expr(ptr))) { if((left->op == OP_CONSTANT) && (right->op == OP_CONSTANT)) { have_result = true; switch(ptr->op) { case OP_CMP_EQ: result = (left->number == right->number); break; case OP_CMP_NE: result = (left->number != right->number); break; case OP_CMP_LT: result = (left->number < right->number); break; case OP_CMP_LE: result = (left->number <= right->number); break; case OP_CMP_GT: result = (left->number > right->number); break; case OP_CMP_GE: result = (left->number >= right->number); break; case OP_ADD: result = (left->number + right->number); break; case OP_SUB: result = (left->number - right->number); break; case OP_OR: result = (DBL)(((DBL)((((DBL)(left->number != 0)) + ((DBL)(right->number != 0))))) != 0); // match VM code break; case OP_MUL: result = (left->number * right->number); break; case OP_DIV: result = (left->number / right->number); break; case OP_AND: result = (DBL)((((DBL)(left->number != 0)) * ((DBL)(right->number != 0)))); // match VM code break; case OP_POW: result = pow(left->number, right->number); break; default: have_result = false; break; } if(have_result == true) { temp = ptr; ptr->prev->next = ptr->next; if(ptr->next != NULL) ptr->next->prev = ptr->prev; ptr = ptr->prev; POV_FREE(temp->child); POV_FREE(temp); left->number = result; } } } } if((node->next == NULL) && (node->child != NULL) && (node->op < OP_FIRST)) { if((node->child->op == OP_CONSTANT) && (node->child->next == NULL)) { node->number = left->number; node->op = OP_CONSTANT; POV_FREE(node->child); node->child = NULL; } } } else { optimise_expr(node->child); optimise_call(node); if((node->child != NULL) && (node->op < OP_FIRST)) { if((node->child->op == OP_CONSTANT) && (node->child->next == NULL)) { node->number = node->child->number; POV_FREE(node->child); node->child = NULL; node->op = OP_CONSTANT; } } } }
FUNCTION_PTR Parser::Parse_DeclareFunction(int *token_id, const char *fn_name, bool is_local) { FUNCTION_PTR ptr = (FUNCTION_PTR)POV_MALLOC(sizeof(FUNCTION), "Function ID"); ExprNode *expression = NULL; FunctionCode function; // default type is float function *token_id = FUNCT_ID_TOKEN; FNCode f(this, &function, is_local, fn_name); f.Parameter(); Parse_Begin(); Get_Token(); if(Token.Token_Id == INTERNAL_TOKEN) { GET(LEFT_PAREN_TOKEN); Get_Token(); if(Token.Function_Id != FLOAT_TOKEN) Expectation_Error("internal function identifier"); expression = FNSyntax_GetTrapExpression((unsigned int)(Token.Token_Float)); function.flags = FN_INLINE_FLAG; GET(RIGHT_PAREN_TOKEN); } else if(Token.Token_Id == TRANSFORM_TOKEN) { if(function.parameter_cnt != 0) Error("Function parameters for transform functions are not allowed."); expression = FNSyntax_GetTrapExpression(1); // 1 refers to POVFPU_TrapSTable[1] = f_transform [trf] function.private_copy_method = (FNCODE_PRIVATE_COPY_METHOD)Copy_Transform; function.private_destroy_method = (FNCODE_PRIVATE_DESTROY_METHOD)Destroy_Transform; function.private_data = reinterpret_cast<void *>(Parse_Transform_Block()); function.return_size = 3; // returns a 3d vector!!! // function type is vector function *token_id = VECTFUNCT_ID_TOKEN; } else if(Token.Token_Id == SPLINE_TOKEN) { if(function.parameter_cnt != 0) Error("Function parameters for spline functions are not allowed."); Experimental_Flag |= EF_SPLINE; expression = FNSyntax_GetTrapExpression(2); // 2 refers to POVFPU_TrapSTable[2] = f_spline [trf] function.private_copy_method = (FNCODE_PRIVATE_COPY_METHOD)Copy_Spline; function.private_destroy_method = (FNCODE_PRIVATE_DESTROY_METHOD)Destroy_Spline; Parse_Begin(); function.private_data = reinterpret_cast<void *>(Parse_Spline()); Parse_End(); function.return_size = (reinterpret_cast<SPLINE *>(function.private_data))->Terms; // returns a 2d, 3d, 4d or 5d vector!!! // function type is vector function *token_id = VECTFUNCT_ID_TOKEN; } else if(Token.Token_Id == PIGMENT_TOKEN) { if(function.parameter_cnt != 0) Error("Function parameters for pigment functions are not allowed."); expression = FNSyntax_GetTrapExpression(0); // 0 refers to POVFPU_TrapSTable[0] = f_pigment [trf] function.private_copy_method = (FNCODE_PRIVATE_COPY_METHOD)Copy_Pigment; function.private_destroy_method = (FNCODE_PRIVATE_DESTROY_METHOD)Destroy_Pigment; Parse_Begin(); function.private_data = reinterpret_cast<void *>(Create_Pigment()); Parse_Pigment(reinterpret_cast<PIGMENT **>(&function.private_data)); Parse_End(); Post_Pigment(reinterpret_cast<PIGMENT *>(function.private_data)); function.return_size = 5; // returns a color!!! // function type is vector function *token_id = VECTFUNCT_ID_TOKEN; } else if(Token.Token_Id == PATTERN_TOKEN) { if(function.parameter_cnt != 0) Error("Function parameters for pattern functions are not allowed."); expression = FNSyntax_GetTrapExpression(77); // 77 refers to POVFPU_TrapTable[77] = f_pattern [trf] function.private_copy_method = (FNCODE_PRIVATE_COPY_METHOD)Copy_Pigment; function.private_destroy_method = (FNCODE_PRIVATE_DESTROY_METHOD)Destroy_Pigment; Parse_Begin(); function.private_data = reinterpret_cast<void *>(Create_Pigment()); // Yes, this is a pigment! [trf] Parse_PatternFunction(reinterpret_cast<TPATTERN *>(function.private_data)); Parse_End(); Post_Pigment(reinterpret_cast<PIGMENT *>(function.private_data)); } else if(Token.Token_Id == STRING_LITERAL_TOKEN) { f.SetFlag(2, Token.Token_String); Get_Token(); if(Token.Token_Id == COMMA_TOKEN) { Get_Token(); if(Token.Token_Id != STRING_LITERAL_TOKEN) Expectation_Error("valid function expression"); f.SetFlag(1, Token.Token_String); } else { Unget_Token(); expression = FNSyntax_ParseExpression(); } } else { Unget_Token(); expression = FNSyntax_ParseExpression(); } f.Compile(expression); FNSyntax_DeleteExpression(expression); Parse_End(); *ptr = sceneData->functionVM->AddFunction(&function); return ptr; }