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 <stdbool.h>
26 : : # if !defined (PROC_D)
27 : : # define PROC_D
28 : : typedef void (*PROC_t) (void);
29 : : typedef struct { PROC_t proc; } PROC;
30 : : # endif
31 : :
32 : : # if !defined (TRUE)
33 : : # define TRUE (1==1)
34 : : # endif
35 : :
36 : : # if !defined (FALSE)
37 : : # define FALSE (1==0)
38 : : # endif
39 : :
40 : : #define _M2Students_H
41 : : #define _M2Students_C
42 : :
43 : : # include "GSymbolTable.h"
44 : : # include "GNameKey.h"
45 : : # include "GM2MetaError.h"
46 : : # include "GLists.h"
47 : : # include "GM2Reserved.h"
48 : : # include "GDynamicStrings.h"
49 : : # include "GFormatStrings.h"
50 : : # include "GM2LexBuf.h"
51 : : # include "GASCII.h"
52 : : # include "GM2Options.h"
53 : :
54 : : static Lists_List ErrantNames;
55 : : static Lists_List ErrantSymbols;
56 : :
57 : : /*
58 : : CheckForVariableThatLooksLikeKeyword - checks for a identifier that looks the same
59 : : as a keyword except for its case.
60 : : */
61 : :
62 : : extern "C" void M2Students_CheckForVariableThatLooksLikeKeyword (NameKey_Name name);
63 : :
64 : : /*
65 : : StudentVariableCheck - checks to see that variables are quite different from keywords and
66 : : issues an message if they are not. It ignores case so to catch
67 : : 1st and 2nd semester programming errors.
68 : : */
69 : :
70 : : extern "C" void M2Students_StudentVariableCheck (void);
71 : :
72 : : /*
73 : : IsNotADuplicate - returns TRUE if either s1 or s2 have not been reported before.
74 : : */
75 : :
76 : : static bool IsNotADuplicate (unsigned int s1, unsigned int s2);
77 : :
78 : : /*
79 : : IsNotADuplicateName - returns TRUE if name has not been reported before.
80 : : */
81 : :
82 : : static bool IsNotADuplicateName (NameKey_Name name);
83 : :
84 : : /*
85 : : PerformVariableKeywordCheck - performs the check and constructs the metaerror notes if appropriate.
86 : : */
87 : :
88 : : static void PerformVariableKeywordCheck (NameKey_Name name);
89 : :
90 : : /*
91 : : CheckAsciiName - checks to see whether ascii names, s1, and, s2, are similar.
92 : : */
93 : :
94 : : static void CheckAsciiName (unsigned int previous, unsigned int s1, unsigned int newblock, unsigned int s2);
95 : :
96 : : /*
97 : : CheckProcedure - checks the procedure, p, for symbols which look like, s.
98 : : */
99 : :
100 : : static void CheckProcedure (unsigned int m, unsigned int p);
101 : :
102 : : /*
103 : : CheckModule - checks the module, m, for symbols which look like, s.
104 : : */
105 : :
106 : : static void CheckModule (unsigned int m, unsigned int s);
107 : :
108 : :
109 : : /*
110 : : IsNotADuplicate - returns TRUE if either s1 or s2 have not been reported before.
111 : : */
112 : :
113 : 0 : static bool IsNotADuplicate (unsigned int s1, unsigned int s2)
114 : : {
115 : 0 : if ((! (Lists_IsItemInList (ErrantSymbols, s1))) && (! (Lists_IsItemInList (ErrantSymbols, s2))))
116 : : {
117 : 0 : Lists_IncludeItemIntoList (ErrantSymbols, s1);
118 : 0 : Lists_IncludeItemIntoList (ErrantSymbols, s2);
119 : 0 : return true;
120 : : }
121 : : else
122 : : {
123 : 0 : return false;
124 : : }
125 : : /* static analysis guarentees a RETURN statement will be used before here. */
126 : : __builtin_unreachable ();
127 : : }
128 : :
129 : :
130 : : /*
131 : : IsNotADuplicateName - returns TRUE if name has not been reported before.
132 : : */
133 : :
134 : 0 : static bool IsNotADuplicateName (NameKey_Name name)
135 : : {
136 : 0 : if (! (Lists_IsItemInList (ErrantNames, name)))
137 : : {
138 : 0 : Lists_IncludeItemIntoList (ErrantNames, name);
139 : 0 : return true;
140 : : }
141 : : else
142 : : {
143 : : return false;
144 : : }
145 : : /* static analysis guarentees a RETURN statement will be used before here. */
146 : : __builtin_unreachable ();
147 : : }
148 : :
149 : :
150 : : /*
151 : : PerformVariableKeywordCheck - performs the check and constructs the metaerror notes if appropriate.
152 : : */
153 : :
154 : 0 : static void PerformVariableKeywordCheck (NameKey_Name name)
155 : : {
156 : 0 : NameKey_Name upper;
157 : 0 : M2Reserved_toktype token;
158 : 0 : DynamicStrings_String orig;
159 : 0 : DynamicStrings_String upperS;
160 : :
161 : 0 : orig = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (name));
162 : 0 : upperS = DynamicStrings_ToUpper (DynamicStrings_Dup (orig));
163 : 0 : upper = NameKey_makekey (DynamicStrings_string (upperS));
164 : 0 : if (M2Reserved_IsReserved (upper, &token))
165 : : {
166 : 0 : if (IsNotADuplicateName (name))
167 : : {
168 : 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)));
169 : 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)));
170 : : }
171 : : }
172 : 0 : upperS = DynamicStrings_KillString (upperS);
173 : 0 : orig = DynamicStrings_KillString (orig);
174 : 0 : }
175 : :
176 : :
177 : : /*
178 : : CheckAsciiName - checks to see whether ascii names, s1, and, s2, are similar.
179 : : */
180 : :
181 : 0 : static void CheckAsciiName (unsigned int previous, unsigned int s1, unsigned int newblock, unsigned int s2)
182 : : {
183 : 0 : NameKey_Name a1;
184 : 0 : NameKey_Name a2;
185 : :
186 : 0 : a1 = SymbolTable_GetSymName (s1);
187 : 0 : a2 = SymbolTable_GetSymName (s2);
188 : 0 : if ((a1 == a2) && (a1 != NameKey_NulName))
189 : : {
190 : : /* avoid dangling else. */
191 : 0 : if (IsNotADuplicate (s1, s2))
192 : : {
193 : 0 : M2MetaError_MetaError2 ((const char *) "identical symbol name in two different scopes, scope {%1Oad} has symbol {%2Mad}", 79, previous, s1);
194 : 0 : M2MetaError_MetaError2 ((const char *) "identical symbol name in two different scopes, scope {%1Oad} has symbol {%2Mad}", 79, newblock, s2);
195 : : }
196 : : }
197 : 0 : else if (NameKey_IsSameExcludingCase (a1, a2))
198 : : {
199 : : /* avoid dangling else. */
200 : 0 : if (IsNotADuplicate (s1, s2))
201 : : {
202 : 0 : M2MetaError_MetaError2 ((const char *) "very similar symbol names (different case) in two different scopes, scope {%1ORad} has symbol {%2Mad}", 101, previous, s1);
203 : 0 : M2MetaError_MetaError2 ((const char *) "very similar symbol names (different case) in two different scopes, scope {%1OCad} has symbol {%2Mad}", 101, newblock, s2);
204 : : }
205 : : }
206 : 0 : }
207 : :
208 : :
209 : : /*
210 : : CheckProcedure - checks the procedure, p, for symbols which look like, s.
211 : : */
212 : :
213 : 0 : static void CheckProcedure (unsigned int m, unsigned int p)
214 : : {
215 : 0 : unsigned int i;
216 : 0 : unsigned int n1;
217 : 0 : unsigned int j;
218 : 0 : unsigned int n2;
219 : :
220 : 0 : if (p != SymbolTable_NulSym)
221 : : {
222 : : i = 1; /* I would have used NoOfParam(p)+1 but Stuart wants parameters checked as well - maybe he is right. */
223 : 0 : do { /* I would have used NoOfParam(p)+1 but Stuart wants parameters checked as well - maybe he is right. */
224 : 0 : n1 = SymbolTable_GetNth (p, i);
225 : 0 : if (n1 != SymbolTable_NulSym)
226 : : {
227 : 0 : if ((((SymbolTable_IsVar (n1)) || (SymbolTable_IsType (n1))) || (SymbolTable_IsProcedure (n1))) || (SymbolTable_IsRecord (n1)))
228 : : {
229 : : j = 1;
230 : 0 : do {
231 : 0 : n2 = SymbolTable_GetNth (m, j);
232 : 0 : if (n2 != SymbolTable_NulSym)
233 : : {
234 : 0 : if ((((SymbolTable_IsVar (n2)) || (SymbolTable_IsType (n2))) || (SymbolTable_IsProcedure (n2))) || (SymbolTable_IsRecord (n2)))
235 : : {
236 : 0 : CheckAsciiName (m, n2, p, n1);
237 : : }
238 : : }
239 : 0 : j += 1;
240 : 0 : } while (! (n2 == SymbolTable_NulSym));
241 : : }
242 : : }
243 : 0 : i += 1;
244 : 0 : } while (! (n1 == SymbolTable_NulSym));
245 : : }
246 : 0 : }
247 : :
248 : :
249 : : /*
250 : : CheckModule - checks the module, m, for symbols which look like, s.
251 : : */
252 : :
253 : 0 : static void CheckModule (unsigned int m, unsigned int s)
254 : : {
255 : 0 : unsigned int i;
256 : 0 : unsigned int n;
257 : :
258 : 0 : if (m != SymbolTable_NulSym)
259 : : {
260 : : i = 1;
261 : 0 : do {
262 : 0 : n = SymbolTable_GetNth (m, i);
263 : 0 : if (n != SymbolTable_NulSym)
264 : : {
265 : 0 : if ((n != SymbolTable_NulSym) && (n != s))
266 : : {
267 : 0 : if ((((SymbolTable_IsVar (n)) || (SymbolTable_IsType (n))) || (SymbolTable_IsProcedure (n))) || (SymbolTable_IsRecord (n)))
268 : : {
269 : 0 : CheckAsciiName (m, s, m, n);
270 : : }
271 : : }
272 : : }
273 : 0 : i += 1;
274 : 0 : } while (! (n == SymbolTable_NulSym));
275 : : }
276 : 0 : }
277 : :
278 : :
279 : : /*
280 : : CheckForVariableThatLooksLikeKeyword - checks for a identifier that looks the same
281 : : as a keyword except for its case.
282 : : */
283 : :
284 : 893099 : extern "C" void M2Students_CheckForVariableThatLooksLikeKeyword (NameKey_Name name)
285 : : {
286 : 893099 : if (M2Options_StyleChecking)
287 : : {
288 : 0 : PerformVariableKeywordCheck (name);
289 : : }
290 : 893099 : }
291 : :
292 : :
293 : : /*
294 : : StudentVariableCheck - checks to see that variables are quite different from keywords and
295 : : issues an message if they are not. It ignores case so to catch
296 : : 1st and 2nd semester programming errors.
297 : : */
298 : :
299 : 0 : extern "C" void M2Students_StudentVariableCheck (void)
300 : : {
301 : 0 : unsigned int i;
302 : 0 : unsigned int n;
303 : 0 : unsigned int m;
304 : :
305 : 0 : m = SymbolTable_GetMainModule ();
306 : : /* first check global scope */
307 : 0 : i = 1;
308 : 0 : do {
309 : 0 : n = SymbolTable_GetNth (m, i);
310 : 0 : if (n != SymbolTable_NulSym)
311 : : {
312 : 0 : if ((((SymbolTable_IsVar (n)) || (SymbolTable_IsType (n))) || (SymbolTable_IsProcedure (n))) || (SymbolTable_IsRecord (n)))
313 : : {
314 : 0 : CheckModule (m, n);
315 : : }
316 : : }
317 : 0 : i += 1;
318 : 0 : } while (! (n == SymbolTable_NulSym));
319 : : /* now check local scope */
320 : : i = 1;
321 : 0 : do {
322 : 0 : n = SymbolTable_GetNthProcedure (m, i);
323 : 0 : if (n != SymbolTable_NulSym)
324 : : {
325 : 0 : if (SymbolTable_IsProcedure (n))
326 : : {
327 : 0 : CheckProcedure (m, n);
328 : : }
329 : : }
330 : 0 : i += 1;
331 : 0 : } while (! (n == SymbolTable_NulSym));
332 : 0 : }
333 : :
334 : 16817 : extern "C" void _M2_M2Students_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
335 : : {
336 : 16817 : Lists_InitList (&ErrantSymbols);
337 : 16817 : Lists_InitList (&ErrantNames);
338 : 16817 : }
339 : :
340 : 0 : extern "C" void _M2_M2Students_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
341 : : {
342 : 0 : }
|