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