1 /*
2  * (C) Copyright 2001-2015 Diomidis Spinellis
3  *
4  * This file is part of CScout.
5  *
6  * CScout 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * CScout 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
17  * along with CScout.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *
20  * A token identifier.
21  * This uniquelly identifies any token (part).
22  * It is used to compose input tokens, symbol table antries,
23  * as a map source for equivalence classes, and as a member in
24  * equivalence classes.
25  *
26  * Rationale: the program works by assigning tokens to equivalence
27  * classes.  Each class must know its tokens, and each token its
28  * equivalence class.  Because equivalence classes can be merged and split
29  * it is easier, instead of maintaining two-way relationships between ECs
30  * and their tokens, to have a fixed way to represent EC contents,
31  * and identifier EC membership.  Tokids satisfy this property, because
32  * they remain constant and with the same meaining throughout the program's
33  * lifetime.
34  *
35  */
36 
37 #ifndef TOKID_
38 #define TOKID_
39 
40 #include <deque>
41 #include <map>
42 
43 using namespace std;
44 
45 #include "cpp.h"
46 #include "fileid.h"
47 
48 class Eclass;
49 
50 class Tokid;
51 class Tpart;
52 typedef deque <Tokid> dequeTokid;
53 typedef deque <Tpart> dequeTpart;
54 
55 class Tokid;
56 typedef map <Tokid, Eclass *> mapTokidEclass;
57 
58 class Tokid {
59 #ifdef PICO_QL
60 public:
61 #else
62 private:
63 #endif
64 	static mapTokidEclass tm;	// Map from tokens to their equivalence
65 private:
66 					// classes
67 	Fileid fi;			// File
68 	cs_offset_t offs;		// Offset
69 public:
70 	// Construct it, based on the fileid and offset in that file
Tokid(Fileid i,streampos l)71 	Tokid(Fileid i, streampos l) : fi(i), offs((cs_offset_t)l) {};
72 	// Construct it uninitialised to be filled-in later
Tokid()73 	Tokid() {}
74 	// Return a tokid that uniquely represents all same tokids coming from identical files
75 	// (The first element of the identical files set is invariant)
76 	Tokid unique() const;
77 	// Print it (for debugging)
78 	friend ostream& operator<<(ostream& o,const Tokid t);
79 	inline friend bool operator ==(const class Tokid a, const class Tokid b);
80 	inline friend bool operator !=(const class Tokid a, const class Tokid b);
81 	inline friend bool operator <(const class Tokid a, const class Tokid b);
82 	inline friend bool operator <=(const class Tokid a, const class Tokid b);
83 	inline friend bool operator >=(const class Tokid a, const class Tokid b);
84 	// Advance i character positions
85 	inline Tokid& operator +=(int i);
86 	inline friend Tokid operator +(const Tokid& a, int i);
87 	// Advance one position
88 	inline Tokid operator ++(int);		// Int signifies postfix (Str97 11.11 p. 292)
89 	// Return offset distance
90 	inline friend int operator -(const Tokid& a, const Tokid& b);
91 	// Return its equivalence class
92 	inline Eclass *get_ec() const;
93 	// Return its equivalence class or NULL if none
94 	inline Eclass *check_ec() const;
95 	// Set its equivalence class to ec (done when adding it to an Eclass)
96 	// use Eclass:add_tokid, not this method in all other contexts
97 	inline void set_ec(Eclass *ec) const;
98 	// Return an iterator for accessing the map or the end_ec() value
99 	inline mapTokidEclass::iterator find_ec() const;
100 	// The not-found value
101 	inline mapTokidEclass::iterator end_ec();
102 	// Erase the tokid's EC from the map
103 	inline void erase_ec(mapTokidEclass::iterator i) const;
104 	inline void erase_ec(Eclass *e) const;
105 	// Returns the Tokids participating in all ECs for a token of length l
106 	dequeTpart constituents(int l);
107 	// Set the Tokid's equivalence class attribute
108 	void set_ec_attribute(enum e_attribute a, int len) const;
109 	// Return true if one of the tokid's ECs has the specified attribute
110 	bool has_ec_attribute(enum e_attribute a, int l) const;
111 	// Clear the map of tokid equivalence classes
112 	static void clear();
113 	// Print the contents of the class map
114 	friend ostream& operator<<(ostream& o,const map <Tokid, Eclass *>& dummy);
115 	// Return true if the underlying file is read-only
get_readonly()116 	bool get_readonly() const { return fi.get_readonly(); }
117 	// Accessor functions
get_path()118 	inline const string& get_path() const { return fi.get_path(); }
get_fileid()119 	inline Fileid get_fileid() const { return fi; }
get_streampos()120 	inline streampos get_streampos() const { return (streampos)offs; }
map_size()121 	static map <Tokid, Eclass *>::size_type map_size() { return tm.size(); }
122 };
123 
124 // Print dequeTokid sequences
125 ostream& operator<<(ostream& o,const dequeTokid& dt);
126 
127 extern mapTokidEclass tokid_map;		// Dummy; used for printing
128 
129 inline Tokid
130 operator +(const Tokid& a, int i)
131 {
132 	Tokid r = a;
133 
134 	return (r += i);
135 }
136 
137 inline int
138 operator -(const Tokid& a, const Tokid &b)
139 {
140 	return (a.offs - b.offs);
141 }
142 
143 inline Tokid&
144 Tokid::operator +=(int i)
145 {
146 	offs += i;
147 	return (*this);
148 }
149 
150 inline Tokid
151 Tokid::operator ++(int dummy)
152 {
153 	offs++;
154 	return (*this);
155 }
156 
157 inline bool
158 operator ==(const class Tokid a, const class Tokid b)
159 {
160 	return (a.fi == b.fi && a.offs == b.offs);
161 }
162 
163 inline bool
164 operator !=(const class Tokid a, const class Tokid b)
165 {
166 	return (!(a == b));
167 }
168 
169 
170 inline bool
171 operator <(const class Tokid a, const class Tokid b)
172 {
173 	if (a.fi == b.fi)
174 		return (a.offs < b.offs);
175 	else
176 		return (a.fi < b.fi);
177 }
178 
179 inline bool
180 operator <=(const class Tokid a, const class Tokid b)
181 {
182 	return a < b || a == b;
183 }
184 
185 inline bool
186 operator >=(const class Tokid a, const class Tokid b)
187 {
188 	return b < a || a == b;
189 }
190 
191 inline Eclass *
get_ec()192 Tokid::get_ec() const
193 {
194 	return tm[*this];
195 }
196 
197 inline Eclass *
check_ec()198 Tokid::check_ec() const
199 {
200 	mapTokidEclass::const_iterator i = tm.find(*this);
201 	if (i == tm.end())
202 		return NULL;
203 	else
204 		return ((*i).second);
205 }
206 
207 inline void
set_ec(Eclass * ec)208 Tokid::set_ec(Eclass *ec) const
209 {
210 	/*
211 	 * tm[*this] = ec;
212 	 * Efficiently implement the functionality we need.
213 	 * See Meyers Effective STL, Item 24.
214 	 */
215 	mapTokidEclass::iterator i = tm.lower_bound(*this);
216 	if (i != tm.end() && i->first == *this)
217 		i->second = ec;
218 	else
219 		tm.insert(i, mapTokidEclass::value_type(*this, ec));
220 }
221 
222 inline void
erase_ec(mapTokidEclass::iterator i)223 Tokid::erase_ec(mapTokidEclass::iterator i) const
224 {
225 	tm.erase(i);
226 }
227 
228 inline void
erase_ec(Eclass * e)229 Tokid::erase_ec(Eclass *e) const
230 {
231 	mapTokidEclass::iterator i = tm.find(*this);
232 	csassert(i != tm.end());
233 	tm.erase(i);
234 }
235 
236 inline mapTokidEclass::iterator
find_ec()237 Tokid::find_ec() const
238 {
239 	return tm.find(*this);
240 }
241 
242 inline mapTokidEclass::iterator
end_ec()243 Tokid::end_ec()
244 {
245 	return tm.end();
246 }
247 #endif /* TOKID_ */
248