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