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