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