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