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