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