Branch data Line data Source code
1 : : /* do not edit automatically generated by mc from M2Students. */
2 : : /* M2Students.mod checks for new programmer errors.
3 : :
4 : : Copyright (C) 2001-2024 Free Software Foundation, Inc.
5 : : Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 : :
7 : : This file is part of GNU Modula-2.
8 : :
9 : : GNU Modula-2 is free software; you can redistribute it and/or modify
10 : : it under the terms of the GNU General Public License as published by
11 : : the Free Software Foundation; either version 3, or (at your option)
12 : : any later version.
13 : :
14 : : GNU Modula-2 is distributed in the hope that it will be useful, but
15 : : WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : General Public License for more details.
18 : :
19 : : You should have received a copy of the GNU General Public License
20 : : along with GNU Modula-2; see the file COPYING3. If not see
21 : : <http://www.gnu.org/licenses/>. */
22 : :
23 : : #include "config.h"
24 : : #include "system.h"
25 : : #include "gcc-consolidation.h"
26 : :
27 : : #include <stdbool.h>
28 : : # if !defined (PROC_D)
29 : : # define PROC_D
30 : : typedef void (*PROC_t) (void);
31 : : typedef struct { PROC_t proc; } PROC;
32 : : # endif
33 : :
34 : : # if !defined (TRUE)
35 : : # define TRUE (1==1)
36 : : # endif
37 : :
38 : : # if !defined (FALSE)
39 : : # define FALSE (1==0)
40 : : # endif
41 : :
42 : : #define _M2Students_C
43 : :
44 : : #include "GM2Students.h"
45 : : # include "GSymbolTable.h"
46 : : # include "GNameKey.h"
47 : : # include "GM2MetaError.h"
48 : : # include "GLists.h"
49 : : # include "GM2Reserved.h"
50 : : # include "GDynamicStrings.h"
51 : : # include "GFormatStrings.h"
52 : : # include "GM2LexBuf.h"
53 : : # include "GASCII.h"
54 : : # include "GM2Options.h"
55 : :
56 : : static Lists_List ErrantNames;
57 : : static Lists_List ErrantSymbols;
58 : :
59 : : /*
60 : : CheckVariableAgainstKeyword - checks for a identifier that looks the same
61 : : as a keyword except for its case.
62 : : */
63 : :
64 : : extern "C" void M2Students_CheckVariableAgainstKeyword (NameKey_Name name);
65 : :
66 : : /*
67 : : StudentVariableCheck - checks to see that variables are quite different from keywords and
68 : : issues an message if they are not. It ignores case so to catch
69 : : 1st and 2nd semester programming errors.
70 : : */
71 : :
72 : : extern "C" void M2Students_StudentVariableCheck (void);
73 : :
74 : : /*
75 : : IsNotADuplicate - returns TRUE if either s1 or s2 have not been reported before.
76 : : */
77 : :
78 : : static bool IsNotADuplicate (unsigned int s1, unsigned int s2);
79 : :
80 : : /*
81 : : IsNotADuplicateName - returns TRUE if name has not been reported before.
82 : : */
83 : :
84 : : static bool IsNotADuplicateName (NameKey_Name name);
85 : :
86 : : /*
87 : : PerformVariableKeywordCheck - performs the check and constructs the metaerror notes if appropriate.
88 : : */
89 : :
90 : : static void PerformVariableKeywordCheck (NameKey_Name name);
91 : :
92 : : /*
93 : : CheckAsciiName - checks to see whether ascii names, s1, and, s2, are similar.
94 : : */
95 : :
96 : : static void CheckAsciiName (unsigned int previous, unsigned int s1, unsigned int newblock, unsigned int s2);
97 : :
98 : : /*
99 : : CheckProcedure - checks the procedure, p, for symbols which look like, s.
100 : : */
101 : :
102 : : static void CheckProcedure (unsigned int m, unsigned int p);
103 : :
104 : : /*
105 : : CheckModule - checks the module, m, for symbols which look like, s.
106 : : */
107 : :
108 : : static void CheckModule (unsigned int m, unsigned int s);
109 : :
110 : :
111 : : /*
112 : : IsNotADuplicate - returns TRUE if either s1 or s2 have not been reported before.
113 : : */
114 : :
115 : 0 : static bool IsNotADuplicate (unsigned int s1, unsigned int s2)
116 : : {
117 : 0 : if ((! (Lists_IsItemInList (ErrantSymbols, s1))) && (! (Lists_IsItemInList (ErrantSymbols, s2))))
118 : : {
119 : 0 : Lists_IncludeItemIntoList (ErrantSymbols, s1);
120 : 0 : Lists_IncludeItemIntoList (ErrantSymbols, s2);
121 : 0 : return true;
122 : : }
123 : : else
124 : : {
125 : 0 : return false;
126 : : }
127 : : /* static analysis guarentees a RETURN statement will be used before here. */
128 : : __builtin_unreachable ();
129 : : }
130 : :
131 : :
132 : : /*
133 : : IsNotADuplicateName - returns TRUE if name has not been reported before.
134 : : */
135 : :
136 : 0 : static bool IsNotADuplicateName (NameKey_Name name)
137 : : {
138 : 0 : if (! (Lists_IsItemInList (ErrantNames, name)))
139 : : {
140 : 0 : Lists_IncludeItemIntoList (ErrantNames, name);
141 : 0 : return true;
142 : : }
143 : : else
144 : : {
145 : : return false;
146 : : }
147 : : /* static analysis guarentees a RETURN statement will be used before here. */
148 : : __builtin_unreachable ();
149 : : }
150 : :
151 : :
152 : : /*
153 : : PerformVariableKeywordCheck - performs the check and constructs the metaerror notes if appropriate.
154 : : */
155 : :
156 : 0 : static void PerformVariableKeywordCheck (NameKey_Name name)
157 : : {
158 : 0 : NameKey_Name upper;
159 : 0 : M2Reserved_toktype token;
160 : 0 : DynamicStrings_String orig;
161 : 0 : DynamicStrings_String upperS;
162 : :
163 : 0 : orig = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (name));
164 : 0 : upperS = DynamicStrings_ToUpper (DynamicStrings_Dup (orig));
165 : 0 : upper = NameKey_makekey (DynamicStrings_string (upperS));
166 : 0 : if (M2Reserved_IsReserved (upper, &token))
167 : : {
168 : 0 : if (IsNotADuplicateName (name))
169 : : {
170 : 0 : M2MetaError_MetaErrorString0 (FormatStrings_Sprintf2 (DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "either the identifier has the same name as a keyword or alternatively a keyword has the wrong case ({%%K%s} and {!%%O:{%%K%s}})", 127)), (const unsigned char *) &upperS, (sizeof (upperS)-1), (const unsigned char *) &orig, (sizeof (orig)-1)));
171 : 0 : M2MetaError_MetaErrorString0 (FormatStrings_Sprintf1 (DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "the symbol name {!%%O:{%%K%s}} is legal as an identifier, however as such it might cause confusion and is considered bad programming practice", 141)), (const unsigned char *) &orig, (sizeof (orig)-1)));
172 : : }
173 : : }
174 : 0 : upperS = DynamicStrings_KillString (upperS);
175 : 0 : orig = DynamicStrings_KillString (orig);
176 : 0 : }
177 : :
178 : :
179 : : /*
180 : : CheckAsciiName - checks to see whether ascii names, s1, and, s2, are similar.
181 : : */
182 : :
183 : 0 : static void CheckAsciiName (unsigned int previous, unsigned int s1, unsigned int newblock, unsigned int s2)
184 : : {
185 : 0 : NameKey_Name a1;
186 : 0 : NameKey_Name a2;
187 : :
188 : 0 : a1 = SymbolTable_GetSymName (s1);
189 : 0 : a2 = SymbolTable_GetSymName (s2);
190 : 0 : if ((a1 == a2) && (a1 != NameKey_NulName))
191 : : {
192 : : /* avoid dangling else. */
193 : 0 : if (IsNotADuplicate (s1, s2))
194 : : {
195 : 0 : M2MetaError_MetaError2 ((const char *) "identical symbol name in two different scopes, scope {%1Oad} has symbol {%2Mad}", 79, previous, s1);
196 : 0 : M2MetaError_MetaError2 ((const char *) "identical symbol name in two different scopes, scope {%1Oad} has symbol {%2Mad}", 79, newblock, s2);
197 : : }
198 : : }
199 : 0 : else if (NameKey_IsSameExcludingCase (a1, a2))
200 : : {
201 : : /* avoid dangling else. */
202 : 0 : if (IsNotADuplicate (s1, s2))
203 : : {
204 : 0 : M2MetaError_MetaError2 ((const char *) "very similar symbol names (different case) in two different scopes, scope {%1ORad} has symbol {%2Mad}", 101, previous, s1);
205 : 0 : M2MetaError_MetaError2 ((const char *) "very similar symbol names (different case) in two different scopes, scope {%1OCad} has symbol {%2Mad}", 101, newblock, s2);
206 : : }
207 : : }
208 : 0 : }
209 : :
210 : :
211 : : /*
212 : : CheckProcedure - checks the procedure, p, for symbols which look like, s.
213 : : */
214 : :
215 : 0 : static void CheckProcedure (unsigned int m, unsigned int p)
216 : : {
217 : 0 : unsigned int i;
218 : 0 : unsigned int n1;
219 : 0 : unsigned int j;
220 : 0 : unsigned int n2;
221 : :
222 : 0 : if (p != SymbolTable_NulSym)
223 : : {
224 : : i = 1; /* I would have used NoOfParam(p)+1 but Stuart wants parameters checked as well - maybe he is right. */
225 : 0 : do { /* I would have used NoOfParam(p)+1 but Stuart wants parameters checked as well - maybe he is right. */
226 : 0 : n1 = SymbolTable_GetNth (p, i);
227 : 0 : if (n1 != SymbolTable_NulSym)
228 : : {
229 : 0 : if ((((SymbolTable_IsVar (n1)) || (SymbolTable_IsType (n1))) || (SymbolTable_IsProcedure (n1))) || (SymbolTable_IsRecord (n1)))
230 : : {
231 : : j = 1;
232 : 0 : do {
233 : 0 : n2 = SymbolTable_GetNth (m, j);
234 : 0 : if (n2 != SymbolTable_NulSym)
235 : : {
236 : 0 : if ((((SymbolTable_IsVar (n2)) || (SymbolTable_IsType (n2))) || (SymbolTable_IsProcedure (n2))) || (SymbolTable_IsRecord (n2)))
237 : : {
238 : 0 : CheckAsciiName (m, n2, p, n1);
239 : : }
240 : : }
241 : 0 : j += 1;
242 : 0 : } while (! (n2 == SymbolTable_NulSym));
243 : : }
244 : : }
245 : 0 : i += 1;
246 : 0 : } while (! (n1 == SymbolTable_NulSym));
247 : : }
248 : 0 : }
249 : :
250 : :
251 : : /*
252 : : CheckModule - checks the module, m, for symbols which look like, s.
253 : : */
254 : :
255 : 0 : static void CheckModule (unsigned int m, unsigned int s)
256 : : {
257 : 0 : unsigned int i;
258 : 0 : unsigned int n;
259 : :
260 : 0 : if (m != SymbolTable_NulSym)
261 : : {
262 : : i = 1;
263 : 0 : do {
264 : 0 : n = SymbolTable_GetNth (m, i);
265 : 0 : if (n != SymbolTable_NulSym)
266 : : {
267 : 0 : if ((n != SymbolTable_NulSym) && (n != s))
268 : : {
269 : 0 : if ((((SymbolTable_IsVar (n)) || (SymbolTable_IsType (n))) || (SymbolTable_IsProcedure (n))) || (SymbolTable_IsRecord (n)))
270 : : {
271 : 0 : CheckAsciiName (m, s, m, n);
272 : : }
273 : : }
274 : : }
275 : 0 : i += 1;
276 : 0 : } while (! (n == SymbolTable_NulSym));
277 : : }
278 : 0 : }
279 : :
280 : :
281 : : /*
282 : : CheckVariableAgainstKeyword - checks for a identifier that looks the same
283 : : as a keyword except for its case.
284 : : */
285 : :
286 : 934894 : extern "C" void M2Students_CheckVariableAgainstKeyword (NameKey_Name name)
287 : : {
288 : 934894 : if (M2Options_StyleChecking)
289 : : {
290 : 0 : PerformVariableKeywordCheck (name);
291 : : }
292 : 934894 : }
293 : :
294 : :
295 : : /*
296 : : StudentVariableCheck - checks to see that variables are quite different from keywords and
297 : : issues an message if they are not. It ignores case so to catch
298 : : 1st and 2nd semester programming errors.
299 : : */
300 : :
301 : 0 : extern "C" void M2Students_StudentVariableCheck (void)
302 : : {
303 : 0 : unsigned int i;
304 : 0 : unsigned int n;
305 : 0 : unsigned int m;
306 : :
307 : 0 : m = SymbolTable_GetMainModule ();
308 : : /* first check global scope */
309 : 0 : i = 1;
310 : 0 : do {
311 : 0 : n = SymbolTable_GetNth (m, i);
312 : 0 : if (n != SymbolTable_NulSym)
313 : : {
314 : 0 : if ((((SymbolTable_IsVar (n)) || (SymbolTable_IsType (n))) || (SymbolTable_IsProcedure (n))) || (SymbolTable_IsRecord (n)))
315 : : {
316 : 0 : CheckModule (m, n);
317 : : }
318 : : }
319 : 0 : i += 1;
320 : 0 : } while (! (n == SymbolTable_NulSym));
321 : : /* now check local scope */
322 : : i = 1;
323 : 0 : do {
324 : 0 : n = SymbolTable_GetNthProcedure (m, i);
325 : 0 : if (n != SymbolTable_NulSym)
326 : : {
327 : 0 : if (SymbolTable_IsProcedure (n))
328 : : {
329 : 0 : CheckProcedure (m, n);
330 : : }
331 : : }
332 : 0 : i += 1;
333 : 0 : } while (! (n == SymbolTable_NulSym));
334 : 0 : }
335 : :
336 : 14232 : extern "C" void _M2_M2Students_init (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
337 : : {
338 : 14232 : Lists_InitList (&ErrantSymbols);
339 : 14232 : Lists_InitList (&ErrantNames);
340 : 14232 : }
341 : :
342 : 0 : extern "C" void _M2_M2Students_fini (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
343 : : {
344 : 0 : }
|