home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d0xx / d028 / cpp.lha / Cpp / cpp2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-07-17  |  16.1 KB  |  595 lines

  1. /*
  2.  *                C P P 2 . C
  3.  *
  4.  *               Process #control lines
  5.  *
  6.  * Edit history
  7.  * 13-Nov-84    MM    Split from cpp1.c
  8.  * 21-Oct-85    RMS    Do not turn on `instring' while reading #include arg.
  9.  *            Rename `token' to `tokenbuf'.
  10.  *            Flush tabs at end of #include line, like spaces.
  11.  * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  12.  *            Port to Commodore AMIGA.
  13.  * 25-May-86    FNF    Change handling of fully qualified include file
  14.  *            pathnames (like "/usr/include/stdio.h" for unix,
  15.  *            or "df0:include/stdio.h" for the Amiga) to be
  16.  *            used verbatum in the first open attempt.
  17.  */
  18.  
  19. #include    <stdio.h>
  20. #include    <ctype.h>
  21. #include    "cppdef.h"
  22. #include    "cpp.h"
  23. #if HOST == SYS_VMS
  24. /*
  25.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  26.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  27.  * By including things by hand, we can CPP ourself.)
  28.  */
  29. #include    <nam.h>
  30. #include    <fab.h>
  31. #include    <rab.h>
  32. #include    <rmsdef.h>
  33. #endif
  34.  
  35. /*
  36.  * Generate (by hand-inspection) a set of unique values for each control
  37.  * operator.  Note that this is not guaranteed to work for non-Ascii
  38.  * machines.  CPP won't compile if there are hash conflicts.
  39.  */
  40.  
  41. #define    L_assert    ('a' + ('s' << 1))
  42. #define    L_define    ('d' + ('f' << 1))
  43. #define    L_elif        ('e' + ('i' << 1))
  44. #define    L_else        ('e' + ('s' << 1))
  45. #define    L_endif        ('e' + ('d' << 1))
  46. #define    L_if        ('i' + (EOS << 1))
  47. #define    L_ifdef        ('i' + ('d' << 1))
  48. #define    L_ifndef    ('i' + ('n' << 1))
  49. #define    L_include    ('i' + ('c' << 1))
  50. #define    L_line        ('l' + ('n' << 1))
  51. #define    L_nogood    (EOS + (EOS << 1))    /* To catch #i        */
  52. #define    L_pragma    ('p' + ('a' << 1))
  53. #define L_undef        ('u' + ('d' << 1))
  54. #if DEBUG
  55. #define    L_debug        ('d' + ('b' << 1))    /* #debug        */
  56. #define    L_nodebug    ('n' + ('d' << 1))    /* #nodebug        */
  57. #endif
  58.  
  59. int
  60. control(counter)
  61. int        counter;    /* Pending newline counter        */
  62. /*
  63.  * Process #control lines.  Simple commands are processed inline,
  64.  * while complex commands have their own subroutines.
  65.  *
  66.  * The counter is used to force out a newline before #line, and
  67.  * #pragma commands.  This prevents these commands from ending up at
  68.  * the end of the previous line if cpp is invoked with the -C option.
  69.  */
  70. {
  71.     register int        c;
  72.     register char        *tp;
  73.     register int        hash;
  74.     char            *ep;
  75.  
  76.     DBUG_ENTER ("control");
  77.     c = skipws();
  78.     if (c == '\n' || c == EOF_CHAR)
  79.         DBUG_RETURN (counter + 1);
  80.     if (!isdigit(c))
  81.         scanid(c);            /* Get #word to tokenbuf    */
  82.     else {
  83.         unget();            /* Hack -- allow #123 as a    */
  84.         strcpy(tokenbuf, "line");    /* synonym for #line 123    */
  85.     }
  86.     hash = (tokenbuf[1] == EOS) ? L_nogood : (tokenbuf[0] + (tokenbuf[2] << 1));
  87.     switch (hash) {
  88.     case L_assert:    tp = "assert";        break;
  89.     case L_define:    tp = "define";        break;
  90.     case L_elif:    tp = "elif";        break;
  91.     case L_else:    tp = "else";        break;
  92.     case L_endif:    tp = "endif";        break;
  93.     case L_if:    tp = "if";        break;
  94.     case L_ifdef:    tp = "ifdef";        break;
  95.     case L_ifndef:    tp = "ifndef";        break;
  96.     case L_include:    tp = "include";        break;
  97.     case L_line:    tp = "line";        break;
  98.     case L_pragma:    tp = "pragma";        break;
  99.     case L_undef:    tp = "undef";        break;
  100. #if DEBUG
  101.     case L_debug:    tp = "debug";        break;
  102.     case L_nodebug:    tp = "nodebug";        break;
  103. #endif
  104.     default:    hash = L_nogood;
  105.     case L_nogood:    tp = "";        break;
  106.     }
  107.     if (!streq(tp, tokenbuf))
  108.         hash = L_nogood;
  109.     /*
  110.      * hash is set to a unique value corresponding to the
  111.      * control keyword (or L_nogood if we think it's nonsense).
  112.      */
  113.     if (infile->fp == NULL)
  114.         cwarn("Control line \"%s\" within macro expansion", tokenbuf);
  115.     if (!compiling) {            /* Not compiling now    */
  116.         switch (hash) {
  117.         case L_if:                /* These can't turn    */
  118.         case L_ifdef:            /*  compilation on, but    */
  119.         case L_ifndef:            /*   we must nest #if's    */
  120.         if (++ifptr >= &ifstack[BLK_NEST])
  121.             goto if_nest_err;
  122.         *ifptr = 0;            /* !WAS_COMPILING    */
  123.         case L_line:            /* Many            */
  124.         /*
  125.          * Are pragma's always processed?
  126.          */
  127.         case L_pragma:            /*  options        */
  128.         case L_include:            /*   are uninteresting    */
  129.         case L_define:            /*    if we        */
  130.         case L_undef:            /*     aren't        */
  131.         case L_assert:            /*      compiling.    */
  132. dump_line:    skipnl();            /* Ignore rest of line    */
  133.         DBUG_RETURN (counter + 1);
  134.         }
  135.     }
  136.     /*
  137.      * Make sure that #line and #pragma are output on a fresh line.
  138.      */
  139.     if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  140.         putchar('\n');
  141.         counter--;
  142.     }
  143.     switch (hash) {
  144.     case L_line:
  145.         /*
  146.          * Parse the line to update the line number and "progname"
  147.          * field and line number for the next input line.
  148.          * Set wrongline to force it out later.
  149.          */
  150.         c = skipws();
  151.         workp = work;            /* Save name in work    */
  152.         while (c != '\n' && c != EOF_CHAR) {
  153.         save(c);
  154.         c = get();
  155.         }
  156.         unget();
  157.         save(EOS);
  158.         /*
  159.          * Split #line argument into <line-number> and <name>
  160.          * We subtract 1 as we want the number of the next line.
  161.          */
  162.         line = atoi(work) - 1;        /* Reset line number    */
  163.         for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  164.         ;                /* Skip over digits    */
  165.         if (*tp != EOS) {            /* Got a filename, so:    */
  166.         if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  167.             tp++;            /* Skip over left quote    */
  168.             *ep = EOS;            /* And ignore right one    */
  169.         }
  170.         if (infile->progname != NULL)    /* Give up the old name    */
  171.             free(infile->progname);    /* if it's allocated.    */
  172.             infile->progname = savestring(tp);
  173.         }
  174.         wrongline = TRUE;            /* Force output later    */
  175.         break;
  176.  
  177.     case L_include:
  178.         doinclude();
  179.         break;
  180.  
  181.     case L_define:
  182.         dodefine();
  183.         break;
  184.  
  185.     case L_undef:
  186.         doundef();
  187.         break;
  188.  
  189.     case L_else:
  190.         if (ifptr == &ifstack[0])
  191.         goto nest_err;
  192.         else if ((*ifptr & ELSE_SEEN) != 0)
  193.         goto else_seen_err;
  194.         *ifptr |= ELSE_SEEN;
  195.         if ((*ifptr & WAS_COMPILING) != 0) {
  196.         if (compiling || (*ifptr & TRUE_SEEN) != 0)
  197.             compiling = FALSE;
  198.         else {
  199.             compiling = TRUE;
  200.         }
  201.         }
  202.         break;
  203.  
  204.     case L_elif:
  205.         if (ifptr == &ifstack[0])
  206.         goto nest_err;
  207.         else if ((*ifptr & ELSE_SEEN) != 0) {
  208. else_seen_err:    cerror("#%s may not follow #else", tokenbuf);
  209.         goto dump_line;
  210.         }
  211.         if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  212.         compiling = FALSE;        /* Done compiling stuff    */
  213.         goto dump_line;            /* Skip this clause    */
  214.         }
  215.         doif(L_if);
  216.         break;
  217.  
  218.     case L_if:
  219.     case L_ifdef:
  220.     case L_ifndef:
  221.         if (++ifptr >= &ifstack[BLK_NEST])
  222. if_nest_err:    cfatal("Too many nested #%s statements", tokenbuf);
  223.         *ifptr = WAS_COMPILING;
  224.         doif(hash);
  225.         break;
  226.  
  227.     case L_endif:
  228.         if (ifptr == &ifstack[0]) {
  229. nest_err:    cerror("#%s must be in an #if", tokenbuf);
  230.         goto dump_line;
  231.         }
  232.         if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  233.         wrongline = TRUE;
  234.         compiling = ((*ifptr & WAS_COMPILING) != 0);
  235.         --ifptr;
  236.         break;
  237.  
  238.     case L_assert:
  239.         if (eval() == 0)
  240.         cerror("Preprocessor assertion failure", NULLST);
  241.         break;
  242.  
  243.     case L_pragma:
  244.         /*
  245.          * #pragma is provided to pass "options" to later
  246.          * passes of the compiler.  cpp doesn't have any yet.
  247.          */
  248.         printf("#pragma ");
  249.         while ((c = get()) != '\n' && c != EOF_CHAR)
  250.         cput(c);
  251.         unget();
  252.         break;
  253.  
  254. #if DEBUG
  255.     case L_debug:
  256.         if (debug == 0)
  257.         dumpdef("debug set on");
  258.         debug++;
  259.         break;
  260.  
  261.     case L_nodebug:
  262.         debug--;
  263.         break;
  264. #endif
  265.  
  266.     default:
  267.         /*
  268.          * Undefined #control keyword.
  269.          * Note: the correct behavior may be to warn and
  270.          * pass the line to a subsequent compiler pass.
  271.          * This would allow #asm or similar extensions.
  272.          */
  273.         cerror("Illegal # command \"%s\"", tokenbuf);
  274.         break;
  275.     }
  276.     if (hash != L_include) {
  277. #if OLD_PREPROCESSOR
  278.         /*
  279.          * Ignore the rest of the #control line so you can write
  280.          *        #if    foo
  281.          *        #endif    foo
  282.          */
  283.         goto dump_line;            /* Take common exit    */
  284. #else
  285.         if (skipws() != '\n') {
  286.         cwarn("Unexpected text in #control line ignored", NULLST);
  287.         skipnl();
  288.         }
  289. #endif
  290.     }
  291.     DBUG_RETURN (counter + 1);
  292. }
  293.  
  294. FILE_LOCAL
  295. doif(hash)
  296. int        hash;
  297. /*
  298.  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
  299.  * while #if needs a subroutine of its own to evaluate the expression.
  300.  *
  301.  * doif() is called only if compiling is TRUE.  If false, compilation
  302.  * is always supressed, so we don't need to evaluate anything.  This
  303.  * supresses unnecessary warnings.
  304.  */
  305. {
  306.     register int        c;
  307.     register int        found;
  308.  
  309.     DBUG_ENTER ("doif");
  310.     if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  311.         unget();
  312.         goto badif;
  313.     }
  314.     if (hash == L_if) {
  315.         unget();
  316.         found = (eval() != 0);    /* Evaluate expr, != 0 is  TRUE    */
  317.         hash = L_ifdef;        /* #if is now like #ifdef    */
  318.     }
  319.     else {
  320.         if (type[c] != LET)        /* Next non-blank isn't letter    */
  321.         goto badif;        /* ... is an error        */
  322.         found = (lookid(c) != NULL); /* Look for it in symbol table    */
  323.     }
  324.     if (found == (hash == L_ifdef)) {
  325.         compiling = TRUE;
  326.         *ifptr |= TRUE_SEEN;
  327.     }
  328.     else {
  329.         compiling = FALSE;
  330.     }
  331.     DBUG_VOID_RETURN;
  332.  
  333. badif:    cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  334. #if !OLD_PREPROCESSOR
  335.     skipnl();                /* Prevent an extra    */
  336.     unget();                /* Error message    */
  337. #endif
  338.     DBUG_VOID_RETURN;
  339. }
  340.  
  341. FILE_LOCAL
  342. doinclude()
  343. /*
  344.  * Process the #include control line.
  345.  * There are three variations:
  346.  *    #include "file"        search somewhere relative to the
  347.  *                current source file, if not found,
  348.  *                treat as #include <file>.
  349.  *    #include <file>        Search in an implementation-dependent
  350.  *                list of places.
  351.  *    #include token        Expand the token, it must be one of
  352.  *                "file" or <file>, process as such.
  353.  *
  354.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  355.  * This restriction is unnecessary and not implemented.
  356.  */
  357. {
  358.     register int        c;
  359.     register int        delim;
  360. #if HOST == SYS_VMS
  361.     char            def_filename[NAM$C_MAXRSS + 1];
  362. #endif
  363.  
  364.     DBUG_ENTER ("doinclude");
  365.     delim = macroid(skipws());
  366.     if (delim != '<' && delim != '"')
  367.         goto incerr;
  368.     if (delim == '<')
  369.         delim = '>';
  370.     workp = work;
  371.     while ((c = get()) != '\n' && c != EOF_CHAR)
  372.         save(c);            /* Put it away.            */
  373.     unget();            /* Force nl after includee    */
  374.     /*
  375.      * The draft is unclear if the following should be done.
  376.      */
  377.     while (--workp >= work && (*workp == ' ' || *workp == '\t'))
  378.         ;                /* Trim blanks from filename    */
  379.     if (*workp != delim)
  380.         goto incerr;
  381.     *workp = EOS;            /* Terminate filename        */
  382. #if HOST == SYS_VMS
  383.     /*
  384.      * Assume the default .h filetype.
  385.      */
  386.     if (!vmsparse(work, ".H", def_filename)) {
  387.         perror(work);        /* Oops.            */
  388.         goto incerr;
  389.     }
  390.     else if (openinclude(def_filename, (delim == '"')))
  391.         DBUG_VOID_RETURN;
  392. #else
  393.     if (openinclude(work, (delim == '"')))
  394.         DBUG_VOID_RETURN;
  395. #endif
  396.     /*
  397.      * No sense continuing if #include file isn't there.
  398.      */
  399.     cfatal("Cannot open include file \"%s\"", work);
  400.  
  401. incerr:    cerror("#include syntax error", NULLST);
  402.     DBUG_VOID_RETURN;
  403. }
  404.  
  405. FILE_LOCAL int
  406. openinclude(filename, searchlocal)
  407. char        *filename;        /* Input file name        */
  408. int        searchlocal;        /* TRUE if #include "file"    */
  409. /*
  410.  * Actually open an include file.  This routine is only called from
  411.  * doinclude() above, but was written as a separate subroutine for
  412.  * programmer convenience.  It searches the list of directories
  413.  * and actually opens the file, linking it into the list of
  414.  * active files.  Returns TRUE if the file was opened, FALSE
  415.  * if openinclude() fails.  No error message is printed.
  416.  */
  417. {
  418.     register char        **incptr;
  419. #if HOST == SYS_VMS
  420. #if NWORK < (NAM$C_MAXRSS + 1)
  421.     << error, NWORK isn't greater than NAM$C_MAXRSS >>
  422. #endif
  423. #endif
  424.     char            tmpname[NWORK];    /* Filename work area    */
  425.  
  426.     DBUG_ENTER ("openinclude");
  427. #if HOST == SYS_UNIX
  428.     if ((filename[0] == '/') && openfile(filename)) {
  429.         DBUG_RETURN (TRUE);
  430.     }
  431. #endif
  432. #if HOST == SYS_AMIGADOS
  433.     if ((strchr (filename, ':') != NULL) && openfile (filename)) {
  434.         DBUG_RETURN (TRUE);
  435.     }
  436. #endif
  437.     if (searchlocal) {
  438.         /*
  439.          * Look in local directory first.
  440.          * Try to open filename relative to the directory of the current
  441.          * source file (as opposed to the current directory). (ARF, SCK).
  442.          * Note that the fully qualified pathname is always built by
  443.          * discarding the last pathname component of the source file
  444.          * name then tacking on the #include argument.
  445.          */
  446.         if(hasdirectory(infile->filename, tmpname)) {
  447.         strcat(tmpname, filename);
  448.         } else {
  449.         strcpy(tmpname, filename);
  450.         }
  451.         if (openfile(tmpname))
  452.         DBUG_RETURN (TRUE);
  453.     }
  454.     /*
  455.      * Look in any directories specified by -I command line
  456.      * arguments, then in the builtin search list.
  457.      */
  458.     for (incptr = incdir; incptr < incend; incptr++) {
  459.         if (strlen(*incptr) + strlen(filename) >= sizeof(tmpname)) {
  460.         cfatal("Filename work buffer overflow", NULLST);
  461.         } else {
  462. #if HOST == SYS_UNIX || HOST == SYS_AMIGADOS    /* Implied '/' */
  463.         sprintf(tmpname, "%s/%s", *incptr, filename);
  464. #else
  465.         sprintf(tmpname, "%s%s", *incptr, filename);
  466. #endif
  467.         if (openfile(tmpname))
  468.             DBUG_RETURN (TRUE);
  469.         }
  470.     }
  471.     DBUG_RETURN (FALSE);
  472. }
  473.  
  474. FILE_LOCAL int
  475. hasdirectory(source, result)
  476. char        *source;    /* Directory to examine            */
  477. char        *result;    /* Put directory stuff here        */
  478. /*
  479.  * If a device or directory is found in the source filename string, the
  480.  * node/device/directory part of the string is copied to result and
  481.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  482.  */
  483. {
  484. #if HOST == SYS_UNIX || HOST == SYS_AMIGADOS
  485.     register char        *tp;
  486.  
  487.     DBUG_ENTER ("hasdirectory");
  488.     if ((tp = strrchr(source, '/')) == NULL)
  489.         DBUG_RETURN (FALSE);
  490.     else {
  491.         strncpy(result, source, tp - source + 1);
  492.         result[tp - source + 1] = EOS;
  493.         DBUG_RETURN (TRUE);
  494.     }
  495. #else
  496. #if HOST == SYS_VMS
  497.     DBUG_ENTER ("hasdirectory");
  498.     if (vmsparse(source, NULLST, result)
  499.      && result[0] != EOS)
  500.         DBUG_RETURN (TRUE);
  501.     else {
  502.         DBUG_RETURN (FALSE);
  503.     }
  504. #else
  505.     /*
  506.      * Random DEC operating system (RSX, RT11, RSTS/E)
  507.      */
  508.     register char        *tp;
  509.  
  510.         DBUG_ENTER ("hasdirectory");
  511.     if ((tp = strrchr(source, ']')) == NULL
  512.      && (tp = strrchr(source, ':')) == NULL)
  513.         DBUG_RETURN (FALSE);
  514.     else {
  515.         strncpy(result, source, tp - source + 1);
  516.         result[tp - source + 1] = EOS;
  517.         DBUG_RETURN (TRUE);
  518.     }
  519. #endif
  520. #endif
  521. }
  522.  
  523. #if HOST == SYS_VMS
  524.  
  525. /*
  526.  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
  527.  * is specified.  (Both set indicate a file-logical, but EXP_DEV
  528.  * would be set by itself if you are reading, say, SYS$INPUT:)
  529.  */
  530. #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
  531.  
  532. FILE_LOCAL int
  533. vmsparse(source, defstring, result)
  534. char        *source;
  535. char        *defstring;    /* non-NULL -> default string.        */
  536. char        *result;    /* Size is at least NAM$C_MAXRSS + 1    */
  537. /*
  538.  * Parse the source string, applying the default (properly, using
  539.  * the system parse routine), storing it in result.
  540.  * TRUE if it parsed, FALSE on error.
  541.  *
  542.  * If defstring is NULL, there are no defaults and result gets
  543.  * (just) the node::[directory] part of the string (possibly "")
  544.  */
  545. {
  546.     struct FAB    fab = cc$rms_fab;    /* File access block    */
  547.     struct NAM    nam = cc$rms_nam;    /* File name block    */
  548.     char        fullname[NAM$C_MAXRSS + 1];
  549.     register char    *rp;            /* Result pointer    */
  550.  
  551.     DBUG_ENTER ("vmsparse");
  552.     fab.fab$l_nam = &nam;            /* fab -> nam        */
  553.     fab.fab$l_fna = source;            /* Source filename    */
  554.     fab.fab$b_fns = strlen(source);        /* Size of source    */
  555.     fab.fab$l_dna = defstring;        /* Default string    */
  556.     if (defstring != NULLST)
  557.         fab.fab$b_dns = strlen(defstring);    /* Size of default    */
  558.     nam.nam$l_esa = fullname;        /* Expanded filename    */
  559.     nam.nam$b_ess = NAM$C_MAXRSS;        /* Expanded name size    */
  560.     if (sys$parse(&fab) == RMS$_NORMAL) {    /* Parse away        */
  561.         fullname[nam.nam$b_esl] = EOS;    /* Terminate string    */
  562.         result[0] = EOS;            /* Just in case        */
  563.         rp = &result[0];
  564.         /*
  565.          * Remove stuff added implicitly, accepting node names and
  566.          * dev:[directory] strings (but not process-permanent files).
  567.          */
  568.         if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  569.         if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  570.             strncpy(result, nam.nam$l_node, nam.nam$b_node);
  571.             rp += nam.nam$b_node;
  572.             *rp = EOS;
  573.         }
  574.         if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
  575.             strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
  576.             rp += nam.nam$b_dev + nam.nam$b_dir;
  577.             *rp = EOS;
  578.         }
  579.         }
  580.         if (defstring != NULLST) {
  581.         strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  582.         rp += nam.nam$b_name + nam.nam$b_type;
  583.         *rp = EOS;
  584.         if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  585.             strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  586.             rp[nam.nam$b_ver] = EOS;
  587.         }
  588.         }
  589.         DBUG_RETURN (TRUE);
  590.     }
  591.     DBUG_RETURN (FALSE);
  592. }
  593. #endif
  594.  
  595.