home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / pathalias10 / part02 / parse.y < prev    next >
Text File  |  1990-06-07  |  11KB  |  539 lines

  1. %{
  2. /* pathalias -- by steve bellovin, as told to peter honeyman */
  3. #ifndef lint
  4. static char    *sccsid = "@(#)parse.y    9.10 88/09/07";
  5. #endif /* lint */
  6.  
  7. #include "def.h"
  8.  
  9. /* scanner states (yylex, parse) */
  10. #define OTHER        0
  11. #define COSTING        1
  12. #define NEWLINE        2
  13. #define FILENAME    3
  14.  
  15. /* exports */
  16. long Tcount;
  17. extern void yyerror();
  18.  
  19. /* imports */
  20. extern node *addnode(), *addprivate();
  21. extern void fixprivate(), alias(), deadlink(), deletelink();
  22. extern link *addlink();
  23. extern int strcmp();
  24. extern char *strsave();
  25. extern int optind;
  26. extern char *Cfile, *Netchars, **Argv;
  27. extern int Lineno, Argc;
  28.  
  29. /* privates */
  30. STATIC void fixnet(), adjust();
  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.     node    *y_node;
  40.     Cost    y_cost;
  41.     char    y_net;
  42.     char    *y_name;
  43.     struct {
  44.         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 nhost
  54. %type <y_node>    usite delem dlist
  55. %type <y_cost>    cost cexpr
  56.  
  57. %token <y_name>    SITE HOST STRING
  58. %token <y_cost>    COST
  59. %token <y_net>    NET
  60. %token EOL PRIVATE DEAD DELETE FILETOK ADJUST
  61.  
  62. %left    '+' '-'
  63. %left    '*' '/'
  64.  
  65. %%
  66. map    :    /* empty */
  67.     |    map        EOL
  68.     |    map links    EOL
  69.     |    map aliases    EOL
  70.     |    map network    EOL
  71.     |    map private    EOL
  72.     |    map dead    EOL
  73.     |    map delete    EOL
  74.     |    map file    EOL
  75.     |    map adjust    EOL
  76.     |    error        EOL
  77.     ;
  78.  
  79. links    : host site cost {
  80.         struct link *l;
  81.  
  82.         l = addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir);
  83.         if (GATEWAYED($2.ys_node))
  84.             l->l_flag |= LGATEWAY;
  85.         if ($2.ys_flag & TERMINAL)
  86.             l->l_flag |= LTERMINAL;
  87.       }            
  88.     | links ',' site cost {
  89.         struct link *l;
  90.  
  91.         l = addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir);
  92.         if (GATEWAYED($3.ys_node))
  93.             l->l_flag |= LGATEWAY;
  94.         if ($3.ys_flag & TERMINAL)
  95.             l->l_flag |= LTERMINAL;
  96.       }
  97.     | links ','    /* benign error */
  98.     ;
  99.  
  100. host    : HOST        {$$ = addnode($1);}
  101.     | PRIVATE    {$$ = addnode("private");}
  102.     | DEAD        {$$ = addnode("dead");}
  103.     | DELETE    {$$ = addnode("delete");}
  104.     | FILETOK    {$$ = addnode("file");}
  105.     | ADJUST    {$$ = addnode("adjust");}
  106.     ;
  107.  
  108. site    : asite {
  109.         $$ = $1;
  110.         $$.ys_net = DEFNET;
  111.         $$.ys_dir = DEFDIR;
  112.       }
  113.     | NET asite {
  114.         $$ = $2;
  115.         $$.ys_net = $1;
  116.         $$.ys_dir = LRIGHT;
  117.       }
  118.     | asite NET {
  119.         $$ = $1;
  120.         $$.ys_net = $2;
  121.         $$.ys_dir = LLEFT;
  122.       }
  123.     ;
  124.  
  125. asite    : SITE {
  126.         $$.ys_node = addnode($1);
  127.         $$.ys_flag = 0;
  128.       }
  129.     | '<' SITE '>' {
  130.         Tcount++;
  131.         $$.ys_node = addnode($2);
  132.         $$.ys_flag = TERMINAL;
  133.       }
  134.     ;
  135.  
  136. aliases    : host '=' SITE    {alias($1, addnode($3));}
  137.     | aliases ',' SITE    {alias($1, addnode($3));}
  138.     | aliases ','    /* benign error */
  139.     ;
  140.  
  141. network    : nhost '{' nlist '}' cost    {fixnet($1, $3, $5, DEFNET, DEFDIR);}
  142.     | nhost NET '{' nlist '}' cost    {fixnet($1, $4, $6, $2, LRIGHT);}
  143.     | nhost '{' nlist '}' NET cost    {fixnet($1, $3, $6, $5, LLEFT);}
  144.     ;
  145.  
  146. nhost    : '='        {$$ = 0;    /* anonymous net */}
  147.     | host '='    {$$ = $1;    /* named net */}
  148.     ;
  149.  
  150. nlist    : SITE        {$$ = addnode($1);}
  151.     | nlist ',' SITE {
  152.         node *n;
  153.  
  154.         n = addnode($3);
  155.         if (n->n_net == 0) {
  156.             n->n_net = $1;
  157.             $$ = n;
  158.         }
  159.       }
  160.     | nlist ','    /* benign error */
  161.     ;
  162.         
  163. private    : PRIVATE '{' plist '}'            /* list of privates */
  164.     | PRIVATE '{' '}'    {fixprivate();}    /* end scope of privates */
  165.     ;
  166.  
  167. plist    : SITE            {addprivate($1)->n_flag |= ISPRIVATE;}
  168.     | plist ',' SITE    {addprivate($3)->n_flag |= ISPRIVATE;}
  169.     | plist ','        /* benign error */
  170.     ;
  171.  
  172. dead    : DEAD '{' dlist '}';
  173.  
  174. dlist    : delem
  175.     | dlist ',' delem
  176.     | dlist ','        /* benign error */
  177.     ;
  178.  
  179. delem    : SITE            {deadlink(addnode($1), (node *) 0);}
  180.     | usite NET usite    {deadlink($1, $3);}
  181.     ;
  182.  
  183. usite    : SITE    {$$ = addnode($1);} ;    /* necessary unit production */
  184.  
  185. delete    : DELETE '{' dellist '}';
  186.  
  187. dellist    : delelem
  188.     | dellist ',' delelem
  189.     | dellist ','        /* benign error */
  190.     ;
  191.  
  192. delelem    : SITE {
  193.         node *n;
  194.  
  195.         n = addnode($1);
  196.         deletelink(n, (node *) 0);
  197.         n->n_flag |= ISPRIVATE;
  198.       }
  199.     | usite NET usite    {deletelink($1, $3);}
  200.     ;
  201.  
  202. file    : FILETOK '{' {Scanstate = FILENAME;} STRING {Scanstate = OTHER;} '}' {
  203.         Lineno = 0;
  204.         Cfile = strsave($4);
  205.     }
  206.  
  207. adjust    : ADJUST '{' adjlist '}' ;
  208.  
  209. adjlist    : adjelem
  210.     | adjlist ',' adjelem
  211.     | adjlist ','        /* benign error */
  212.     ;
  213.  
  214. adjelem    : usite cost    {adjust($1, $2);} ;
  215.  
  216. cost    : {$$ = DEFCOST;    /* empty -- cost is always optional */}
  217.     | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')'
  218.         {$$ = $3;}
  219.     ;
  220.  
  221. cexpr    : COST
  222.     | '-' cexpr      {$$ = -$2;}
  223.     | '(' cexpr ')'   {$$ = $2;}
  224.     | cexpr '+' cexpr {$$ = $1 + $3;}
  225.     | cexpr '-' cexpr {$$ = $1 - $3;}
  226.     | cexpr '*' cexpr {$$ = $1 * $3;}
  227.     | cexpr '/' cexpr {
  228.         if ($3 == 0)
  229.             yyerror("zero divisor\n");
  230.         else
  231.             $$ = $1 / $3;
  232.       }
  233.     ;
  234. %%
  235.  
  236. void
  237. #ifdef YYDEBUG
  238. /*VARARGS1*/
  239. yyerror(fmt, arg)
  240.     char *fmt, *arg;
  241. #else
  242. yyerror(s)
  243.     char *s;
  244. #endif
  245. {
  246.     /* a concession to bsd error(1) */
  247.     fprintf(stderr, "\"%s\", ", Cfile);
  248. #ifdef YYDEBUG
  249.     fprintf(stderr, "line %d: ", Lineno);
  250.     fprintf(stderr, fmt, arg);
  251.     putc('\n', stderr);
  252. #else
  253.     fprintf(stderr, "line %d: %s\n", Lineno, s);
  254. #endif
  255. }
  256.  
  257. /*
  258.  * patch in the costs of getting on/off the network.
  259.  *
  260.  * for each network member on netlist, add links:
  261.  *    network -> member    cost = 0;
  262.  *    member -> network    cost = parameter.
  263.  *
  264.  * if network and member both require gateways, assume network
  265.  * is a gateway to member (but not v.v., to avoid such travesties
  266.  * as topaz!seismo.css.gov.edu.rutgers).
  267.  *
  268.  * note that members can have varying costs to a network, by suitable
  269.  * multiple declarations.  this is a feechur, albeit a useless one.
  270.  */
  271. STATIC void
  272. fixnet(network, nlist, cost, netchar, netdir)
  273.     register node *network;
  274.     node *nlist;
  275.     Cost cost;
  276.     char netchar, netdir;
  277. {    register node *member, *nextnet;
  278.     link *l;
  279.     static int netanon = 0;
  280.     char anon[25];
  281.  
  282.     if (network == 0) {
  283.         sprintf(anon, "[unnamed net %d]", netanon++);
  284.         network = addnode(anon);
  285.     }
  286.     network->n_flag |= NNET;
  287.  
  288.     /* insert the links */
  289.     for (member = nlist ; member; member = nextnet) {
  290.  
  291.         /* network -> member, cost is 0 */
  292.         l = addlink(network, member, (Cost) 0, netchar, netdir);
  293.         if (GATEWAYED(network) && GATEWAYED(member))
  294.             l->l_flag |= LGATEWAY;
  295.  
  296.         /* member -> network, cost is parameter */
  297.         /* never ever ever crawl up from a domain*/
  298.         if (!ISADOMAIN(network))
  299.             (void) addlink(member, network, cost, netchar, netdir);
  300.  
  301.         nextnet = member->n_net;
  302.         member->n_net = 0;    /* clear for later use */
  303.     }
  304. }
  305.  
  306. /* scanner */
  307.  
  308. #define QUOTE '"'
  309. #define STR_EQ(s1, s2) (s1[2] == s2[2] && strcmp(s1, s2) == 0)
  310. #define NLRETURN() {Scanstate = NEWLINE; return EOL;}
  311.  
  312. static struct ctable {
  313.     char *cname;
  314.     Cost cval;
  315. } ctable[] = {
  316.     /* ordered by frequency of appearance in a "typical" dataset */
  317.     {"DIRECT", 200},
  318.     {"DEMAND", 300},
  319.     {"DAILY", 5000},
  320.     {"HOURLY", 500},
  321.     {"DEDICATED", 100},
  322.     {"EVENING", 2000},
  323.     {"LOCAL", 25},
  324.     {"LOW", 5},    /* baud rate, quality penalty */
  325.     {"DEAD", MILLION},
  326.     {"POLLED", 5000},
  327.     {"WEEKLY", 30000},
  328.     {"HIGH", -5},    /* baud rate, quality bonus */
  329.     {"FAST", -80},    /* high speed (>= 9.6 kbps) modem */
  330.     /* deprecated */
  331.     {"ARPA", 100},
  332.     {"DIALED", 300},
  333.     {0, 0}
  334. };
  335.  
  336. STATIC int
  337. yylex()
  338. {    static char retbuf[128];    /* for return to yacc part */
  339.     register int c;
  340.     register char *buf = retbuf;
  341.     register struct ctable *ct;
  342.     register Cost cost;
  343.     char errbuf[128];
  344.  
  345.     if (feof(stdin) && yywrap())
  346.         return EOF;
  347.  
  348.     /* count lines, skip over space and comments */
  349.     if ((c = getchar()) == EOF)
  350.         NLRETURN();
  351.     
  352. continuation:
  353.     while (c == ' ' || c == '\t')
  354.         if ((c = getchar()) == EOF)
  355.             NLRETURN();
  356.  
  357.     if (c == '#')
  358.         while ((c = getchar()) != '\n')
  359.             if (c == EOF)
  360.                 NLRETURN();
  361.  
  362.     /* scan token */
  363.     if (c == '\n') {
  364.         Lineno++;
  365.         if ((c = getchar()) != EOF) {
  366.             if (c == ' ' || c == '\t')
  367.                 goto continuation;
  368.             ungetc(c, stdin);
  369.         }
  370.         NLRETURN();
  371.     }
  372.  
  373.     switch(Scanstate) {
  374.     case COSTING:
  375.         if (isdigit(c)) {
  376.             cost = c - '0';
  377.             for (c = getchar(); isdigit(c); c = getchar())
  378.                 cost = (cost * 10) + c - '0';
  379.             ungetc(c, stdin);
  380.             yylval.y_cost = cost;
  381.             return COST;
  382.         }
  383.  
  384.         if (getword(buf, c) == 0) {
  385.             for (ct = ctable; ct->cname; ct++)
  386.                 if (STR_EQ(buf, ct->cname)) {
  387.                     yylval.y_cost = ct->cval;
  388.                     return COST;
  389.                 }
  390.             sprintf(errbuf, "unknown cost (%s), using default", buf);
  391.             yyerror(errbuf);
  392.             yylval.y_cost = DEFCOST;
  393.             return COST;
  394.         }
  395.  
  396.         return c;    /* pass the buck */
  397.  
  398.     case NEWLINE:
  399.         Scanstate = OTHER;
  400.         if (getword(buf, c) != 0)
  401.             return c;
  402.         /*
  403.          * special purpose tokens.
  404.          *
  405.          * the "switch" serves the dual-purpose of recognizing
  406.          * unquoted tokens only.
  407.          */
  408.         switch(c) {
  409.         case 'p':
  410.             if (STR_EQ(buf, "private"))
  411.                 return PRIVATE;
  412.             break;
  413.         case 'd':
  414.             if (STR_EQ(buf, "dead"))
  415.                 return DEAD;
  416.             if (STR_EQ(buf, "delete"))
  417.                 return DELETE;
  418.             break;
  419.         case 'f':
  420.             if (STR_EQ(buf, "file"))
  421.                 return FILETOK;
  422.             break;
  423.         case 'a':
  424.             if (STR_EQ(buf, "adjust"))
  425.                 return ADJUST;
  426.             break;
  427.         }
  428.  
  429.         yylval.y_name = buf;
  430.         return HOST;
  431.  
  432.     case FILENAME:
  433.         while (c != EOF && isprint(c)) {
  434.             if (c == ' ' || c == '\t' || c == '\n' || c == '}')
  435.                 break;
  436.             *buf++ = c;
  437.             c = getchar();
  438.         }
  439.         if (c != EOF)
  440.             ungetc(c, stdin);
  441.         *buf = 0;
  442.         yylval.y_name = retbuf;
  443.         return STRING;
  444.     }
  445.  
  446.     if (getword(buf, c) == 0) {
  447.         yylval.y_name = buf;
  448.         return SITE;
  449.     }
  450.  
  451.     if (index(Netchars, c)) {
  452.         yylval.y_net = c;
  453.         return NET;
  454.     }
  455.  
  456.     return c;
  457. }
  458.  
  459. /*
  460.  * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted
  461.  * string that contains no newline.  return -1 on failure or EOF, 0 o.w.
  462.  */ 
  463. STATIC int
  464. getword(str, c)
  465.     register char *str;
  466.     register int c;
  467. {
  468.     if (c == QUOTE) {
  469.         while ((c = getchar()) != QUOTE) {
  470.             if (c == '\n') {
  471.                 yyerror("newline in quoted string\n");
  472.                 ungetc(c, stdin);
  473.                 return -1;
  474.             }
  475.             if (c == EOF) {
  476.                 yyerror("EOF in quoted string\n");
  477.                 return -1;
  478.             }
  479.             *str++ = c;
  480.         }
  481.         *str = 0;
  482.         return 0;
  483.     }
  484.  
  485.     /* host name must start with alphanumeric or `.' */
  486.     if (!isalnum(c) && c != '.')
  487.         return -1;
  488.  
  489. yymore:
  490.     do {
  491.         *str++ = c;
  492.         c = getchar();
  493.     } while (isalnum(c) || c == '.' || c == '_');
  494.  
  495.     if (c == '-' && Scanstate != COSTING)
  496.         goto yymore;
  497.  
  498.     ungetc(c, stdin);
  499.     *str = 0;
  500.     return 0;
  501. }
  502.  
  503. STATIC int
  504. yywrap()
  505. {    char errbuf[100];
  506.  
  507.     fixprivate();    /* munge private host definitions */
  508.     Lineno = 1;
  509.     while (optind < Argc) {
  510.         if (freopen((Cfile = Argv[optind++]), "r", stdin) != 0)
  511.             return 0;
  512.         sprintf(errbuf, "%s: %s", Argv[0], Cfile);
  513.         perror(errbuf);
  514.     }
  515.     freopen("/dev/null", "r", stdin);
  516.     return -1;
  517. }
  518.  
  519. STATIC void
  520. adjust(n, cost)
  521.     node *n;
  522.     Cost cost;
  523. {    link *l;
  524.  
  525.     n->n_cost += cost;    /* cumulative */
  526.  
  527.     /* hit existing links */
  528.     for (l = n->n_link; l; l = l->l_next) {
  529.         if ((l->l_cost += cost) < 0) {
  530.             char buf[100];
  531.  
  532.             l->l_flag |= LDEAD;
  533.             sprintf(buf, "link to %s deleted with negative cost",
  534.                             l->l_to->n_name);
  535.             yyerror(buf);
  536.         }
  537.     }
  538. }
  539.