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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 /* 29 * University Copyright- Copyright (c) 1982, 1986, 1988 30 * The Regents of the University of California 31 * All Rights Reserved 32 * 33 * University Acknowledgment- Portions of this document are derived from 34 * software developed by the University of California, Berkeley, and its 35 * contributors. 36 */ 37 38 /* 39 * rpc_scan.c, Scanner for the RPC protocol compiler 40 */ 41 42 #include <sys/wait.h> 43 #include <stdio.h> 44 #include <ctype.h> 45 #include <string.h> 46 #include <strings.h> 47 #include "rpc_scan.h" 48 #include "rpc_parse.h" 49 #include "rpc_util.h" 50 51 #define startcomment(where) (where[0] == '/' && where[1] == '*') 52 #define endcomment(where) (where[-1] == '*' && where[0] == '/') 53 54 static int pushed = 0; /* is a token pushed */ 55 static token lasttok; /* last token, if pushed */ 56 57 static void unget_token(token *); 58 static void findstrconst(char **, char **); 59 static void findchrconst(char **, char **); 60 static void findconst(char **, char **); 61 static void findkind(char **, token *); 62 static int cppline(char *); 63 static int directive(char *); 64 static void printdirective(char *); 65 static void docppline(char *, int *, char **); 66 67 /* 68 * scan expecting 1 given token 69 */ 70 void 71 scan(tok_kind expect, token *tokp) 72 { 73 get_token(tokp); 74 if (tokp->kind != expect) 75 expected1(expect); 76 } 77 78 /* 79 * scan expecting any of the 2 given tokens 80 */ 81 void 82 scan2(tok_kind expect1, tok_kind expect2, token *tokp) 83 { 84 get_token(tokp); 85 if (tokp->kind != expect1 && tokp->kind != expect2) 86 expected2(expect1, expect2); 87 } 88 89 /* 90 * scan expecting any of the 3 given token 91 */ 92 void 93 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp) 94 { 95 get_token(tokp); 96 if (tokp->kind != expect1 && tokp->kind != expect2 && 97 tokp->kind != expect3) 98 expected3(expect1, expect2, expect3); 99 } 100 101 /* 102 * scan expecting a constant, possibly symbolic 103 */ 104 void 105 scan_num(token *tokp) 106 { 107 get_token(tokp); 108 switch (tokp->kind) { 109 case TOK_IDENT: 110 break; 111 default: 112 error("constant or identifier expected"); 113 } 114 } 115 116 /* 117 * Peek at the next token 118 */ 119 void 120 peek(token *tokp) 121 { 122 get_token(tokp); 123 unget_token(tokp); 124 } 125 126 /* 127 * Peek at the next token and scan it if it matches what you expect 128 */ 129 int 130 peekscan(tok_kind expect, token *tokp) 131 { 132 peek(tokp); 133 if (tokp->kind == expect) { 134 get_token(tokp); 135 return (1); 136 } 137 return (0); 138 } 139 140 /* 141 * Get the next token, printing out any directive that are encountered. 142 */ 143 void 144 get_token(token *tokp) 145 { 146 int commenting; 147 int stat = 0; 148 149 if (pushed) { 150 pushed = 0; 151 *tokp = lasttok; 152 return; 153 } 154 commenting = 0; 155 for (;;) { 156 if (*where == 0) { 157 for (;;) { 158 if (!fgets(curline, MAXLINESIZE, fin)) { 159 tokp->kind = TOK_EOF; 160 /* 161 * now check if cpp returned 162 * non NULL value 163 */ 164 (void) waitpid(childpid, &stat, 165 WUNTRACED); 166 if (stat > 0) { 167 /* Set return value from rpcgen */ 168 nonfatalerrors = stat >> 8; 169 } 170 *where = 0; 171 return; 172 } 173 linenum++; 174 if (commenting) { 175 break; 176 } else if (cppline(curline)) { 177 docppline(curline, &linenum, 178 &infilename); 179 } else if (directive(curline)) { 180 printdirective(curline); 181 } else { 182 break; 183 } 184 } 185 where = curline; 186 } else if (isspace(*where)) { 187 while (isspace(*where)) { 188 where++; /* eat */ 189 } 190 } else if (commenting) { 191 for (where++; *where; where++) { 192 if (endcomment(where)) { 193 where++; 194 commenting--; 195 break; 196 } 197 } 198 } else if (startcomment(where)) { 199 where += 2; 200 commenting++; 201 } else { 202 break; 203 } 204 } 205 206 /* 207 * 'where' is not whitespace, comment or directive Must be a token! 208 */ 209 switch (*where) { 210 case ':': 211 tokp->kind = TOK_COLON; 212 where++; 213 break; 214 case ';': 215 tokp->kind = TOK_SEMICOLON; 216 where++; 217 break; 218 case ',': 219 tokp->kind = TOK_COMMA; 220 where++; 221 break; 222 case '=': 223 tokp->kind = TOK_EQUAL; 224 where++; 225 break; 226 case '*': 227 tokp->kind = TOK_STAR; 228 where++; 229 break; 230 case '[': 231 tokp->kind = TOK_LBRACKET; 232 where++; 233 break; 234 case ']': 235 tokp->kind = TOK_RBRACKET; 236 where++; 237 break; 238 case '{': 239 tokp->kind = TOK_LBRACE; 240 where++; 241 break; 242 case '}': 243 tokp->kind = TOK_RBRACE; 244 where++; 245 break; 246 case '(': 247 tokp->kind = TOK_LPAREN; 248 where++; 249 break; 250 case ')': 251 tokp->kind = TOK_RPAREN; 252 where++; 253 break; 254 case '<': 255 tokp->kind = TOK_LANGLE; 256 where++; 257 break; 258 case '>': 259 tokp->kind = TOK_RANGLE; 260 where++; 261 break; 262 263 case '"': 264 tokp->kind = TOK_STRCONST; 265 findstrconst(&where, &tokp->str); 266 break; 267 case '\'': 268 tokp->kind = TOK_CHARCONST; 269 findchrconst(&where, &tokp->str); 270 break; 271 272 case '-': 273 case '0': 274 case '1': 275 case '2': 276 case '3': 277 case '4': 278 case '5': 279 case '6': 280 case '7': 281 case '8': 282 case '9': 283 tokp->kind = TOK_IDENT; 284 findconst(&where, &tokp->str); 285 break; 286 287 default: 288 if (!(isalpha(*where) || *where == '_')) { 289 char buf[100]; 290 char *p; 291 size_t blen; 292 293 (void) snprintf(buf, sizeof (buf), 294 "illegal character in file: "); 295 blen = strlen(buf); 296 p = buf + blen; 297 if (isprint(*where)) { 298 (void) snprintf(p, sizeof (buf) - blen, 299 "%c", *where); 300 } else { 301 (void) snprintf(p, sizeof (buf) - blen, 302 "%d", *where); 303 } 304 error(buf); 305 } 306 findkind(&where, tokp); 307 break; 308 } 309 } 310 311 static void 312 unget_token(token *tokp) 313 { 314 lasttok = *tokp; 315 pushed = 1; 316 } 317 318 static void 319 findstrconst(char **str, char **val) 320 { 321 char *p; 322 int size; 323 324 p = *str; 325 do { 326 p++; 327 } while (*p && *p != '"'); 328 if (*p == 0) { 329 error("unterminated string constant"); 330 } 331 p++; 332 size = p - *str; 333 *val = malloc(size + 1); 334 (void) strncpy(*val, *str, size); 335 (*val)[size] = 0; 336 *str = p; 337 } 338 339 static void 340 findchrconst(char **str, char **val) 341 { 342 char *p; 343 int size; 344 345 p = *str; 346 do { 347 p++; 348 } while (*p && *p != '\''); 349 if (*p == 0) 350 error("unterminated string constant"); 351 p++; 352 size = p - *str; 353 if (size != 3) 354 error("empty char string"); 355 *val = malloc(size + 1); 356 (void) strncpy(*val, *str, size); 357 (*val)[size] = 0; 358 *str = p; 359 } 360 361 static void 362 findconst(char **str, char **val) 363 { 364 char *p; 365 int size; 366 367 p = *str; 368 if (*p == '0' && *(p + 1) == 'x') { 369 p++; 370 do { 371 p++; 372 } while (isxdigit(*p)); 373 } else { 374 do { 375 p++; 376 } while (isdigit(*p)); 377 } 378 size = p - *str; 379 *val = malloc(size + 1); 380 (void) strncpy(*val, *str, size); 381 (*val)[size] = 0; 382 *str = p; 383 } 384 385 static token symbols[] = { 386 {TOK_CONST, "const"}, 387 {TOK_UNION, "union"}, 388 {TOK_SWITCH, "switch"}, 389 {TOK_CASE, "case"}, 390 {TOK_DEFAULT, "default"}, 391 {TOK_STRUCT, "struct"}, 392 {TOK_TYPEDEF, "typedef"}, 393 {TOK_ENUM, "enum"}, 394 {TOK_OPAQUE, "opaque"}, 395 {TOK_BOOL, "bool"}, 396 {TOK_VOID, "void"}, 397 {TOK_ONEWAY, "oneway"}, 398 {TOK_CHAR, "char"}, 399 {TOK_INT, "int"}, 400 {TOK_UNSIGNED, "unsigned"}, 401 {TOK_SHORT, "short"}, 402 {TOK_LONG, "long"}, 403 {TOK_HYPER, "hyper"}, 404 {TOK_FLOAT, "float"}, 405 {TOK_DOUBLE, "double"}, 406 {TOK_QUAD, "quadruple"}, 407 {TOK_STRING, "string"}, 408 {TOK_PROGRAM, "program"}, 409 {TOK_VERSION, "version"}, 410 {TOK_EOF, "??????"}, 411 }; 412 413 static void 414 findkind(char **mark, token *tokp) 415 { 416 int len; 417 token *s; 418 char *str; 419 420 str = *mark; 421 for (s = symbols; s->kind != TOK_EOF; s++) { 422 len = strlen(s->str); 423 if (strncmp(str, s->str, len) == 0) { 424 if (!isalnum(str[len]) && str[len] != '_') { 425 tokp->kind = s->kind; 426 tokp->str = s->str; 427 *mark = str + len; 428 return; 429 } 430 } 431 } 432 tokp->kind = TOK_IDENT; 433 for (len = 0; isalnum(str[len]) || str[len] == '_'; len++) 434 /* LOOP */; 435 tokp->str = malloc(len + 1); 436 (void) strncpy(tokp->str, str, len); 437 tokp->str[len] = 0; 438 *mark = str + len; 439 } 440 441 static int 442 cppline(char *line) 443 { 444 return (line == curline && *line == '#'); 445 } 446 447 static int 448 directive(char *line) 449 { 450 return (line == curline && *line == '%'); 451 } 452 453 static void 454 printdirective(char *line) 455 { 456 f_print(fout, "%s", line + 1); 457 } 458 459 static void 460 docppline(char *line, int *lineno, char **fname) 461 { 462 char *file; 463 int num; 464 char *p; 465 466 line++; 467 while (isspace(*line)) 468 line++; 469 num = atoi(line); 470 while (isdigit(*line)) 471 line++; 472 while (isspace(*line)) 473 line++; 474 if (*line != '"') 475 error("preprocessor error"); 476 line++; 477 p = file = malloc(strlen(line) + 1); 478 while (*line && *line != '"') 479 *p++ = *line++; 480 if (*line == 0) 481 error("preprocessor error"); 482 *p = 0; 483 if (*file == 0) 484 *fname = NULL; 485 else 486 *fname = file; 487 *lineno = num - 1; 488 } 489