1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)pi.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include "error.h"
16
17 extern char *currentfilename;
18 static char *c_linenumber;
19 static char *unk_hdr[] = {"In", "program", "???"};
20 static char **c_header = &unk_hdr[0];
21
22 /*
23 * Attempt to handle error messages produced by pi (and by pc)
24 *
25 * problem #1: There is no file name available when a file does not
26 * use a #include; this will have to be given to error
27 * in the command line.
28 * problem #2: pi doesn't always tell you what line number
29 * a error refers to; for example during the tree
30 * walk phase of code generation and error detection,
31 * an error can refer to "variable foo in procedure bletch"
32 * without giving a line number
33 * problem #3: line numbers, when available, are attached to
34 * the source line, along with the source line itself
35 * These line numbers must be extracted, and
36 * the source line thrown away.
37 * problem #4: Some error messages produce more than one line number
38 * on the same message.
39 * There are only two (I think):
40 * %s undefined on line%s
41 * %s improperly used on line%s
42 * here, the %s makes line plural or singular.
43 *
44 * Here are the error strings used in pi version 1.2 that can refer
45 * to a file name or line number:
46 *
47 * Multiply defined label in case, lines %d and %d
48 * Goto %s from line %d is into a structured statement
49 * End matched %s on line %d
50 * Inserted keyword end matching %s on line %d
51 *
52 * Here are the general pi patterns recognized:
53 * define piptr == -.*^-.*
54 * define msg = .*
55 * define digit = [0-9]
56 * definename = .*
57 * define date_format letter*3 letter*3 (digit | (digit digit))
58 * (digit | (digit digit)):digit*2 digit*4
59 *
60 * {e,E} (piptr) (msg) Encounter an error during textual scan
61 * E {digit}* - (msg) Have an error message that refers to a new line
62 * E - msg Have an error message that refers to current
63 * function, program or procedure
64 * (date_format) (name): When switch compilation files
65 * ... (msg) When refer to the previous line
66 * 'In' ('procedure'|'function'|'program') (name):
67 * pi is now complaining about 2nd pass errors.
68 *
69 * Here is the output from a compilation
70 *
71 *
72 * 2 var i:integer;
73 * e --------------^--- Inserted ';'
74 * E 2 - All variables must be declared in one var part
75 * E 5 - Include filename must end in .i
76 * Mon Apr 21 15:56 1980 test.h:
77 * 2 begin
78 * e ------^--- Inserted ';'
79 * Mon Apr 21 16:06 1980 test.p:
80 * E 2 - Function type must be specified
81 * 6 procedure foo(var x:real);
82 * e ------^--- Inserted ';'
83 * In function bletch:
84 * E - No assignment to the function variable
85 * w - variable x is never used
86 * E 6 - foo is already defined in this block
87 * In procedure foo:
88 * w - variable x is neither used nor set
89 * 9 z : = 23;
90 * E --------------^--- Undefined variable
91 * 10 y = [1];
92 * e ----------------^--- Inserted ':'
93 * 13 z := 345.;
94 * e -----------------------^--- Digits required after decimal point
95 * E 10 - Constant set involved in non set context
96 * E 11 - Type clash: real is incompatible with integer
97 * ... Type of expression clashed with type of variable in assignment
98 * E 12 - Parameter type not identical to type of var parameter x of foo
99 * In program mung:
100 * w - variable y is never used
101 * w - type foo is never used
102 * w - function bletch is never used
103 * E - z undefined on lines 9 13
104 */
105 char *Months[] = {
106 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
107 "Jul", "Aug", "Sep", "Oct","Nov", "Dec",
108 0
109 };
110 char *Days[] = {
111 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0
112 };
113 char *Piroutines[] = {
114 "program", "function", "procedure", 0
115 };
116
117
118 static boolean structured, multiple;
119
120 char *pi_Endmatched[] = {"End", "matched"};
121 char *pi_Inserted[] = {"Inserted", "keyword", "end", "matching"};
122
123 char *pi_multiple[] = {"Mutiply", "defined", "label", "in", "case,", "line"};
124 char *pi_structured[] = {"is", "into", "a", "structured", "statement"};
125
126 char *pi_und1[] = {"undefined", "on", "line"};
127 char *pi_und2[] = {"undefined", "on", "lines"};
128 char *pi_imp1[] = {"improperly", "used", "on", "line"};
129 char *pi_imp2[] = {"improperly", "used", "on", "lines"};
130
alldigits(string)131 boolean alldigits(string)
132 reg char *string;
133 {
134 for (; *string && isdigit(*string); string++)
135 continue;
136 return(*string == '\0');
137 }
instringset(member,set)138 boolean instringset(member, set)
139 char *member;
140 reg char **set;
141 {
142 for(; *set; set++){
143 if (strcmp(*set, member) == 0)
144 return(TRUE);
145 }
146 return(FALSE);
147 }
148
isdateformat(wordc,wordv)149 boolean isdateformat(wordc, wordv)
150 int wordc;
151 char **wordv;
152 {
153 return(
154 (wordc == 5)
155 && (instringset(wordv[0], Days))
156 && (instringset(wordv[1], Months))
157 && (alldigits(wordv[2]))
158 && (alldigits(wordv[4])) );
159 }
160
piptr(string)161 boolean piptr(string)
162 reg char *string;
163 {
164 if (*string != '-')
165 return(FALSE);
166 while (*string && *string == '-')
167 string++;
168 if (*string != '^')
169 return(FALSE);
170 string++;
171 while (*string && *string == '-')
172 string++;
173 return(*string == '\0');
174 }
175
176 extern int wordc;
177 extern char **wordv;
178
pi()179 Errorclass pi()
180 {
181 char **nwordv;
182
183 if (wordc < 2)
184 return (C_UNKNOWN);
185 if ( ( strlen(wordv[1]) == 1)
186 && ( (wordv[1][0] == 'e') || (wordv[1][0] == 'E') )
187 && ( piptr(wordv[2]) )
188 ) {
189 boolean longpiptr = 0;
190 /*
191 * We have recognized a first pass error of the form:
192 * letter ------^---- message
193 *
194 * turn into an error message of the form:
195 *
196 * file line 'pascal errortype' letter \n |---- message
197 * or of the form:
198 * file line letter |---- message
199 * when there are strlen("(*[pi]") or more
200 * preceding '-' on the error pointer.
201 *
202 * Where the | is intended to be a down arrow, so that
203 * the pi error messages can be inserted above the
204 * line in error, instead of below. (All of the other
205 * langauges put thier messages before the source line,
206 * instead of after it as does pi.)
207 *
208 * where the pointer to the error has been truncated
209 * by 6 characters to account for the fact that
210 * the pointer points into a tab preceded input line.
211 */
212 language = INPI;
213 (void)substitute(wordv[2], '^', '|');
214 longpiptr = position(wordv[2],'|') > (6+8);
215 nwordv = wordvsplice(longpiptr ? 2 : 4, wordc, wordv+1);
216 nwordv[0] = strsave(currentfilename);
217 nwordv[1] = strsave(c_linenumber);
218 if (!longpiptr){
219 nwordv[2] = "pascal errortype";
220 nwordv[3] = wordv[1];
221 nwordv[4] = strsave("%%%\n");
222 if (strlen(nwordv[5]) > (8-2)) /* this is the pointer */
223 nwordv[5] += (8-2); /* bump over 6 characters */
224 }
225 wordv = nwordv - 1; /* convert to 1 based */
226 wordc += longpiptr ? 2 : 4;
227 return(C_TRUE);
228 }
229 if ( (wordc >= 4)
230 && (strlen(wordv[1]) == 1)
231 && ( (*wordv[1] == 'E') || (*wordv[1] == 'w') || (*wordv[1] == 'e') )
232 && (alldigits(wordv[2]))
233 && (strlen(wordv[3]) == 1)
234 && (wordv[3][0] == '-')
235 ){
236 /*
237 * Message of the form: letter linenumber - message
238 * Turn into form: filename linenumber letter - message
239 */
240 language = INPI;
241 nwordv = wordvsplice(1, wordc, wordv + 1);
242 nwordv[0] = strsave(currentfilename);
243 nwordv[1] = wordv[2];
244 nwordv[2] = wordv[1];
245 c_linenumber = wordv[2];
246 wordc += 1;
247 wordv = nwordv - 1;
248 return(C_TRUE);
249 }
250 if ( (wordc >= 3)
251 && (strlen(wordv[1]) == 1)
252 && ( (*(wordv[1]) == 'E') || (*(wordv[1]) == 'w') || (*(wordv[1]) == 'e') )
253 && (strlen(wordv[2]) == 1)
254 && (wordv[2][0] == '-')
255 ) {
256 /*
257 * Message of the form: letter - message
258 * This happens only when we are traversing the tree
259 * during the second pass of pi, and discover semantic
260 * errors.
261 *
262 * We have already (presumably) saved the header message
263 * and can now construct a nulled error message for the
264 * current file.
265 *
266 * Turns into a message of the form:
267 * filename (header) letter - message
268 *
269 * First, see if it is a message referring to more than
270 * one line number. Only of the form:
271 * %s undefined on line%s
272 * %s improperly used on line%s
273 */
274 boolean undefined = 0;
275 int wordindex;
276
277 language = INPI;
278 if ( (undefined = (wordvcmp(wordv+2, 3, pi_und1) == 0) )
279 || (undefined = (wordvcmp(wordv+2, 3, pi_und2) == 0) )
280 || (wordvcmp(wordv+2, 4, pi_imp1) == 0)
281 || (wordvcmp(wordv+2, 4, pi_imp2) == 0)
282 ){
283 for (wordindex = undefined ? 5 : 6; wordindex <= wordc;
284 wordindex++){
285 nwordv = wordvsplice(2, undefined ? 2 : 3, wordv+1);
286 nwordv[0] = strsave(currentfilename);
287 nwordv[1] = wordv[wordindex];
288 if (wordindex != wordc)
289 erroradd(undefined ? 4 : 5, nwordv,
290 C_TRUE, C_UNKNOWN);
291 }
292 wordc = undefined ? 4 : 5;
293 wordv = nwordv - 1;
294 return(C_TRUE);
295 }
296
297 nwordv = wordvsplice(1+3, wordc, wordv+1);
298 nwordv[0] = strsave(currentfilename);
299 nwordv[1] = strsave(c_header[0]);
300 nwordv[2] = strsave(c_header[1]);
301 nwordv[3] = strsave(c_header[2]);
302 wordv = nwordv - 1;
303 wordc += 1 + 3;
304 return(C_THISFILE);
305 }
306 if (strcmp(wordv[1], "...") == 0){
307 /*
308 * have a continuation error message
309 * of the form: ... message
310 * Turn into form : filename linenumber message
311 */
312 language = INPI;
313 nwordv = wordvsplice(1, wordc, wordv+1);
314 nwordv[0] = strsave(currentfilename);
315 nwordv[1] = strsave(c_linenumber);
316 wordv = nwordv - 1;
317 wordc += 1;
318 return(C_TRUE);
319 }
320 if( (wordc == 6)
321 && (lastchar(wordv[6]) == ':')
322 && (isdateformat(5, wordv + 1))
323 ){
324 /*
325 * Have message that tells us we have changed files
326 */
327 language = INPI;
328 currentfilename = strsave(wordv[6]);
329 clob_last(currentfilename, '\0');
330 return(C_SYNC);
331 }
332 if( (wordc == 3)
333 && (strcmp(wordv[1], "In") == 0)
334 && (lastchar(wordv[3]) == ':')
335 && (instringset(wordv[2], Piroutines))
336 ) {
337 language = INPI;
338 c_header = wordvsplice(0, wordc, wordv+1);
339 return(C_SYNC);
340 }
341 /*
342 * now, check for just the line number followed by the text
343 */
344 if (alldigits(wordv[1])){
345 language = INPI;
346 c_linenumber = wordv[1];
347 return(C_IGNORE);
348 }
349 /*
350 * Attempt to match messages refering to a line number
351 *
352 * Multiply defined label in case, lines %d and %d
353 * Goto %s from line %d is into a structured statement
354 * End matched %s on line %d
355 * Inserted keyword end matching %s on line %d
356 */
357 multiple = structured = 0;
358 if (
359 ( (wordc == 6) && (wordvcmp(wordv+1, 2, pi_Endmatched) == 0))
360 || ( (wordc == 8) && (wordvcmp(wordv+1, 4, pi_Inserted) == 0))
361 || ( multiple = ((wordc == 9) && (wordvcmp(wordv+1,6, pi_multiple) == 0) ) )
362 || ( structured = ((wordc == 10) && (wordvcmp(wordv+6,5, pi_structured) == 0 ) ))
363 ){
364 language = INPI;
365 nwordv = wordvsplice(2, wordc, wordv+1);
366 nwordv[0] = strsave(currentfilename);
367 nwordv[1] = structured ? wordv [5] : wordv[wordc];
368 wordc += 2;
369 wordv = nwordv - 1;
370 if (!multiple)
371 return(C_TRUE);
372 erroradd(wordc, nwordv, C_TRUE, C_UNKNOWN);
373 nwordv = wordvsplice(0, wordc, nwordv);
374 nwordv[1] = wordv[wordc - 2];
375 return(C_TRUE);
376 }
377 return(C_UNKNOWN);
378 }
379