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