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