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