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
8: static char sccsid[] = "@(#)errorpi.c 5.1 (Berkeley) 5/31/85";
9: #endif not lint
10:
11: #include <stdio.h>
12: #include <ctype.h>
13: #include "error.h"
14:
15: extern char *currentfilename;
16: static char *c_linenumber;
17: static char *unk_hdr[] = {"In", "program", "???"};
18: static char ** = &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: */
103: char *Months[] = {
104: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
105: "Jul", "Aug", "Sep", "Oct","Nov", "Dec",
106: 0
107: };
108: char *Days[] = {
109: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0
110: };
111: char *Piroutines[] = {
112: "program", "function", "procedure", 0
113: };
114:
115:
116: static boolean structured, multiple;
117:
118: char *pi_Endmatched[] = {"End", "matched"};
119: char *pi_Inserted[] = {"Inserted", "keyword", "end", "matching"};
120:
121: char *pi_multiple[] = {"Mutiply", "defined", "label", "in", "case,", "line"};
122: char *pi_structured[] = {"is", "into", "a", "structured", "statement"};
123:
124: char *pi_und1[] = {"undefined", "on", "line"};
125: char *pi_und2[] = {"undefined", "on", "lines"};
126: char *pi_imp1[] = {"improperly", "used", "on", "line"};
127: char *pi_imp2[] = {"improperly", "used", "on", "lines"};
128:
129: boolean alldigits(string)
130: reg char *string;
131: {
132: for (; *string && isdigit(*string); string++)
133: continue;
134: return(*string == '\0');
135: }
136: boolean instringset(member, set)
137: char *member;
138: reg char **set;
139: {
140: for(; *set; set++){
141: if (strcmp(*set, member) == 0)
142: return(TRUE);
143: }
144: return(FALSE);
145: }
146:
147: boolean 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:
159: boolean piptr(string)
160: reg char *string;
161: {
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:
174: extern int wordc;
175: extern char **wordv;
176:
177: Errorclass pi()
178: {
179: char **nwordv;
180:
181: if (wordc < 2)
182: return (C_UNKNOWN);
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;
211: (void)substitute(wordv[2], '^', '|');
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: }