1/*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part.  Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
8 *
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12 *
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
16 *
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
20 *
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
24 *
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California  94043
28 */
29
30#if 0
31#ifndef lint
32#ident	"@(#)rpc_scan.c	1.13	93/07/05 SMI"
33static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
34#endif
35#endif
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD$");
39
40/*
41 * rpc_scan.c, Scanner for the RPC protocol compiler
42 * Copyright (C) 1987, Sun Microsystems, Inc.
43 */
44
45#include <sys/types.h>
46
47#include <sys/wait.h>
48#include <stdio.h>
49#include <ctype.h>
50#include <string.h>
51#include "rpc_parse.h"
52#include "rpc_scan.h"
53#include "rpc_util.h"
54
55#define startcomment(where) (where[0] == '/' && where[1] == '*')
56#define endcomment(where) (where[-1] == '*' && where[0] == '/')
57
58static int pushed = 0;	/* is a token pushed */
59static token lasttok;	/* last token, if pushed */
60
61static void unget_token( token * );
62static void findstrconst(char **, const char **);
63static void findchrconst(char **, const char **);
64static void findconst(char **, const char **);
65static void findkind( char **, token * );
66static int cppline( char * );
67static int directive( char * );
68static void printdirective( char * );
69static void docppline(char *, int *, const char **);
70
71/*
72 * scan expecting 1 given token
73 */
74void
75scan(tok_kind expect, token *tokp)
76{
77	get_token(tokp);
78	if (tokp->kind != expect) {
79		expected1(expect);
80	}
81}
82
83/*
84 * scan expecting any of the 2 given tokens
85 */
86void
87scan2(tok_kind expect1, tok_kind expect2, token *tokp)
88{
89	get_token(tokp);
90	if (tokp->kind != expect1 && tokp->kind != expect2) {
91		expected2(expect1, expect2);
92	}
93}
94
95/*
96 * scan expecting any of the 3 given token
97 */
98void
99scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
100{
101	get_token(tokp);
102	if (tokp->kind != expect1 && tokp->kind != expect2
103	    && tokp->kind != expect3) {
104		expected3(expect1, expect2, expect3);
105	}
106}
107
108/*
109 * scan expecting a constant, possibly symbolic
110 */
111void
112scan_num(token *tokp)
113{
114	get_token(tokp);
115	switch (tokp->kind) {
116	case TOK_IDENT:
117		break;
118	default:
119		error("constant or identifier expected");
120	}
121}
122
123/*
124 * Peek at the next token
125 */
126void
127peek(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 */
136int
137peekscan(tok_kind expect, token *tokp)
138{
139	peek(tokp);
140	if (tokp->kind == expect) {
141		get_token(tokp);
142		return (1);
143	}
144	return (0);
145}
146
147/*
148 * Get the next token, printing out any directive that are encountered.
149 */
150void
151get_token(token *tokp)
152{
153	int commenting;
154	int stat = 0;
155
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					/* now check if cpp returned non NULL value */
169					waitpid(childpid, &stat, WUNTRACED);
170					if (stat > 0) {
171					/* Set return value from rpcgen */
172						nonfatalerrors = stat >> 8;
173					}
174					*where = 0;
175					return;
176				}
177				linenum++;
178				if (commenting) {
179					break;
180				} else if (cppline(curline)) {
181					docppline(curline, &linenum,
182						  &infilename);
183				} else if (directive(curline)) {
184					printdirective(curline);
185				} else {
186					break;
187				}
188			}
189			where = curline;
190		} else if (isspace(*where)) {
191			while (isspace(*where)) {
192				where++;	/* eat */
193			}
194		} else if (commenting) {
195			for (where++; *where; where++) {
196				if (endcomment(where)) {
197					where++;
198					commenting--;
199					break;
200				}
201			}
202		} else if (startcomment(where)) {
203			where += 2;
204			commenting++;
205		} else {
206			break;
207		}
208	}
209
210	/*
211	 * 'where' is not whitespace, comment or directive Must be a token!
212	 */
213	switch (*where) {
214	case ':':
215		tokp->kind = TOK_COLON;
216		where++;
217		break;
218	case ';':
219		tokp->kind = TOK_SEMICOLON;
220		where++;
221		break;
222	case ',':
223		tokp->kind = TOK_COMMA;
224		where++;
225		break;
226	case '=':
227		tokp->kind = TOK_EQUAL;
228		where++;
229		break;
230	case '*':
231		tokp->kind = TOK_STAR;
232		where++;
233		break;
234	case '[':
235		tokp->kind = TOK_LBRACKET;
236		where++;
237		break;
238	case ']':
239		tokp->kind = TOK_RBRACKET;
240		where++;
241		break;
242	case '{':
243		tokp->kind = TOK_LBRACE;
244		where++;
245		break;
246	case '}':
247		tokp->kind = TOK_RBRACE;
248		where++;
249		break;
250	case '(':
251		tokp->kind = TOK_LPAREN;
252		where++;
253		break;
254	case ')':
255		tokp->kind = TOK_RPAREN;
256		where++;
257		break;
258	case '<':
259		tokp->kind = TOK_LANGLE;
260		where++;
261		break;
262	case '>':
263		tokp->kind = TOK_RANGLE;
264		where++;
265		break;
266
267	case '"':
268		tokp->kind = TOK_STRCONST;
269		findstrconst(&where, &tokp->str);
270		break;
271	case '\'':
272		tokp->kind = TOK_CHARCONST;
273		findchrconst(&where, &tokp->str);
274		break;
275
276	case '-':
277	case '0':
278	case '1':
279	case '2':
280	case '3':
281	case '4':
282	case '5':
283	case '6':
284	case '7':
285	case '8':
286	case '9':
287		tokp->kind = TOK_IDENT;
288		findconst(&where, &tokp->str);
289		break;
290
291	default:
292		if (!(isalpha(*where) || *where == '_')) {
293			char buf[100];
294			char *p;
295
296			s_print(buf, "illegal character in file: ");
297			p = buf + strlen(buf);
298			if (isprint(*where)) {
299				s_print(p, "%c", *where);
300			} else {
301				s_print(p, "%d", *where);
302			}
303			error(buf);
304		}
305		findkind(&where, tokp);
306		break;
307	}
308}
309
310static void
311unget_token(token *tokp)
312{
313	lasttok = *tokp;
314	pushed = 1;
315}
316
317static void
318findstrconst(char **str, const char **val)
319{
320	char *p;
321	char *tmp;
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 + 1;
333	tmp = xmalloc(size);
334	(void) strlcpy(tmp, *str, size);
335	*val = tmp;
336	*str = p;
337}
338
339static void
340findchrconst(char **str, const char **val)
341{
342	char *p;
343	char *tmp;
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 + 1;
355	if (size != 4) {
356		error("empty char string");
357	}
358	tmp = xmalloc(size);
359	(void) strlcpy(tmp, *str, size);
360	*val = tmp;
361	*str = p;
362}
363
364static void
365findconst(char **str, const char **val)
366{
367	char *p;
368	char *tmp;
369	int size;
370
371	p = *str;
372	if (*p == '0' && *(p + 1) == 'x') {
373		p++;
374		do {
375			p++;
376		} while (isxdigit(*p));
377	} else {
378		do {
379			p++;
380		} while (isdigit(*p));
381	}
382	size = p - *str + 1;
383	tmp = xmalloc(size);
384	(void) strlcpy(tmp, *str, size);
385	*val = tmp;
386	*str = p;
387}
388
389static token symbols[] = {
390			  {TOK_CONST, "const"},
391			  {TOK_UNION, "union"},
392			  {TOK_SWITCH, "switch"},
393			  {TOK_CASE, "case"},
394			  {TOK_DEFAULT, "default"},
395			  {TOK_STRUCT, "struct"},
396			  {TOK_TYPEDEF, "typedef"},
397			  {TOK_ENUM, "enum"},
398			  {TOK_OPAQUE, "opaque"},
399			  {TOK_BOOL, "bool"},
400			  {TOK_VOID, "void"},
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
416static void
417findkind(char **mark, token *tokp)
418{
419	int len;
420	token *s;
421	char *str, *tmp;
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	tmp = xmalloc(len + 1);
438	(void) strlcpy(tmp, str, len + 1);
439	tokp->str = tmp;
440	*mark = str + len;
441}
442
443static int
444cppline(char *line)
445{
446	return (line == curline && *line == '#');
447}
448
449static int
450directive(char *line)
451{
452	return (line == curline && *line == '%');
453}
454
455static void
456printdirective(char *line)
457{
458	f_print(fout, "%s", line + 1);
459}
460
461static void
462docppline(char *line, int *lineno, const char **fname)
463{
464	char *file;
465	int num;
466	char *p;
467
468	line++;
469	while (isspace(*line)) {
470		line++;
471	}
472	num = atoi(line);
473	while (isdigit(*line)) {
474		line++;
475	}
476	while (isspace(*line)) {
477		line++;
478	}
479	if (*line != '"') {
480		error("preprocessor error");
481	}
482	line++;
483	p = file = xmalloc(strlen(line) + 1);
484	while (*line && *line != '"') {
485		*p++ = *line++;
486	}
487	if (*line == 0) {
488		error("preprocessor error");
489	}
490	*p = 0;
491	if (*file == 0) {
492		*fname = NULL;
493	} else {
494		*fname = file;
495	}
496	*lineno = num - 1;
497}
498