/**
 * Function representing the <functions> prods
 */
void RecursiveDescentParser::functions() {
	if(errorCondition) return;
	
	if(token == TK_VOID || token == TK_INT ||
			token == TK_CHAR) {
#if DEBUG_PARSER
		std::cout<<"<functions> --> <funct_def><functions_prime>\n";
#endif
		funct_def();
		functions_prime();
	} else {
		errorHandler();
	}
}
        void OpenMP_PreTransform::purge_local_threadprivates()
        {
            ObjectList<Symbol> involved_functions = get_all_functions(_function_sym_list);

            for (ObjectList<Symbol>::iterator it = involved_functions.begin();
                    it != involved_functions.end();
                    it++)
            {
                Symbol &funct_sym(*it);
                AST_t funct_point_of_decl = funct_sym.get_point_of_declaration();

                ObjectList<Symbol> local_syms = get_symbols_of_function(_function_sym_list, funct_sym);

                Source pragma_line, threadprivate_args;
                pragma_line
                    << "#pragma omp threadprivate("
                    << threadprivate_args
                    ;

                TL::ReplaceIdExpression replacement;

                for (ObjectList<Symbol>::iterator localsym_it = local_syms.begin();
                        localsym_it != local_syms.end();
                        localsym_it++)
                {
                    Symbol &local_sym(*localsym_it);

                    Type type = local_sym.get_type();

                    Source global_var_name;
                    global_var_name
                        <<  "__" << funct_sym.get_name() << "_" << _function_num << "_" << local_sym.get_name();

                    replacement.add_replacement(local_sym, global_var_name);

                    threadprivate_args.append_with_separator(global_var_name, ",");

                    // FIXME - In C++ we have to be careful where we put this new declaration
                    // Templates will mess things -> Scope must be judiciously chosen
                    Source global_decl_src;

                    global_decl_src
                        << "static "
                        << type.get_declaration(local_sym.get_scope(), global_var_name)
                        << ";"
                        ;

                    // FIXME - C++!
                    AST_t global_decl_tree = global_decl_src.parse_global(
                            funct_point_of_decl, _scope_link);

                    // 1. Declare globally just before the function
                    funct_point_of_decl.prepend(global_decl_tree);
                }

                pragma_line << ")\n";

                // 2. Add the pragma line with all local symbols
                AST_t pragma_line_tree = pragma_line.parse_global(
                        funct_point_of_decl, _scope_link);

                funct_point_of_decl.prepend(pragma_line_tree);

                for (ObjectList<Symbol>::iterator localsym_it = local_syms.begin();
                        localsym_it != local_syms.end();
                        localsym_it++)
                {
                    Symbol &local_sym(*localsym_it);

                    remove_symbol_declaration(local_sym);
                }

                FunctionDefinition funct_def(funct_point_of_decl,
                        _scope_link);
                Statement function_body = funct_def.get_function_body();
                // 4. Change old references to the new ones
                Statement replaced_function_body = replacement.replace(function_body);
                function_body.get_ast().replace(replaced_function_body.get_ast());

                // Next function number
                _function_num++;
            }
        }
        static void convert_vla(Symbol sym, ObjectList<Symbol>& converted_vlas, ScopeLink sl)
        {
            if (converted_vlas.contains(sym))
                return;

            ObjectList<Source> dim_decls;
            ObjectList<Source> dim_names;

            dimensional_replacements_of_variable_type_aux(sym.get_type(),
                    sym, dim_names, dim_decls);

            Source new_decls;
            for (ObjectList<Source>::iterator it = dim_decls.begin();
                    it != dim_decls.end();
                    it++)
            {
                new_decls << *it << ";"
                    ;
            }

            AST_t point_of_decl = sym.get_point_of_declaration();
            AST_t enclosing_stmt_tree;
            if (sym.is_parameter())
            {
                FunctionDefinition 
                    funct_def(point_of_decl.get_enclosing_function_definition(), sl);

                enclosing_stmt_tree = funct_def.get_function_body().get_inner_statements()[0].get_ast();
            }
            else
            {
                enclosing_stmt_tree = point_of_decl.get_enclosing_statement();
            }

            AST_t statement_seq 
                = new_decls.parse_statement(enclosing_stmt_tree, sl);
            enclosing_stmt_tree.prepend(statement_seq);

            if (!sym.is_parameter())
            {
                // If this is not a parameter, we'll want to rewrite the declaration itself
                Type new_type_spawn = compute_replacement_type_for_vla(sym.get_type(), dim_names.begin(), dim_names.end());

                // Now redeclare
                Source redeclaration, initializer;
                redeclaration
                    << new_type_spawn.get_declaration(sym.get_scope(), sym.get_name())
                    << initializer
                    << ";"
                    ;

                if (sym.has_initialization()) 
                {
                    initializer << sym.get_initialization().prettyprint()
                        ;
                }

                AST_t redeclaration_tree = redeclaration.parse_statement(enclosing_stmt_tree,
                        sl, Source::ALLOW_REDECLARATION);

                enclosing_stmt_tree.prepend(redeclaration_tree);

                // Now remove the declarator of the declaration
                Declaration decl(point_of_decl, sl);

                if (decl.get_declared_entities().size() == 1)
                {
                    // We have to remove all the whole declaration
                    enclosing_stmt_tree.remove_in_list();
                }
                else
                {
                    // Remove only this entity
                    ObjectList<DeclaredEntity> entities = decl.get_declared_entities();
                    for (ObjectList<DeclaredEntity>::iterator it = entities.begin();
                            it != entities.end();
                            it++)
                    {
                        if (it->get_declared_symbol() == sym)
                        {
                            it->get_ast().remove_in_list();
                        }
                    }
                }
            }

            ObjectList<Source>* new_dim_ptr = new ObjectList<Source>(dim_names);

            RefPtr<ObjectList<Source> > dim_names_ref(new_dim_ptr);
            sym.set_attribute(OMP_NANOX_VLA_DIMS, dim_names_ref);

            converted_vlas.insert(sym);
        }