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