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