1 /* $OpenBSD: rpc_scan.c,v 1.15 2010/09/01 14:43:34 millert Exp $ */ 2 /* $NetBSD: rpc_scan.c,v 1.4 1995/06/11 21:50:02 pk Exp $ */ 3 4 /* 5 * Copyright (c) 2010, Oracle America, Inc. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials 16 * provided with the distribution. 17 * * Neither the name of the "Oracle America, Inc." nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * rpc_scan.c, Scanner for the RPC protocol compiler 37 */ 38 #include <sys/cdefs.h> 39 #include <stdlib.h> 40 #include <stdio.h> 41 #include <ctype.h> 42 #include <string.h> 43 #include "rpc_scan.h" 44 #include "rpc_parse.h" 45 #include "rpc_util.h" 46 47 static void unget_token(token *tokp); 48 static void findstrconst(char **, char **); 49 static void findchrconst(char **, char **); 50 static void findconst(char **, char **); 51 static void findkind(char **, token *); 52 static int cppline(char *); 53 static int directive(char *); 54 static void printdirective(char *); 55 static void docppline(char *, int *, char **); 56 57 #define startcomment(where) (where[0] == '/' && where[1] == '*') 58 #define endcomment(where) (where[-1] == '*' && where[0] == '/') 59 60 static int pushed = 0; /* is a token pushed */ 61 static token lasttok; /* last token, if pushed */ 62 63 /* 64 * scan expecting 1 given token 65 */ 66 void 67 scan(expect, tokp) 68 tok_kind expect; 69 token *tokp; 70 { 71 get_token(tokp); 72 if (tokp->kind != expect) 73 expected1(expect); 74 } 75 76 /* 77 * scan expecting any of the 2 given tokens 78 */ 79 void 80 scan2(expect1, expect2, tokp) 81 tok_kind expect1; 82 tok_kind expect2; 83 token *tokp; 84 { 85 get_token(tokp); 86 if (tokp->kind != expect1 && tokp->kind != expect2) 87 expected2(expect1, expect2); 88 } 89 90 /* 91 * scan expecting any of the 3 given token 92 */ 93 void 94 scan3(expect1, expect2, expect3, tokp) 95 tok_kind expect1; 96 tok_kind expect2; 97 tok_kind expect3; 98 token *tokp; 99 { 100 get_token(tokp); 101 if (tokp->kind != expect1 && tokp->kind != expect2 && 102 tokp->kind != expect3) 103 expected3(expect1, expect2, expect3); 104 } 105 106 /* 107 * scan expecting a constant, possibly symbolic 108 */ 109 void 110 scan_num(tokp) 111 token *tokp; 112 { 113 get_token(tokp); 114 switch (tokp->kind) { 115 case TOK_IDENT: 116 break; 117 default: 118 error("constant or identifier expected"); 119 } 120 } 121 122 /* 123 * Peek at the next token 124 */ 125 void 126 peek(tokp) 127 token *tokp; 128 { 129 get_token(tokp); 130 unget_token(tokp); 131 } 132 133 /* 134 * Peek at the next token and scan it if it matches what you expect 135 */ 136 int 137 peekscan(expect, tokp) 138 tok_kind expect; 139 token *tokp; 140 { 141 peek(tokp); 142 if (tokp->kind == expect) { 143 get_token(tokp); 144 return (1); 145 } 146 return (0); 147 } 148 149 /* 150 * Get the next token, printing out any directive that are encountered. 151 */ 152 void 153 get_token(tokp) 154 token *tokp; 155 { 156 int commenting; 157 158 if (pushed) { 159 pushed = 0; 160 *tokp = lasttok; 161 return; 162 } 163 commenting = 0; 164 for (;;) { 165 if (*where == 0) { 166 for (;;) { 167 if (!fgets(curline, MAXLINESIZE, fin)) { 168 tokp->kind = TOK_EOF; 169 *where = 0; 170 return; 171 } 172 linenum++; 173 if (commenting) { 174 break; 175 } else if (cppline(curline)) { 176 docppline(curline, &linenum, 177 &infilename); 178 } else if (directive(curline)) { 179 printdirective(curline); 180 } else { 181 break; 182 } 183 } 184 where = curline; 185 } else if (isspace(*where)) { 186 while (isspace(*where)) { 187 where++; /* eat */ 188 } 189 } else if (commenting) { 190 for (where++; *where; where++) { 191 if (endcomment(where)) { 192 where++; 193 commenting--; 194 break; 195 } 196 } 197 } else if (startcomment(where)) { 198 where += 2; 199 commenting++; 200 } else { 201 break; 202 } 203 } 204 205 /* 206 * 'where' is not whitespace, comment or directive Must be a token! 207 */ 208 switch (*where) { 209 case ':': 210 tokp->kind = TOK_COLON; 211 where++; 212 break; 213 case ';': 214 tokp->kind = TOK_SEMICOLON; 215 where++; 216 break; 217 case ',': 218 tokp->kind = TOK_COMMA; 219 where++; 220 break; 221 case '=': 222 tokp->kind = TOK_EQUAL; 223 where++; 224 break; 225 case '*': 226 tokp->kind = TOK_STAR; 227 where++; 228 break; 229 case '[': 230 tokp->kind = TOK_LBRACKET; 231 where++; 232 break; 233 case ']': 234 tokp->kind = TOK_RBRACKET; 235 where++; 236 break; 237 case '{': 238 tokp->kind = TOK_LBRACE; 239 where++; 240 break; 241 case '}': 242 tokp->kind = TOK_RBRACE; 243 where++; 244 break; 245 case '(': 246 tokp->kind = TOK_LPAREN; 247 where++; 248 break; 249 case ')': 250 tokp->kind = TOK_RPAREN; 251 where++; 252 break; 253 case '<': 254 tokp->kind = TOK_LANGLE; 255 where++; 256 break; 257 case '>': 258 tokp->kind = TOK_RANGLE; 259 where++; 260 break; 261 262 case '"': 263 tokp->kind = TOK_STRCONST; 264 findstrconst(&where, &tokp->str); 265 break; 266 case '\'': 267 tokp->kind = TOK_CHARCONST; 268 findchrconst(&where, &tokp->str); 269 break; 270 271 case '-': 272 case '0': 273 case '1': 274 case '2': 275 case '3': 276 case '4': 277 case '5': 278 case '6': 279 case '7': 280 case '8': 281 case '9': 282 tokp->kind = TOK_IDENT; 283 findconst(&where, &tokp->str); 284 break; 285 286 default: 287 if (!(isalpha(*where) || *where == '_')) { 288 char buf[100], chs[20]; 289 290 if (isprint(*where)) { 291 snprintf(chs, sizeof chs, "%c", *where); 292 } else { 293 snprintf(chs, sizeof chs, "%d", *where); 294 } 295 296 snprintf(buf, sizeof buf, 297 "illegal character in file: %s", chs); 298 error(buf); 299 } 300 findkind(&where, tokp); 301 break; 302 } 303 } 304 305 static void 306 unget_token(tokp) 307 token *tokp; 308 { 309 lasttok = *tokp; 310 pushed = 1; 311 } 312 313 static void 314 findstrconst(str, val) 315 char **str; 316 char **val; 317 { 318 char *p; 319 int size; 320 321 p = *str; 322 do { 323 p++; 324 } while (*p && *p != '"'); 325 if (*p == 0) { 326 error("unterminated string constant"); 327 } 328 p++; 329 size = p - *str; 330 *val = alloc(size + 1); 331 if (val == NULL) 332 error("alloc failed"); 333 (void) strncpy(*val, *str, size); 334 (*val)[size] = 0; 335 *str = p; 336 } 337 338 static void 339 findchrconst(str, val) 340 char **str; 341 char **val; 342 { 343 char *p; 344 int size; 345 346 p = *str; 347 do { 348 p++; 349 } while (*p && *p != '\''); 350 if (*p == 0) { 351 error("unterminated string constant"); 352 } 353 p++; 354 size = p - *str; 355 if (size != 3) { 356 error("empty char string"); 357 } 358 *val = alloc(size + 1); 359 if (val == NULL) 360 error("alloc failed"); 361 (void) strncpy(*val, *str, size); 362 (*val)[size] = 0; 363 *str = p; 364 } 365 366 static void 367 findconst(str, val) 368 char **str; 369 char **val; 370 { 371 char *p; 372 int size; 373 374 p = *str; 375 if (*p == '0' && *(p + 1) == 'x') { 376 p++; 377 do { 378 p++; 379 } while (isxdigit(*p)); 380 } else { 381 do { 382 p++; 383 } while (isdigit(*p)); 384 } 385 size = p - *str; 386 *val = alloc(size + 1); 387 if (val == NULL) 388 error("alloc failed"); 389 (void) strncpy(*val, *str, size); 390 (*val)[size] = 0; 391 *str = p; 392 } 393 394 static token symbols[] = { 395 {TOK_CONST, "const"}, 396 {TOK_UNION, "union"}, 397 {TOK_SWITCH, "switch"}, 398 {TOK_CASE, "case"}, 399 {TOK_DEFAULT, "default"}, 400 {TOK_STRUCT, "struct"}, 401 {TOK_TYPEDEF, "typedef"}, 402 {TOK_ENUM, "enum"}, 403 {TOK_OPAQUE, "opaque"}, 404 {TOK_BOOL, "bool"}, 405 {TOK_VOID, "void"}, 406 {TOK_CHAR, "char"}, 407 {TOK_INT, "int"}, 408 {TOK_UNSIGNED, "unsigned"}, 409 {TOK_SHORT, "short"}, 410 {TOK_LONG, "long"}, 411 {TOK_FLOAT, "float"}, 412 {TOK_DOUBLE, "double"}, 413 {TOK_STRING, "string"}, 414 {TOK_PROGRAM, "program"}, 415 {TOK_VERSION, "version"}, 416 {TOK_EOF, "??????"}, 417 }; 418 419 static void 420 findkind(mark, tokp) 421 char **mark; 422 token *tokp; 423 { 424 int len; 425 token *s; 426 char *str; 427 428 str = *mark; 429 for (s = symbols; s->kind != TOK_EOF; s++) { 430 len = strlen(s->str); 431 if (strncmp(str, s->str, len) == 0) { 432 if (!isalnum(str[len]) && str[len] != '_') { 433 tokp->kind = s->kind; 434 tokp->str = s->str; 435 *mark = str + len; 436 return; 437 } 438 } 439 } 440 tokp->kind = TOK_IDENT; 441 for (len = 0; isalnum(str[len]) || str[len] == '_'; len++); 442 tokp->str = alloc(len + 1); 443 if (tokp->str == NULL) 444 error("alloc failed"); 445 (void) strncpy(tokp->str, str, len); 446 tokp->str[len] = 0; 447 *mark = str + len; 448 } 449 450 static int 451 cppline(line) 452 char *line; 453 { 454 return (line == curline && *line == '#'); 455 } 456 457 static int 458 directive(line) 459 char *line; 460 { 461 return (line == curline && *line == '%'); 462 } 463 464 static void 465 printdirective(line) 466 char *line; 467 { 468 fprintf(fout, "%s", line + 1); 469 } 470 471 static void 472 docppline(line, lineno, fname) 473 char *line; 474 int *lineno; 475 char **fname; 476 { 477 char *file; 478 int num; 479 char *p; 480 481 line++; 482 while (isspace(*line)) { 483 line++; 484 } 485 num = atoi(line); 486 while (isdigit(*line)) { 487 line++; 488 } 489 while (isspace(*line)) { 490 line++; 491 } 492 if (*line != '"') { 493 error("preprocessor error"); 494 } 495 line++; 496 p = file = alloc(strlen(line) + 1); 497 if (p == NULL) 498 error("alloc failed"); 499 while (*line && *line != '"') { 500 *p++ = *line++; 501 } 502 if (*line == 0) { 503 error("preprocessor error"); 504 } 505 *p = 0; 506 if (*file == 0) { 507 *fname = NULL; 508 free(file); 509 } else { 510 *fname = file; 511 } 512 *lineno = num - 1; 513 } 514