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