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