int main ( int argc, char **argv ) { read_args ( argc, argv ); yyparse (); #ifdef DUMPTREES FILE *pre = fopen ( "pre.tree", "w" ), *post = fopen ( "post.tree", "w" ); print_node ( pre, root, 0 ); #endif root = simplify_tree ( root ); #ifdef DUMPTREES print_node ( post, root, 0 ); fclose ( pre ); fclose ( post ); #endif init_scopes ( 256 ); find_symbols ( root ); destroy_scopes (); destroy_subtree ( root ); exit ( EXIT_SUCCESS ); }
int main(int argc, char **argv) { options(argc, argv); yyparse(); #ifdef DUMP_TREES if ((DUMP_TREES & 1) != 0) node_print(stderr, root, 0); #endif simplify_tree(&root, root); #ifdef DUMP_TREES if ((DUMP_TREES & 2) != 0) node_print(stderr, root, 0); #endif /* Parsing and semantics are ok, redirect stdout to file (if requested) */ if (outfile != NULL) { if (freopen(outfile, "w", stdout) == NULL) { fprintf(stderr, "Could not open output file '%s'\n", outfile); exit(EXIT_FAILURE); } free(outfile); } destroy_subtree(root); exit(EXIT_SUCCESS); }
int main ( int argc, char **argv ) { yyparse(); simplify_tree ( &root, root ); // node_print(root, 0); find_globals(); size_t n_globals = tlhash_size(global_names); symbol_t *global_list[n_globals]; tlhash_values ( global_names, (void **)&global_list ); for ( size_t i=0; i<n_globals; i++ ) if ( global_list[i]->type == SYM_FUNCTION ) bind_names ( global_list[i], global_list[i]->node ); // print_globals(); generate_program (); destroy_subtree ( root ); destroy_symtab(); }
node_t* simplify_tree ( node_t* node ){ if ( node != NULL ){ // Recursively simplify the children of the current node for ( uint32_t i=0; i<node->n_children; i++ ){ node->children[i] = simplify_tree ( node->children[i] ); } // After the children have been simplified, we look at the current node // What we do depend upon the type of node switch ( node->type.index ){ // These are lists which needs to be flattened. Their structure // is the same, so they can be treated the same way. case FUNCTION_LIST: case STATEMENT_LIST: case PRINT_LIST: case EXPRESSION_LIST: case VARIABLE_LIST: if(node->n_children == 2){ node_t *current; current = node; node = current->children[0]; node->n_children++; node->children = (node_t**) realloc(node->children, node->n_children*sizeof(node_t*)); node->children[node->n_children-1] = current->children[1]; finalize_node(current); } break; // Declaration lists should also be flattened, but their stucture is sligthly // different, so they need their own case case DECLARATION_LIST: if(node->n_children == 2){ if(node->children[0] == NULL){ node_t *child; child = node->children[1]; free(node->children); node->children = (node_t**) malloc(sizeof(node_t*)); node->n_children--; node->children[0] = child; } else { //Else do the same as the case above... node_t *current; current = node; node = current->children[0]; node->n_children++; node->children = (node_t**) realloc(node->children, node->n_children*sizeof(node_t*)); node->children[node->n_children-1] = current->children[1]; finalize_node(current); } } break; // These have only one child, so they are not needed case STATEMENT: case PARAMETER_LIST: case ARGUMENT_LIST: if(node->n_children == 1){ node_t *current; current = node; node = current->children[0]; finalize_node(current); } break; // Expressions where both children are integers can be evaluated (and replaced with // integer nodes). Expressions whith just one child can be removed (like statements etc above) case EXPRESSION: //Mistenker at feilen avhenger av min forståelse av hvilke cases som skal dekkes/hvordan case'ene fungerer. //liker ikke at vi selv må finne ut av hvilke cases vi skal dekke når dette ikke er skrevet eksplisitt i oppgaveteksten (PDF'en). //Sliter med å finne ut hvilken av if-testene nedenfor som forårsaker feilen. Mistenker det har noe å gjøre med den //nederste, men klarer ikke å tenke ut hva som er feil med den, eller hva som faktisk går galt... if(node->n_children == 2 && node->children[0]->type.index == INTEGER && node->children[1]->type.index == INTEGER){ node_t *current = node; node = node->children[0]; if(strcmp(current->data, "+") == 0){ *((int*)node->data) = *((int*)node->data) + (*(int*)current->children[1]->data); } else if(strcmp(current->data, "-") == 0){ *((int*)node->data) = *((int*)node->data) - (*(int*)current->children[1]->data); } else if (strcmp(current->data, "*") == 0){ *((int*)node->data) = *((int*)node->data) * (*(int*)current->children[1]->data); } else if (strcmp(current->data, "/") == 0){ *((int*)node->data) = *((int*)node->data) / (*(int*)current->children[1]->data); } else if (strcmp(current->data, "==") == 0){ *((int*)node->data) = *((int*)node->data) == (*(int*)current->children[1]->data); } else if (strcmp(current->data, "!=") == 0){ *((int*)node->data) = *((int*)node->data) != (*(int*)current->children[1]->data); } else if (strcmp(current->data, "<=") == 0){ *((int*)node->data) = *((int*)node->data) <= (*(int*)current->children[1]->data); } else if (strcmp(current->data, ">=") == 0){ *((int*)node->data) = *((int*)node->data) >= (*(int*)current->children[1]->data); } else if (strcmp(current->data, "<") == 0){ *((int*)node->data) = *((int*)node->data) < (*(int*)current->children[1]->data); } else if (strcmp(current->data, ">") == 0){ *((int*)node->data) = *((int*)node->data) > (*(int*)current->children[1]->data); } finalize_node(current->children[1]); finalize_node(current); } else if (node->n_children == 1){ node_t *other = node; node = node->children[0]; if(other->data == NULL){ free(other); } else if(strcmp(other->data, "-") && node->children[0]->type.index == INTEGER){ *((int*)node->data) = *((int*)node->data) - 2*(*((int*)node->data)); node->type = other->type; finalize_node(other); } } break; } } return node; }
void simplify_tree ( node_t **simplified, node_t *root ) { node_t *result = root; /* * First, we ensure that we have a node to look at. This has the * convenient side-effect that optional elements in the syntax * remain marked by a NULL placeholder in the tree, keeping it simple * to recognize the structures imposed by the grammar. */ if ( root != NULL ) { /* Recur before treating any single node: depth-first traversal */ for ( uint32_t i=0; i<root->n_children; i++ ) simplify_tree ( &root->children[i], root->children[i] ); /* Here is where we do something to the lowest nodes in the tree */ switch ( root->type.index ) { /* * These types have only syntactic value, so we can throw * them out now: * STATEMENT always has one child, which can identify itself * PARAMETER_LIST only serves to make variable lists optional * in function declarations * ARGUMENT_LIST does the same thing for function calls */ case STATEMENT: case PRINT_ITEM: case PARAMETER_LIST: case ARGUMENT_LIST: result = root->children[0]; node_finalize ( root ); break; /* * Print statements always have exactly one PRINT_LIST child. * Since we are done with the recursive list definition, * its descendants may instead be children of the print statement * itself now. (Quick hack - it's easier to rename the list node * and eliminate the old statement than to copy/move all children.) */ case PRINT_STATEMENT: result = root->children[0]; result->type = root->type; node_finalize ( root ); break; /* * DECLARATION_LIST can be NULL altogether, but we preserved * that at the beginning of the function. This has a somewhat * nasty side-effect in the grammar, however, as it gets a * different structure from the other lists when it DOES exist * (such as here). Other lists have a single-element list with * the last list item at the bottom of the tree, whereas * declaration lists have a 2-element list with NULL and the * last item. The code that follows molds the bottom of a * declaration list into the same form as the other lists, so * the rest can be handled by the otherwise standard * list-flattening code. */ case DECLARATION_LIST: if ( root->children[0] == NULL ) { root->children[0] = root->children[1]; root->n_children--; root->children = realloc ( root->children, root->n_children * sizeof(node_t *) ); } /* NB! There is no 'break' here on purpose - since the * declaration list is now in the standard form, we WANT * control to fall through to the standard list-handling * code below. */ /* * All these lists have the same structure, so general flattening * is quite simple: extend the left child's list with the right * child, and substitute the parent. */ case FUNCTION_LIST: case STATEMENT_LIST: case PRINT_LIST: case EXPRESSION_LIST: case VARIABLE_LIST: if ( root->n_children >= 2 ) { result = root->children[0]; uint32_t n = (result->n_children += 1); result->children = realloc ( result->children, n * sizeof(node_t *) ); result->children[n-1] = root->children[1]; node_finalize ( root ); } break; case EXPRESSION: switch ( root->n_children ) { case 1: if ( root->children[0]->type.index == INTEGER ) { /* Single integers */ result = root->children[0]; if ( root->data != NULL ) /* Negative constants */ *((int32_t *)result->data) *= -1; node_finalize ( root ); } else if ( root->data == NULL ) { /* Single variables, parentheses, etc. */ result = root->children[0]; node_finalize ( root ); } break; case 2: /* Constant binary expressions */ if ( root->children[0]->type.index == INTEGER && root->children[1]->type.index == INTEGER && root->data != NULL ) { result = root->children[0]; int32_t *a = result->data, *b = root->children[1]->data; switch ( *((char *)root->data) ) { case '+': *a += *b; break; case '-': *a -= *b; break; case '*': *a *= *b; break; case '/': *a /= *b; break; case '^': if (*b < 0 && *a != 1) *a = 0; else { *a = 1; for (int32_t x=*a, c=*b; c > 0; c--) *a *= x; } break; } node_finalize ( root->children[1] ); node_finalize ( root ); } break; } break; } } *simplified = result; }
node_t* simplify_tree ( node_t* node ) { if ( node != NULL ){ // Recursively simplify the children of the current node for ( uint32_t i=0; i<node->n_children; i++ ){ node->children[i] = simplify_tree ( node->children[i] ); } // After the children have been simplified, we look at the current node // What we do depend upon the type of node switch ( node->type.index ) { // These are lists which needs to be flattened. Their structure // is the same, so they can be treated the same way. case FUNCTION_LIST: case STATEMENT_LIST: case PRINT_LIST: case EXPRESSION_LIST: case VARIABLE_LIST: if(node->n_children > 1){ node_t *temp, *simplified; temp = node->children[node->n_children - 1]; node->n_children += simplified->n_children; node->children = realloc(node->children, (1 + simplified->n_children)*sizeof(node_t)); for(int i = 0; i < simplified->n_children; i++){ node->children[i] = simplified->children[i]; } node->children[simplified->n_children] = temp; } else{ node->type = node->children[0]->type; node->data = node->children[0]->data; node->entry = node->children[0]->entry; node->n_children = 0; node_finalize(node->children[0]); } break; // Declaration lists should also be flattened, but their stucture is sligthly // different, so they need their own case case DECLARATION_LIST: if(node->n_children > 1){ node_t *temp, *simplified; temp = node->children[node->n_children -1]; node->n_children += simplified->n_children; node->children = realloc(node->children, (1+simplified->n_children)*sizeof(node_t)); for(int i = 0; i < simplified->n_children; i++){ node->children[i] = simplified->children[i]; } node->children[simplified->n_children] = temp; } else if (node->n_children == 1){ node->type = node->children[0]->type; node->data = node->children[0]->data; node->entry = node->children[0]->entry; node->n_children = 0; node_finalize(node->children[0]); } break; // These have only one child, so they are not needed case STATEMENT: case PARAMETER_LIST: case ARGUMENT_LIST: node->type = node->children[0]->type; node->data = node->children[0]->data; node->entry = node->children[0]->entry; node->n_children = 0; node_finalize(node->children[0]); break; // Expressions where both children are integers can be evaluated (and replaced with // integer nodes). Expressions whith just one child can be removed (like statements etc above) case EXPRESSION: if(node->n_children = 1){ node->type = node->children[0]->type; node->data = node->children[0]->data; node->entry = node->children[0]->entry; node->n_children = 0; node_finalize(node->children[0]); } else if( node->n_children = 2){ if(node->children[0]->type.index == INTEGER && node->children[0]->type.index == INTEGER){ node->type = node->children[0]->type; int *a = (node->children[0]->data); int *b = (node->children[0]->data); int *result = malloc(sizeof(int)); { switch(((char *)node->data)[0]){ case '+': *result = *a + *b; break; case '-': *result = *a - *b; break; case '*': *result = (*a) * (*b); break; case '/': *result = (*a) / (*b); break; } } node->data = &result; node->entry = node->children[0]->entry; node->n_children = 0; node_finalize(node->children[0]); node_finalize(node->children[1]); } } break; } } return node; }