xref: /illumos-gate/usr/src/cmd/rpcgen/rpc_scan.c (revision 4bb7efa72ed531c10f097919636e67724ec4c25a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30  * University Copyright- Copyright (c) 1982, 1986, 1988
31  * The Regents of the University of California
32  * All Rights Reserved
33  *
34  * University Acknowledgment- Portions of this document are derived from
35  * software developed by the University of California, Berkeley, and its
36  * contributors.
37  */
38 
39 #pragma ident	"%Z%%M%	%I%	%E% SMI"
40 
41 /*
42  * rpc_scan.c, Scanner for the RPC protocol compiler
43  */
44 
45 #include <sys/wait.h>
46 #include <stdio.h>
47 #include <ctype.h>
48 #include <string.h>
49 #include <strings.h>
50 #include "rpc_scan.h"
51 #include "rpc_parse.h"
52 #include "rpc_util.h"
53 
54 #define	startcomment(where)	(where[0] == '/' && where[1] == '*')
55 #define	endcomment(where)	(where[-1] == '*' && where[0] == '/')
56 
57 static int pushed = 0;	/* is a token pushed */
58 static token lasttok;	/* last token, if pushed */
59 
60 static void unget_token(token *);
61 static void findstrconst(char **, char **);
62 static void findchrconst(char **, char **);
63 static void findconst(char **, char **);
64 static void findkind(char **, token *);
65 static int cppline(char *);
66 static int directive(char *);
67 static void printdirective(char *);
68 static void docppline(char *, int *, char **);
69 
70 /*
71  * scan expecting 1 given token
72  */
73 void
74 scan(tok_kind expect, token *tokp)
75 {
76 	get_token(tokp);
77 	if (tokp->kind != expect)
78 		expected1(expect);
79 }
80 
81 /*
82  * scan expecting any of the 2 given tokens
83  */
84 void
85 scan2(tok_kind expect1, tok_kind expect2, token *tokp)
86 {
87 	get_token(tokp);
88 	if (tokp->kind != expect1 && tokp->kind != expect2)
89 		expected2(expect1, expect2);
90 }
91 
92 /*
93  * scan expecting any of the 3 given token
94  */
95 void
96 scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
97 {
98 	get_token(tokp);
99 	if (tokp->kind != expect1 && tokp->kind != expect2 &&
100 						tokp->kind != expect3)
101 		expected3(expect1, expect2, expect3);
102 }
103 
104 /*
105  * scan expecting a constant, possibly symbolic
106  */
107 void
108 scan_num(token *tokp)
109 {
110 	get_token(tokp);
111 	switch (tokp->kind) {
112 	case TOK_IDENT:
113 		break;
114 	default:
115 		error("constant or identifier expected");
116 	}
117 }
118 
119 /*
120  * Peek at the next token
121  */
122 void
123 peek(token *tokp)
124 {
125 	get_token(tokp);
126 	unget_token(tokp);
127 }
128 
129 /*
130  * Peek at the next token and scan it if it matches what you expect
131  */
132 int
133 peekscan(tok_kind expect, token *tokp)
134 {
135 	peek(tokp);
136 	if (tokp->kind == expect) {
137 		get_token(tokp);
138 		return (1);
139 	}
140 	return (0);
141 }
142 
143 /*
144  * Get the next token, printing out any directive that are encountered.
145  */
146 void
147 get_token(token *tokp)
148 {
149 	int commenting;
150 	int stat = 0;
151 
152 	if (pushed) {
153 		pushed = 0;
154 		*tokp = lasttok;
155 		return;
156 	}
157 	commenting = 0;
158 	for (;;) {
159 		if (*where == 0) {
160 			for (;;) {
161 				if (!fgets(curline, MAXLINESIZE, fin)) {
162 					tokp->kind = TOK_EOF;
163 					/*
164 					 * now check if cpp returned
165 					 * non NULL value
166 					 */
167 					(void) waitpid(childpid, &stat,
168 								WUNTRACED);
169 					if (stat > 0) {
170 					/* Set return value from rpcgen */
171 						nonfatalerrors = stat >> 8;
172 					}
173 					*where = 0;
174 					return;
175 				}
176 				linenum++;
177 				if (commenting) {
178 					break;
179 				} else if (cppline(curline)) {
180 					docppline(curline, &linenum,
181 						&infilename);
182 				} else if (directive(curline)) {
183 					printdirective(curline);
184 				} else {
185 					break;
186 				}
187 			}
188 			where = curline;
189 		} else if (isspace(*where)) {
190 			while (isspace(*where)) {
191 				where++;	/* eat */
192 			}
193 		} else if (commenting) {
194 			for (where++; *where; where++) {
195 				if (endcomment(where)) {
196 					where++;
197 					commenting--;
198 					break;
199 				}
200 			}
201 		} else if (startcomment(where)) {
202 			where += 2;
203 			commenting++;
204 		} else {
205 			break;
206 		}
207 	}
208 
209 	/*
210 	 * 'where' is not whitespace, comment or directive Must be a token!
211 	 */
212 	switch (*where) {
213 	case ':':
214 		tokp->kind = TOK_COLON;
215 		where++;
216 		break;
217 	case ';':
218 		tokp->kind = TOK_SEMICOLON;
219 		where++;
220 		break;
221 	case ',':
222 		tokp->kind = TOK_COMMA;
223 		where++;
224 		break;
225 	case '=':
226 		tokp->kind = TOK_EQUAL;
227 		where++;
228 		break;
229 	case '*':
230 		tokp->kind = TOK_STAR;
231 		where++;
232 		break;
233 	case '[':
234 		tokp->kind = TOK_LBRACKET;
235 		where++;
236 		break;
237 	case ']':
238 		tokp->kind = TOK_RBRACKET;
239 		where++;
240 		break;
241 	case '{':
242 		tokp->kind = TOK_LBRACE;
243 		where++;
244 		break;
245 	case '}':
246 		tokp->kind = TOK_RBRACE;
247 		where++;
248 		break;
249 	case '(':
250 		tokp->kind = TOK_LPAREN;
251 		where++;
252 		break;
253 	case ')':
254 		tokp->kind = TOK_RPAREN;
255 		where++;
256 		break;
257 	case '<':
258 		tokp->kind = TOK_LANGLE;
259 		where++;
260 		break;
261 	case '>':
262 		tokp->kind = TOK_RANGLE;
263 		where++;
264 		break;
265 
266 	case '"':
267 		tokp->kind = TOK_STRCONST;
268 		findstrconst(&where, &tokp->str);
269 		break;
270 	case '\'':
271 		tokp->kind = TOK_CHARCONST;
272 		findchrconst(&where, &tokp->str);
273 		break;
274 
275 	case '-':
276 	case '0':
277 	case '1':
278 	case '2':
279 	case '3':
280 	case '4':
281 	case '5':
282 	case '6':
283 	case '7':
284 	case '8':
285 	case '9':
286 		tokp->kind = TOK_IDENT;
287 		findconst(&where, &tokp->str);
288 		break;
289 
290 	default:
291 		if (!(isalpha(*where) || *where == '_')) {
292 			char buf[100];
293 			char *p;
294 			size_t blen;
295 
296 			(void) snprintf(buf, sizeof (buf),
297 						"illegal character in file: ");
298 			blen = strlen(buf);
299 			p = buf + blen;
300 			if (isprint(*where)) {
301 				(void) snprintf(p, sizeof (buf) - blen,
302 								"%c", *where);
303 			} else {
304 				(void) snprintf(p, sizeof (buf) - blen,
305 								"%d", *where);
306 			}
307 			error(buf);
308 		}
309 		findkind(&where, tokp);
310 		break;
311 	}
312 }
313 
314 static void
315 unget_token(token *tokp)
316 {
317 	lasttok = *tokp;
318 	pushed = 1;
319 }
320 
321 static void
322 findstrconst(char **str, char **val)
323 {
324 	char *p;
325 	int size;
326 
327 	p = *str;
328 	do {
329 		p++;
330 	} while (*p && *p != '"');
331 	if (*p == 0) {
332 		error("unterminated string constant");
333 	}
334 	p++;
335 	size = p - *str;
336 	*val = malloc(size + 1);
337 	(void) strncpy(*val, *str, size);
338 	(*val)[size] = 0;
339 	*str = p;
340 }
341 
342 static void
343 findchrconst(char **str, char **val)
344 {
345 	char *p;
346 	int size;
347 
348 	p = *str;
349 	do {
350 		p++;
351 	} while (*p && *p != '\'');
352 	if (*p == 0)
353 		error("unterminated string constant");
354 	p++;
355 	size = p - *str;
356 	if (size != 3)
357 		error("empty char string");
358 	*val = malloc(size + 1);
359 	(void) strncpy(*val, *str, size);
360 	(*val)[size] = 0;
361 	*str = p;
362 }
363 
364 static void
365 findconst(char **str, char **val)
366 {
367 	char *p;
368 	int size;
369 
370 	p = *str;
371 	if (*p == '0' && *(p + 1) == 'x') {
372 		p++;
373 		do {
374 			p++;
375 		} while (isxdigit(*p));
376 	} else {
377 		do {
378 			p++;
379 		} while (isdigit(*p));
380 	}
381 	size = p - *str;
382 	*val = malloc(size + 1);
383 	(void) strncpy(*val, *str, size);
384 	(*val)[size] = 0;
385 	*str = p;
386 }
387 
388 static token symbols[] = {
389 			{TOK_CONST, "const"},
390 			{TOK_UNION, "union"},
391 			{TOK_SWITCH, "switch"},
392 			{TOK_CASE, "case"},
393 			{TOK_DEFAULT, "default"},
394 			{TOK_STRUCT, "struct"},
395 			{TOK_TYPEDEF, "typedef"},
396 			{TOK_ENUM, "enum"},
397 			{TOK_OPAQUE, "opaque"},
398 			{TOK_BOOL, "bool"},
399 			{TOK_VOID, "void"},
400 			{TOK_ONEWAY, "oneway"},
401 			{TOK_CHAR, "char"},
402 			{TOK_INT, "int"},
403 			{TOK_UNSIGNED, "unsigned"},
404 			{TOK_SHORT, "short"},
405 			{TOK_LONG, "long"},
406 			{TOK_HYPER, "hyper"},
407 			{TOK_FLOAT, "float"},
408 			{TOK_DOUBLE, "double"},
409 			{TOK_QUAD, "quadruple"},
410 			{TOK_STRING, "string"},
411 			{TOK_PROGRAM, "program"},
412 			{TOK_VERSION, "version"},
413 			{TOK_EOF, "??????"},
414 };
415 
416 static void
417 findkind(char **mark, token *tokp)
418 {
419 	int len;
420 	token *s;
421 	char *str;
422 
423 	str = *mark;
424 	for (s = symbols; s->kind != TOK_EOF; s++) {
425 		len = strlen(s->str);
426 		if (strncmp(str, s->str, len) == 0) {
427 			if (!isalnum(str[len]) && str[len] != '_') {
428 				tokp->kind = s->kind;
429 				tokp->str = s->str;
430 				*mark = str + len;
431 				return;
432 			}
433 		}
434 	}
435 	tokp->kind = TOK_IDENT;
436 	for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
437 	tokp->str = malloc(len + 1);
438 	(void) strncpy(tokp->str, str, len);
439 	tokp->str[len] = 0;
440 	*mark = str + len;
441 }
442 
443 static int
444 cppline(char *line)
445 {
446 	return (line == curline && *line == '#');
447 }
448 
449 static int
450 directive(char *line)
451 {
452 	return (line == curline && *line == '%');
453 }
454 
455 static void
456 printdirective(char *line)
457 {
458 	f_print(fout, "%s", line + 1);
459 }
460 
461 static void
462 docppline(char *line, int *lineno, char **fname)
463 {
464 	char *file;
465 	int num;
466 	char *p;
467 
468 	line++;
469 	while (isspace(*line))
470 		line++;
471 	num = atoi(line);
472 	while (isdigit(*line))
473 		line++;
474 	while (isspace(*line))
475 		line++;
476 	if (*line != '"')
477 		error("preprocessor error");
478 	line++;
479 	p = file = malloc(strlen(line) + 1);
480 	while (*line && *line != '"')
481 		*p++ = *line++;
482 	if (*line == 0)
483 		error("preprocessor error");
484 	*p = 0;
485 	if (*file == 0)
486 		*fname = NULL;
487 	else
488 		*fname = file;
489 	*lineno = num - 1;
490 }
491