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