1 /* $NetBSD: rpc_scan.c,v 1.15 2015/05/09 23:28:43 dholland Exp $ */
2 /*
3 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4 * unrestricted use provided that this legend is included on all tape
5 * media and as a part of the software program in whole or part. Users
6 * may copy or modify Sun RPC without charge, but are not authorized
7 * to license or distribute it to anyone else except as part of a product or
8 * program developed by the user or with the express written consent of
9 * Sun Microsystems, Inc.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California 94043
30 */
31
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
40 #else
41 __RCSID("$NetBSD: rpc_scan.c,v 1.15 2015/05/09 23:28:43 dholland Exp $");
42 #endif
43 #endif
44
45 /*
46 * rpc_scan.c, Scanner for the RPC protocol compiler
47 * Copyright (C) 1987, Sun Microsystems, Inc.
48 */
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <string.h>
53 #include "rpc_scan.h"
54 #include "rpc_parse.h"
55 #include "rpc_util.h"
56
57 #define startcomment(where) (where[0] == '/' && where[1] == '*')
58 #define endcomment(where) (where[-1] == '*' && where[0] == '/')
59
60 static void unget_token(token *);
61 static void findstrconst(char **, const char **);
62 static void findchrconst(char **, const char **);
63 static void findconst(char **, const char **);
64 static void findkind(char **, token *);
65 static int cppline(const char *);
66 static int directive(const char *);
67 static void printdirective(const char *);
68 static void docppline(char *, int *, const char **);
69
70 static int pushed = 0; /* is a token pushed */
71 static token lasttok; /* last token, if pushed */
72
73 /*
74 * scan expecting 1 given token
75 */
76 void
scan(tok_kind expect,token * tokp)77 scan(tok_kind expect, token *tokp)
78 {
79 get_token(tokp);
80 if (tokp->kind != expect) {
81 expected1(expect);
82 }
83 }
84 /*
85 * scan expecting any of the 2 given tokens
86 */
87 void
scan2(tok_kind expect1,tok_kind expect2,token * tokp)88 scan2(tok_kind expect1, tok_kind expect2, token *tokp)
89 {
90 get_token(tokp);
91 if (tokp->kind != expect1 && tokp->kind != expect2) {
92 expected2(expect1, expect2);
93 }
94 }
95 /*
96 * scan expecting any of the 3 given token
97 */
98 void
scan3(tok_kind expect1,tok_kind expect2,tok_kind expect3,token * tokp)99 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
100 {
101 get_token(tokp);
102 if (tokp->kind != expect1 && tokp->kind != expect2
103 && tokp->kind != expect3) {
104 expected3(expect1, expect2, expect3);
105 }
106 }
107 /*
108 * scan expecting a constant, possibly symbolic
109 */
110 void
scan_num(token * tokp)111 scan_num(token *tokp)
112 {
113 get_token(tokp);
114 switch (tokp->kind) {
115 case TOK_IDENT:
116 break;
117 default:
118 error("Expected constant or identifier");
119 }
120 }
121 /*
122 * Peek at the next token
123 */
124 void
peek(token * tokp)125 peek(token *tokp)
126 {
127 get_token(tokp);
128 unget_token(tokp);
129 }
130 /*
131 * Peek at the next token and scan it if it matches what you expect
132 */
133 int
peekscan(tok_kind expect,token * tokp)134 peekscan(tok_kind expect, token *tokp)
135 {
136 peek(tokp);
137 if (tokp->kind == expect) {
138 get_token(tokp);
139 return (1);
140 }
141 return (0);
142 }
143 /*
144 * Get the next token, printing out any directive that are encountered.
145 */
146 void
get_token(token * tokp)147 get_token(token *tokp)
148 {
149 int commenting;
150
151 if (pushed) {
152 pushed = 0;
153 *tokp = lasttok;
154 return;
155 }
156 commenting = 0;
157 for (;;) {
158 if (*where == 0) {
159 for (;;) {
160 if (!fgets(curline, MAXLINESIZE, fin)) {
161 tokp->kind = TOK_EOF;
162 *where = 0;
163 return;
164 }
165 linenum++;
166 if (commenting) {
167 break;
168 } else
169 if (cppline(curline)) {
170 docppline(curline, &linenum,
171 &infilename);
172 } else
173 if (directive(curline)) {
174 printdirective(curline);
175 } else {
176 break;
177 }
178 }
179 where = curline;
180 } else
181 if (isspace((unsigned char)*where)) {
182 while (isspace((unsigned char)*where)) {
183 where++; /* eat */
184 }
185 } else
186 if (commenting) {
187 for (where++; *where; where++) {
188 if (endcomment(where)) {
189 where++;
190 commenting--;
191 break;
192 }
193 }
194 } else
195 if (startcomment(where)) {
196 where += 2;
197 commenting++;
198 } else {
199 break;
200 }
201 }
202
203 /*
204 * 'where' is not whitespace, comment or directive Must be a token!
205 */
206 switch (*where) {
207 case ':':
208 tokp->kind = TOK_COLON;
209 where++;
210 break;
211 case ';':
212 tokp->kind = TOK_SEMICOLON;
213 where++;
214 break;
215 case ',':
216 tokp->kind = TOK_COMMA;
217 where++;
218 break;
219 case '=':
220 tokp->kind = TOK_EQUAL;
221 where++;
222 break;
223 case '*':
224 tokp->kind = TOK_STAR;
225 where++;
226 break;
227 case '[':
228 tokp->kind = TOK_LBRACKET;
229 where++;
230 break;
231 case ']':
232 tokp->kind = TOK_RBRACKET;
233 where++;
234 break;
235 case '{':
236 tokp->kind = TOK_LBRACE;
237 where++;
238 break;
239 case '}':
240 tokp->kind = TOK_RBRACE;
241 where++;
242 break;
243 case '(':
244 tokp->kind = TOK_LPAREN;
245 where++;
246 break;
247 case ')':
248 tokp->kind = TOK_RPAREN;
249 where++;
250 break;
251 case '<':
252 tokp->kind = TOK_LANGLE;
253 where++;
254 break;
255 case '>':
256 tokp->kind = TOK_RANGLE;
257 where++;
258 break;
259
260 case '"':
261 tokp->kind = TOK_STRCONST;
262 findstrconst(&where, &tokp->str);
263 break;
264 case '\'':
265 tokp->kind = TOK_CHARCONST;
266 findchrconst(&where, &tokp->str);
267 break;
268
269 case '-':
270 case '0':
271 case '1':
272 case '2':
273 case '3':
274 case '4':
275 case '5':
276 case '6':
277 case '7':
278 case '8':
279 case '9':
280 tokp->kind = TOK_IDENT;
281 findconst(&where, &tokp->str);
282 break;
283
284 default:
285 if (!(isalpha((unsigned char)*where) || *where == '_')) {
286 if (isprint((unsigned char)*where)) {
287 error("Illegal character '%c' in file", *where);
288 } else {
289 error("Illegal character %d in file", *where);
290 }
291 }
292 findkind(&where, tokp);
293 break;
294 }
295 }
296
297 static void
unget_token(token * tokp)298 unget_token(token *tokp)
299 {
300 lasttok = *tokp;
301 pushed = 1;
302 }
303
304 static void
findstrconst(char ** str,const char ** val)305 findstrconst(char **str, const char **val)
306 {
307 char *p;
308 int size;
309 char *tmp;
310
311 p = *str;
312 do {
313 p++;
314 } while (*p && *p != '"');
315 if (*p == 0) {
316 error("Unterminated string constant");
317 }
318 p++;
319 size = p - *str;
320 tmp = alloc(size + 1);
321 (void) strncpy(tmp, *str, size);
322 tmp[size] = 0;
323 *val = tmp;
324 *str = p;
325 }
326
327 static void
findchrconst(char ** str,const char ** val)328 findchrconst(char **str, const char **val)
329 {
330 char *p;
331 int size;
332 char *tmp;
333
334 p = *str;
335 do {
336 p++;
337 } while (*p && *p != '\'');
338 if (*p == 0) {
339 error("Unterminated string constant");
340 }
341 p++;
342 size = p - *str;
343 if (size != 3) {
344 error("Empty character");
345 }
346 tmp = alloc(size + 1);
347 (void) strncpy(tmp, *str, size);
348 tmp[size] = 0;
349 *val = tmp;
350 *str = p;
351 }
352
353 static void
findconst(char ** str,const char ** val)354 findconst(char **str, const char **val)
355 {
356 char *p;
357 int size;
358 char *tmp;
359
360 p = *str;
361 if (*p == '0' && *(p + 1) == 'x') {
362 p++;
363 do {
364 p++;
365 } while (isxdigit((unsigned char)*p));
366 } else {
367 do {
368 p++;
369 } while (isdigit((unsigned char)*p));
370 }
371 size = p - *str;
372 tmp = alloc(size + 1);
373 (void) strncpy(tmp, *str, size);
374 tmp[size] = 0;
375 *val = tmp;
376 *str = p;
377 }
378
379 static const token symbols[] = {
380 {TOK_CONST, "const"},
381 {TOK_UNION, "union"},
382 {TOK_SWITCH, "switch"},
383 {TOK_CASE, "case"},
384 {TOK_DEFAULT, "default"},
385 {TOK_STRUCT, "struct"},
386 {TOK_TYPEDEF, "typedef"},
387 {TOK_ENUM, "enum"},
388 {TOK_OPAQUE, "opaque"},
389 {TOK_BOOL, "bool"},
390 {TOK_VOID, "void"},
391 {TOK_CHAR, "char"},
392 {TOK_INT, "int"},
393 {TOK_UNSIGNED, "unsigned"},
394 {TOK_SHORT, "short"},
395 {TOK_LONG, "long"},
396 {TOK_HYPER, "hyper"},
397 {TOK_FLOAT, "float"},
398 {TOK_DOUBLE, "double"},
399 {TOK_QUAD, "quadruple"},
400 {TOK_STRING, "string"},
401 {TOK_PROGRAM, "program"},
402 {TOK_VERSION, "version"},
403 {TOK_EOF, "??????"},
404 };
405
406 static void
findkind(char ** mark,token * tokp)407 findkind(char **mark, token *tokp)
408 {
409 int len;
410 const token *s;
411 char *str;
412 char *tmp;
413
414 str = *mark;
415 for (s = symbols; s->kind != TOK_EOF; s++) {
416 len = strlen(s->str);
417 if (strncmp(str, s->str, len) == 0) {
418 if (!isalnum((unsigned char)str[len]) &&
419 str[len] != '_') {
420 tokp->kind = s->kind;
421 tokp->str = s->str;
422 *mark = str + len;
423 return;
424 }
425 }
426 }
427 tokp->kind = TOK_IDENT;
428 for (len = 0; isalnum((unsigned char)str[len]) ||
429 str[len] == '_'; len++);
430 tmp = alloc(len + 1);
431 (void) strncpy(tmp, str, len);
432 tmp[len] = 0;
433 tokp->str = tmp;
434 *mark = str + len;
435 }
436
437 static int
cppline(const char * line)438 cppline(const char *line)
439 {
440 return (line == curline && *line == '#');
441 }
442
443 static int
directive(const char * line)444 directive(const char *line)
445 {
446 return (line == curline && *line == '%');
447 }
448
449 static void
printdirective(const char * line)450 printdirective(const char *line)
451 {
452 f_print(fout, "%s", line + 1);
453 }
454
455 static void
docppline(char * line,int * lineno,const char ** fname)456 docppline(char *line, int *lineno, const char **fname)
457 {
458 char *file;
459 int num;
460 char *p;
461
462 line++;
463 while (isspace((unsigned char)*line)) {
464 line++;
465 }
466 num = atoi(line);
467 while (isdigit((unsigned char)*line)) {
468 line++;
469 }
470 while (isspace((unsigned char)*line)) {
471 line++;
472 }
473 if (*line != '"') {
474 error("Preprocessor error");
475 }
476 line++;
477 p = file = alloc(strlen(line) + 1);
478 while (*line && *line != '"') {
479 *p++ = *line++;
480 }
481 if (*line == 0) {
482 error("Preprocessor error");
483 }
484 *p = 0;
485 if (*file == 0) {
486 *fname = NULL;
487 free(file);
488 } else {
489 *fname = file;
490 }
491 *lineno = num - 1;
492 }
493