home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 319_01 / dir.c < prev    next >
C/C++ Source or Header  |  1990-06-18  |  21KB  |  1,023 lines

  1. /*
  2.     CPP V5 -- directives
  3.  
  4.     source:  dir.c
  5.     started: October 7, 1985
  6.     version: May 31, 1988
  7.  
  8.     External routines defined in this file: do_pp
  9.  
  10.     Written by Edward K. Ream.
  11.     This software is in the public domain.
  12.  
  13.     See the read.me file for disclaimer and other information.
  14. */
  15.  
  16. #include "cpp.h"
  17.  
  18. #define TRACE_LINE(name) TRACEP(name, printf("line %d\n", t_line))
  19.  
  20. static long    eval        (void);
  21. static long     eval1        (void);
  22. static bool    gt_prec        (en_tokens, en_tokens);
  23. static bool    isfnch        (int, en_tokens);
  24.  
  25. static void    pp_elif        (void);
  26. static void    pp_else        (void);
  27. static void    pp_endif    (void);
  28. static void    pp_enum        (void);
  29. static void    pp_error    (void);
  30. static void    pp_if        (void);
  31. static void    pp_ifdef    (bool);
  32. static void    pp_incl        (void);
  33. static void    pp_line        (void);
  34. static void    pp_undef    (void);
  35. static int    prec        (int);
  36.  
  37. static void    push_op        (en_tokens);
  38. static en_tokens pop_op        (void);
  39. static void    push_val    (long);
  40. static long    pop_val        (void);
  41. static void    skip_lines    (void);
  42.  
  43. /*
  44.     Do one preprocessor directive.
  45. */
  46.  
  47. #define EQL(string) str_eq(t_symbol+1,string+1)
  48.  
  49. void
  50. do_pp()
  51. {
  52.     TICK("do_pp");
  53.  
  54.     skip_ws(FALSE);
  55.  
  56.     /* Get the directive into t_symbol[]. */
  57.     if (!isalpha(ch)) {
  58.         goto not_alpha;
  59.     }
  60.     t_id(t_symbol, MAX_SYMBOL);
  61.  
  62.     /* 3/3/89: bug fix:  full white space allowed here. */
  63.     skip_ws(FALSE);
  64.  
  65.     /* Skip simple white space after the directive. */
  66.     /* -----
  67.     while (ch == ' ' || ch == '\t') {
  68.         sysnext();
  69.     }
  70.     ----- */
  71.  
  72.     switch(t_symbol [0]) {
  73.  
  74.     case 'd':
  75.         if (t_length == 6 && EQL("define")) {
  76.             pp_def();
  77.             return;
  78.         }
  79.         goto not_pp;
  80.  
  81.     case 'e':
  82.         if (t_length == 4) {
  83.             if (EQL("else")) {
  84.                 pp_else();
  85.                 return;
  86.             }
  87.             else if (EQL("elif")) {
  88.                 pp_elif();
  89.                 return;
  90.             }
  91.         }
  92. #ifdef HAS_PP_ENUM
  93.         else if (t_length == 4 && EQL("enum")) {
  94.             pp_enum();
  95.             return;
  96.         }
  97. #endif
  98.         else if (t_length == 5 && EQL("endif")) {
  99.             pp_endif();
  100.             return;
  101.         }
  102.         else if (t_length == 5 && EQL("error")) {
  103.             pp_error();
  104.             return;
  105.         }
  106.         goto not_pp;
  107.  
  108.     case 'i':
  109.         switch(t_length) {
  110.         case 2:    if (EQL("if")) {
  111.                 pp_if();
  112.                 return;
  113.             }
  114.             goto not_pp;
  115.         case 5:    if (EQL("ifdef")) {
  116.                 pp_ifdef(TRUE);
  117.                 return;
  118.             }
  119.             goto not_pp;
  120.         case 6:    if (EQL("ifndef")) {
  121.                 pp_ifdef(FALSE);
  122.                 return;
  123.             }
  124.             goto not_pp;
  125.         case 7:    if (EQL("include")) {
  126.                 pp_incl();
  127.                 return;
  128.             }
  129.             goto not_pp;
  130.         }
  131.         goto not_pp;
  132.  
  133.     case 'l':
  134.         if (t_length == 4 && EQL("line")) {
  135.             pp_line();
  136.             return;
  137.         }
  138.         goto not_pp;
  139.  
  140.     case 'p':
  141.         if (t_length == 6 && EQL("pragma")) {
  142.             /* Do NOTHING!! */
  143.             skip_pp();
  144.             return;
  145.         }
  146.         goto not_pp;
  147.     
  148.     case 'u':
  149.         if (t_length == 5 && EQL("undef")) {
  150.             pp_undef();
  151.             return;
  152.         }
  153.         goto not_pp;
  154.  
  155.     default:
  156.         goto not_pp;
  157.     }
  158.     
  159. not_alpha:
  160.     /*
  161.         Be more permissive than the new C standard.
  162.         Just skip the rest of the line.
  163.     */
  164.     skip_pp();
  165.     return;
  166.  
  167. not_pp:
  168.     err2(t_symbol, " is not a valid preprocessor directive.");
  169.     skip_pp();
  170. }
  171.  
  172. #undef EQL
  173.  
  174. /*
  175.     Handle the #error directive.
  176.     Produce a diagnostic message.
  177. */
  178. static char    err_msg[] = "#error:  ";
  179.  
  180. static void
  181. pp_error()
  182. {
  183.     char    message[MAX_SYMBOL];
  184.     int    i;
  185.  
  186.     strcpy(message, err_msg);
  187.     for (i = strlen(message); i < MAX_SYMBOL; i++) {
  188.         if (ch == '\n' || ch == END_FILE) {
  189.             break;
  190.         }
  191.         else {
  192.             message[i] = ch;
  193.             sysnext();
  194.         }
  195.     }
  196.     message[i] = '\0';
  197.     fatal(message);
  198. }
  199.         
  200.     
  201. /*
  202.     Evaluate a constant expression to either true or false.
  203.     A constant expression consists of:
  204.  
  205.     1. integer constants or character constants
  206.     2. the unary - + and ~ operators
  207.     3. the binary + - * / & | ^ << >> == != < > <= >= oprators
  208.     4. the ternary ? : operator
  209.     5. the ( and ) groupers.
  210.  
  211.     Identifiers are expanded if they are defined, otherwise they
  212.     are taken to have a value of zero. All arithmetic is integer and
  213.     ints are expanded to long.
  214. */
  215.  
  216. #define MAX_EVAL_VAL 100
  217. #define MAX_EVAL_OP 50
  218.  
  219. static    long         val_stack[MAX_EVAL_VAL];
  220. static    int        val_ptr = 0;
  221. static    en_tokens    op_stack[MAX_EVAL_OP];
  222. static    int        op_ptr = 0;
  223. static long result;
  224. static bool paren_seen;
  225. static bool error_seen;
  226.  
  227. static long
  228. eval()
  229. {
  230.     TRACETOK("eval");
  231.  
  232.     error_seen = FALSE;
  233.     get_token(TRUE);
  234.     result = eval1();
  235.  
  236.     RETURN_LONG("eval", result);
  237. }
  238.  
  239. static char    * junk;
  240. static int    junki;
  241.  
  242. static long
  243. eval1()
  244. {
  245.     register en_tokens op, op2;
  246.     register long val1, val2, val3;
  247.     int op_1ptr;
  248.  
  249.     TRACETOK("eval1");
  250.  
  251.     op_1ptr  = op_ptr;
  252.  
  253.     /* State S1: unary +, unary -, !, ~, constant or id is expected here. */
  254.  
  255. s1:
  256.     TRACEPN("v_eval1", printf("at state 1\n"));
  257.  
  258.     while (is(PLUS_TOK) || is(MINUS_TOK) || is(TILDE_TOK) || is(NOT_TOK)) {
  259.         if (is(PLUS_TOK)) {
  260.             push_op(UPLUS_TOK);
  261.         }
  262.         else if (is(MINUS_TOK)) {
  263.             push_op(UMINUS_TOK);
  264.         }
  265.         else if (is(NOT_TOK)) {
  266.             push_op(NOT_TOK);
  267.         }
  268.         else {
  269.             push_op(TILDE_TOK);
  270.         }
  271.         get_token(TRUE);
  272.     }
  273.  
  274.     /* We expect a constant or identifier here. */
  275.     if (is(INT_TOK) || is(LONG_TOK) || is(CHAR_TOK)) {
  276.         push_val((long) t_value);
  277.         get_token(TRUE);
  278.     }
  279.     else if (is(ID_TOK)) {
  280.         /* Special case defined id and defined(id). */
  281.         if (str_eq(t_symbol, "defined")) {
  282.  
  283.             /* Do not macro expand an id here! */
  284.             get_token(FALSE);
  285.             if (!is(ID_TOK) && !is(LPAREN_TOK)) {
  286.                 error("Id or '(' expected after 'defined'.");
  287.                 goto bad_expr;
  288.             }
  289.             paren_seen = is(LPAREN_TOK);
  290.             if (paren_seen) {
  291.                 get_token(FALSE);
  292.                 if (!is(ID_TOK)) {
  293.                     error("Id expected after '('.");
  294.                     goto bad_expr;
  295.                 }
  296.             }
  297.             if(mst_lookup(t_symbol, &junk, &junki)) {
  298.                 push_val(1L);
  299.             }
  300.             else {
  301.                 push_val(0L);
  302.             }
  303.             get_token(TRUE);
  304.             if (paren_seen) {
  305.                 if (is(RPAREN_TOK)) {
  306.                     get_token(TRUE);
  307.                 }
  308.                 else {
  309.                     error("')' expected.");
  310.                     goto bad_expr;
  311.                 }
  312.             }
  313.         }
  314.         else {
  315.             /* The identifier must be undefined, so it gets 0. */
  316.             push_val(0L);
  317.             get_token(TRUE);
  318.         }
  319.     }
  320.     else if (is(LPAREN_TOK)) {
  321.         get_token(TRUE);
  322.  
  323.         /* Evaluate the expression recursively. */        
  324.         result = eval1();
  325.         if (is(RPAREN_TOK)) {
  326.             get_token(TRUE);
  327.             push_val(result);
  328.         }
  329.         else {
  330.             error("')' expected.");
  331.             goto bad_expr;
  332.         }
  333.     }        
  334.     else {
  335.         error("Integer constant or parenthesized expression expected.");
  336.         goto bad_expr;
  337.     }
  338.  
  339.     /* Perform all unary ops and enter state S2. */
  340.     TRACEPN("v_eval1", printf("at state 1A\n"));
  341.     while (op_ptr > op_1ptr) {
  342.         switch (op = pop_op()) {
  343.         case UPLUS_TOK:     break;
  344.         case UMINUS_TOK: push_val(-pop_val());        break;
  345.         case NOT_TOK:     push_val((long)(!pop_val()));    break;
  346.         case TILDE_TOK:     push_val(~pop_val());        break;
  347.         default:     push_op(op);            goto s2;
  348.         }
  349.     }
  350.  
  351.     /* State S2: binary op or end_of_expression expected here. */
  352.  
  353. s2:
  354.     TRACEPN("v_eval1", printf("at state 2\n"));
  355.  
  356.     /*
  357.         Perform binary operators until the operator stack is
  358.         empty or until token operator has a higher precedence
  359.         than the operator on the top of the operator stack.
  360.     */
  361.  
  362.     while (op_ptr > op_1ptr && gt_prec(op_stack[op_ptr - 1], token)) {
  363.  
  364.         val2 = pop_val();
  365.         val1 = pop_val();
  366.         op   = pop_op();
  367.  
  368.         switch (op) {
  369.         case PLUS_TOK:        push_val(val1 + val2);    break;
  370.         case MINUS_TOK:        push_val(val1 - val2);    break;
  371.         case STAR_TOK:        push_val(val1 * val2);    break;
  372.         case DIV_TOK:        push_val((long)(val2?(val1/val2):0));
  373.                     break;
  374.         case MOD_TOK:        push_val(val1 % val2);    break;
  375.         case AND_TOK:        push_val(val1 & val2);    break;
  376.         case OR_TOK:        push_val(val1 | val2);    break;
  377.         case XOR_TOK:        push_val(val1 ^ val2);    break;
  378.         case LSHIFT_TOK:    push_val(val1 << val2);    break;
  379.         case RSHIFT_TOK:    push_val(val1 >> val2);    break;
  380.         case EQUAL_TOK:        push_val((long)(val1 == val2));    break;
  381.         case NE_TOK:        push_val((long)(val1 != val2));    break;
  382.         case LT_TOK:        push_val((long)(val1 <  val2));    break;
  383.         case GT_TOK:        push_val((long)(val1 >  val2));    break;
  384.         case LE_TOK:        push_val((long)(val1 <= val2));    break;
  385.         case GE_TOK:        push_val((long)(val1 >= val2));    break;
  386.         case LAND_TOK:        push_val((long)(val1 && val2)); break;
  387.         case LOR_TOK:        push_val((long)(val1 || val2)); break;
  388.  
  389.         case COLON_TOK:        op2 = pop_op();
  390.                     if (op2 != QUESTION_TOK) {
  391.                         goto bad_expr;
  392.                     }
  393.                     val3 = pop_val();        
  394.                     push_val(val3 ? val1 : val2);
  395.                     break;
  396.  
  397.         default:        goto bad_expr;
  398.         }
  399.     }
  400.         
  401.     /* Enter state S1 or return on end-of-expression. */
  402.     if (is(NULL_TOK) || is(RPAREN_TOK)) {
  403.         val1 = pop_val();
  404.         RETURN_LONG("eval1", val1);
  405.     }
  406.     else if (is(ERR_TOK)) {
  407.         goto bad_expr;
  408.     }
  409.     else {
  410.         push_op(token);
  411.         get_token(TRUE);
  412.         goto s1;
  413.     }
  414.  
  415. bad_expr:
  416.     if (!error_seen) {
  417.         error("Bad constant expression--zero assumed.");
  418.     }
  419.     error_seen = TRUE;
  420.     RETURN_LONG("eval1", 0L);
  421. }
  422.  
  423.  
  424. /*
  425.     Return TRUE if a reduction is possible with op1 on the operator stack 
  426.     and op2 as the new operator.  
  427.  
  428.     Always return TRUE if op2 delimits the expression, otherwise
  429.     return TRUE if op1 has higher precedence than op2, otherwise
  430.     return TRUE if they associate left to right.
  431.  
  432.     This code reflects the table on page 49 of K & R.
  433. */
  434.  
  435. static bool
  436. gt_prec(op1, op2)
  437. register en_tokens op1;
  438. register en_tokens op2;
  439. {
  440.     register int prec1, prec2;
  441.  
  442.     TRACEP("gt_prec", printf("(%s, %s)\n",
  443.         pr_op(op1), pr_op(op2)));
  444.  
  445.     if (op2 == RPAREN_TOK || op2 == NULL_TOK) {
  446.         return TRUE;
  447.     }
  448.     else if (op2 == ERR_TOK) {
  449.         /* Abort immediately. */
  450.         return FALSE;
  451.     }
  452.  
  453.     prec1 = prec((int)op1);
  454.     prec2 = prec((int)op2);
  455.  
  456.     if (prec1 != prec2) {
  457.         /* Associativity doesn't matter. */
  458.         return prec1 > prec2;
  459.     }
  460.     else if (prec1 == 14 || prec1 == 3 || prec1 == 2) {
  461.         /* Associate right to left. */
  462.         return FALSE;
  463.     }
  464.     else {
  465.         /* Associate left to right. */
  466.         return TRUE;
  467.     }
  468. }
  469.  
  470.  
  471. /*
  472.     Return TRUE if c is legal in a file name.
  473.     Assume that the delim character is not legal.
  474. */
  475. static bool
  476. isfnch(c, delim)
  477. int      c;
  478. en_tokens delim;
  479. {
  480.     TICK("isfnch");
  481.  
  482.     switch (c) {
  483.     case '*':
  484.     case '?':
  485.     case '\n':
  486.     case ' ':
  487.     case '\t':
  488.     case END_FILE:
  489.                 return FALSE;
  490.  
  491.     default:        return (c != (int)delim);
  492.     }
  493. }
  494.  
  495.  
  496. /*
  497.     Return the precedence of an operator.
  498.  
  499.     This code reflects the table on page 49 of K & R.
  500. */
  501.  
  502. static int
  503. prec(operator)
  504. int operator;
  505. {
  506.     TRACEP("prec", printf("(%s)\n", pr_op(operator)));
  507.  
  508.     switch (operator) {
  509.     case TILDE_TOK:        return 14;
  510.     case STAR_TOK:
  511.     case DIV_TOK:
  512.     case MOD_TOK:        return 13;
  513.     case PLUS_TOK:
  514.     case MINUS_TOK:        return 12;
  515.     case LSHIFT_TOK:
  516.     case RSHIFT_TOK:    return 11;
  517.     case LT_TOK:
  518.     case LE_TOK:
  519.     case GT_TOK:
  520.     case GE_TOK:        return 10;
  521.     case EQUAL_TOK:
  522.     case NE_TOK:        return 9;
  523.     case XOR_TOK:        return 7;
  524.     case OR_TOK:        return 6;
  525.     case COLON_TOK:
  526.     case QUESTION_TOK:    return 3;
  527.     default:        return -1;
  528.     }
  529. }
  530.  
  531.  
  532. /*
  533.     Routines to push and pop the operator and operand stacks.
  534. */
  535. static void
  536. push_op(op)
  537. en_tokens op;
  538. {
  539.     TRACEP("push_op", printf("(%s), op_ptr = %d\n",
  540.         pr_op(op), op_ptr));
  541.  
  542.     if (op_ptr < MAX_EVAL_OP) {
  543.         op_stack[op_ptr++] = op;
  544.     }
  545.     else {
  546.         fatal("Operator stack overflow.");
  547.     }
  548. }
  549.  
  550. static en_tokens
  551. pop_op()
  552. {
  553.     TRACEP("pop_op", printf("op_ptr = %d\n", op_ptr));
  554.  
  555.     if (op_ptr > 0) {
  556.  
  557.         TRACEP("pop_op", printf("returns: %s\n",
  558.             pr_op(op_stack[op_ptr - 1])));
  559.         
  560.         return op_stack [--op_ptr];
  561.     }
  562.     else {
  563.         syserr("Operator stack underflow.");
  564.         return NULL_TOK;
  565.     }
  566. }
  567.  
  568. static void
  569. push_val(val)
  570. long val;
  571. {
  572.     TRACEP("push_val", printf("(%ld), val_ptr = %d\n", val, val_ptr));
  573.  
  574.     if (val_ptr < MAX_EVAL_VAL) {
  575.         val_stack [val_ptr++] = val;
  576.     }
  577.     else {
  578.         fatal("Value stack overflow.");
  579.     }
  580. }
  581.  
  582. static long
  583. pop_val()
  584. {
  585.     TRACEP("pop_val", printf("val_ptr = %d\n", val_ptr));
  586.  
  587.     if (val_ptr > 0) {
  588.  
  589.         TRACEP("pop_val", printf("returns %ld\n",
  590.             val_stack [val_ptr - 1]));
  591.  
  592.         return val_stack [--val_ptr];
  593.     }
  594.     else {
  595.         syserr("Value stack underflow.");
  596.         return 0L;
  597.     }
  598. }
  599.  
  600. /*
  601.     Handle the #elif directive when lines are NOT being skipped.
  602.     The skip_lines() routines handles #elif when lines ARE being skipped.
  603. */
  604. static void
  605. pp_elif()
  606. {
  607.     TRACE_LINE("pp_elif");
  608.  
  609.     if (t_iflevel == 0) {
  610.         error("#elif ignored--no matching #if.");
  611.         skip_pp();
  612.         return;
  613.     }
  614.  
  615.     /* Skip lines if the constant expression evaluates to zero. */
  616.     if (eval() == 0L) {
  617.         /* Skip until #else or #endif. */
  618.         skip_lines();
  619.     }
  620. }
  621.  
  622.  
  623. /*
  624.     Handle the #else directive when lines are NOT being skipped.
  625.     The skip_lines() routine handles #else when lines ARE being skipped.    
  626. */
  627. static void
  628. pp_else()
  629. {
  630.     TRACE_LINE("pp_else");
  631.  
  632.     if (t_iflevel == 0) {
  633.         error("#else ignored--no matching #if.");
  634.         skip_pp();
  635.     }
  636.     else if (t_ifstack [t_iflevel - 1] == TRUE) {
  637.         error("Duplicate #else ignored.");
  638.         skip_pp();
  639.     }
  640.     else {
  641.         t_ifstack [t_iflevel - 1] = TRUE;
  642.         skip_lines();
  643.     }
  644. }
  645.  
  646.  
  647. /*
  648.     Handle the #endif directive when lines are NOT being skipped.
  649.     The skip_lines() routine handles #endif when lines ARE being skipped.
  650. */
  651. static void
  652. pp_endif()
  653. {
  654.     TRACE_LINE("pp_endif");
  655.  
  656.     if (t_iflevel == 0) {
  657.         error("#endif ignored--no matching #if.");
  658.         skip_pp();
  659.     }
  660.     else {
  661.         t_iflevel--;
  662.         skip_pp();
  663.     }
  664. }
  665.             
  666. /*
  667.     Handle the #if directive when lines are NOT being skipped.
  668.     The skip_lines() routine handles #if when lines ARE being skipped.
  669. */
  670. static void
  671. pp_if()
  672. {
  673.     TRACE_LINE("pp_if");
  674.  
  675.     /* Indicate that no #else has been seen. */
  676.     if (t_iflevel >= MAX_IF) {
  677.         error("#if ignored--nested too deeply.");
  678.         skip_pp();
  679.         return;
  680.     }
  681.     t_ifstack [t_iflevel++] = FALSE;
  682.  
  683.     /* Skip lines if the constant expression evaluates to zero. */
  684.     if (eval() == 0L) {
  685.         /* Skip until #else or #endif. */
  686.         skip_lines();
  687.     }
  688. }
  689.  
  690. /*
  691.     Handle the #ifdef and #ifndef directives when lines are NOT being 
  692.     skipped.
  693.     The skip_lines() routine handles #if when lines ARE being skipped.
  694.  
  695.         flag == TRUE:    #ifdef
  696.         flag == FALSE:    #ifndef
  697. */
  698. static void
  699. pp_ifdef(flag)
  700. bool flag;
  701. {
  702.     bool result;
  703.     char *text;
  704.     int nargs;
  705.  
  706.     TRACE_LINE("pp_ifdef");
  707.  
  708.     if(t_iflevel > MAX_IF) {
  709.         error("#ifdef or #ifndef ignored--nested too deeply.");
  710.         skip_pp();
  711.         return;
  712.     }
  713.  
  714.     if (!isid1(ch)) {
  715.         error("#ifdef or #ifndef ignored--identifier expected.");
  716.         skip_pp();
  717.         return;
  718.     }
  719.     
  720.     /* Get id into t_symbol[]. */
  721.     t_id(t_symbol, MAX_SYMBOL);
  722.     skip_pp();
  723.     
  724.     /* Indicate that no #else has been seen. */
  725.     t_ifstack [t_iflevel++] = FALSE;
  726.  
  727.     /* Skip lines if required. */
  728.     result = mst_lookup(t_symbol, &text, &nargs);
  729.     if ((flag && result == FALSE) || (!flag && result == TRUE)) {
  730.         /* Skip until #else or #endif. */
  731.         skip_lines();
  732.     }
  733. }
  734.  
  735.  
  736. /*
  737.     Handle the #include directive.
  738. */
  739. static void
  740. pp_incl()
  741. {
  742.     bool    old_mflag;
  743.     bool    err_flag;
  744.     int    i;
  745.     char    f_name [MAX_FILE_NAME];
  746.     char    path_name [200];
  747.     char    delim;
  748.  
  749.     TRACE_LINE("pp_incl");
  750.  
  751.     /* File name is OK. */
  752.     err_flag = FALSE;
  753.  
  754.     /*
  755.         Check for opening delimiter.
  756.         Allow simple macro expansions here.
  757.     */
  758.     if (isid1(ch)) {
  759.         old_mflag = m_flag;
  760.         t_id(&t_symbol[0], MAX_SYMBOL);
  761.  
  762.         /* We expect a proper macro here. */
  763.         outer_expand(&t_symbol[0], old_mflag);
  764.     }
  765.  
  766.     if (ch == '"') {
  767.         delim = '"';
  768.         sysnext();
  769.     }
  770.     else if (ch == '<') {
  771.         delim = '>';
  772.         sysnext();
  773.     }
  774.     else {
  775.         err_flag = TRUE;
  776.         delim = '\r';
  777.     }
  778.  
  779.     /* Get file name into f_name[]. */
  780.     for (i = 0; i < MAX_FILE_NAME-1 && isfnch(ch,(en_tokens)delim); i++) {
  781.         f_name[i] = ch;
  782.         sysnext();
  783.     }
  784.     f_name[i] = '\0';
  785.  
  786.     if (err_flag || ch != delim) {
  787.         err3("#include ", f_name, " ignored--bad delimiter.");
  788.         skip_pp();
  789.         return;
  790.     }
  791.  
  792.     /* Skip over the delimiter. */
  793.     sysnext();
  794.  
  795.     /*
  796.         We must skip the line here, because after
  797.         sysopen() is called we would not be able to skip
  798.         characters in the old level.
  799.     */
  800.         
  801.     skip_pp();
  802.     if (ch == '\n') {
  803.         sysnlput();
  804.         sysnext();
  805.     }
  806.     bump_line();
  807.  
  808.     if (t_inlevel >= MAX_INCLUDE) {
  809.         t_line--;
  810.         err3("#include ", f_name, " ignored--nested too deeply.");
  811.         t_line++;
  812.         return;
  813.     }
  814.  
  815.     /* Open the file. */
  816.     if(sysopen(f_name) == FALSE) {
  817.         for (i = 0; i < n_paths; i++) {
  818.             strcpy(path_name, paths [i]);
  819.             strcat(path_name, f_name);
  820.  
  821.             TRACEP("pp_incl", printf("attempting to open %s\n",
  822.                 path_name));
  823.  
  824.             if (sysopen(path_name) == TRUE) {
  825.                 return;
  826.             }
  827.         }
  828.         t_line--;
  829.         err3("#include ", f_name, " ignored--file not found.");
  830.         t_line++;
  831.     }
  832. }
  833.  
  834.  
  835. /*
  836.     Set the line number and file name.
  837. */
  838. static void
  839. pp_line()
  840. {
  841.     bool    old_mflag;
  842.     int    i;
  843.  
  844.     TRACE_LINE("pp_line");
  845.  
  846.     /* Allow macro expansion. */
  847.     if (isid1(ch)) {
  848.         old_mflag = m_flag;
  849.         t_id(&t_symbol[0], MAX_SYMBOL);
  850.  
  851.         /* We expect a macro id here. */
  852.         outer_expand(&t_symbol[0], old_mflag);
  853.     }
  854.  
  855.     (void) t_number(FALSE);
  856.     t_line = (int) t_value;
  857.  
  858.     /* See if an optional file name is present. */
  859.     skip_ws(FALSE);
  860.  
  861.     /* Allow macro expansion. */
  862.     if (isid1(ch)) {
  863.         old_mflag = m_flag;
  864.         t_id(&t_symbol[0], MAX_SYMBOL);
  865.  
  866.         /* We expect a macro id here. */
  867.         outer_expand(&t_symbol[0], old_mflag);
  868.     }
  869.     if (ch == '\n' || ch == END_FILE) {
  870.         return;
  871.     }
  872.  
  873.     /* Copy line to t_file[]. */
  874.     for(i = 0; i < MAX_FILE_NAME - 1; i++) {
  875.         if (ch == END_FILE || ch == '\n') {
  876.             break;
  877.         }
  878.         t_file[i] = ch;
  879.         sysnext();
  880.     }
  881.     t_file [i] = '\0';
  882.     skip_pp();
  883. }
  884.  
  885.  
  886. /*
  887.     Undefine a previously #defined variable.
  888. */
  889. static void
  890. pp_undef()
  891. {
  892.     TRACE_LINE("pp_undef");
  893.  
  894.     /* Get the identifier into t_symbol[]. */
  895.     if (!isid1(ch)) {
  896.         error("#undef ignored--identifier expected.");
  897.         skip_pp();
  898.         return;
  899.     }
  900.     t_id(t_symbol, MAX_SYMBOL);
  901.  
  902.     /* Delete the identifier. Give no warning if it doesn't exist. */
  903.     mst_delete(t_symbol);
  904.     skip_pp();
  905. }
  906.  
  907.  
  908. /*
  909.     Skip lines until a matching #else or #endif directive is found.
  910.     Thus,  interior #ifdef, #ifndef, #if, #elif and  #else directives
  911.     must be recognized and dealt with.
  912.  
  913.     A fine point:  This code skips lines without doing any parsing of the
  914.     line.  The ONLY things this code looks for are lines which start with
  915.     #ifdef, #ifndef, #if or #else.  One should not detect "unknown"
  916.     preprocessor directives or other possible "errors," for the very good
  917.     reason that one wants to use conditional compilation to exclude lines
  918.     which might not even be written in the C language.
  919.  
  920.     Examples can be given where this action might be suspect.  Consider a
  921.     string which is continued from one line to the next using the backslash
  922.     newline convention.  If the continuation line starts with one of the
  923.     four directives that this routine is looking for then either the lex or
  924.     the person using the lex will become confused.  This is a minor hole in
  925.     the C language, and it seems better to ignore the fine points and do
  926.     what is sensible in most cases, namely skip entire lines as a unit.
  927.  
  928.     The routine skip_past() is used to do the skipping of exactly 1 line.
  929. */
  930.  
  931. #define EQL(string) str_eq(t_symbol,string)
  932. static void
  933. skip_lines()
  934. {
  935.     register int level = 0;        /* Inner nesting level */
  936.  
  937.     TRACE_LINE("skip_lines");
  938.  
  939.     /* Just in case. */
  940.     if (t_iflevel <= 0) {
  941.         syserr("skip_lines: Can't happen.");
  942.     }
  943.  
  944.     /* Start a new line. */
  945. loop:
  946.  
  947.     if (ch == END_FILE) {
  948.         error("File ends inside range of #ifdef.");
  949.         return;
  950.     }
  951.  
  952.     /* Skip the line if it doesn't start with '#'. */
  953.     if (ch != '#') {
  954.         skip_past();
  955.         goto loop;
  956.     }
  957.  
  958.     /* Skip the line if '#' isn't followed by an id. */
  959.     sysnext();
  960.     skip_ws(FALSE);
  961.  
  962.     if (!isid1(ch)) {
  963.         skip_past();
  964.         goto loop;
  965.     }
  966.  
  967.     /* Get the directive into t_symbol[]. */
  968.     t_id(t_symbol, MAX_SYMBOL);
  969.  
  970.     if (EQL("ifdef") || EQL("ifndef") || EQL("if")) {
  971.         level++;
  972.     }
  973.     else if (EQL("elif")) {
  974.         if (level > 0) {
  975.             /* This directive will itself be skipped. */
  976.             skip_pp();
  977.         }
  978.         else if (eval() == 0L) {
  979.             /* Call to eval will bump line number. */
  980.             TRACEPN("skip_lines",
  981.                 printf("stopped by #elif at line %d\n",
  982.                     t_line - 1));
  983.             return;
  984.         }
  985.     }
  986.     else if (EQL("else")) {
  987.         if (level > 0) {
  988.             /* Skip this directive. */
  989.             skip_pp();
  990.         }
  991.         else if (t_ifstack [t_iflevel - 1] == FALSE) {
  992.             t_ifstack [t_iflevel - 1] = TRUE;
  993.             skip_pp();
  994.             TRACEPN("skip_lines",
  995.                 printf("stopped by #else at line %d\n",
  996.                     t_line));
  997.             return;
  998.         }
  999.         else {
  1000.             error("Extra #else ignored.");
  1001.         }
  1002.     }
  1003.     else if (EQL("endif")) {
  1004.         if (level > 0) {
  1005.             level--;
  1006.         }
  1007.         else {
  1008.             t_iflevel--;
  1009.             skip_pp();
  1010.             TRACEPN("skip_lines",
  1011.                 printf("stopped by #endif at line %d\n",
  1012.                     t_line));
  1013.             return;
  1014.         }
  1015.     }
  1016.     else {
  1017.         skip_past();
  1018.     }
  1019.     goto loop;
  1020. }
  1021.  
  1022. #undef EQL
  1023.