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