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
scan(expect,tokp)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
scan2(expect1,expect2,tokp)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
scan3(expect1,expect2,expect3,tokp)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
scan_num(tokp)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
peek(tokp)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
peekscan(expect,tokp)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
get_token(tokp)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
unget_token(tokp)305 unget_token(tokp)
306 token *tokp;
307 {
308 lasttok = *tokp;
309 pushed = 1;
310 }
311
312 static void
findstrconst(str,val)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
findchrconst(str,val)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
findconst(str,val)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
findkind(mark,tokp)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
cppline(line)455 cppline(line)
456 char *line;
457 {
458 return (line == curline && *line == '#');
459 }
460
461 static int
directive(line)462 directive(line)
463 char *line;
464 {
465 return (line == curline && *line == '%');
466 }
467
468 static void
printdirective(line)469 printdirective(line)
470 char *line;
471 {
472 fprintf(fout, "%s", line + 1);
473 }
474
475 static void
docppline(line,lineno,fname)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