📄 parse.y
字号:
%{/* pathalias -- by steve bellovin, as told to peter honeyman */#ifndef lintstatic char *sccsid = "@(#)parse.y 9.11 91/06/01";#endif /* lint */#include "def.h"/* scanner states (yylex, parse) */#define OTHER 0#define COSTING 1#define NEWLINE 2#define FILENAME 3/* exports */long Tcount;extern void yyerror();/* imports */extern node *addnode(), *addprivate();extern void fixprivate(), alias(), deadlink(), deletelink();extern link *addlink();extern int strcmp();extern char *strsave();extern int optind;extern char *Cfile, *Netchars, **Argv;extern int Lineno, Argc;extern node *Home;/* privates */STATIC void fixnet(), adjust();STATIC int yylex(), yywrap(), getword();static int Scanstate = NEWLINE; /* scanner (yylex) state *//* flags for ys_flags */#define TERMINAL 1%}%union { node *y_node; Cost y_cost; char y_net; char *y_name; struct { node *ys_node; Cost ys_cost; short ys_flag; char ys_net; char ys_dir; } y_s;}%type <y_s> site asite%type <y_node> links aliases plist network nlist host nhost%type <y_node> usite delem dlist%type <y_cost> cost cexpr%token <y_name> SITE HOST STRING%token <y_cost> COST%token <y_net> NET%token EOL PRIVATE DEAD DELETE FILETOK ADJUST%left '+' '-'%left '*' '/'%%map : /* empty */ | map EOL | map links EOL | map aliases EOL | map network EOL | map private EOL | map dead EOL | map delete EOL | map file EOL | map adjust EOL | error EOL ;links : host site cost { struct link *l; l = addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir); if (GATEWAYED($2.ys_node)) l->l_flag |= LGATEWAY; if ($2.ys_flag & TERMINAL) l->l_flag |= LTERMINAL; } | links ',' site cost { struct link *l; l = addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir); if (GATEWAYED($3.ys_node)) l->l_flag |= LGATEWAY; if ($3.ys_flag & TERMINAL) l->l_flag |= LTERMINAL; } | links ',' /* benign error */ ;host : HOST {$$ = addnode($1);} | PRIVATE {$$ = addnode("private");} | DEAD {$$ = addnode("dead");} | DELETE {$$ = addnode("delete");} | FILETOK {$$ = addnode("file");} | ADJUST {$$ = addnode("adjust");} ;site : asite { $$ = $1; $$.ys_net = DEFNET; $$.ys_dir = DEFDIR; } | NET asite { $$ = $2; $$.ys_net = $1; $$.ys_dir = LRIGHT; } | asite NET { $$ = $1; $$.ys_net = $2; $$.ys_dir = LLEFT; } ;asite : SITE { $$.ys_node = addnode($1); $$.ys_flag = 0; } | '<' SITE '>' { Tcount++; $$.ys_node = addnode($2); $$.ys_flag = TERMINAL; } ;aliases : host '=' SITE {alias($1, addnode($3));} | aliases ',' SITE {alias($1, addnode($3));} | aliases ',' /* benign error */ ;network : nhost '{' nlist '}' cost {fixnet($1, $3, $5, DEFNET, DEFDIR);} | nhost NET '{' nlist '}' cost {fixnet($1, $4, $6, $2, LRIGHT);} | nhost '{' nlist '}' NET cost {fixnet($1, $3, $6, $5, LLEFT);} ;nhost : '=' {$$ = 0; /* anonymous net */} | host '=' {$$ = $1; /* named net */} ;nlist : SITE {$$ = addnode($1);} | nlist ',' SITE { node *n; n = addnode($3); if (n->n_net == 0) { n->n_net = $1; $$ = n; } } | nlist ',' /* benign error */ ; private : PRIVATE '{' plist '}' /* list of privates */ | PRIVATE '{' '}' {fixprivate();} /* end scope of privates */ ;plist : SITE {addprivate($1)->n_flag |= ISPRIVATE;} | plist ',' SITE {addprivate($3)->n_flag |= ISPRIVATE;} | plist ',' /* benign error */ ;dead : DEAD '{' dlist '}';dlist : delem | dlist ',' delem | dlist ',' /* benign error */ ;delem : SITE {deadlink(addnode($1), (node *) 0);} | usite NET usite {deadlink($1, $3);} ;usite : SITE {$$ = addnode($1);} ; /* necessary unit production */delete : DELETE '{' dellist '}';dellist : delelem | dellist ',' delelem | dellist ',' /* benign error */ ;delelem : SITE { node *n; n = addnode($1); deletelink(n, (node *) 0); n->n_flag |= ISPRIVATE; /* reset Home if it's deleted */ if (n == Home) Home = addnode(Home->n_name); } | usite NET usite {deletelink($1, $3);} ;file : FILETOK '{' {Scanstate = FILENAME;} STRING {Scanstate = OTHER;} '}' { Lineno = 0; Cfile = strsave($4); }adjust : ADJUST '{' adjlist '}' ;adjlist : adjelem | adjlist ',' adjelem | adjlist ',' /* benign error */ ;adjelem : usite cost {adjust($1, $2);} ;cost : {$$ = DEFCOST; /* empty -- cost is always optional */} | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')' {$$ = $3;} ;cexpr : COST | '-' cexpr {$$ = -$2;} | '(' cexpr ')' {$$ = $2;} | cexpr '+' cexpr {$$ = $1 + $3;} | cexpr '-' cexpr {$$ = $1 - $3;} | cexpr '*' cexpr {$$ = $1 * $3;} | cexpr '/' cexpr { if ($3 == 0) yyerror("zero divisor\n"); else $$ = $1 / $3; } ;%%void#ifdef YYDEBUG/*VARARGS1*/yyerror(fmt, arg) char *fmt, *arg;#elseyyerror(s) char *s;#endif{ /* a concession to bsd error(1) */ fprintf(stderr, "\"%s\", ", Cfile);#ifdef YYDEBUG fprintf(stderr, "line %d: ", Lineno); fprintf(stderr, fmt, arg); putc('\n', stderr);#else fprintf(stderr, "line %d: %s\n", Lineno, s);#endif}/* * patch in the costs of getting on/off the network. * * for each network member on netlist, add links: * network -> member cost = 0; * member -> network cost = parameter. * * if network and member both require gateways, assume network * is a gateway to member (but not v.v., to avoid such travesties * as topaz!seismo.css.gov.edu.rutgers). * * note that members can have varying costs to a network, by suitable * multiple declarations. this is a feechur, albeit a useless one. */STATIC voidfixnet(network, nlist, cost, netchar, netdir) register node *network; node *nlist; Cost cost; char netchar, netdir;{ register node *member, *nextnet; link *l; static int netanon = 0; char anon[25]; if (network == 0) { sprintf(anon, "[unnamed net %d]", netanon++); network = addnode(anon); } network->n_flag |= NNET; /* insert the links */ for (member = nlist ; member; member = nextnet) { /* network -> member, cost is 0 */ l = addlink(network, member, (Cost) 0, netchar, netdir); if (GATEWAYED(network) && GATEWAYED(member)) l->l_flag |= LGATEWAY; /* member -> network, cost is parameter */ /* never ever ever crawl up from a domain*/ if (!ISADOMAIN(network)) (void) addlink(member, network, cost, netchar, netdir); nextnet = member->n_net; member->n_net = 0; /* clear for later use */ }}/* scanner */#define QUOTE '"'#define STR_EQ(s1, s2) (s1[2] == s2[2] && strcmp(s1, s2) == 0)#define NLRETURN() {Scanstate = NEWLINE; return EOL;}static struct ctable { char *cname; Cost cval;} ctable[] = { /* ordered by frequency of appearance in a "typical" dataset */ {"DIRECT", 200}, {"DEMAND", 300}, {"DAILY", 5000}, {"HOURLY", 500}, {"DEDICATED", 100}, {"EVENING", 2000}, {"LOCAL", 25}, {"LOW", 5}, /* baud rate, quality penalty */ {"DEAD", MILLION}, {"POLLED", 5000}, {"WEEKLY", 30000}, {"HIGH", -5}, /* baud rate, quality bonus */ {"FAST", -80}, /* high speed (>= 9.6 kbps) modem */ /* deprecated */ {"ARPA", 100}, {"DIALED", 300}, {0, 0}};STATIC intyylex(){ static char retbuf[128]; /* for return to yacc part */ register int c; register char *buf = retbuf; register struct ctable *ct; register Cost cost; char errbuf[128]; if (feof(stdin) && yywrap()) return EOF; /* count lines, skip over space and comments */ if ((c = getchar()) == EOF) NLRETURN(); continuation: while (c == ' ' || c == '\t') if ((c = getchar()) == EOF) NLRETURN(); if (c == '#') while ((c = getchar()) != '\n') if (c == EOF) NLRETURN(); /* scan token */ if (c == '\n') { Lineno++; if ((c = getchar()) != EOF) { if (c == ' ' || c == '\t') goto continuation; ungetc(c, stdin); } NLRETURN(); } switch(Scanstate) { case COSTING: if (isdigit(c)) { cost = c - '0'; for (c = getchar(); isdigit(c); c = getchar()) cost = (cost * 10) + c - '0'; ungetc(c, stdin); yylval.y_cost = cost; return COST; } if (getword(buf, c) == 0) { for (ct = ctable; ct->cname; ct++) if (STR_EQ(buf, ct->cname)) { yylval.y_cost = ct->cval; return COST; } sprintf(errbuf, "unknown cost (%s), using default", buf); yyerror(errbuf); yylval.y_cost = DEFCOST; return COST; } return c; /* pass the buck */ case NEWLINE: Scanstate = OTHER; if (getword(buf, c) != 0) return c; /* * special purpose tokens. * * the "switch" serves the dual-purpose of recognizing * unquoted tokens only. */ switch(c) { case 'p': if (STR_EQ(buf, "private")) return PRIVATE; break; case 'd': if (STR_EQ(buf, "dead")) return DEAD; if (STR_EQ(buf, "delete")) return DELETE; break; case 'f': if (STR_EQ(buf, "file")) return FILETOK; break; case 'a': if (STR_EQ(buf, "adjust")) return ADJUST; break; } yylval.y_name = buf; return HOST; case FILENAME: while (c != EOF && isprint(c)) { if (c == ' ' || c == '\t' || c == '\n' || c == '}') break; *buf++ = c; c = getchar(); } if (c != EOF) ungetc(c, stdin); *buf = 0; yylval.y_name = retbuf; return STRING; } if (getword(buf, c) == 0) { yylval.y_name = buf; return SITE; } if (index(Netchars, c)) { yylval.y_net = c; return NET; } return c;}/* * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted * string that contains no newline. return -1 on failure or EOF, 0 o.w. */ STATIC intgetword(str, c) register char *str; register int c;{ if (c == QUOTE) { while ((c = getchar()) != QUOTE) { if (c == '\n') { yyerror("newline in quoted string\n"); ungetc(c, stdin); return -1; } if (c == EOF) { yyerror("EOF in quoted string\n"); return -1; } *str++ = c; } *str = 0; return 0; } /* host name must start with alphanumeric or `.' */ if (!isalnum(c) && c != '.') return -1;yymore: do { *str++ = c; c = getchar(); } while (isalnum(c) || c == '.' || c == '_'); if (c == '-' && Scanstate != COSTING) goto yymore; ungetc(c, stdin); *str = 0; return 0;}STATIC intyywrap(){ char errbuf[100]; fixprivate(); /* munge private host definitions */ Lineno = 1; while (optind < Argc) { if (freopen((Cfile = Argv[optind++]), "r", stdin) != 0) return 0; sprintf(errbuf, "%s: %s", Argv[0], Cfile); perror(errbuf); } freopen("/dev/null", "r", stdin); return -1;}STATIC voidadjust(n, cost) node *n; Cost cost;{ link *l; n->n_cost += cost; /* cumulative */ /* hit existing links */ for (l = n->n_link; l; l = l->l_next) { if ((l->l_cost += cost) < 0) { char buf[100]; l->l_flag |= LDEAD; sprintf(buf, "link to %s deleted with negative cost", l->l_to->n_name); yyerror(buf); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -