home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bsd / src / make / make-amiga / cond.c < prev    next >
C/C++ Source or Header  |  1993-09-23  |  29KB  |  1,209 lines

  1. /*
  2.  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
  3.  * Copyright (c) 1988, 1989 by Adam de Boor
  4.  * Copyright (c) 1989 by Berkeley Softworks
  5.  * All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Adam de Boor.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *    This product includes software developed by the University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #ifndef lint
  40. static char sccsid[] = "@(#)cond.c    5.6 (Berkeley) 6/1/90";
  41. #endif /* not lint */
  42.  
  43. /*-
  44.  * cond.c --
  45.  *    Functions to handle conditionals in a makefile.
  46.  *
  47.  * Interface:
  48.  *    Cond_Eval     Evaluate the conditional in the passed line.
  49.  *
  50.  */
  51.  
  52. #include    "make.h"
  53. #include    <buf.h>
  54. #include    <ctype.h>
  55.  
  56. /*
  57.  * The parsing of conditional expressions is based on this grammar:
  58.  *    E -> F || E
  59.  *    E -> F
  60.  *    F -> T && F
  61.  *    F -> T
  62.  *    T -> defined(variable)
  63.  *    T -> make(target)
  64.  *    T -> exists(file)
  65.  *    T -> empty(varspec)
  66.  *    T -> target(name)
  67.  *    T -> symbol
  68.  *    T -> $(varspec) op value
  69.  *    T -> $(varspec) == "string"
  70.  *    T -> $(varspec) != "string"
  71.  *    T -> ( E )
  72.  *    T -> ! T
  73.  *    op -> == | != | > | < | >= | <=
  74.  *
  75.  * 'symbol' is some other symbol to which the default function (condDefProc)
  76.  * is applied.
  77.  *
  78.  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
  79.  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
  80.  * LParen for '(', RParen for ')' and will evaluate the other terminal
  81.  * symbols, using either the default function or the function given in the
  82.  * terminal, and return the result as either True or False.
  83.  *
  84.  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
  85.  */
  86. typedef enum {
  87.     And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
  88. } Token;
  89.  
  90. /*-
  91.  * Structures to handle elegantly the different forms of #if's. The
  92.  * last two fields are stored in condInvert and condDefProc, respectively.
  93.  */
  94. static Boolean      CondDoDefined(),
  95.           CondDoMake();
  96.  
  97. static struct If {
  98.     char    *form;          /* Form of if */
  99.     int        formlen;      /* Length of form */
  100.     Boolean    doNot;          /* TRUE if default function should be negated */
  101.     Boolean    (*defProc)(); /* Default function to apply */
  102. } ifs[] = {
  103.     "ifdef",      5,      FALSE,  CondDoDefined,
  104.     "ifndef",      6,      TRUE,      CondDoDefined,
  105.     "ifmake",      6,      FALSE,  CondDoMake,
  106.     "ifnmake",      7,      TRUE,      CondDoMake,
  107.     "if",      2,      FALSE,  CondDoDefined,
  108.     (char *)0,      0,      FALSE,  (Boolean (*)())0,
  109. };
  110.  
  111. static Boolean      condInvert;            /* Invert the default function */
  112. static Boolean      (*condDefProc)();     /* Default function to apply */
  113. static char       *condExpr;            /* The expression to parse */
  114. static Token      condPushBack=None;    /* Single push-back token used in
  115.                      * parsing */
  116.  
  117. #define    MAXIF        30      /* greatest depth of #if'ing */
  118.  
  119. static Boolean      condStack[MAXIF];     /* Stack of conditionals's values */
  120. static int        condTop = MAXIF;      /* Top-most conditional */
  121. static int        skipIfLevel=0;        /* Depth of skipped conditionals */
  122. static Boolean      skipLine = FALSE;     /* Whether the parse module is skipping
  123.                      * lines */
  124.  
  125. static Token      CondT(), CondF(), CondE();
  126.  
  127. /*-
  128.  *-----------------------------------------------------------------------
  129.  * CondPushBack --
  130.  *    Push back the most recent token read. We only need one level of
  131.  *    this, so the thing is just stored in 'condPushback'.
  132.  *
  133.  * Results:
  134.  *    None.
  135.  *
  136.  * Side Effects:
  137.  *    condPushback is overwritten.
  138.  *
  139.  *-----------------------------------------------------------------------
  140.  */
  141. static void
  142. CondPushBack (t)
  143.     Token         t;    /* Token to push back into the "stream" */
  144. {
  145.     condPushBack = t;
  146. }
  147.  
  148. /*-
  149.  *-----------------------------------------------------------------------
  150.  * CondGetArg --
  151.  *    Find the argument of a built-in function.
  152.  *
  153.  * Results:
  154.  *    The length of the argument and the address of the argument.
  155.  *
  156.  * Side Effects:
  157.  *    The pointer is set to point to the closing parenthesis of the
  158.  *    function call.
  159.  *
  160.  *-----------------------------------------------------------------------
  161.  */
  162. static int
  163. CondGetArg (linePtr, argPtr, func, parens)
  164.     char          **linePtr;
  165.     char          **argPtr;
  166.     char          *func;
  167.     Boolean       parens;       /* TRUE if arg should be bounded by parens */
  168. {
  169.     register char *cp;
  170.     int              argLen;
  171.     register Buffer buf;
  172.  
  173.     cp = *linePtr;
  174.     if (parens) {
  175.     while (*cp != '(' && *cp != '\0') {
  176.         cp++;
  177.     }
  178.     if (*cp == '(') {
  179.         cp++;
  180.     }
  181.     }
  182.  
  183.     if (*cp == '\0') {
  184.     /*
  185.      * No arguments whatsoever. Because 'make' and 'defined' aren't really
  186.      * "reserved words", we don't print a message. I think this is better
  187.      * than hitting the user with a warning message every time s/he uses
  188.      * the word 'make' or 'defined' at the beginning of a symbol...
  189.      */
  190.     *argPtr = cp;
  191.     return (0);
  192.     }
  193.  
  194.     while (*cp == ' ' || *cp == '\t') {
  195.     cp++;
  196.     }
  197.  
  198.     /*
  199.      * Create a buffer for the argument and start it out at 16 characters
  200.      * long. Why 16? Why not?
  201.      */
  202.     buf = Buf_Init(16);
  203.     
  204.     while ((index(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {
  205.     if (*cp == '$') {
  206.         /*
  207.          * Parse the variable spec and install it as part of the argument
  208.          * if it's valid. We tell Var_Parse to complain on an undefined
  209.          * variable, so we don't do it too. Nor do we return an error,
  210.          * though perhaps we should...
  211.          */
  212.         char      *cp2;
  213.         int        len;
  214.         Boolean    doFree;
  215.  
  216.         cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
  217.  
  218.         Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
  219.         if (doFree) {
  220.         free(cp2);
  221.         }
  222.         cp += len;
  223.     } else {
  224.         Buf_AddByte(buf, (Byte)*cp);
  225.         cp++;
  226.     }
  227.     }
  228.  
  229.     Buf_AddByte(buf, (Byte)'\0');
  230.     *argPtr = (char *)Buf_GetAll(buf, &argLen);
  231.     Buf_Destroy(buf, FALSE);
  232.  
  233.     while (*cp == ' ' || *cp == '\t') {
  234.     cp++;
  235.     }
  236.     if (parens && *cp != ')') {
  237.     Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",
  238.              func);
  239.     return (0);
  240.     } else if (parens) {
  241.     /*
  242.      * Advance pointer past close parenthesis.
  243.      */
  244.     cp++;
  245.     }
  246.     
  247.     *linePtr = cp;
  248.     return (argLen);
  249. }
  250.  
  251. /*-
  252.  *-----------------------------------------------------------------------
  253.  * CondDoDefined --
  254.  *    Handle the 'defined' function for conditionals.
  255.  *
  256.  * Results:
  257.  *    TRUE if the given variable is defined.
  258.  *
  259.  * Side Effects:
  260.  *    None.
  261.  *
  262.  *-----------------------------------------------------------------------
  263.  */
  264. static Boolean
  265. CondDoDefined (argLen, arg)
  266.     int        argLen;
  267.     char    *arg;
  268. {
  269.     char    savec = arg[argLen];
  270.     Boolean result;
  271.  
  272.     arg[argLen] = '\0';
  273.     if (Var_Value (arg, VAR_CMD) != (char *)NULL) {
  274.     result = TRUE;
  275.