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