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