111820Sjulian/*
211820Sjulian * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
311820Sjulian * unrestricted use provided that this legend is included on all tape
411820Sjulian * media and as a part of the software program in whole or part.  Users
511820Sjulian * may copy or modify Sun RPC without charge, but are not authorized
611820Sjulian * to license or distribute it to anyone else except as part of a product or
711820Sjulian * program developed by the user.
811820Sjulian *
911820Sjulian * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1011820Sjulian * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1111820Sjulian * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1211820Sjulian *
1311820Sjulian * Sun RPC is provided with no support and without any obligation on the
1411820Sjulian * part of Sun Microsystems, Inc. to assist in its use, correction,
1511820Sjulian * modification or enhancement.
1611820Sjulian *
1711820Sjulian * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
1811820Sjulian * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
1911820Sjulian * OR ANY PART THEREOF.
2011820Sjulian *
2111820Sjulian * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2211820Sjulian * or profits or other special, indirect and consequential damages, even if
2311820Sjulian * Sun has been advised of the possibility of such damages.
2411820Sjulian *
2511820Sjulian * Sun Microsystems, Inc.
2611820Sjulian * 2550 Garcia Avenue
2711820Sjulian * Mountain View, California  94043
2811820Sjulian */
2911820Sjulian
3011820Sjulian#if 0
3111820Sjulian#ifndef lint
3211820Sjulian#ident	"@(#)rpc_scan.c	1.13	93/07/05 SMI"
3311820Sjulianstatic char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
3411820Sjulian#endif
3511820Sjulian#endif
3611820Sjulian
3711820Sjulian#include <sys/cdefs.h>
3811820Sjulian__FBSDID("$FreeBSD$");
3950479Speter
4011820Sjulian/*
4111820Sjulian * rpc_scan.c, Scanner for the RPC protocol compiler
4211820Sjulian * Copyright (C) 1987, Sun Microsystems, Inc.
4311820Sjulian */
4411820Sjulian
4511820Sjulian#include <sys/types.h>
4611820Sjulian
4711820Sjulian#include <sys/wait.h>
4811820Sjulian#include <stdio.h>
4911820Sjulian#include <ctype.h>
5011820Sjulian#include <string.h>
5111820Sjulian#include "rpc_parse.h"
5211820Sjulian#include "rpc_scan.h"
5311820Sjulian#include "rpc_util.h"
5411820Sjulian
5511820Sjulian#define startcomment(where) (where[0] == '/' && where[1] == '*')
5611820Sjulian#define endcomment(where) (where[-1] == '*' && where[0] == '/')
5711820Sjulian
5811820Sjulianstatic int pushed = 0;	/* is a token pushed */
5911820Sjulianstatic token lasttok;	/* last token, if pushed */
6011820Sjulian
6111820Sjulianstatic void unget_token( token * );
6211820Sjulianstatic void findstrconst(char **, const char **);
6311820Sjulianstatic void findchrconst(char **, const char **);
6411820Sjulianstatic void findconst(char **, const char **);
6511820Sjulianstatic void findkind( char **, token * );
6611820Sjulianstatic int cppline( char * );
6711820Sjulianstatic int directive( char * );
6811820Sjulianstatic void printdirective( char * );
6911820Sjulianstatic void docppline(char *, int *, const char **);
7011820Sjulian
7111820Sjulian/*
7211820Sjulian * scan expecting 1 given token
7311820Sjulian */
7411820Sjulianvoid
7511820Sjulianscan(tok_kind expect, token *tokp)
7611820Sjulian{
7711820Sjulian	get_token(tokp);
7811820Sjulian	if (tokp->kind != expect) {
7911820Sjulian		expected1(expect);
8011820Sjulian	}
8111820Sjulian}
8211820Sjulian
8311820Sjulian/*
8411820Sjulian * scan expecting any of the 2 given tokens
8511820Sjulian */
8611820Sjulianvoid
8711820Sjulianscan2(tok_kind expect1, tok_kind expect2, token *tokp)
8811820Sjulian{
8927244Sjhay	get_token(tokp);
9011820Sjulian	if (tokp->kind != expect1 && tokp->kind != expect2) {
9111820Sjulian		expected2(expect1, expect2);
9211820Sjulian	}
9311820Sjulian}
9411820Sjulian
9511820Sjulian/*
9611820Sjulian * scan expecting any of the 3 given token
9711820Sjulian */
9811820Sjulianvoid
9911820Sjulianscan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp)
10015248Sjhay{
10111820Sjulian	get_token(tokp);
10211820Sjulian	if (tokp->kind != expect1 && tokp->kind != expect2
10311820Sjulian	    && tokp->kind != expect3) {
10411820Sjulian		expected3(expect1, expect2, expect3);
10511820Sjulian	}
10611820Sjulian}
10711820Sjulian
10811820Sjulian/*
10911820Sjulian * scan expecting a constant, possibly symbolic
11011820Sjulian */
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