| /* |
| Copyright (c) 2009 Peter Andrew Jamieson (jamieson.peter@gmail.com) |
| |
| Permission is hereby granted, free of charge, to any person |
| obtaining a copy of this software and associated documentation |
| files (the "Software"), to deal in the Software without |
| restriction, including without limitation the rights to use, |
| copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following |
| conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <math.h> |
| #include "odin_types.h" |
| #include "ast_util.h" |
| #include "ast_elaborate.h" |
| #include "ast_loop_unroll.h" |
| #include "parse_making_ast.h" |
| #include "verilog_bison.h" |
| #include "netlist_create_from_ast.h" |
| #include "ctype.h" |
| #include "vtr_util.h" |
| #include "vtr_memory.h" |
| #include <string> |
| #include <iostream> |
| #include <vector> |
| #include <stack> |
| |
| #define read_node 1 |
| #define write_node 2 |
| |
| #define e_data 1 |
| #define e_operation 2 |
| #define e_variable 3 |
| |
| #define N 64 |
| #define Max_size 64 |
| |
| long count_id = 0; |
| long count_assign = 0; |
| long count; |
| long count_write; |
| enode *head, *p; |
| |
| |
| int simplify_ast_module(ast_node_t **ast_module) |
| { |
| /* for loop support */ |
| unroll_loops(ast_module); |
| /* reduce parameters with their values if they have been set */ |
| reduce_parameter(*ast_module); |
| /* simplify assignment expressions */ |
| reduce_assignment_expression(*ast_module); |
| /* find multiply or divide operation that can be replaced with shift operation */ |
| shift_operation(*ast_module); |
| |
| return 1; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: optimize_for_tree) |
| * simplify the FOR loop syntax tree |
| * TODO fix this.. leaking memmory |
| *-------------------------------------------------------------------------*/ |
| void optimize_for_tree() |
| { |
| // find out the most unique_count prepared for new AST nodes |
| for (long i = 0; i < num_modules; i++) |
| if (count_id < ast_modules[i]->unique_count) |
| count_id = ast_modules[i]->unique_count; |
| |
| /* we will find the top module */ |
| for (long i = 0; i < num_modules; i++) |
| { |
| std::vector<ast_node_t *> list_for_node; |
| std::vector<ast_node_t *> list_parent; |
| /* search the tree looking for FOR node */ |
| search_for_node(ast_modules[i], list_for_node, list_parent); |
| |
| /* simplify every FOR node */ |
| for (long j = 0; j < list_for_node.size() ; j++) |
| { |
| |
| long v_value = list_for_node[j]->children[0]->children[1]->types.number.value; |
| long terminal = list_for_node[j]->children[1]->children[1]->types.number.value; |
| std::vector<std::string> expression; |
| std::vector<std::string> node_write; |
| |
| ast_node_t *temp_parent_node = (ast_node_t*)vtr::malloc(sizeof(ast_node_t)); //used to connect copied branches from the for loop |
| count_write = 0; |
| count = 0; |
| bool found = FALSE; |
| record_expression(list_for_node[j]->children[2], expression, &found); |
| mark_node_write(list_for_node[j]->children[3], node_write); |
| mark_node_read(list_for_node[j]->children[3], node_write); |
| |
| while(v_value < terminal) |
| { |
| add_child_to_node(temp_parent_node, |
| get_copy_tree((list_for_node[j])->children[3], |
| v_value, |
| (std::string )list_for_node[j]->children[0]->children[0]->types.identifier |
| ) |
| ); |
| |
| std::vector<std::string> infix_exp; |
| std::vector<std::string> postfix_exp; |
| |
| for (long k = 0; expression[k].size() ; k++) |
| { |
| if (expression[k] == (std::string)list_for_node[j]->children[0]->children[0]->types.identifier){ |
| std::string valued_at; |
| valued_at = v_value; |
| infix_exp.push_back(valued_at); |
| }else{ |
| infix_exp.push_back(expression[k]); |
| } |
| } |
| |
| translate_expression(infix_exp, postfix_exp); |
| v_value = calculation(postfix_exp); |
| } |
| if (has_intermediate_variable(temp_parent_node)) //there are intermediate variables involved in operations so remove the last branch from the node |
| remove_intermediate_variable(temp_parent_node, node_write, v_value, (std::string) list_for_node[j]->children[0]->children[0]->types.identifier); |
| |
| //the index of the FOR node belonging to its parent node may change after every for loop support iteration, so it needs to be checked again |
| int idx; |
| for (idx = list_parent[j]->num_children ; idx >= 0 ; idx--) |
| if (list_parent[j]->children[i] == list_for_node[j]) |
| break; |
| |
| keep_all_branch(temp_parent_node, list_parent[j], idx); |
| reallocate_node(list_parent[j], idx); |
| vtr::free(temp_parent_node); |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: search_for_node) |
| * search the tree looking for FOR node |
| *-------------------------------------------------------------------------*/ |
| void search_for_node(ast_node_t *root, std::vector<ast_node_t *> list_for_node, std::vector<ast_node_t *> list_parent) |
| { |
| for(long i = 0; root && i < root->num_children; i++) |
| search_for_node(root->children[i], list_for_node, list_parent); |
| |
| for (long j = 0; root && j < root->num_children; j++) |
| { |
| if (root->children[j] && root->children[j]->type == FOR) |
| { |
| list_for_node.push_back(root->children[j]); |
| list_parent.push_back(root); |
| } |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: get_copy_tree) |
| *-------------------------------------------------------------------------*/ |
| ast_node_t *get_copy_tree(ast_node_t *node, long virtual_value, std::string virtual_name) |
| { |
| if (!node) |
| return NULL; |
| |
| ast_node_t *new_node = (ast_node_t *)vtr::malloc(sizeof(ast_node_t)); |
| memcpy(new_node, node, sizeof(ast_node_t)); |
| //Copy contents |
| new_node->types.identifier = vtr::strdup(node->types.identifier); |
| new_node->types.number.number = vtr::strdup(node->types.number.number); |
| new_node->types.number.binary_string = vtr::strdup(node->types.number.binary_string); |
| |
| new_node->unique_count = ++count_id; |
| |
| if (node->type == IDENTIFIERS && (std::string) node->types.identifier == virtual_name) |
| change_to_number_node(new_node, virtual_value); |
| |
| new_node->children = (ast_node_t**)vtr::malloc(node->num_children*sizeof(ast_node_t*)); |
| for(long i=0; i<node->num_children; i++){ |
| new_node->children[i] = get_copy_tree(node->children[i],virtual_value,virtual_name); |
| } |
| return new_node; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: expression) |
| * in order traversal |
| *-------------------------------------------------------------------------*/ |
| void record_expression(ast_node_t *node, std::vector<std::string> expressions, bool *found_statement) |
| { |
| if (node){ |
| |
| if(node->num_children > 0) |
| record_expression(node->children[0], expressions, found_statement); |
| |
| if(!(*found_statement) && (node->type == NON_BLOCKING_STATEMENT || node->type == BLOCKING_STATEMENT)){ |
| *found_statement = TRUE; |
| |
| }else if(*found_statement){ |
| switch(node->type) |
| { |
| case IDENTIFIERS: |
| expressions.push_back(node->types.identifier); |
| break; |
| |
| case NUMBERS: |
| expressions.push_back(node->types.number.number); |
| break; |
| |
| case BINARY_OPERATION: |
| switch(node->types.operation.op) |
| { |
| case ADD: |
| expressions.push_back("+"); |
| break; |
| case MINUS: |
| expressions.push_back("-"); |
| break; |
| case MULTIPLY: |
| expressions.push_back("*"); |
| break; |
| case DIVIDE: |
| expressions.push_back("/"); |
| break; |
| |
| default: |
| break; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if(node->num_children > 1) |
| record_expression(node->children[1], expressions, found_statement); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: calculate) |
| *-------------------------------------------------------------------------*/ |
| long calculation(std::vector<std::string> post_exp) |
| { |
| std::stack<long> stacked; |
| for (long i = 0; i< post_exp.size(); i++) |
| { |
| long second_exp(stacked.top()); |
| stacked.pop(); |
| |
| long first_exp(stacked.top()); |
| stacked.pop(); |
| |
| if (post_exp[i] == "+"){ |
| stacked.push(first_exp + second_exp); |
| |
| }else if (post_exp[i] == "-"){ |
| stacked.push(first_exp - second_exp); |
| |
| }else if (post_exp[i] == "*"){ |
| stacked.push(first_exp * second_exp); |
| |
| }else if (post_exp[i] == "/"){ |
| stacked.push(first_exp / second_exp); |
| |
| }else{ |
| stacked.push(first_exp); |
| stacked.push(second_exp); |
| stacked.push(std::strtoll(post_exp[i].c_str(),NULL,10)); |
| } |
| } |
| return stacked.top(); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: translate_expression) |
| * translate infix expression into postfix expression |
| *-------------------------------------------------------------------------*/ |
| void translate_expression(std::vector<std::string> infix_exp, std::vector<std::string> postfix_exp) |
| { |
| std::stack<std::string> stacked; |
| for (long i = 0; i < infix_exp.size() ; i++) |
| { |
| if(infix_exp[i] == "+" || infix_exp[i] == "-" || infix_exp[i] == "*" || infix_exp[i] == "/" ){ |
| if ( (infix_exp[i] == "+" || infix_exp[i] == "-") && |
| !stacked.empty() && |
| ( stacked.top() == "*" || stacked.top() == "/" ) ) |
| { |
| while (!stacked.empty()){ |
| postfix_exp.push_back(stacked.top()); |
| stacked.pop(); |
| } |
| } |
| stacked.push(infix_exp[i]); |
| }else{// number |
| postfix_exp.push_back(infix_exp[i]); |
| } |
| } |
| while (!stacked.empty()){ |
| postfix_exp.push_back(stacked.top()); |
| stacked.pop(); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: reallocate_node) |
| *-------------------------------------------------------------------------*/ |
| void reallocate_node(ast_node_t *node, int idx) |
| { |
| node->children[idx] = free_whole_tree(node->children[idx]); |
| |
| for (long i = idx; i < node->num_children; i++) |
| node->children[i] = node->children[i+1]; |
| |
| node->num_children = node->num_children - 1; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: find_most_unique_count) |
| *-------------------------------------------------------------------------*/ |
| void find_most_unique_count() |
| { |
| for (long i = 0; i < num_modules; i++) |
| if (count_id < ast_modules[i]->unique_count) |
| count_id = ast_modules[i]->unique_count; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: mark_node_write) |
| * mark the node that is write |
| *-------------------------------------------------------------------------*/ |
| void mark_node_write(ast_node_t *node, std::vector<std::string> list) |
| { |
| if (node && ( node->type == BLOCKING_STATEMENT || node->type == NON_BLOCKING_STATEMENT ) && node->children[0]->type == IDENTIFIERS){ |
| node->children[0]->is_read_write = 2; |
| list.push_back(node->children[0]->types.identifier); |
| } |
| |
| for (long i = 0; node && i < node->num_children; i++) |
| mark_node_write(node->children[i], list); |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: mark_node_read) |
| * mark the node that is read |
| *-------------------------------------------------------------------------*/ |
| void mark_node_read(ast_node_t *node, std::vector<std::string> list) |
| { |
| for (long i = 0; node && node->type == IDENTIFIERS && i < list.size() ; i++) |
| if ((std::string)node->types.identifier == list[i] && node->is_read_write != 2) |
| node->is_read_write = 1; |
| |
| for (long j = 0; node && j < node->num_children; j++) |
| mark_node_read(node->children[j], list); |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: remove_intermediate_variable) |
| * remove the intermediate variables, and prune the syntax tree of FOR loop |
| *-------------------------------------------------------------------------*/ |
| void remove_intermediate_variable(ast_node_t *node, std::vector<std::string> list, long virtual_value, std::string virtual_name) |
| { |
| long k = 0; |
| |
| for (long i = 0; i < node->num_children-1; i++) |
| { |
| for (long j = 0; j < count_write; j++) |
| { |
| ast_node_t *write = search_marked_node(node->children[i], 2, list[j]); //search for "write" nodes |
| ast_node_t *read = search_marked_node(node->children[i+1], 1, list[j]); // search for "read" nodes |
| for (long n = 0; n < read->num_children; n++){ |
| if (read->children[n]->is_read_write == 1) |
| { |
| free_single_node(read->children[n]); |
| read->children[n] = get_copy_tree(write->children[1],virtual_value,virtual_name); |
| } |
| } |
| } |
| |
| node->children[i] = free_whole_tree(node->children[i]); |
| } |
| |
| for (long i = 0; i < node->num_children; i++) |
| if (node->children[i]) |
| node->children[k++] = node->children[i]; |
| |
| for (long i = k; i < node->num_children; i++) |
| node->children[i] = NULL; |
| |
| node->num_children = k; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: search_marked_node) |
| * search the marked nodes as requirement |
| *-------------------------------------------------------------------------*/ |
| ast_node_t *search_marked_node(ast_node_t *node, int is, std::string temp) |
| { |
| for (long i = 0; node && i < node->num_children; i++) |
| { |
| if(node->children[i]->type == IDENTIFIERS && (std::string)node->children[0]->types.identifier == temp && node->children[0]->is_read_write == is) |
| return node; |
| |
| ast_node_t *to_return = search_marked_node(node->children[i], is, temp); |
| if(to_return){ |
| return to_return; |
| } |
| } |
| return NULL; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: reduce_assignment_expression) |
| * reduce the number nodes which can be calculated to optimize the AST |
| *-------------------------------------------------------------------------*/ |
| void reduce_assignment_expression(ast_node_t *ast_module) |
| { |
| head = NULL; |
| p = NULL; |
| ast_node_t *T = NULL; |
| |
| |
| // find out most unique_count prepared for new AST nodes |
| //for (long i = 0; i < num_modules; i++) |
| |
| if (count_id < ast_module->unique_count) |
| count_id = ast_module->unique_count; |
| |
| count_assign = 0; |
| std::vector<ast_node_t *> list_assign; |
| find_assign_node(ast_module, list_assign); |
| for (long j = 0; j < count_assign; j++) |
| { |
| if (check_tree_operation(list_assign[j]->children[1]) && (list_assign[j]->children[1]->num_children > 0)) |
| { |
| store_exp_list(list_assign[j]->children[1]); |
| if (deal_with_bracket(list_assign[j]->children[1])) // there are multiple brackets multiplying -- ()*(), stop expanding brackets which may not simplify AST but make it mroe complex |
| return; |
| |
| if (simplify_expression()) |
| { |
| enode *tail = find_tail(head); |
| free_whole_tree(list_assign[j]->children[1]); |
| T = (ast_node_t*)vtr::malloc(sizeof(ast_node_t)); |
| construct_new_tree(tail, T, list_assign[j]->line_number, list_assign[j]->file_number); |
| list_assign[j]->children[1] = T; |
| } |
| free_exp_list(); |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: search_assign_node) |
| * find the top of the assignment expression |
| *-------------------------------------------------------------------------*/ |
| void find_assign_node(ast_node_t *node, std::vector<ast_node_t *> list) |
| { |
| if (node && node->num_children>0 && (node->type == BLOCKING_STATEMENT || node->type == NON_BLOCKING_STATEMENT)) |
| list.push_back(node); |
| |
| for (long i = 0; node && i < node->num_children; i++) |
| find_assign_node(node->children[i], list); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: simplify_expression) |
| * simplify the expression stored in the linked_list |
| *-------------------------------------------------------------------------*/ |
| bool simplify_expression() |
| { |
| bool build = adjoin_constant(); |
| reduce_enode_list(); |
| |
| if(delete_continuous_multiply()) |
| build = TRUE; |
| |
| if(combine_constant()) |
| build = TRUE; |
| |
| reduce_enode_list(); |
| return build; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: find_tail) |
| *-------------------------------------------------------------------------*/ |
| enode *find_tail(enode *node) |
| { |
| enode *temp; |
| enode *tail = NULL; |
| for (temp = node; temp != NULL; temp = temp->next) |
| if (temp->next == NULL) |
| tail = temp; |
| |
| return tail; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: reduce_enode_list) |
| *-------------------------------------------------------------------------*/ |
| void reduce_enode_list() |
| { |
| enode *temp; |
| int a; |
| |
| while(head != NULL && (head->type.data == 0) && (head->next->priority == 2) && (head->next->type.operation == '+')){ |
| temp=head; |
| head = head->next->next; |
| head->pre = NULL; |
| |
| vtr::free(temp->next); |
| vtr::free(temp); |
| } |
| |
| if(head == NULL){ |
| return; |
| } |
| |
| temp = head->next; |
| while (temp != NULL) |
| { |
| if ((temp->flag == 1) && (temp->pre->priority == 2)) |
| { |
| if (temp->type.data == 0) |
| { |
| if (temp->next == NULL) |
| temp->pre->pre->next = NULL; |
| else |
| { |
| temp->pre->pre->next = temp->next; |
| temp->next->pre = temp->pre->pre; |
| } |
| vtr::free(temp->pre); |
| |
| enode *toBeDeleted = temp; |
| temp = temp->next; |
| vtr::free(toBeDeleted); |
| } else if (temp->type.data < 0) |
| { |
| if (temp->pre->type.operation == '+') |
| temp->pre->type.operation = '-'; |
| else |
| temp->pre->type.operation = '+'; |
| a = temp->type.data; |
| temp->type.data = -a; |
| |
| temp = temp->next; |
| } else { |
| temp = temp->next; |
| } |
| } else { |
| temp = temp->next; |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: store_exp_list) |
| *-------------------------------------------------------------------------*/ |
| void store_exp_list(ast_node_t *node) |
| { |
| enode *temp; |
| head = (enode*)vtr::malloc(sizeof(enode)); |
| p = head; |
| record_tree_info(node); |
| temp = head; |
| head = head->next; |
| head->pre = NULL; |
| p->next = NULL; |
| vtr::free(temp); |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: record_tree_info) |
| *-------------------------------------------------------------------------*/ |
| void record_tree_info(ast_node_t *node) |
| { |
| if (node){ |
| if (node->num_children > 0) |
| { |
| record_tree_info(node->children[0]); |
| create_enode(node); |
| if (node->num_children > 1) |
| record_tree_info(node->children[1]); |
| }else{ |
| create_enode(node); |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: create_enode) |
| * store elements of an expression in nodes consisting the linked_list |
| *-------------------------------------------------------------------------*/ |
| void create_enode(ast_node_t *node) |
| { |
| enode *s; |
| s = (enode*)vtr::malloc(sizeof(enode)); |
| s->flag = -1; |
| s->priority = -1; |
| s->id = node->unique_count; |
| switch (node->type) |
| { |
| case NUMBERS: |
| s->type.data = node->types.number.value; |
| s->flag = 1; |
| s->priority = 0; |
| break; |
| |
| case IDENTIFIERS: |
| s->type.variable = node->types.identifier; |
| s->flag = 3; |
| s->priority = 0; |
| break; |
| |
| case BINARY_OPERATION: |
| { |
| switch(node->types.operation.op) |
| { |
| case ADD: |
| s->type.operation = '+'; |
| s->flag = 2; |
| s->priority = 2; |
| break; |
| |
| case MINUS: |
| s->type.operation = '-'; |
| s->flag =2; |
| s->priority = 2; |
| break; |
| |
| case MULTIPLY: |
| s->type.operation = '*'; |
| s->flag = 2; |
| s->priority = 1; |
| break; |
| |
| case DIVIDE: |
| s->type.operation = '/'; |
| s->flag = 2; |
| s->priority = 1; |
| break; |
| |
| default: |
| break; |
| } |
| |
| default: |
| break; |
| } |
| |
| |
| } |
| |
| p->next = s; |
| s->pre = p; |
| p = s; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: adjoin_constant) |
| * compute the constant numbers in the linked_list |
| *-------------------------------------------------------------------------*/ |
| bool adjoin_constant() |
| { |
| bool build = FALSE; |
| enode *t, *replace; |
| int a, b, result = 0; |
| int mark; |
| for (t = head; t->next!= NULL; ) |
| { |
| mark = 0; |
| if ((t->flag == 1) && (t->next->next != NULL) && (t->next->next->flag ==1)) |
| { |
| switch (t->next->priority) |
| { |
| case 1: |
| a = t->type.data; |
| b = t->next->next->type.data; |
| if (t->next->type.operation == '*') |
| result = a * b; |
| else |
| result = a / b; |
| replace = replace_enode(result, t, 1); |
| build = TRUE; |
| mark = 1; |
| break; |
| |
| case 2: |
| if (((t == head) || (t->pre->priority == 2)) && ((t->next->next->next == NULL) ||(t->next->next->next->priority ==2))) |
| { |
| a = t->type.data; |
| b = t->next->next->type.data; |
| if (t->pre->type.operation == '+') |
| { |
| if (t->next->type.operation == '+') |
| result = a + b; |
| else |
| result = a - b; |
| } |
| if (t->pre->type.operation == '-') |
| { |
| if (t->next->type.operation == '+') |
| result = a - b; |
| else |
| result = a + b; |
| } |
| |
| replace = replace_enode(result, t, 1); |
| build = TRUE; |
| mark = 1; |
| } |
| break; |
| default: |
| //pass |
| break; |
| } |
| } |
| if (mark == 0) |
| t = t->next; |
| else |
| if (mark == 1) |
| t = replace; |
| |
| } |
| return build; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: replace_enode) |
| *-------------------------------------------------------------------------*/ |
| enode *replace_enode(int data, enode *t, int mark) |
| { |
| enode *replace; |
| replace = (enode*)vtr::malloc(sizeof(enode)); |
| replace->type.data = data; |
| replace->flag = 1; |
| replace->priority = 0; |
| |
| if (t == head) |
| { |
| replace->pre = NULL; |
| head = replace; |
| } |
| |
| else |
| { |
| replace->pre = t->pre; |
| t->pre->next = replace; |
| } |
| |
| if (mark == 1) |
| { |
| replace->next = t->next->next->next; |
| if (t->next->next->next == NULL) |
| replace->next = NULL; |
| else |
| t->next->next->next->pre = replace; |
| vtr::free(t->next->next); |
| vtr::free(t->next); |
| } |
| else |
| { |
| replace->next = t->next; |
| t->next->pre = replace; |
| } |
| |
| vtr::free(t); |
| return replace; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: combine_constant) |
| *-------------------------------------------------------------------------*/ |
| bool combine_constant() |
| { |
| enode *temp, *m, *s1, *s2, *replace; |
| int a, b, result; |
| int mark; |
| bool build = FALSE; |
| |
| for (temp = head; temp != NULL; ) |
| { |
| mark = 0; |
| if ((temp->flag == 1) && (temp->next != NULL) && (temp->next->priority == 2)) |
| { |
| if ((temp == head) || (temp->pre->priority == 2)) |
| { |
| for (m = temp->next; m != NULL; m = m->next) |
| { |
| if((m->flag == 1) && (m->pre->priority == 2) && ((m->next == NULL) || (m->next->priority == 2))) |
| { |
| s1 = temp; |
| s2 = m; |
| a = s1->type.data; |
| b = s2->type.data; |
| if ((s1 == head) || (s1->pre->type.operation == '+')) |
| { |
| if (s2->pre->type.operation == '+') |
| result = a + b; |
| else |
| result = a - b; |
| } |
| else |
| { |
| if (s2->pre->type.operation == '+') |
| result = a - b; |
| else |
| result = a + b; |
| } |
| replace = replace_enode(result, s1, 2); |
| if (s2->next == NULL) |
| { |
| s2->pre->pre->next = NULL; |
| mark = 2; |
| } |
| else |
| { |
| s2->pre->pre->next = s2->next; |
| s2->next->pre = s2->pre->pre; |
| } |
| |
| vtr::free(s2->pre); |
| vtr::free(s2); |
| if (replace == head) |
| { |
| temp = replace; |
| mark = 1; |
| } |
| else |
| temp = replace->pre; |
| build = TRUE; |
| |
| break; |
| } |
| } |
| } |
| } |
| if (mark == 0) |
| temp = temp->next; |
| else |
| if (mark == 1) |
| continue; |
| else |
| break; |
| } |
| return build; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: construct_new_tree) |
| *-------------------------------------------------------------------------*/ |
| void construct_new_tree(enode *tail, ast_node_t *node, int line_num, int file_num) |
| { |
| enode *temp, *tail1 = NULL, *tail2 = NULL; |
| int prio = 0; |
| |
| if (tail == NULL) |
| return; |
| |
| prio = check_exp_list(tail); |
| if (prio == 1) |
| { |
| for (temp = tail; temp != NULL; temp = temp->pre) |
| if ((temp->flag == 2) && (temp->priority == 2)) |
| { |
| create_ast_node(temp, node, line_num, file_num); |
| tail1 = temp->pre; |
| tail2 = find_tail(temp->next); |
| tail1->next = NULL; |
| temp->next->pre = NULL; |
| break; |
| } |
| |
| } |
| else |
| if(prio == 2) |
| { |
| for (temp = tail; temp != NULL; temp = temp->pre) |
| if ((temp->flag ==2) && (temp->priority == 1)) |
| { |
| create_ast_node(temp, node, line_num, file_num); |
| tail1 = temp->pre; |
| tail2 = temp->next; |
| tail2->pre = NULL; |
| tail2->next = NULL; |
| break; |
| } |
| } |
| else |
| if (prio == 3) |
| create_ast_node(tail, node, line_num, file_num); |
| |
| if (prio == 1 || prio == 2) |
| { |
| node->children = (ast_node_t**)vtr::malloc(2*sizeof(ast_node_t*)); |
| node->children[0] = (ast_node_t*)vtr::malloc(sizeof(ast_node_t)); |
| node->children[1] = (ast_node_t*)vtr::malloc(sizeof(ast_node_t)); |
| construct_new_tree(tail1, node->children[0], line_num, file_num); |
| construct_new_tree(tail2, node->children[1], line_num, file_num); |
| } |
| |
| return; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: check_exp_list) |
| *-------------------------------------------------------------------------*/ |
| int check_exp_list(enode *tail) |
| { |
| enode *temp; |
| for (temp = tail; temp != NULL; temp = temp->pre) |
| if ((temp->flag == 2) && (temp->priority == 2)) |
| return 1; |
| |
| for (temp = tail; temp != NULL; temp = temp->pre) |
| if ((temp->flag == 2) && (temp->priority ==1)) |
| return 2; |
| |
| return 3; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: delete_continuous_multiply) |
| *-------------------------------------------------------------------------*/ |
| bool delete_continuous_multiply() |
| { |
| enode *temp, *t, *m, *replace; |
| bool build = FALSE; |
| int a, b, result; |
| int mark; |
| for (temp = head; temp != NULL; ) |
| { |
| mark = 0; |
| if ((temp->flag == 1) && (temp->next != NULL) && (temp->next->priority == 1)) |
| { |
| for (t = temp->next; t != NULL; t = t->next) |
| { |
| if ((t->flag == 1) && (t->pre->priority ==1)) |
| { |
| for (m = temp->next; m != t; m = m->next) |
| { |
| if ((m->flag == 2) && (m->priority != 1)) |
| { |
| mark = 1; |
| break; |
| } |
| |
| } |
| if (mark == 0) |
| { |
| a = temp->type.data; |
| b = t->type.data; |
| if (t->pre->type.operation == '*') |
| result = a * b; |
| else |
| result = a / b; |
| replace = replace_enode(result, temp, 3); |
| if (t->next == NULL) |
| t->pre->pre->next = NULL; |
| else |
| { |
| t->pre->pre->next = t->next; |
| t->next->pre = t->pre->pre; |
| } |
| mark = 2; |
| build = TRUE; |
| vtr::free(t->pre); |
| vtr::free(t); |
| break; |
| } |
| break; |
| } |
| } |
| } |
| if ((mark == 0) || (mark == 1)) |
| temp = temp->next; |
| else |
| if (mark == 2) |
| temp = replace; |
| |
| } |
| return build; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: create_ast_node) |
| *-------------------------------------------------------------------------*/ |
| void create_ast_node(enode *temp, ast_node_t *node, int line_num, int file_num) |
| { |
| switch(temp->flag) |
| { |
| case 1: |
| initial_node(node, NUMBERS, line_num, file_num, ++count_id); |
| change_to_number_node(node, temp->type.data); |
| break; |
| |
| case 2: |
| create_op_node(node, temp, line_num, file_num); |
| break; |
| |
| case 3: |
| initial_node(node, IDENTIFIERS, line_num, file_num, ++count_id); |
| node->types.identifier = vtr::strdup(temp->type.variable.c_str()); |
| break; |
| |
| default: |
| break; |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: create_op_node) |
| *-------------------------------------------------------------------------*/ |
| void create_op_node(ast_node_t *node, enode *temp, int line_num, int file_num) |
| { |
| initial_node(node, BINARY_OPERATION, line_num, file_num, ++count_id); |
| node->num_children = 2; |
| switch(temp->type.operation) |
| { |
| case '+': |
| node->types.operation.op = ADD; |
| break; |
| |
| case '-': |
| node->types.operation.op = MINUS; |
| break; |
| |
| case '*': |
| node->types.operation.op = MULTIPLY; |
| break; |
| |
| case '/': |
| node->types.operation.op = DIVIDE; |
| break; |
| default: |
| oassert(FALSE); |
| break; |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: free_exp_list) |
| *-------------------------------------------------------------------------*/ |
| void free_exp_list() |
| { |
| enode *next, *temp; |
| for (temp = head; temp != NULL; temp = next) |
| { |
| next = temp->next; |
| vtr::free(temp); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: deal_with_bracket) |
| *-------------------------------------------------------------------------*/ |
| bool deal_with_bracket(ast_node_t *node) |
| { |
| std::vector<int> list_bracket; |
| |
| recursive_tree(node, list_bracket); |
| if (!check_mult_bracket(list_bracket)) //if there are brackets multiplying continuously ()*(), stop expanding brackets which may not simplify AST but make it mroe complex |
| { |
| for (int i = list_bracket.size()-2; i >= 0; i = i - 2) |
| delete_bracket(list_bracket[i], list_bracket[i+1]); |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: check_mult_bracket) |
| * check if the brackets are continuously multiplying |
| *-------------------------------------------------------------------------*/ |
| bool check_mult_bracket(std::vector<int> list) |
| { |
| for (long i = 1; i < list.size() - 2; i = i + 2) |
| { |
| enode *node = head; |
| while (node != NULL && node->next != NULL && node->next->next != NULL) |
| { |
| if (node->id == list[i] && node->next->next->id == list[i+1] && |
| node->next->flag == 2 && |
| (node->next->type.operation == '*' || node->next->type.operation == '/')) |
| |
| return TRUE; |
| |
| node = node->next; |
| } |
| } |
| return FALSE; |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: recursive_tree) |
| * search the AST recursively to find brackets |
| *-------------------------------------------------------------------------*/ |
| void recursive_tree(ast_node_t *node, std::vector<int> list_bracket) |
| { |
| if (node && (node->type == BINARY_OPERATION) && (node->types.operation.op == MULTIPLY)) |
| { |
| for (long i = 0; i < node->num_children; i++) |
| { |
| if ((node->children[i]->type == BINARY_OPERATION) && (node->children[i]->types.operation.op == ADD || node->children[i]->types.operation.op == MINUS)) |
| { |
| find_leaf_node(node->children[i], list_bracket, 0); |
| find_leaf_node(node->children[i], list_bracket, 1); |
| } |
| } |
| |
| } |
| |
| for (long i = 0; node && i < node->num_children; i++) |
| recursive_tree(node->children[i], list_bracket); |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: find_lead_node) |
| *-------------------------------------------------------------------------*/ |
| void find_leaf_node(ast_node_t *node, std::vector<int> list_bracket, int ids2) |
| { |
| if (node){ |
| if (node->num_children > 0){ |
| find_leaf_node(node->children[ids2], list_bracket, ids2); |
| }else{ |
| list_bracket.push_back(node->unique_count); |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: delete_bracket) |
| *-------------------------------------------------------------------------*/ |
| void delete_bracket(int begin, int end) |
| { |
| enode *s1 = NULL, *s2 = NULL, *temp, *p2; |
| int mark = 0; |
| for (temp = head; temp != NULL; temp = temp->next) |
| { |
| if (temp->id == begin) |
| { |
| s1 = temp; |
| for (p2 = temp; p2 != NULL; p2 = p2->next) |
| if (p2->id == end) |
| { |
| s2 = p2; |
| mark = 1; |
| break; |
| } |
| } |
| if (mark == 1) |
| break; |
| } |
| |
| if (s1 == head) |
| delete_bracket_head(s1, s2); |
| else |
| if (s2->next == NULL) |
| delete_bracket_tail(s1, s2); |
| else |
| delete_bracket_body(s1, s2); |
| if (s1 != head) |
| check_operation(s1, s2); |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: delete_bracket_head) |
| *-------------------------------------------------------------------------*/ |
| void delete_bracket_head(enode *begin, enode *end) |
| { |
| enode *temp; |
| enode *s = NULL; |
| for (temp = end; temp != NULL; temp = temp->next) |
| { |
| if ((temp->flag == 2) && (temp->priority == 2)) |
| { |
| s = temp->pre; |
| break; |
| } |
| if (temp->next == NULL) |
| s = temp; |
| } |
| change_exp_list(begin, end, s, 1); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_exp_list) |
| *-------------------------------------------------------------------------*/ |
| void change_exp_list(enode *begin, enode *end, enode *s, int flag) |
| { |
| enode *temp, *new_head, *tail, *p2, *partial = NULL, *start = NULL; |
| int mark; |
| switch (flag) |
| { |
| case 1: |
| { |
| for (temp = begin; temp != end; temp = p2->next) |
| { |
| mark = 0; |
| for (p2 = temp; p2 != end->next; p2 = p2->next) |
| { |
| if (p2 == end) |
| { |
| mark = 2; |
| break; |
| } |
| if ((p2->flag == 2) && (p2->priority == 2)) |
| { |
| partial = p2->pre; |
| mark = 1; |
| break; |
| } |
| } |
| if (mark == 1) |
| { |
| new_head = (enode*)vtr::malloc(sizeof(enode)); |
| tail = copy_enode_list(new_head, end->next, s); |
| tail = tail->pre; |
| vtr::free(tail->next); |
| partial->next = new_head; |
| new_head->pre = partial; |
| tail->next = p2; |
| p2->pre = tail; |
| } |
| if (mark == 2) |
| break; |
| } |
| break; |
| } |
| |
| case 2: |
| { |
| for (temp = begin; temp != end->next; temp = temp->next) |
| if ((temp->flag == 2) && (temp->priority == 2)) |
| { |
| start = temp; |
| break; |
| } |
| for (temp = start; temp != end->next; temp = partial->next) |
| { |
| mark = 0; |
| for (p2 = temp; p2 != end->next; p2 = p2->next) |
| { |
| if (p2 == end) |
| { |
| mark = 2; |
| break; |
| } |
| if ((p2->flag == 2) && (p2->priority == 2)) |
| { |
| partial = p2->next; |
| mark = 1; |
| break; |
| } |
| } |
| if (mark == 1) |
| { |
| new_head = (enode*)vtr::malloc(sizeof(enode)); |
| tail = copy_enode_list(new_head, s, begin->pre); |
| tail = tail->pre; |
| vtr::free(tail->next); |
| p2->next = new_head; |
| new_head->pre = p2; |
| tail->next = partial; |
| partial->pre = tail; |
| |
| } |
| if (mark == 2) |
| break; |
| } |
| break; |
| } |
| default: |
| break; |
| |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: copy_enode_list) |
| *-------------------------------------------------------------------------*/ |
| enode *copy_enode_list(enode *new_head, enode *begin, enode *end) |
| { |
| enode *temp, *new_enode, *next_enode; |
| new_enode = new_head; |
| for (temp = begin; temp != end->next; temp = temp->next) |
| { |
| copy_enode(temp, new_enode); |
| next_enode = (enode*)vtr::malloc(sizeof(enode)); |
| new_enode->next = next_enode; |
| next_enode->pre = new_enode; |
| new_enode = next_enode; |
| } |
| |
| return new_enode; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: copy_enode) |
| *-------------------------------------------------------------------------*/ |
| void copy_enode(enode *node, enode *new_node) |
| { |
| new_node->type = node->type; |
| new_node->flag = node->flag; |
| new_node->priority = node->priority; |
| new_node->id = -1; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: deleted_bracket_tail) |
| *-------------------------------------------------------------------------*/ |
| void delete_bracket_tail(enode *begin, enode *end) |
| { |
| enode *temp, *s = NULL; |
| for (temp = begin; temp != NULL; temp = temp->pre) |
| if ((temp->flag == 2) && (temp->priority == 2)) // '+' or '-' |
| { |
| s = temp->next; |
| break; |
| } |
| change_exp_list(begin, end, s, 2); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: delete_bracket_body) |
| *-------------------------------------------------------------------------*/ |
| void delete_bracket_body(enode *begin, enode *end) |
| { |
| enode *temp; |
| if ((begin->pre->priority == 1) && (end->next->priority == 2)) |
| delete_bracket_tail(begin, end); |
| if ((begin->pre->priority == 2) && (end->next->priority == 1)) |
| delete_bracket_head(begin, end); |
| if ((begin->pre->priority == 1) && (end->next->priority == 1)) |
| { |
| delete_bracket_tail(begin, end); |
| for (temp = begin; temp != NULL; temp = temp->pre) |
| if ((temp->flag == 2) && (temp->priority == 2)) |
| { |
| begin = temp->next; |
| break; |
| } |
| delete_bracket_head(begin, end); |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: check_tree_operation) |
| *-------------------------------------------------------------------------*/ |
| bool check_tree_operation(ast_node_t *node) |
| { |
| if (node && (node->type == BINARY_OPERATION) && ((node->types.operation.op == ADD ) || (node->types.operation.op == MINUS) || (node->types.operation.op == MULTIPLY))) |
| return TRUE; |
| |
| for (long i = 0; node && i < node->num_children; i++) |
| if(check_tree_operation(node->children[i])) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: check_operation) |
| *-------------------------------------------------------------------------*/ |
| void check_operation(enode *begin, enode *end) |
| { |
| enode *temp, *op; |
| for (temp = begin; temp != head; temp = temp->pre) |
| { |
| if (temp->flag == 2 && temp->priority == 2 && temp->type.operation == '-') |
| { |
| for (op = begin; op != end; op = op->next) |
| { |
| if (op->flag == 2 && op->priority == 2) |
| { |
| if (op->type.operation == '+') |
| op->type.operation = '-'; |
| else |
| op->type.operation = '+'; |
| } |
| } |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: reduce_parameter) |
| * replace parameters with their values in the AST |
| *-------------------------------------------------------------------------*/ |
| void reduce_parameter(ast_node_t *ast_module) |
| { |
| std::vector<ast_node_t *>para; |
| find_parameter(ast_module, para); |
| if (ast_module->types.module.is_instantiated == 0 && !para.empty()) |
| remove_para_node(ast_module, para); |
| |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: find_parameter) |
| *-------------------------------------------------------------------------*/ |
| void find_parameter(ast_node_t *node, std::vector<ast_node_t *>para) |
| { |
| for (long i = 0; node && i < node->num_children; i++) |
| { |
| if (node->children[i] && node->children[i]->type == VAR_DECLARE && node->children[i]->types.variable.is_parameter == 1) |
| para.push_back(node->children[i]); |
| |
| find_parameter(node->children[i], para); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: remove_para_node) |
| *-------------------------------------------------------------------------*/ |
| void remove_para_node(ast_node_t *top, std::vector<ast_node_t *> para) |
| { |
| std::vector<ast_node_t *> list; |
| |
| count_assign = 0; |
| find_assign_node(top, list); |
| if (count_assign!= 0){ |
| for (long i = 0; i < para.size(); i++) |
| { |
| std::string name; |
| long value = 0; |
| if (para[i] && para[i]->children[0]) |
| name = para[i]->children[0]->types.identifier; |
| |
| if (node_is_constant(para[i]->children[5])) |
| value = para[i]->children[5]->types.number.value; |
| |
| for (long j = 0; j < count_assign; j++){ |
| change_para_node(list[j], name, value); |
| } |
| |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_para_node) |
| *-------------------------------------------------------------------------*/ |
| void change_para_node(ast_node_t *node, std::string name, long value) |
| { |
| if (node && node->type == IDENTIFIERS && name == (std::string) node->types.identifier) |
| change_to_number_node(node, value); |
| |
| for (long i = 0; node && i < node->num_children; i++) |
| change_para_node(node->children[i], name, value); |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: copy_tree) |
| * find multiply or divide operation that can be replaced with shift operation |
| *-------------------------------------------------------------------------*/ |
| void shift_operation(ast_node_t *ast_module) |
| { |
| if(ast_module){ |
| search_certain_operation(ast_module); |
| } |
| |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_ast_node) |
| * search all AST to find multiply or divide operations |
| *-------------------------------------------------------------------------*/ |
| void search_certain_operation(ast_node_t *node) |
| { |
| for (long i = 0; node && i < node->num_children; i++){ |
| check_binary_operation(node->children[i]); |
| search_certain_operation(node->children[i]); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_ast_node) |
| * check the children nodes of an operation node |
| *-------------------------------------------------------------------------*/ |
| void check_binary_operation(ast_node_t *node) |
| { |
| if(node && node->type == BINARY_OPERATION){ |
| switch(node->types.operation.op){ |
| case MULTIPLY: |
| if (node->children[0]->type == IDENTIFIERS && node->children[1]->type == NUMBERS) |
| check_node_number(node, node->children[1], 1); // 1 means multiply and don't need to move children nodes |
| if (node->children[0]->type == NUMBERS && node->children[1]->type == IDENTIFIERS) |
| check_node_number(node, node->children[0], 2); // 2 means multiply and needs to move children nodes |
| break; |
| case DIVIDE: |
| if (node->children[0]->type == IDENTIFIERS && node->children[1]->type == NUMBERS) |
| check_node_number(node, node->children[1], 3); // 3 means divide |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: change_ast_node) |
| * check if the number is the power of 2 |
| *-------------------------------------------------------------------------*/ |
| void check_node_number(ast_node_t *parent, ast_node_t *child, int flag) |
| { |
| long power = 0; |
| long number = child->types.number.value; |
| if (number <= 1) |
| return; |
| while (((number % 2) == 0) && number > 1) // While number is even and > 1 |
| { |
| number >>= 1; |
| power++; |
| } |
| if (number == 1) // the previous number is a power of 2 |
| { |
| change_to_number_node(child, power); |
| if (flag == 1) // multiply |
| parent->types.operation.op = SL; |
| else if (flag == 2) // multiply and needs to move children nodes |
| { |
| parent->types.operation.op = SL; |
| parent->children[0] = parent->children[1]; |
| parent->children[1] = child; |
| } |
| else if (flag == 3) // divide |
| parent->types.operation.op = SR; |
| } |
| } |
| |
| |
| /*--------------------------------------------------------------------------- |
| * (function: check_intermediate_variable) |
| * check if there are intermediate variables |
| *-------------------------------------------------------------------------*/ |
| short has_intermediate_variable(ast_node_t *node){ |
| if (node && (node->is_read_write == 1 || node->is_read_write == 2)) |
| return TRUE; |
| |
| for (long i = 0; node && i < node->num_children; i++){ |
| if(has_intermediate_variable(node->children[i])) |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: keep_all_branch) |
| * keep all the branches and allocate them to the parent node of the FOR node |
| TODO ########## POINTER DEREFERENCE!!! ############### |
| *-------------------------------------------------------------------------*/ |
| void keep_all_branch(ast_node_t *temp_node, ast_node_t *for_parent, int mark) |
| { |
| long index = mark; |
| for (long i = 0; i < temp_node->num_children; i++) |
| { |
| for_parent->children = (ast_node_t**)vtr::realloc(for_parent->children, sizeof(ast_node_t*)*(for_parent->num_children+1)); |
| for_parent->num_children ++; |
| if (temp_node->children[i]){ |
| for (long j = for_parent->num_children - 1; j > index; j--) |
| for_parent->children[j] = for_parent->children[j-1]; |
| |
| for_parent->children[++index] = temp_node->children[i]; |
| } |
| } |
| } |