xref: /titanic_53/usr/src/tools/ndrgen/ndr_lex.c (revision d0e518695adc90b82233b99af7dffbb3d3f92c00)
1*d0e51869Samw /*
2*d0e51869Samw  * CDDL HEADER START
3*d0e51869Samw  *
4*d0e51869Samw  * The contents of this file are subject to the terms of the
5*d0e51869Samw  * Common Development and Distribution License (the "License").
6*d0e51869Samw  * You may not use this file except in compliance with the License.
7*d0e51869Samw  *
8*d0e51869Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d0e51869Samw  * or http://www.opensolaris.org/os/licensing.
10*d0e51869Samw  * See the License for the specific language governing permissions
11*d0e51869Samw  * and limitations under the License.
12*d0e51869Samw  *
13*d0e51869Samw  * When distributing Covered Code, include this CDDL HEADER in each
14*d0e51869Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d0e51869Samw  * If applicable, add the following below this CDDL HEADER, with the
16*d0e51869Samw  * fields enclosed by brackets "[]" replaced with your own identifying
17*d0e51869Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d0e51869Samw  *
19*d0e51869Samw  * CDDL HEADER END
20*d0e51869Samw  */
21*d0e51869Samw 
22*d0e51869Samw /*
23*d0e51869Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*d0e51869Samw  * Use is subject to license terms.
25*d0e51869Samw  */
26*d0e51869Samw 
27*d0e51869Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*d0e51869Samw 
29*d0e51869Samw #include <errno.h>
30*d0e51869Samw #include <stdarg.h>
31*d0e51869Samw #include "ndrgen.h"
32*d0e51869Samw #include "y.tab.h"
33*d0e51869Samw 
34*d0e51869Samw /*
35*d0e51869Samw  * C-like lexical analysis.
36*d0e51869Samw  *
37*d0e51869Samw  * 1. Define a "struct node"
38*d0e51869Samw  * 2. Define a "struct symbol" that encapsulates a struct node.
39*d0e51869Samw  * 3. Define a "struct integer" that encapsulates a struct node.
40*d0e51869Samw  * 4. Set the YACC stack type in the grammar:
41*d0e51869Samw  *		%{
42*d0e51869Samw  *		#define YYSTYPE struct node *
43*d0e51869Samw  *		%}
44*d0e51869Samw  * 5. Define %token's in the grammer for IDENTIFIER, STRING and INTEGER.
45*d0e51869Samw  *    Using "_KW" as a suffix for keyword tokens, i.e. "struct" is
46*d0e51869Samw  *    "%token STRUCT_KW":
47*d0e51869Samw  *	// atomic values
48*d0e51869Samw  *	%token INTEGER STRING IDENTIFIER
49*d0e51869Samw  *	// keywords
50*d0e51869Samw  *	%token STRUCT_KW CASE_KW
51*d0e51869Samw  *	// operators
52*d0e51869Samw  *	%token PLUS MINUS ASSIGN ARROW
53*d0e51869Samw  *	// overloaded tokens (++ --, < > <= >=, == !=, += -= *= ...)
54*d0e51869Samw  *	%token INCOP RELOP EQUOP ASSOP
55*d0e51869Samw  * 6. It's easiest to use the yacc(1) generated token numbers for node
56*d0e51869Samw  *    labels.  For node labels that are not actually part of the grammer,
57*d0e51869Samw  *    use a %token with an L_ prefix:
58*d0e51869Samw  *	// node labels (can't be generated by lex)
59*d0e51869Samw  *	%token L_LT L_LTE L_GT L_GTE L_EQU L_NEQ
60*d0e51869Samw  * 7. Call set_lex_input() before parsing.
61*d0e51869Samw  */
62*d0e51869Samw 
63*d0e51869Samw #define	SQ	'\''
64*d0e51869Samw #define	DQ	'"'
65*d0e51869Samw 
66*d0e51869Samw #define	isquote(c) ((c) == SQ || (c) == DQ)
67*d0e51869Samw #define	iswhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
68*d0e51869Samw 
69*d0e51869Samw #define	is_between(c, l, u)  ((l) <= (c) && (c) <= (u))
70*d0e51869Samw #define	is_white(c)	((c) == ' ' || c == '\r' || c == '\t' || c == '\f')
71*d0e51869Samw #define	is_lower(c)	is_between((c), 'a', 'z')
72*d0e51869Samw #define	is_upper(c)	is_between((c), 'A', 'Z')
73*d0e51869Samw #define	is_alpha(c)	(is_lower(c) || is_upper(c))
74*d0e51869Samw #define	is_digit(c)	is_between((c), '0', '9')
75*d0e51869Samw #define	is_sstart(c)	(is_alpha(c) || (c) == '_')
76*d0e51869Samw #define	is_sfollow(c)	(is_sstart(c) || is_digit(c))
77*d0e51869Samw #define	is_xdigit(c)	\
78*d0e51869Samw 	(is_digit(c) || is_between((c), 'A', 'F') || is_between((c), 'a', 'f'))
79*d0e51869Samw 
80*d0e51869Samw ndr_symbol_t		*symbol_list;
81*d0e51869Samw static ndr_integer_t	*integer_list;
82*d0e51869Samw static FILE		*lex_infp;
83*d0e51869Samw static ndr_symbol_t	*file_name;
84*d0e51869Samw int			line_number;
85*d0e51869Samw int			n_compile_error;
86*d0e51869Samw 
87*d0e51869Samw static int		lex_at_bol;
88*d0e51869Samw 
89*d0e51869Samw /* In yacc(1) generated parser */
90*d0e51869Samw extern struct node	*yylval;
91*d0e51869Samw 
92*d0e51869Samw /*
93*d0e51869Samw  * The keywtab[] and optable[] could be external to this lex
94*d0e51869Samw  * and it would all still work.
95*d0e51869Samw  */
96*d0e51869Samw static ndr_keyword_t keywtable[] = {
97*d0e51869Samw 	{ "struct",	STRUCT_KW,	0 },
98*d0e51869Samw 	{ "union",	UNION_KW,	0 },
99*d0e51869Samw 	{ "typedef",	TYPEDEF_KW,	0 },
100*d0e51869Samw 
101*d0e51869Samw 	{ "interface",	INTERFACE_KW,	0 },
102*d0e51869Samw 	{ "uuid",	UUID_KW,	0 },
103*d0e51869Samw 	{ "_no_reorder", _NO_REORDER_KW, 0 },
104*d0e51869Samw 	{ "extern",	EXTERN_KW,	0 },
105*d0e51869Samw 	{ "reference",	REFERENCE_KW,	0 },
106*d0e51869Samw 
107*d0e51869Samw 	{ "align",	ALIGN_KW,	0 },
108*d0e51869Samw 	{ "operation",	OPERATION_KW,	0 },
109*d0e51869Samw 	{ "in",		IN_KW,		0 },
110*d0e51869Samw 	{ "out",	OUT_KW,		0 },
111*d0e51869Samw 
112*d0e51869Samw 	{ "string",	STRING_KW,	0 },
113*d0e51869Samw 	{ "size_is",	SIZE_IS_KW,	0 },
114*d0e51869Samw 	{ "length_is",	LENGTH_IS_KW,	0 },
115*d0e51869Samw 
116*d0e51869Samw 	{ "switch_is",	SWITCH_IS_KW,	0 },
117*d0e51869Samw 	{ "case",	CASE_KW,	0 },
118*d0e51869Samw 	{ "default",	DEFAULT_KW,	0 },
119*d0e51869Samw 
120*d0e51869Samw 	{ "transmit_as", TRANSMIT_AS_KW, 0 },
121*d0e51869Samw 	{ "arg_is",	ARG_IS_KW,	0 },
122*d0e51869Samw 
123*d0e51869Samw 	{ "char",	BASIC_TYPE,	1 },
124*d0e51869Samw 	{ "uchar",	BASIC_TYPE,	1 },
125*d0e51869Samw 	{ "wchar",	BASIC_TYPE,	2 },
126*d0e51869Samw 	{ "short",	BASIC_TYPE,	2 },
127*d0e51869Samw 	{ "ushort",	BASIC_TYPE,	2 },
128*d0e51869Samw 	{ "long",	BASIC_TYPE,	4 },
129*d0e51869Samw 	{ "ulong",	BASIC_TYPE,	4 },
130*d0e51869Samw 	{0}
131*d0e51869Samw };
132*d0e51869Samw 
133*d0e51869Samw static ndr_keyword_t optable[] = {
134*d0e51869Samw 	{ "{",		LC,		0 },
135*d0e51869Samw 	{ "}",		RC,		0 },
136*d0e51869Samw 	{ "(",		LP,		0 },
137*d0e51869Samw 	{ ")",		RP,		0 },
138*d0e51869Samw 	{ "[",		LB,		0 },
139*d0e51869Samw 	{ "]",		RB,		0 },
140*d0e51869Samw 	{ "*",		STAR,		0 },
141*d0e51869Samw 	{ ";",		SEMI,		0 },
142*d0e51869Samw 	{0}
143*d0e51869Samw };
144*d0e51869Samw 
145*d0e51869Samw static int getch(FILE *fp);
146*d0e51869Samw static ndr_integer_t *int_enter(long);
147*d0e51869Samw static ndr_symbol_t *sym_find(char *);
148*d0e51869Samw static int str_to_sv(char *, char *sv[]);
149*d0e51869Samw 
150*d0e51869Samw /*
151*d0e51869Samw  * Enter the symbols for keyword.
152*d0e51869Samw  */
153*d0e51869Samw static void
154*d0e51869Samw keyw_tab_init(ndr_keyword_t kwtable[])
155*d0e51869Samw {
156*d0e51869Samw 	int			i;
157*d0e51869Samw 	ndr_keyword_t		*kw;
158*d0e51869Samw 	ndr_symbol_t		*sym;
159*d0e51869Samw 
160*d0e51869Samw 	for (i = 0; kwtable[i].name; i++) {
161*d0e51869Samw 		kw = &kwtable[i];
162*d0e51869Samw 
163*d0e51869Samw 		sym = sym_enter(kw->name);
164*d0e51869Samw 		sym->kw = kw;
165*d0e51869Samw 	}
166*d0e51869Samw }
167*d0e51869Samw 
168*d0e51869Samw void
169*d0e51869Samw set_lex_input(FILE *fp, char *name)
170*d0e51869Samw {
171*d0e51869Samw 	keyw_tab_init(keywtable);
172*d0e51869Samw 	keyw_tab_init(optable);
173*d0e51869Samw 
174*d0e51869Samw 	lex_infp = fp;
175*d0e51869Samw 	file_name = sym_enter(name);
176*d0e51869Samw 	line_number = 1;
177*d0e51869Samw 	lex_at_bol = 1;
178*d0e51869Samw }
179*d0e51869Samw 
180*d0e51869Samw static int
181*d0e51869Samw getch(FILE *fp)
182*d0e51869Samw {
183*d0e51869Samw 	return (getc(fp));
184*d0e51869Samw }
185*d0e51869Samw 
186*d0e51869Samw int
187*d0e51869Samw yylex(void)
188*d0e51869Samw {
189*d0e51869Samw 	char		lexeme[512];
190*d0e51869Samw 	char		*p = lexeme;
191*d0e51869Samw 	FILE		*fp = lex_infp;
192*d0e51869Samw 	int		c, xc;
193*d0e51869Samw 	ndr_symbol_t	*sym;
194*d0e51869Samw 	ndr_integer_t	*intg;
195*d0e51869Samw 
196*d0e51869Samw top:
197*d0e51869Samw 	p = lexeme;
198*d0e51869Samw 
199*d0e51869Samw 	c = getch(fp);
200*d0e51869Samw 	if (c == EOF)
201*d0e51869Samw 		return (EOF);
202*d0e51869Samw 
203*d0e51869Samw 	if (c == '\n') {
204*d0e51869Samw 		line_number++;
205*d0e51869Samw 		lex_at_bol = 1;
206*d0e51869Samw 		goto top;
207*d0e51869Samw 	}
208*d0e51869Samw 
209*d0e51869Samw 	/*
210*d0e51869Samw 	 * Handle preprocessor lines. This just notes
211*d0e51869Samw 	 * which file we're processing.
212*d0e51869Samw 	 */
213*d0e51869Samw 	if (c == '#' && lex_at_bol) {
214*d0e51869Samw 		char		*sv[10];
215*d0e51869Samw 		int		sc;
216*d0e51869Samw 
217*d0e51869Samw 		while ((c = getch(fp)) != EOF && c != '\n')
218*d0e51869Samw 			*p++ = c;
219*d0e51869Samw 
220*d0e51869Samw 		*p = 0;
221*d0e51869Samw 		/* note: no ungetc() of newline, we don't want to count it */
222*d0e51869Samw 
223*d0e51869Samw 		if (*lexeme != ' ') {
224*d0e51869Samw 			/* not a line we know */
225*d0e51869Samw 			goto top;
226*d0e51869Samw 		}
227*d0e51869Samw 
228*d0e51869Samw 		sc = str_to_sv(lexeme, sv);
229*d0e51869Samw 		if (sc < 2)
230*d0e51869Samw 			goto top;
231*d0e51869Samw 
232*d0e51869Samw 		file_name = sym_enter(sv[1]);
233*d0e51869Samw 		line_number = atoi(sv[0]);	/* for next input line */
234*d0e51869Samw 		lex_at_bol = 1;
235*d0e51869Samw 		goto top;
236*d0e51869Samw 	}
237*d0e51869Samw 
238*d0e51869Samw 	lex_at_bol = 0;
239*d0e51869Samw 
240*d0e51869Samw 	/*
241*d0e51869Samw 	 * Skip white space
242*d0e51869Samw 	 */
243*d0e51869Samw 	if (is_white(c))
244*d0e51869Samw 		goto top;
245*d0e51869Samw 
246*d0e51869Samw 	/*
247*d0e51869Samw 	 * Symbol? Might be a keyword or just an identifier
248*d0e51869Samw 	 */
249*d0e51869Samw 	if (is_sstart(c)) {
250*d0e51869Samw 		/* we got a symbol */
251*d0e51869Samw 		do {
252*d0e51869Samw 			*p++ = c;
253*d0e51869Samw 			c = getch(fp);
254*d0e51869Samw 		} while (is_sfollow(c));
255*d0e51869Samw 		(void) ungetc(c, fp);
256*d0e51869Samw 		*p = 0;
257*d0e51869Samw 
258*d0e51869Samw 		sym = sym_enter(lexeme);
259*d0e51869Samw 
260*d0e51869Samw 		yylval = &sym->s_node;
261*d0e51869Samw 
262*d0e51869Samw 		if (sym->kw) {
263*d0e51869Samw 			return (sym->kw->token);
264*d0e51869Samw 		} else {
265*d0e51869Samw 			return (IDENTIFIER);
266*d0e51869Samw 		}
267*d0e51869Samw 	}
268*d0e51869Samw 
269*d0e51869Samw 	/*
270*d0e51869Samw 	 * Integer constant?
271*d0e51869Samw 	 */
272*d0e51869Samw 	if (is_digit(c)) {
273*d0e51869Samw 		/* we got a number */
274*d0e51869Samw 		*p++ = c;
275*d0e51869Samw 		if (c == '0') {
276*d0e51869Samw 			c = getch(fp);
277*d0e51869Samw 			if (c == 'x' || c == 'X') {
278*d0e51869Samw 				/* handle hex specially */
279*d0e51869Samw 				do {
280*d0e51869Samw 					*p++ = c;
281*d0e51869Samw 					c = getch(fp);
282*d0e51869Samw 				} while (is_xdigit(c));
283*d0e51869Samw 				goto convert_icon;
284*d0e51869Samw 			} else if (c == 'b' || c == 'B' ||
285*d0e51869Samw 			    c == 'd' || c == 'D' ||
286*d0e51869Samw 			    c == 'o' || c == 'O') {
287*d0e51869Samw 				do {
288*d0e51869Samw 					*p++ = c;
289*d0e51869Samw 					c = getch(fp);
290*d0e51869Samw 				} while (is_digit(c));
291*d0e51869Samw 				goto convert_icon;
292*d0e51869Samw 			}
293*d0e51869Samw 			(void) ungetc(c, fp);
294*d0e51869Samw 		}
295*d0e51869Samw 		/* could be anything */
296*d0e51869Samw 		c = getch(fp);
297*d0e51869Samw 		while (is_digit(c)) {
298*d0e51869Samw 			*p++ = c;
299*d0e51869Samw 			c = getch(fp);
300*d0e51869Samw 		}
301*d0e51869Samw 
302*d0e51869Samw convert_icon:
303*d0e51869Samw 		*p = 0;
304*d0e51869Samw 		(void) ungetc(c, fp);
305*d0e51869Samw 
306*d0e51869Samw 		intg = int_enter(strtol(lexeme, 0, 0));
307*d0e51869Samw 		yylval = &intg->s_node;
308*d0e51869Samw 
309*d0e51869Samw 		return (INTEGER);
310*d0e51869Samw 	}
311*d0e51869Samw 
312*d0e51869Samw 	/* Could handle strings. We don't seem to need them yet */
313*d0e51869Samw 
314*d0e51869Samw 	yylval = 0;		/* operator tokens have no value */
315*d0e51869Samw 	xc = getch(fp);		/* get look-ahead for two-char lexemes */
316*d0e51869Samw 
317*d0e51869Samw 	lexeme[0] = c;
318*d0e51869Samw 	lexeme[1] = xc;
319*d0e51869Samw 	lexeme[2] = 0;
320*d0e51869Samw 
321*d0e51869Samw 	/*
322*d0e51869Samw 	 * Look for to-end-of-line comment
323*d0e51869Samw 	 */
324*d0e51869Samw 	if (c == '/' && xc == '/') {
325*d0e51869Samw 		/* eat the comment */
326*d0e51869Samw 		while ((c = getch(fp)) != EOF && c != '\n')
327*d0e51869Samw 			;
328*d0e51869Samw 		(void) ungetc(c, fp);		/* put back newline */
329*d0e51869Samw 		goto top;
330*d0e51869Samw 	}
331*d0e51869Samw 
332*d0e51869Samw 	/*
333*d0e51869Samw 	 * Look for multi-line comment
334*d0e51869Samw 	 */
335*d0e51869Samw 	if (c == '/' && xc == '*') {
336*d0e51869Samw 		/* eat the comment */
337*d0e51869Samw 		xc = -1;
338*d0e51869Samw 		while ((c = getch(fp)) != EOF) {
339*d0e51869Samw 			if (xc == '*' && c == '/') {
340*d0e51869Samw 				/* that's it */
341*d0e51869Samw 				break;
342*d0e51869Samw 			}
343*d0e51869Samw 			xc = c;
344*d0e51869Samw 			if (c == '\n')
345*d0e51869Samw 				line_number++;
346*d0e51869Samw 		}
347*d0e51869Samw 		goto top;
348*d0e51869Samw 	}
349*d0e51869Samw 
350*d0e51869Samw 	/*
351*d0e51869Samw 	 * Use symbol table lookup for two-character and
352*d0e51869Samw 	 * one character operator tokens.
353*d0e51869Samw 	 */
354*d0e51869Samw 	sym = sym_find(lexeme);
355*d0e51869Samw 	if (sym) {
356*d0e51869Samw 		/* there better be a keyword attached */
357*d0e51869Samw 		yylval = &sym->s_node;
358*d0e51869Samw 		return (sym->kw->token);
359*d0e51869Samw 	}
360*d0e51869Samw 
361*d0e51869Samw 	/* Try a one-character form */
362*d0e51869Samw 	(void) ungetc(xc, fp);
363*d0e51869Samw 	lexeme[1] = 0;
364*d0e51869Samw 	sym = sym_find(lexeme);
365*d0e51869Samw 	if (sym) {
366*d0e51869Samw 		/* there better be a keyword attached */
367*d0e51869Samw 		yylval = &sym->s_node;
368*d0e51869Samw 		return (sym->kw->token);
369*d0e51869Samw 	}
370*d0e51869Samw 
371*d0e51869Samw 	compile_error("unrecognized character 0x%02x", c);
372*d0e51869Samw 	goto top;
373*d0e51869Samw }
374*d0e51869Samw 
375*d0e51869Samw static ndr_symbol_t *
376*d0e51869Samw sym_find(char *name)
377*d0e51869Samw {
378*d0e51869Samw 	ndr_symbol_t		**pp;
379*d0e51869Samw 	ndr_symbol_t		*p;
380*d0e51869Samw 
381*d0e51869Samw 	for (pp = &symbol_list; (p = *pp) != 0; pp = &p->next) {
382*d0e51869Samw 		if (strcmp(p->name, name) == 0)
383*d0e51869Samw 			return (p);
384*d0e51869Samw 	}
385*d0e51869Samw 
386*d0e51869Samw 	return (0);
387*d0e51869Samw }
388*d0e51869Samw 
389*d0e51869Samw ndr_symbol_t *
390*d0e51869Samw sym_enter(char *name)
391*d0e51869Samw {
392*d0e51869Samw 	ndr_symbol_t		**pp;
393*d0e51869Samw 	ndr_symbol_t		*p;
394*d0e51869Samw 
395*d0e51869Samw 	for (pp = &symbol_list; (p = *pp) != 0; pp = &p->next) {
396*d0e51869Samw 		if (strcmp(p->name, name) == 0)
397*d0e51869Samw 			return (p);
398*d0e51869Samw 	}
399*d0e51869Samw 
400*d0e51869Samw 	p = ndr_alloc(1, sizeof (ndr_symbol_t));
401*d0e51869Samw 
402*d0e51869Samw 	if ((p->name = strdup(name)) == NULL)
403*d0e51869Samw 		fatal_error("%s", strerror(ENOMEM));
404*d0e51869Samw 
405*d0e51869Samw 	p->s_node.label = IDENTIFIER;
406*d0e51869Samw 	p->s_node.n_sym = p;
407*d0e51869Samw 
408*d0e51869Samw 	*pp = p;
409*d0e51869Samw 
410*d0e51869Samw 	return (p);
411*d0e51869Samw }
412*d0e51869Samw 
413*d0e51869Samw static ndr_integer_t *
414*d0e51869Samw int_enter(long value)
415*d0e51869Samw {
416*d0e51869Samw 	ndr_integer_t		**pp;
417*d0e51869Samw 	ndr_integer_t		*p;
418*d0e51869Samw 
419*d0e51869Samw 	for (pp = &integer_list; (p = *pp) != 0; pp = &p->next) {
420*d0e51869Samw 		if (p->value == value)
421*d0e51869Samw 			return (p);
422*d0e51869Samw 	}
423*d0e51869Samw 
424*d0e51869Samw 	p = ndr_alloc(1, sizeof (ndr_integer_t));
425*d0e51869Samw 
426*d0e51869Samw 	p->value = value;
427*d0e51869Samw 	p->s_node.label = INTEGER;
428*d0e51869Samw 	p->s_node.n_int = value;
429*d0e51869Samw 
430*d0e51869Samw 	*pp = p;
431*d0e51869Samw 
432*d0e51869Samw 	return (p);
433*d0e51869Samw }
434*d0e51869Samw 
435*d0e51869Samw void *
436*d0e51869Samw ndr_alloc(size_t nelem, size_t elsize)
437*d0e51869Samw {
438*d0e51869Samw 	void *p;
439*d0e51869Samw 
440*d0e51869Samw 	if ((p = calloc(nelem, elsize)) == NULL) {
441*d0e51869Samw 		fatal_error("%s", strerror(ENOMEM));
442*d0e51869Samw 		/* NOTREACHED */
443*d0e51869Samw 	}
444*d0e51869Samw 
445*d0e51869Samw 	return (p);
446*d0e51869Samw }
447*d0e51869Samw 
448*d0e51869Samw /*
449*d0e51869Samw  * The input context (filename, line number) is maintained by the
450*d0e51869Samw  * lexical analysis, and we generally want such info reported for
451*d0e51869Samw  * errors in a consistent manner.
452*d0e51869Samw  */
453*d0e51869Samw void
454*d0e51869Samw compile_error(const char *fmt, ...)
455*d0e51869Samw {
456*d0e51869Samw 	char	buf[NDLBUFSZ];
457*d0e51869Samw 	va_list ap;
458*d0e51869Samw 
459*d0e51869Samw 	va_start(ap, fmt);
460*d0e51869Samw 	(void) vsnprintf(buf, NDLBUFSZ, fmt, ap);
461*d0e51869Samw 	va_end(ap);
462*d0e51869Samw 
463*d0e51869Samw 	(void) fprintf(stderr, "ndrgen: compile error: %s:%d: %s\n",
464*d0e51869Samw 	    file_name->name, line_number, buf);
465*d0e51869Samw 
466*d0e51869Samw 	n_compile_error++;
467*d0e51869Samw }
468*d0e51869Samw 
469*d0e51869Samw void
470*d0e51869Samw fatal_error(const char *fmt, ...)
471*d0e51869Samw {
472*d0e51869Samw 	char	buf[NDLBUFSZ];
473*d0e51869Samw 	va_list ap;
474*d0e51869Samw 
475*d0e51869Samw 	va_start(ap, fmt);
476*d0e51869Samw 	(void) vsnprintf(buf, NDLBUFSZ, fmt, ap);
477*d0e51869Samw 	va_end(ap);
478*d0e51869Samw 
479*d0e51869Samw 	(void) fprintf(stderr, "ndrgen: fatal error: %s\n", buf);
480*d0e51869Samw 	exit(1);
481*d0e51869Samw }
482*d0e51869Samw 
483*d0e51869Samw /*
484*d0e51869Samw  * Setup nodes for the lexical analyzer.
485*d0e51869Samw  */
486*d0e51869Samw struct node *
487*d0e51869Samw n_cons(int label, ...)
488*d0e51869Samw {
489*d0e51869Samw 	ndr_node_t		*np;
490*d0e51869Samw 	va_list ap;
491*d0e51869Samw 
492*d0e51869Samw 	np = ndr_alloc(1, sizeof (ndr_node_t));
493*d0e51869Samw 
494*d0e51869Samw 	va_start(ap, label);
495*d0e51869Samw 	np->label = label;
496*d0e51869Samw 	np->n_arg[0] = va_arg(ap, void *);
497*d0e51869Samw 	np->n_arg[1] = va_arg(ap, void *);
498*d0e51869Samw 	np->n_arg[2] = va_arg(ap, void *);
499*d0e51869Samw 	va_end(ap);
500*d0e51869Samw 
501*d0e51869Samw 	np->line_number = line_number;
502*d0e51869Samw 	np->file_name = file_name;
503*d0e51869Samw 
504*d0e51869Samw 	return (np);
505*d0e51869Samw }
506*d0e51869Samw 
507*d0e51869Samw /*
508*d0e51869Samw  *	list:	item
509*d0e51869Samw  *	|	list item	={ n_splice($1, $2); }
510*d0e51869Samw  *	;
511*d0e51869Samw  */
512*d0e51869Samw void
513*d0e51869Samw n_splice(struct node *np1, struct node *np2)
514*d0e51869Samw {
515*d0e51869Samw 	while (np1->n_next)
516*d0e51869Samw 		np1 = np1->n_next;
517*d0e51869Samw 
518*d0e51869Samw 	np1->n_next = np2;
519*d0e51869Samw }
520*d0e51869Samw 
521*d0e51869Samw /*
522*d0e51869Samw  * Convert a string of words to a vector of strings.
523*d0e51869Samw  * Returns the number of words.
524*d0e51869Samw  */
525*d0e51869Samw static int
526*d0e51869Samw str_to_sv(char *buf, char *sv[])
527*d0e51869Samw {
528*d0e51869Samw 	char		**pp = sv;
529*d0e51869Samw 	char		*p = buf;
530*d0e51869Samw 	char		*q = buf;
531*d0e51869Samw 	int		in_word = 0;
532*d0e51869Samw 	int		c;
533*d0e51869Samw 
534*d0e51869Samw 	for (;;) {
535*d0e51869Samw 		c = *p++;
536*d0e51869Samw 		if (c == 0)
537*d0e51869Samw 			break;
538*d0e51869Samw 
539*d0e51869Samw 		if (!in_word) {
540*d0e51869Samw 			if (iswhite(c))
541*d0e51869Samw 				continue;
542*d0e51869Samw 
543*d0e51869Samw 			*pp++ = q;
544*d0e51869Samw 			in_word = 1;
545*d0e51869Samw 		}
546*d0e51869Samw 
547*d0e51869Samw 		if (isquote(c)) {
548*d0e51869Samw 			int		qc = c;
549*d0e51869Samw 
550*d0e51869Samw 			while (((c = *p++) != 0) && (c != qc))
551*d0e51869Samw 				*q++ = c;
552*d0e51869Samw 			if (c == 0)
553*d0e51869Samw 				break;
554*d0e51869Samw 		} else if (iswhite(c)) {
555*d0e51869Samw 			/* end of word */
556*d0e51869Samw 			*q++ = 0;
557*d0e51869Samw 			in_word = 0;
558*d0e51869Samw 		} else {
559*d0e51869Samw 			/* still inside word */
560*d0e51869Samw 			*q++ = c;
561*d0e51869Samw 		}
562*d0e51869Samw 	}
563*d0e51869Samw 
564*d0e51869Samw 	if (in_word)
565*d0e51869Samw 		*q++ = 0;
566*d0e51869Samw 
567*d0e51869Samw 	*pp = (char *)0;
568*d0e51869Samw 	return (pp - sv);
569*d0e51869Samw }
570