AST_t AST_t::get_enclosing_class_specifier(bool jump_templates) const
    {
        AST node = _ast;

        while (node != NULL
                && ASTType(node) != AST_CLASS_SPECIFIER)
        {
            node = ASTParent(node);
        }

        while (node != NULL
                && ASTType(node) != AST_SIMPLE_DECLARATION)
        {
            node = ASTParent(node);
        }

        if (jump_templates)
        {
            while (node != NULL
                    && ASTParent(node) != NULL
                    && ASTType(ASTParent(node)) == AST_TEMPLATE_DECLARATION)
            {
                node = ASTParent(node);
            }
        }

        AST_t result(node);
        return node;
    }
 bool AST_t::is_extensible_block(AST node)
 {
     return (ASTType(node) == AST_COMPOUND_STATEMENT
             || ASTType(node) == AST_CLASS_SPECIFIER
             || ASTType(node) == AST_TRANSLATION_UNIT
             || ASTType(node) == AST_NAMESPACE_DEFINITION);
 }
    void AST_t::replace(AST_t ast)
    {
        if (ast._ast == NULL)
        {
            internal_error("Trying to replace a tree with an empty tree", 0);
        }

        if (this->_ast == NULL)
        {
            internal_error("Trying to replace an empty tree with another tree", 0);
        }

        if (ASTType(ast._ast) == AST_NODE_LIST)
        {
            // If the replacement is a list but the original is not, let's check two cases
            // maybe this list is a one-element list or not.
            if (ASTType(this->_ast) != AST_NODE_LIST)
            {
                // If it is a one element list
                if (ASTSon0(ast._ast) == NULL)
                {
                    // then replace the whole thing with the list information
                    AST_t repl_tree(ASTSon1(ast._ast));
                    replace_with(repl_tree);
                }
                // If this is not a one-element list then try to replace using
                // a typical replace_in_list but this may fail sometimes
                // because we'll look for the first enclosing list
                else 
                {
                    // Maybe we should yield a message here
                    // std::cerr << "Warning: Replacing a non-list tree at '" 
                    //     << this->get_locus() 
                    //     << "' with a list tree of more than one element" << std::endl;
                    replace_in_list(ast);
                }
            }
            // If both are lists is easy
            else
            {
                replace_in_list(ast);
            }
        }
        // If the thing being replaced is a list, but the replacement
        // is not, then convert the latter into a list
        else if (ASTType(_ast) == AST_NODE_LIST
                && ASTType(_ast) != AST_NODE_LIST)
        {
            // Create a single element list
            AST single(ASTListLeaf(ast._ast));
            replace_in_list(single);
        }
        // Otherwise replace directly. Neither the replaced nor the replacement
        // are lists in this case.
        else
        {
            replace_with(ast);
        }
    }
    AST_t AST_t::get_enclosing_namespace_definition() const
    {
        AST node = _ast;

        while (node != NULL
                && ASTType(node) != AST_NAMESPACE_DEFINITION
                && ASTType(node) != AST_GCC_NAMESPACE_DEFINITION)
        {
            node = ASTParent(node);
        }

        AST_t result(node);
        return node;
    }
    void AST_t::prepend(AST_t t)
    {
        if (t._ast == NULL)
        {
            // Do nothing
            return;
        }

        if (ASTType(t._ast) != AST_NODE_LIST)
        {
            std::cerr << "The prepended tree is not a list. No prepend performed" << std::endl;
            return;
        }

        AST prepended_list = t._ast;

        AST enclosing_list = get_enclosing_list(this->_ast);

        if (enclosing_list == NULL)
        {
            std::cerr << "Cannot found a suitable list to prepend" << std::endl;
        }

        prepend_list(enclosing_list, prepended_list);
    }
    void AST_t::remove_in_list()
    {
        AST list = this->_ast;
        // Look for the enclosing list
        while (list != NULL &&
                ASTType(list) != AST_NODE_LIST)
        {
            list = ASTParent(list);
        }

        if (list == NULL)
        {
            std::cerr << "A suitable list has not been found" << std::endl;
            return;
        }

        AST parent = ASTParent(list);
        AST previous = ASTSon0(list);

        if (previous != NULL)
        {
            ast_set_parent(previous, parent);
        }

        int i;
        for (i = 0; i < ASTNumChildren(parent); i++)
        {
            if (ASTChild(parent, i) == list)
            {
                ast_set_child(parent, i, previous);
                break;
            }
        }
    }
    bool ASTIterator::is_last()
    {
        if (_current == NULL)
            return true;

        AST _possible_next = ASTParent(_current);
        if (_possible_next == NULL
                || ASTType(_possible_next) != AST_NODE_LIST)
        {
            return true;
        }
        else if (ASTType(_possible_next) == AST_NODE_LIST
                && ASTSon0(_possible_next) != _current)
        {
            return true;
        }
        return false;
    }
