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