1 /*
2  *  VHDL abstract syntax elements.
3  *
4  *  Copyright (C) 2008-2011  Nick Gasson (nick@nickg.me.uk)
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "vhdl_element.hh"
22 
23 #include <algorithm>
24 #include <cassert>
25 #include <cstring>
26 #include <typeinfo>
27 #include <iostream>
28 #include <sstream>
29 
30 using namespace std;
31 
32 static const int VHDL_INDENT = 2;  // Spaces to indent
33 
indent(int level)34 int indent(int level)
35 {
36    return level + VHDL_INDENT;
37 }
38 
nl_string(int level)39 std::string nl_string(int level)
40 {
41    std::ostringstream ss;
42    newline(ss, level);
43    return ss.str();
44 }
45 
46 /*
47  * Emit a newline and indent to the correct level.
48  */
newline(std::ostream & of,int level)49 void newline(std::ostream &of, int level)
50 {
51    of << std::endl;
52    while (level--)
53       of << ' ';
54 }
55 
blank_line(std::ostream & of,int level)56 void blank_line(std::ostream &of, int level)
57 {
58    of << std::endl;
59    newline(of, level);
60 }
61 
62 // The array of all vhdl_elements allocated so we can quickly
63 // clean them up just before the code generator exits
64 vector<vhdl_element*> vhdl_element::allocated_;
65 
66 // Just a counter of total bytes allocated for statistics
67 size_t vhdl_element::total_alloc_(0);
68 
set_comment(std::string comment)69 void vhdl_element::set_comment(std::string comment)
70 {
71    comment_ = comment;
72 }
73 
74 /*
75  * Draw the comment for any element. The comment is either on
76  * a line before the element (end_of_line is false) or at the
77  * end of the line containing the element (end_of_line is true).
78  */
emit_comment(std::ostream & of,int level,bool end_of_line) const79 void vhdl_element::emit_comment(std::ostream &of, int level,
80                                 bool end_of_line) const
81 {
82    if (! comment_.empty()) {
83       if (end_of_line)
84          of << "  -- " << comment_;
85       else {
86          // Comment may contain embedded newlines
87          of << "-- ";
88          for (string::const_iterator it = comment_.begin();
89               it != comment_.end(); ++it) {
90             if (*it == '\n') {
91                newline(of, level);
92                of << "-- ";
93             }
94             else
95                of << *it;
96          }
97          newline(of, level);
98       }
99    }
100 }
101 
print() const102 void vhdl_element::print() const
103 {
104    emit(std::cout, 0);
105    std::cout << std::endl;
106 }
107 
108 // Trap allocations of vhdl_element subclasses.
109 // This records the pointer allocated in a static field of vhdl_element
110 // so we can delete it just before the code generator exits.
operator new(size_t size)111 void* vhdl_element::operator new(size_t size)
112 {
113    // Let the default new handle the allocation
114    void* ptr = ::operator new(size);
115 
116    // Remember this element so we can delete it later
117    vhdl_element* elem = static_cast<vhdl_element*>(ptr);
118    allocated_.push_back(elem);
119 
120    total_alloc_ += size;
121 
122    return ptr;
123 }
124 
125 // Explicitly delete a vhdl_element object.
126 // This just sets the corresponding pointer in vhdl_element::allocated_
127 // to NULL (since it's safe to delete a NULL pointer).
operator delete(void * ptr)128 void vhdl_element::operator delete(void* ptr)
129 {
130    // Let the default delete handle the deallocation
131    ::operator delete(ptr);
132 
133    // Remember that we've already deleted this pointer so we don't
134    // delete it again in the call to free_all_objects
135    vector<vhdl_element*>::iterator it =
136       find(allocated_.begin(), allocated_.end(), static_cast<vhdl_element*>(ptr));
137 
138    if (it != allocated_.end()) {
139       *it = NULL;   // It's safe to delete a NULL pointer and much cheaper
140                     // than removing an element from the middle of a vector
141    }
142    else {
143       // This shouldn't really happen but it's harmless
144       cerr << "??? vhdl_element::operator delete called on an object not "
145            << "allocated by vhdl_element::operator new" << endl;
146    }
147 }
148 
149 // Return the total number of bytes our custom operator new has seen.
total_allocated()150 size_t vhdl_element::total_allocated()
151 {
152    return total_alloc_;
153 }
154 
155 // Free every object derived from vhdl_element that has not yet been
156 // explicitly deallocated.
157 // Any pointers to vhdl_elements will be invalid after this call!
158 // Returns the number of objects freed.
free_all_objects()159 int vhdl_element::free_all_objects()
160 {
161    for (vector<vhdl_element*>::iterator it = allocated_.begin();
162         it != allocated_.end(); ++it) {
163       if (*it)
164          ::operator delete(*it);  // Explicitly use the default delete
165    }
166 
167    int freed = allocated_.size();
168 
169    // Just in case we want to allocated any more vhdl_element objects
170    allocated_.clear();
171 
172    return freed;
173 }
174