1: %{ 2: /* pathalias -- by steve bellovin, as told to peter honeyman */ 3: #ifndef lint 4: static char *sccsid = "@(#)parse.y 9.1 87/10/04"; 5: #endif /* lint */ 6: 7: #include "def.h" 8: 9: /* exports */ 10: extern void yyerror(); 11: 12: /* imports */ 13: extern p_node addnode(); 14: extern p_node addprivate(); 15: extern void fixprivate(), alias(), deadlink(); 16: extern p_link addlink(); 17: #ifndef TMPFILES 18: #define getnode(x) x 19: #define getlink(y) y 20: #else /*TMPFILES*/ 21: extern node *getnode(); 22: extern link *getlink(); 23: #endif /*TMPFILES*/ 24: extern int optind; 25: extern char *Cfile, *Netchars, **Argv; 26: extern int Argc; 27: extern long Lineno; 28: 29: /* privates */ 30: STATIC void fixnet(); 31: STATIC int yylex(), yywrap(), getword(); 32: static int Scanstate = NEWLINE; /* scanner (yylex) state */ 33: 34: /* flags for ys_flags */ 35: #define TERMINAL 1 36: %} 37: 38: %union { 39: p_node y_node; 40: Cost y_cost; 41: char y_net; 42: char *y_name; 43: struct { 44: p_node ys_node; 45: Cost ys_cost; 46: short ys_flag; 47: char ys_net; 48: char ys_dir; 49: } y_s; 50: } 51: 52: %type <y_s> site asite 53: %type <y_node> links aliases plist network nlist host pelem snode delem dlist 54: %type <y_cost> cost cexpr 55: 56: %token <y_name> SITE HOST 57: %token <y_cost> COST 58: %token <y_net> NET 59: %token EOL PRIVATE DEAD 60: 61: %left '+' '-' 62: %left '*' '/' 63: 64: %% 65: map : /* empty */ 66: | map EOL 67: | map links EOL 68: | map aliases EOL 69: | map network EOL 70: | map private EOL 71: | map dead EOL 72: | error EOL 73: ; 74: 75: links : host site cost { 76: p_link l; 77: 78: l = addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir); 79: if (GATEWAYED(getnode($2.ys_node))) 80: getlink(l)->l_flag |= LGATEWAY; 81: if ($2.ys_flag & TERMINAL) 82: getlink(l)->l_flag |= LTERMINAL; 83: } 84: | links ',' site cost { 85: p_link l; 86: 87: l = addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir); 88: if (GATEWAYED(getnode($3.ys_node))) 89: getlink(l)->l_flag |= LGATEWAY; 90: if ($3.ys_flag & TERMINAL) 91: getlink(l)->l_flag |= LTERMINAL; 92: } 93: | links ',' /* permit this benign error */ 94: ; 95: 96: aliases : host '=' SITE {alias($1, addnode($3));} 97: | aliases ',' SITE {alias($1, addnode($3));} 98: | aliases ',' /* permit this benign error */ 99: ; 100: 101: network : host '=' '{' nlist '}' cost {fixnet($1, $4, $6, DEFNET, DEFDIR);} 102: | host '=' NET '{' nlist '}' cost {fixnet($1, $5, $7, $3, LRIGHT);} 103: | host '=' '{' nlist '}' NET cost {fixnet($1, $4, $7, $6, LLEFT);} 104: ; 105: 106: private : PRIVATE '{' plist '}' /* list of privates */ 107: | PRIVATE '{' '}' {fixprivate();} /* end scope of privates */ 108: ; 109: 110: dead : DEAD '{' dlist '}'; 111: 112: host : HOST {$$ = addnode($1);} 113: | PRIVATE {$$ = addnode("private");} 114: | DEAD {$$ = addnode("dead");} 115: ; 116: 117: snode : SITE {$$ = addnode($1);} ; 118: 119: asite : SITE { 120: $$.ys_node = addnode($1); 121: $$.ys_flag = 0; 122: } 123: | '<' SITE '>' { 124: $$.ys_node = addnode($2); 125: $$.ys_flag = TERMINAL; 126: } 127: ; 128: 129: site : asite { 130: $$ = $1; 131: $$.ys_net = DEFNET; 132: $$.ys_dir = DEFDIR; 133: } 134: | NET asite { 135: $$ = $2; 136: $$.ys_net = $1; 137: $$.ys_dir = LRIGHT; 138: } 139: | asite NET { 140: $$ = $1; 141: $$.ys_net = $2; 142: $$.ys_dir = LLEFT; 143: } 144: ; 145: 146: pelem : SITE {$$ = addprivate($1);} ; 147: 148: plist : pelem {getnode($1)->n_flag |= ISPRIVATE;} 149: | plist ',' pelem {getnode($3)->n_flag |= ISPRIVATE;} 150: | plist ',' /* permit this benign error */ 151: ; 152: 153: delem : SITE {deadlink(addnode($1), (p_node) 0);} 154: | snode NET snode {deadlink($1, $3);} 155: ; 156: 157: dlist : delem 158: | dlist ',' delem 159: | dlist ',' /* permit this benign error */ 160: ; 161: 162: nlist : SITE {$$ = addnode($1);} 163: | nlist ',' snode { 164: if (getnode($3)->n_net == 0) { 165: getnode($3)->n_net = $1; 166: $$ = $3; 167: } 168: } 169: | nlist ',' /* permit this benign error */ 170: ; 171: 172: cost : {$$ = DEFCOST; /* empty -- cost is always optional */} 173: | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')' 174: {$$ = $3;} 175: ; 176: 177: cexpr : COST 178: | '(' cexpr ')' {$$ = $2;} 179: | cexpr '+' cexpr {$$ = $1 + $3;} 180: | cexpr '-' cexpr {$$ = $1 - $3;} 181: | cexpr '*' cexpr {$$ = $1 * $3;} 182: | cexpr '/' cexpr { 183: if ($3 == 0) 184: yyerror("zero divisor\n"); 185: else 186: $$ = $1 / $3; 187: } 188: ; 189: %% 190: 191: void 192: yyerror(s) 193: char *s; 194: { 195: /* a concession to bsd error(1) */ 196: if (Cfile) 197: fprintf(stderr, "\"%s\", ", Cfile); 198: else 199: fprintf(stderr, "%s: ", Argv[0]); 200: fprintf(stderr, "line %ld: %s\n", Lineno, s); 201: } 202: 203: /* 204: * patch in the costs of getting on/off the network. 205: * 206: * for each network member on netlist, add links: 207: * network -> member cost = 0; 208: * member -> network cost = parameter. 209: * 210: * if network and member both require gateways, assume network 211: * is a gateway to member (but not v.v., to avoid such travesties 212: * as topaz!seismo.css.gov.edu.rutgers). 213: * 214: * note that members can have varying costs to a network, by suitable 215: * multiple declarations. this is a feechur, albeit a useless one. 216: */ 217: STATIC void 218: fixnet(network, nlist, cost, netchar, netdir) 219: register p_node network; 220: p_node nlist; 221: Cost cost; 222: char netchar, netdir; 223: { register p_node member; 224: register p_node nextnet; 225: p_link l; 226: 227: getnode(network)->n_flag |= NNET; 228: 229: /* now insert the links */ 230: for (member = nlist ; member; member = nextnet) { 231: /* network -> member, cost is 0 */ 232: l = addlink(network, member, (Cost) 0, netchar, netdir); 233: if (GATEWAYED(getnode(network)) && GATEWAYED(getnode(member))) 234: getlink(l)->l_flag |= LGATEWAY; 235: 236: /* member -> network, cost is parameter */ 237: (void) addlink(member, network, cost, netchar, netdir); 238: nextnet = getnode(member)->n_net; 239: getnode(member)->n_net = 0; /* clear for later use */ 240: } 241: } 242: 243: /* scanner */ 244: 245: #define QUOTE '"' 246: #define STR_EQ(s1, s2) (s1[2] == s2[2] && strcmp(s1, s2) == 0) 247: #define NLRETURN() {Scanstate = NEWLINE; return EOL;} 248: 249: static struct ctable { 250: char *cname; 251: Cost cval; 252: } ctable[] = { 253: /* ordered by frequency of appearance in a "typical" dataset */ 254: {"DIRECT", 200}, 255: {"DEMAND", 300}, 256: {"DAILY", 5000}, 257: {"HOURLY", 500}, 258: {"DEDICATED", 95}, 259: {"EVENING", 1800}, 260: {"LOCAL", 25}, 261: {"LOW", 5}, /* baud rate, quality penalty */ 262: {"DEAD", INF/2}, 263: {"POLLED", 5000}, 264: {"WEEKLY", 30000}, 265: {"HIGH", -5}, /* baud rate, quality bonus */ 266: {"FAST", -80}, /* high speed (>= 9.6 kbps) modem */ 267: /* deprecated */ 268: {"ARPA", 100}, 269: {"DIALED", 300}, 270: {0, 0} 271: }; 272: 273: STATIC int 274: yylex() 275: { static char retbuf[128]; /* for return to yacc part */ 276: register int c; 277: register char *buf = retbuf; 278: register struct ctable *ct; 279: register Cost cost; 280: char errbuf[128]; 281: 282: if (feof(stdin) && yywrap()) 283: return EOF; 284: 285: /* count lines, skip over space and comments */ 286: if ((c = getchar()) == EOF) 287: NLRETURN(); 288: 289: continuation: 290: while (c == ' ' || c == '\t') 291: if ((c = getchar()) == EOF) 292: NLRETURN(); 293: 294: if (c == '#') 295: while ((c = getchar()) != '\n') 296: if (c == EOF) 297: NLRETURN(); 298: 299: /* scan token */ 300: if (c == '\n') { 301: Lineno++; 302: if ((c = getchar()) != EOF) { 303: if (c == ' ' || c == '\t') 304: goto continuation; 305: ungetc(c, stdin); 306: } 307: NLRETURN(); 308: } 309: 310: switch(Scanstate) { 311: case COSTING: 312: if (isdigit(c)) { 313: cost = c - '0'; 314: for (c = getchar(); isdigit(c); c = getchar()) 315: cost = (cost * 10) + c - '0'; 316: ungetc(c, stdin); 317: yylval.y_cost = cost; 318: return COST; 319: } 320: 321: if (getword(buf, c) == 0) { 322: for (ct = ctable; ct->cname; ct++) 323: if (STR_EQ(buf, ct->cname)) { 324: yylval.y_cost = ct->cval; 325: return COST; 326: } 327: sprintf(errbuf, "unknown cost (%s), using default", buf); 328: yyerror(errbuf); 329: yylval.y_cost = DEFCOST; 330: return COST; 331: } 332: 333: return c; /* pass the buck */ 334: 335: case NEWLINE: 336: Scanstate = OTHER; 337: if (getword(buf, c) != 0) 338: return c; 339: /* `private' (but not `"private"')? */ 340: if (c == 'p' && STR_EQ(buf, "private")) 341: return PRIVATE; 342: /* `dead' (but not `"dead"')? */ 343: if (c == 'd' && STR_EQ(buf, "dead")) 344: return DEAD; 345: 346: yylval.y_name = buf; 347: return HOST; 348: } 349: 350: if (getword(buf, c) == 0) { 351: yylval.y_name = buf; 352: return SITE; 353: } 354: 355: if (index(Netchars, c)) { 356: yylval.y_net = c; 357: return NET; 358: } 359: 360: return c; 361: } 362: 363: /* 364: * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted 365: * string that contains no newline. return -1 on failure or EOF, 0 o.w. 366: */ 367: STATIC int 368: getword(str, c) 369: register char *str; 370: register int c; 371: { 372: if (c == QUOTE) { 373: while ((c = getchar()) != QUOTE) { 374: if (c == '\n') { 375: yyerror("newline in quoted string\n"); 376: ungetc(c, stdin); 377: return -1; 378: } 379: if (c == EOF) { 380: yyerror("EOF in quoted string\n"); 381: return -1; 382: } 383: *str++ = c; 384: } 385: *str = 0; 386: return 0; 387: } 388: 389: /* host name must start with alphanumeric or `.' */ 390: if (!isalnum(c) && c != '.') 391: return -1; 392: 393: yymore: 394: do { 395: *str++ = c; 396: c = getchar(); 397: } while (isalnum(c) || c == '.' || c == '_'); 398: 399: if (c == '-' && Scanstate != COSTING) 400: goto yymore; 401: 402: ungetc(c, stdin); 403: *str = 0; 404: return 0; 405: } 406: 407: STATIC int 408: yywrap() 409: { char errbuf[100]; 410: 411: fixprivate(); /* munge private host definitions */ 412: Lineno = 1; 413: while (optind < Argc) { 414: if (freopen((Cfile = Argv[optind++]), "r", stdin) != 0) 415: return 0; 416: sprintf(errbuf, "%s: %s", Argv[0], Cfile); 417: perror(errbuf); 418: } 419: freopen("/dev/null", "r", stdin); 420: return -1; 421: }