Example #8
0
// static
ASTType ASTType::greaterType(const ASTType& left, const ASTType& right)
{
   if ( left.greater(right) )
      return right;
   else if ( right.greater(left) )
      return left;

   return ASTType();
}
Example #9
0
static void ast_dump_html_rec(AST a, FILE* f, const char* root_id, int id_node)
{
    if (a == NULL)
        return;

    char current_id_node[64];
    memset(current_id_node, 0, sizeof(current_id_node));
    snprintf(current_id_node, 63, "%s.%d", root_id, id_node);
    current_id_node[63] = '\0';

    fprintf(f, "<div id=\"%s\" class=\"node\" style=\"display: none;\">\n"
            "<div class=\"node_info\">"
            "<span id=\"%s.handle\" class=\"handle\">+</span>"
            "<span id=\"%s.kind\" class=\"node_kind\">%s</span>"
            "<span id=\"%s.locus\" class=\"node_locus\">%s</span>",
            current_id_node, // div
            current_id_node, // handle
            current_id_node, ast_node_type_name(ASTType(a)),
            current_id_node, mini_strip_html(ast_location(a))
           ); // kind

    if (ASTText(a) != NULL)
    {
        fprintf(f, 
            "<span id=\"%s.text\" class=\"node_text\">%s</span>",
            current_id_node,
            mini_strip_html(ASTText(a)));
    }

    fprintf(f, "</div>\n");

    if (ASTType(a) == AST_NODE_LIST)
    {
        fprintf(f, "%s", "<div class=\"node_list\">");
        int k = 0;
        AST list = a, iter;
        for_each_element(list, iter)
        {
            AST element = ASTSon1(iter);
            ast_dump_html_rec(element, f, current_id_node, k);

            k++;
        }
    AST AST_t::get_translation_unit(AST node)
    {
        if  (node == NULL)
            return NULL;

        while (node != NULL && 
                ASTType(node) != AST_TRANSLATION_UNIT)
        {
            node = ASTParent(node);
        }

        return node;
    }
    // XXX - Fixme, implement it using ast_list_concat
    void AST_t::prepend_list(AST orig_list, AST prepended_list)
    {
        if (ASTType(orig_list) != AST_NODE_LIST
                || ASTType(prepended_list) != AST_NODE_LIST)
        {
            std::cerr << "You tried to prepend two lists that are not " 
                << "orig_list=" << ast_print_node_type(ASTType(orig_list)) << " "
                << "prepend_list=" << ast_print_node_type(ASTType(prepended_list)) << std::endl;
            return;
        }

        // Relink the parent, first remove pointer to the prepended_list
        if (ASTParent(prepended_list) != NULL)
        {
            AST parent = ASTParent(prepended_list);
            for (int i = 0; i < ASTNumChildren(parent); i++)
            {
                if (ASTChild(parent, i) == prepended_list)
                {
                    ast_set_child(parent, i, NULL);
                    break;
                }
            }
        }

        // Now make the prepended_list as the son
        AST original_previous = ASTSon0(orig_list);

        ast_set_child(orig_list, 0, prepended_list);

        // Go to the deeper node of prepended_list
        AST iter = prepended_list;
        while (ASTSon0(iter) != NULL)
        {
            iter = ASTSon0(iter);
        }

        ast_set_child(iter, 0, original_previous);
    }
    AST_t ASTIterator::get_parent_of_list()
    {
        // This is similar to a rewind, actually, but without modifying
        // _current
        AST it = _ast;

        while (it != NULL
                && ASTType(it) == AST_NODE_LIST)
        {
            it = ASTParent(it);
        }

        return AST_t(it);
    }
    AST_t AST_t::get_enclosing_function_definition(bool jump_templates, bool jump_external_decl) const
    {
        AST node = _ast;

        while (node != NULL && 
                ASTType(node) != AST_FUNCTION_DEFINITION)
        {
            node = ASTParent(node);
        }

        // Jump over template declarations
        if (jump_templates)
        {
            // Now the node is an AST_FUNCTION_DEFINITION
            while (node != NULL 
                    && ASTParent(node) != NULL
                    && ASTType(ASTParent(node)) == AST_TEMPLATE_DECLARATION)
            {
                node = ASTParent(node);
            }
        }

        // Extern declarations pose a problem, let's jump them as well
        if (jump_external_decl)
        {
            while (node != NULL
                    && ASTParent(node) != NULL
                    && ASTType(ASTParent(node)) == AST_LINKAGE_SPEC_DECL)
            {
                node = ASTParent(node);
            }
        }

        AST_t result(node);
        return result;
    }
    // XXX - Fixme, implement it using ast_list_concat
    void AST_t::append_list(AST orig_list, AST appended_list)
    {
        if (ASTType(orig_list) != AST_NODE_LIST
                || ASTType(appended_list) != AST_NODE_LIST)
        {
            std::cerr << "You tried to append two lists that are not" << std::endl;
            return;
        }

        // Appending one list to another is as easy as making the deeper node
        // "appended_list" to point to the top node of "orig_list"

        // First replace appended_list as the new child of the parent of orig_list
        relink_parent(orig_list, appended_list);

        // Now link the deeper node of the list to the top node of "orig_list"
        AST iter = appended_list;
        while (ASTSon0(iter) != NULL)
        {
            iter = ASTSon0(iter);
        }

        ast_set_child(iter, 0, orig_list);
    }
 ASTIterator::ASTIterator(AST ast)
     : _ast(ast), _current(ast)
 {
     if (ast == NULL 
             || ASTType(ast) != AST_NODE_LIST)
     {
         if (ast != NULL)
         {
             std::cerr << "Node at '" 
                 << ast_get_filename(ast) << ":" << ASTLine(ast) 
                 << "' is not a list" << std::endl;
         }
         _ast = NULL;
         _current = NULL;
     }
 }
    AST AST_t::get_enclosing_list(AST ast)
    {
        if (ast == NULL)
        {
            return NULL;
        }

        AST list = ast;

        // Look for the enclosing list
        while (list != NULL &&
                ASTType(list) != AST_NODE_LIST)
        {
            list = ASTParent(list);
        }

        return list;
    }
Example #17
0
void SymbolCheckVisitor::visit(ASTInstanceOf& ast)
{
   mCurrentType.clear();

   checkUnknown(ast.getInstanceType());

   ast.getObject().accept(*this);

   if ( !(mCurrentType.isObject() || mCurrentType.isArray()) )
   {
      error(E0027, UTEXT("Operator instanceof can only be called against objects/arrays."), ast);
   }
   else if ( !mCurrentType.isDerivedFrom(ast.getInstanceType()) )
   {
      error(E0028, UTEXT("Instanceof operator can never be true for ") + mCurrentType.toString() + UTEXT(" and ") + ast.getInstanceType().toString(), ast);
   }

   mCurrentType = ASTType(ASTType::eBoolean);
}
    std::string AST_t::prettyprint(bool with_commas) const
    {
        // This is always internal
        prettyprint_set_internal_output();
        const char *c = NULL;
        if (with_commas && ASTType(this->_ast) == AST_NODE_LIST)
        {
            c = list_handler_in_buffer(this->_ast);
        }
        else
        {
            c = prettyprint_in_buffer(this->_ast);
        }

        std::string result(c == NULL ? "" : c);
        if (c != NULL)
            free((void*)c);
        return result;
    }
Example #19
0
 void Source::fortran_check_expression_adapter(AST a, decl_context_t decl_context, nodecl_t* nodecl_output)
 {
     if (ASTType(a) == AST_COMMON_NAME)
     {
         // We allow common names in expressions
         scope_entry_t* entry = ::query_common_name(decl_context, ASTText(ASTSon0(a)),
                 ast_get_locus(ASTSon0(a)));
         if (entry != NULL)
         {
             *nodecl_output = ::nodecl_make_symbol(entry, ast_get_locus(a));
         }
         else
         {
             *nodecl_output = ::nodecl_make_err_expr(ast_get_locus(a));
         }
     }
     else
     {
         ::fortran_check_expression(a, decl_context, nodecl_output);
     }
 }
    void AST_t::replace_in_list(AST_t ast)
    {
        if (ast._ast == NULL)
        {
            std::cerr << "Cannot replace a list using an empty tree" << std::endl;
            return;
        }
        if (this->_ast == NULL)
        {
            std::cerr << "This tree is empty" << std::endl;
            return;
        }

        if (ASTType(ast._ast) != AST_NODE_LIST)
        {
            std::cerr << "The replacement tree is not a list. No replacement performed" << std::endl;
            return;
        }

        AST list = get_enclosing_list(this->_ast);

        if (list == NULL)
        {
            std::cerr << "A suitable list has not been found" << std::endl;
            return;
        }

        AST previous = ASTSon0(list);

        AST_t replaced(list);
        replaced.replace_with(ast);

        while (ASTSon0(list) != NULL)
        {
            list = ASTSon0(list);
        }

        ast_set_child(list, 0, previous);
    }
 AST AST_t::get_list_of_extensible_block(AST node)
 {
     switch ((int)ASTType(node))
     {
         case AST_COMPOUND_STATEMENT :
             {
                 // This can be null
                 return ASTSon0(node);
                 break;
             }
         case AST_CLASS_SPECIFIER :
             {
                 // This can be null
                 return ASTSon1(node);
                 break;
             }
         case AST_TRANSLATION_UNIT :
             {
                 // This can be null
                 return ASTSon0(node);
                 break;
             }
         case AST_NAMESPACE_DEFINITION :
             {
                 // This can be null
                 return ASTSon1(node);
                 break;
             }
         case AST_NODE_LIST :
             {
                 return node;
                 break;
             }
     }
     return NULL;
 }
Example #22
0
void SymbolCheckVisitor::visit(ASTConcatenate& ast)
{
   ast.getLeft().accept(*this);

   ASTType lefttype = mCurrentType;

   mCurrentType.clear();

   ast.getRight().accept(*this);

   switch ( ast.getMode() )
   {
      case ASTConcatenate::eMul:
      case ASTConcatenate::eDiv:
      case ASTConcatenate::eRem:
      case ASTConcatenate::ePlus:
      case ASTConcatenate::eMinus:
         {
            ASTType righttype = mCurrentType;

            mCurrentType = ASTType::greaterType(lefttype, righttype);
            if ( mCurrentType.isValid() )
            {
               // optionally add casts if necessary

               if ( mCurrentType.isChar() && lefttype.isString() )
               {
                  // add char is now allowed directly:
                  //  str = str + char  <- no casts
                  //  str = char + str  <- casts char to string
                  break;
               }

               if ( !lefttype.equals(mCurrentType) )
               {
                  ASTCast* pcast = new ASTCast();
                  pcast->setType(mCurrentType.clone());
                  pcast->setNode(ast.useLeft());

                  ast.setLeft(pcast);
               }
               if ( !righttype.equals(mCurrentType) )
               {
                  ASTCast* pcast = new ASTCast();
                  pcast->setType(mCurrentType.clone());
                  pcast->setNode(ast.useRight());

                  ast.setRight(pcast);
               }
            }
            else
            {
               String op = UTEXT("+");
               error(E0022, UTEXT("Can not execute operator ") + op + UTEXT(" on types ") + lefttype.toString() + UTEXT(" and ") + righttype.toString(), ast);
            }
         }
         break;

      case ASTConcatenate::eBitwiseOr:
      case ASTConcatenate::eBitwiseXor:
      case ASTConcatenate::eBitwiseAnd:
      case ASTConcatenate::eShiftLeft:
      case ASTConcatenate::eShiftRight:
         {
            ASTType righttype = mCurrentType;

            if ( !lefttype.isInt() || !righttype.isInt() )
            {
               error(E0023, UTEXT("Bitwise operators only operate on int values."), ast);
            }
         }
         break;

      case ASTConcatenate::eAnd:
      case ASTConcatenate::eOr:
         {
            if ( !lefttype.isBoolean() || !mCurrentType.isBoolean() )
            {
               String op = UTEXT("&&"); // add toString to Mode
               error(E0024, UTEXT("Operator ") + op + UTEXT(" requires boolean expressions."), ast);
            }
         }
         break;

      case ASTConcatenate::eEquals:
      case ASTConcatenate::eUnequals:
      case ASTConcatenate::eSmallerEqual:
      case ASTConcatenate::eSmaller:
      case ASTConcatenate::eGreater:
      case ASTConcatenate::eGreaterEqual:
         {
            ASTType comp = ASTType::greaterType(lefttype, mCurrentType);
            if ( !comp.isValid() )
            {
               error(E0025, UTEXT("Can not compare ") + lefttype.toString() + UTEXT(" with ") + mCurrentType.toString(), ast);
            }
            else if ( ast.getMode() >= ASTConcatenate::eSmallerEqual )
            {
               if ( comp.isObject() || comp.isArray() || comp.isBoolean() )
               {
                  error(E0026, UTEXT("Invalid type ") + comp.toString() + UTEXT(" for operator."), ast);
               }
            }

            mCurrentType = ASTType(ASTType::eBoolean);
         }
         break;
         
      case ASTConcatenate::eInvalid:
         error(E0001, UTEXT("Invalid compiler state!"), ast);
         break;
   }
}
static void ast_dump_graphviz_rec(AST a, FILE* f, size_t parent_node, int position, char is_extended UNUSED_PARAMETER)
{
    // static char* octagon = "octagon";
    // static char* doubleoctagon = "doubleoctagon";
    static char* ellipse = "ellipse";
    static char* mdiamond = "Mdiamond";
    static char* box = "box";
    char* shape;

    // I know this is not exact, but there is a %z qualifier in printf
    // while there is not such thing for intptr_t
    size_t current_node = (size_t)a;

    if (a != NULL)
    {
        // Select shape
        shape = box;
        if (ASTType(a) == AST_AMBIGUITY) shape = ellipse;
        if (ASTType(a) == AST_NODE_LIST) shape = mdiamond;
        // if (a->construct_type == CT_SPECIFICATION) shape = ellipse;
        // else if (a->construct_type == CT_OMP_SPECIFICATION) shape = mdiamond;
        // else if (a->construct_type == CT_EXECUTABLE) shape = octagon;
        // else if (a->construct_type == CT_OMP_EXECUTABLE) shape = doubleoctagon;

        if (ASTText(a))
        {
            char *quoted = quote_protect(ASTText(a));

            fprintf(f, "n%zd[shape=%s,label=\"%s\\nNode=%p\\nParent=%p\\n%s\\nText: \\\"%s\\\"\"]\n", 
                    current_node, shape, ast_print_node_type(ASTType(a)), a, ASTParent(a), ast_location(a), quoted);

            free(quoted);
        }
        else
        {
            fprintf(f, "n%zd[shape=%s,label=\"%s\\nNode=%p\\nParent=%p\\n%s\"]\n", 
                    current_node, shape, ast_print_node_type(ASTType(a)), a, ASTParent(a), ast_location(a));
        }

        // Print this only for non extended referenced nodes
        if (parent_node != 0)
        {
            fprintf(f, "n%zd -> n%zd [label=\"%d\"]\n", parent_node, current_node, position);
        }

        if (ASTType(a) != AST_AMBIGUITY)
        {
            int i;
            if (!is_extended)
            {
                for(i = 0; i < ASTNumChildren(a); i++)
                {
                    if (ASTChild(a, i) != NULL)
                    {
                        ast_dump_graphviz_rec(ASTChild(a, i), f, current_node, i, /* is_extended */ is_extended);
                    }
                }
            }

            // Now print all extended trees referenced here
            // First get all TL_AST in 'orig' that point to its childrens

            extensible_struct_t* extended_data = ast_get_extensible_struct(a);

            if (extended_data != NULL
                    && !is_extended)
            {
                int num_fields = 0;
                const char** keys = NULL;
                const void** values = NULL;

                extensible_struct_get_all_data(extended_data, &num_fields, &keys, &values);

                for (i = 0; i < num_fields; i++)
                {
                    const char* field_name = keys[i];
                    tl_type_t* tl_data = (tl_type_t*)values[i];
                    if (tl_data->kind == TL_AST)
                    {
                        if (tl_data->data._ast != a)
                        {
                            ast_dump_graphviz_rec(tl_data->data._ast, f, /* parent_node */ 0, /* position */ 0, /* is_extended */ 1);
                        }

                        // Add an edge
                        fprintf(f, "n%zd -> n%zd [label=\"%s\",style=dashed]\n",
                                current_node,
                                (size_t)(tl_data->data._ast),
                                field_name);
                    }
                }
            }
        }
        else if (ASTType(a) == AST_AMBIGUITY)
        {
            int i;
            for(i = 0; i < ast_get_num_ambiguities(a); i++)
            {
                ast_dump_graphviz_rec(ast_get_ambiguity(a, i), f, current_node, i, /* is_extended */ 0);
            }
        }
    }
    else
    {
        fprintf(f, "n%zd[shape=circle,label=\"\",fixedsize=true,style=filled,fillcolor=black,height=0.1,width=0.1]\n", current_node);
        if (parent_node != 0)
        {
            fprintf(f, "n%zd -> n%zd [label=\"%d\"]\n", parent_node, current_node, position);
        }
    }
}
static void fortran_simplify_tree_stmt(AST a, AST *out)
{
    // FIXME: Think ways of improving this
    switch (ASTType(a))
    {
        case AST_ALLOCATE_STATEMENT:
        case AST_ARITHMETIC_IF_STATEMENT:
        case AST_ASSIGNED_GOTO_STATEMENT:
        case AST_BREAK_STATEMENT:
        case AST_CLOSE_STATEMENT:
        case AST_COMPUTED_GOTO_STATEMENT:
        case AST_CONTINUE_STATEMENT:
        case AST_DEALLOCATE_STATEMENT:
        case AST_EMPTY_STATEMENT:
        case AST_EXPRESSION_STATEMENT:
        case AST_GOTO_STATEMENT:
        case AST_IO_STATEMENT:
        case AST_LABEL_ASSIGN_STATEMENT:
        case AST_NULLIFY_STATEMENT:
        case AST_OPEN_STATEMENT:
        case AST_PRINT_STATEMENT:
        case AST_READ_STATEMENT:
        case AST_RETURN_STATEMENT:
        case AST_STOP_STATEMENT:
        case AST_PAUSE_STATEMENT:
        case AST_WRITE_STATEMENT:
        case AST_PRAGMA_CUSTOM_DIRECTIVE:
            {
                // Simple copy
                *out = ast_copy_with_scope_link(a, CURRENT_COMPILED_FILE->scope_link);
                break;
            }
        case AST_BLOCK_CONSTRUCT:
            {
                AST block = ASTSon1(a);
                AST new_block = NULL;
                AST it;
                for_each_element(block, it)
                {
                    AST stmt = ASTSon1(it);
                    AST new_stmt = NULL;

                    fortran_simplify_tree_stmt(stmt, &new_stmt);

                    if (new_stmt != NULL)
                    {
                        new_block = ASTList(new_block, new_stmt);
                    }
                }
                *out = ASTMake1(AST_COMPOUND_STATEMENT, new_block, ASTFileName(a), ASTLine(a), NULL);
                break;
            }
        case AST_COMPOUND_STATEMENT:
            {
                AST list = ASTSon0(a);
                AST new_list = NULL;
                AST it;
                for_each_element(list, it)
                {
                    AST stmt = ASTSon1(it);
                    AST new_stmt = NULL;

                    fortran_simplify_tree_stmt(stmt, &new_stmt);

                    if (new_stmt != NULL)
                    {
                        new_list = ASTList(new_list, new_stmt);
                    }
                }
                *out = ASTMake1(AST_COMPOUND_STATEMENT, new_list, ASTFileName(a), ASTLine(a), NULL);
                break;
            }
 std::string AST_t::internal_ast_type() const
 {
     char* inner_name = ast_node_names[ASTType(this->_ast)];
     std::string result(inner_name);
     return result;
 }
 bool AST_t::is_list() const
 {
     return is_valid()
         && ASTType(_ast) == AST_NODE_LIST;
 }
 node_t AST_t::internal_ast_type_() const
 {
     return ASTType(this->_ast);
 }
Example #28
0
static void ast_dump_graphviz_rec(AST a, FILE* f, int parent_node, int position)
{
    // static char* octagon = "octagon";
    // static char* doubleoctagon = "doubleoctagon";
    static char* ellipse = "ellipse";
    static char* mdiamond = "Mdiamond";
    static char* box = "box";
    char* shape;

    int node_actual = nodes_counter++;
    if (a != NULL)
    {
        // Select shape
        shape = box;
        if (ASTType(a) == AST_AMBIGUITY) shape = ellipse;
        if (ASTType(a) == AST_NODE_LIST) shape = mdiamond;
        // if (a->construct_type == CT_SPECIFICATION) shape = ellipse;
        // else if (a->construct_type == CT_OMP_SPECIFICATION) shape = mdiamond;
        // else if (a->construct_type == CT_EXECUTABLE) shape = octagon;
        // else if (a->construct_type == CT_OMP_EXECUTABLE) shape = doubleoctagon;

        if (ASTText(a))
        {
            fprintf(f, "n%d[shape=%s,label=\"%s\\nNode=%p\\nParent=%p\\n%s\\nText: -%s-\"]\n", 
                    node_actual, shape, ast_print_node_type(ASTType(a)), a, ASTParent(a), ast_location(a), ASTText(a));
        }
        else
        {
            fprintf(f, "n%d[shape=%s,label=\"%s\\nNode=%p\\nParent=%p\\n%s\"]\n", 
                    node_actual, shape, ast_print_node_type(ASTType(a)), a, ASTParent(a), ast_location(a));
        }

        if (parent_node != 0)
        {
            fprintf(f, "n%d -> n%d [label=\"%d\"]\n", parent_node, node_actual, position);
        }


        if (ASTType(a) != AST_AMBIGUITY)
        {
            int i;
            for(i = 0; i < ASTNumChildren(a); i++)
            {
                ast_dump_graphviz_rec(ASTChild(a, i),f,  node_actual, i);
            }
        }
        else if (ASTType(a) == AST_AMBIGUITY)
        {
            int i;
            for(i = 0; i < ast_get_num_ambiguities(a); i++)
            {
                ast_dump_graphviz_rec(ast_get_ambiguity(a, i), f, node_actual, i);
            }
        }
    }
    else
    {
        fprintf(f, "n%d[shape=circle,label=\"\",fixedsize=true,style=filled,fillcolor=black,height=0.1,width=0.1]\n", node_actual);
        if (parent_node != 0)
        {
            fprintf(f, "n%d -> n%d [label=\"%d\"]\n", parent_node, node_actual, position);
        }
    }
}