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

  1. /*
  2.     CPP V5 -- Main routine
  3.  
  4.     source:  cpp.c
  5.     started: October 7, 1985
  6.     version: see below
  7.  
  8.     Written by Edward K. Ream.
  9.     This software is in the public domain.
  10.  
  11.     See the read.me file for disclaimer and other information.
  12. */
  13.  
  14. #include "cpp.h"
  15.  
  16. #define SIGNON "CPP V5.3:  August 4, 1989"
  17.  
  18. #ifdef SHERLOCK
  19. #define USAGE1 "usage: cpp in out [options] ++/--routine\n\n"
  20. #else
  21. #define USAGE1 "usage: cpp in out [options]\n\n"
  22. #endif
  23.  
  24. #define USAGE2    "-c           keep all comments and white space\n"
  25. #define USAGE3  "-d id=value  #define id value\n"
  26. #define USAGE4  "-n           comments DO nest\n"
  27. #define USAGE5  "-s <path>    set search path for #include's\n"
  28. #define USAGE6  "-u id        #undef id\n"
  29. #define USAGE7  "-x           disallow single-line comments\n"
  30.  
  31. main(argc, argv)
  32. int argc;
  33. char **argv;
  34. {
  35.     char *in = NULL, *out = NULL;
  36.     char *arg;
  37.     char *def;
  38.     char *p1, *p;
  39.     char path_buf[200];
  40.  
  41.     /* These two calls MUST come before any others. */
  42.     SL_INIT();
  43.     SL_PARSE(argc, argv, "++", "--");
  44.  
  45.     /*
  46.         The call to mst_init() MUST be placed here so we can define
  47.         macros using the -d option.
  48.  
  49.         The call to mst2_init() must FOLLOW the gathering of
  50.         command line arguments so that the __line__ and __file__
  51.         macros may be disabled using the -u option.
  52.     */
  53.     mst_init();
  54.  
  55.     /* Allow user to abort. */
  56.     syscsts();
  57.  
  58.     TICKB("main");
  59.  
  60.     /* Always put out the sign on message. */
  61.     printf("%s\n", SIGNON);
  62.  
  63.     /* Set search path from the INCLUDE environment variable. */
  64.     arg = getenv("INCLUDE");
  65.     if (arg != 0) {
  66.         strcpy(path_buf, arg);
  67.         arg = path_buf;
  68.         for (p = &path_buf[0]; ;) {
  69.             if (*p != ';' && *p != '\0') {
  70.                 p++;
  71.                 continue;
  72.             }
  73.             if (*p == ';') {
  74.                 *p = '\0';
  75.                 p++;
  76.             }
  77.             if (n_paths >= MAX_PATHS) {
  78.                 printf("too many default path names.\n");
  79.                 exit(BAD_EXIT);
  80.             }
  81.             else {
  82.                 p1 = str_mcat(arg, "\\");
  83.                 TRACEP("main",
  84.                     printf("default path: %s\n", arg));
  85.                 paths [n_paths++] = p1;
  86.             }
  87.             if (*p == '\0') {
  88.                 break;
  89.             }
  90.             else {
  91.                 arg = p;
  92.             }
  93.         }
  94.     }
  95.  
  96.     /* Make first test for correct command line. */
  97.     if (argc < 3) {
  98.         printf("%s%s%s%s", USAGE1, USAGE2,  USAGE3,  USAGE4);
  99.         printf("%s%s%s", USAGE5, USAGE6, USAGE7);
  100.         exit(BAD_EXIT);
  101.     }
  102.  
  103.     /* Process all the arguments on the command line. */
  104.     argc--;
  105.     argv++;
  106.     while (argc-- > 0) {
  107.         arg = *argv++;
  108.  
  109.         if (str_eq(arg, "-c")) {
  110.             /* Keep comments in output. */
  111.             com_flag = TRUE;
  112.         }
  113.         else if(str_eq(arg, "-d")) {
  114.             /* Define a variable. */
  115.             if (argc--) {
  116.                 arg = *argv++;
  117.                 /* Scan for an optional equal sign. */
  118.                 for (def = arg;    *def; def++) {
  119.                     if (*def == '=') {
  120.                         *def = '\0';
  121.                         def++;
  122.                         break;
  123.                     }
  124.                 }
  125.                 mst_enter(arg, def, -1);
  126.             }
  127.             else {
  128.                 printf("Trailing -d\n");
  129.                 exit(BAD_EXIT);
  130.             }
  131.         }
  132.         else if (str_eq(arg, "-n")) {
  133.             /* Disallow nested comments. */
  134.             nest_flag = FALSE;
  135.         }
  136.         else if (str_eq(arg, "-s")) {
  137.             /* Define a path. */
  138.             if (argc--) {
  139.                 arg = *argv++;
  140.                 if (n_paths >= MAX_PATHS) {
  141.                     printf("too many path names.\n");
  142.                     exit(BAD_EXIT);
  143.                 }
  144.                 else {
  145.                     p1 = str_mcat(arg, "\\");
  146.                     paths [n_paths++] = p1;
  147.                 }
  148.             }
  149.             else {
  150.                 printf("Trailing -s.\n");
  151.                 exit(BAD_EXIT);
  152.             }
  153.         }
  154.         else if(str_eq(arg, "-u")) {
  155.             /* Suppress the initial definition of a variable. */
  156.             if (argc--) {
  157.                 arg = *argv++;
  158.                 mst_unarg(arg);
  159.             }
  160.             else {
  161.                 printf("Trailing -u.\n");
  162.                 exit(BAD_EXIT);
  163.             }
  164.         }
  165.         else if (str_eq(arg, "-x")) {
  166.             /* 8/1/89 Disable single-line comments. */
  167.             slc_flag = FALSE;
  168.         }
  169.         else if (in == NULL) {
  170.             in = arg;
  171.         }
  172.         else if (out == NULL) {
  173.             out = arg;
  174.         }
  175.         else {
  176.             printf("Extra file argument: %s\n", arg);
  177.             exit(BAD_EXIT);
  178.         }
  179.     }
  180.  
  181.     /* Make sure that both file arguments were provided. */
  182.     if (in == NULL) {
  183.         printf("Missing input, output file arguments.\n");
  184.         exit(BAD_EXIT);
  185.     }
  186.     else if (out == NULL) {
  187.         printf("Missing output file argument.\n");
  188.         exit(BAD_EXIT);
  189.     }
  190.     else if (str_eq(in, out)) {
  191.         fatal("Can not copy input file to output file.");
  192.     }
  193.  
  194.     /*
  195.         Open the output file.
  196.  
  197.         This should be done BEFORE opening the input file because
  198.         opening the input file will cause a character to be written
  199.         to the output file.
  200.     */
  201.     if (syscreat(out) == FALSE) {
  202.         printf("Can not open %s\n", out);
  203.         exit(BAD_EXIT);
  204.     }
  205.  
  206.     /* Open the input file. */
  207.     if (sysopen(in) == FALSE) {
  208.         printf("Can not open %s\n", in);
  209.         sysabort();
  210.     }
  211.  
  212.     /*
  213.         Initialize the predefined macros (__line__ and __file__) here
  214.         so that they can be suppressed with the -u command line option.
  215.     */
  216.     mst2_init();
  217.  
  218.     /* Start off at a new line. */
  219.     begin_line(TRUE);
  220.  
  221.     /* Copy the program to the output file. */
  222.     copy_file();
  223.  
  224.     /* Close the output file. */
  225.     sysoclose();
  226.  
  227.     TRACE("m_stat", m_stat());
  228.     TRACE("dump", sl_dump());
  229.  
  230.     sysend();
  231.  
  232.     LEAVE("main");
  233.     exit(0);
  234. }
  235.  
  236. /*
  237.     Copy the input file to the output file.
  238. */
  239.  
  240. void
  241. copy_file()
  242. {
  243.     int    i;
  244.     bool    old_mflag;
  245.     char    id_buf[MAX_SYMBOL];
  246.  
  247.     TICKB("copy_file");
  248.  
  249.     t_symbol[0] = '\0';
  250.     t_subtype = 0;
  251.  
  252.     /*
  253.         We branch to the 'rescan' label whenever a construct is seen
  254.         that does not result directly in a token being returned, i.e.,
  255.         for macros, PP directives and whitespace.
  256.     */
  257.  
  258. loop:
  259.     TRACEP("copy_file_loop", printf("ch: %s\n", pr_ch(ch)));
  260.  
  261.     if (isid1(ch)) {
  262.         old_mflag = m_flag;
  263.         t_id(&t_symbol[0], MAX_SYMBOL);
  264.         if (!outer_expand(&t_symbol[0], old_mflag)) {
  265.             syssput(&t_symbol[0]);
  266.         }
  267.         goto loop;
  268.     }
  269.  
  270.     switch (ch) {
  271.  
  272.     case ' ':
  273.     case '\t':
  274.         syscput(ch);
  275.         sysnext();
  276.         goto loop;
  277.  
  278.     case '\n':
  279.  
  280.                 /* Allow user to abort here. */
  281.         syscsts();
  282.  
  283.         sysnlput();
  284.         sysnext();
  285.         bump_line();
  286.         begin_line(TRUE);
  287.         goto loop;
  288.  
  289.     case '#':
  290.         error("Unexpected # ignored.");
  291.         sysnext();
  292.         goto loop;
  293.  
  294.     case '/':
  295.         /* comment or / or /= or // */
  296.         sysnext();
  297.         if (ch == '*') {
  298.             sysnext();
  299.             if (com_flag) {
  300.                 syscput('/');
  301.                 syscput('*');
  302.                 copy_comment();
  303.             }
  304.             else {
  305.                 skip_comment();
  306.             }
  307.         }
  308.         else if (slc_flag && ch == '/') {
  309.             /* 8/1/89 C++ style single-line comment. */
  310.             skip_past();
  311.             goto loop;
  312.         }
  313.         else {
  314.             syscput('/');
  315.         }
  316.         goto loop;
  317.  
  318.     case '\'':
  319.         t_string(&t_symbol[0], MAX_SYMBOL, TRUE);
  320.         syssput(&t_symbol[0]);
  321.         goto loop;
  322.  
  323.     case '"':
  324.         /* Do concatenation of string literals here. */
  325.         TRACE("nocat",
  326.             t_string(&t_symbol[0], MAX_SYMBOL, TRUE);
  327.             syssput(&t_symbol[0]);
  328.             goto loop;
  329.         );
  330.  
  331.         /*
  332.             Note that a macro may expand into several strings,
  333.             so that we have to be careful not to stop searching
  334.             for more strings to concatenate too soon.
  335.         */
  336.  
  337.         t_symbol[0] = '"';
  338.         for(i = 1;;) {
  339.             if (ch == ' ' || ch == '\t') {
  340.                 sysnext();
  341.             }
  342.             else if (ch == '"') {
  343.                 t_string(&t_symbol[i], MAX_SYMBOL-i, FALSE);
  344.                 i = strlen(&t_symbol[0]);
  345.             }
  346.             else if (isid1(ch)) {
  347.                 old_mflag = m_flag;
  348.                 t_id(&id_buf[0], MAX_SYMBOL);
  349.                 if (!outer_expand(&id_buf[0], old_mflag)) {
  350.                     /* Not a macro. */
  351.                     syssput(&id_buf[0]);
  352.                     goto loop;
  353.                 }
  354.             }
  355.             else {
  356.                 break;
  357.             }
  358.         }
  359.         t_symbol[i++] = '"';
  360.         t_symbol[i]   = '\0';
  361.         syssput(&t_symbol[0]);
  362.         goto loop;
  363.  
  364.     /*
  365.         We must be VERY careful about exactly when we switch from one
  366.         input file to the next.  This is the place. 
  367.     */
  368.  
  369.     case END_FILE:
  370.  
  371.         /* Switch input streams. */
  372.         sysiclose();
  373.         if (t_inlevel == -1) {
  374.             RETURN_VOID("copy_file");
  375.         }
  376.         else {
  377.             begin_line(TRUE);
  378.             goto loop;
  379.         }
  380.  
  381.     default:
  382.         /* Be permissive. */
  383.         syscput(ch);
  384.         sysnext();
  385.         goto loop;
  386.     }
  387. }
  388.  
  389. /*
  390.     Return the next preprocessor token.
  391.     This should be called only in contexts where output is NOT required.
  392. */
  393.  
  394. #ifdef SHERLOCK
  395. char bug_s1 [] = "get_token";
  396. char bug_s2 [] = "returns token %d, %s\n";
  397. #endif
  398.  
  399. /* CAUTION: evaluate value only once! */
  400. #define T_RETURN(value)\
  401.     token = value;\
  402.     TRACEPN(bug_s1, printf(bug_s2, token, pr_tok()));\
  403.     return;
  404.  
  405. void
  406. get_token(expand_flag)
  407. bool expand_flag;
  408. {
  409.     int i;
  410.     bool    old_mflag;
  411.     unsigned char mesgbuf [40];
  412.     unsigned char cbuf [2];
  413.  
  414.     TRACEP("get_token", printf("(%s) line %d\n",
  415.         pr_bool(expand_flag), t_line));
  416.  
  417.     t_symbol[0] = '\0';
  418.     t_subtype = 0;
  419.  
  420.     /*
  421.         We branch to the 'rescan' label whenever a construct is seen
  422.         that does not result directly in a token being returned, i.e.,
  423.         for macros, PP directives and whitespace.
  424.     */
  425. rescan:
  426.  
  427.     /* Special case for "wide" characters and strings. */
  428.     if (ch == 'L') {
  429.         sysnext();
  430.         if (isid2(ch)) {
  431.             syspushback(ch);
  432.             ch = 'L';
  433.         }
  434.     }
  435.  
  436.     if (isid1(ch)) {
  437.         old_mflag = m_flag;
  438.         t_id(&t_symbol[0], MAX_SYMBOL);
  439.         if (expand_flag && outer_expand(&t_symbol[0], old_mflag)) {
  440.             goto rescan;
  441.         }
  442.         else {
  443.             T_RETURN(ID_TOK);
  444.         }
  445.     }
  446.  
  447.     TICK("get_token1");
  448.  
  449.     switch (ch) {
  450.  
  451.     case ' ':
  452.     case '\t':
  453.         sysnext();
  454.         goto rescan;
  455.  
  456.     case '\n':
  457.     case END_FILE:
  458.  
  459.         TRACEPN("get_token", printf("con_flag: NULL_TOK\n"));
  460.         T_RETURN(NULL_TOK);
  461.  
  462.     case '#':
  463.         error("Unexpected # ignored.");
  464.         sysnext();
  465.         goto rescan;
  466.  
  467.     case '0': case '1': case '2': case '3': case '4':
  468.     case '5': case '6': case '7': case '8': case '9':
  469.  
  470.         T_RETURN(t_number(FALSE));
  471.  
  472.     case '.':
  473.         sysnext();
  474.         if (ch >= '0' && ch <= '9') {
  475.             T_RETURN(t_number(TRUE));
  476.         }
  477.         else if (ch == '.') {
  478.             sysnext();
  479.             if (ch == '.') {
  480.                 sysnext();
  481.                 T_RETURN(DOTS3);
  482.             }
  483.         }
  484.         else {
  485.             T_RETURN(DOT_TOK);
  486.         }
  487.  
  488.     case '"':
  489.         t_string(&t_symbol[0], MAX_SYMBOL, FALSE);
  490.         T_RETURN(STRING_TOK);
  491.  
  492.     case '\'':
  493.         t_string(&t_symbol[0], MAX_SYMBOL, FALSE);
  494.         t_value = (long) char_val(&t_symbol[0]);
  495.         T_RETURN(CHAR_TOK);
  496.  
  497.  
  498.     case '=':    /* = or == */
  499.  
  500.         sysnext();
  501.         if (ch == '=') {
  502.             sysnext();
  503.             T_RETURN(EQUAL_TOK);
  504.         }
  505.         else {
  506.             T_RETURN(ASSN_TOK);
  507.         }
  508.  
  509.  
  510.     case '+':    /* + or ++ or += */
  511.  
  512.         sysnext();
  513.         if (ch == '+') {
  514.             sysnext();
  515.             T_RETURN(INC_TOK);
  516.         }
  517.         else if (ch == '=') {
  518.             sysnext();
  519.             T_RETURN(PLUS_ASSN_TOK);
  520.         }
  521.         else {
  522.             T_RETURN(PLUS_TOK);
  523.         }
  524.  
  525.  
  526.     case '-':    /* - or -- or -> */
  527.  
  528.         sysnext();
  529.         if (ch == '=') {
  530.             sysnext();
  531.             T_RETURN(MINUS_ASSN_TOK);
  532.         }
  533.         else if (ch == '-') {
  534.             sysnext();
  535.             T_RETURN(DEC_TOK);
  536.         }
  537.         else if (ch == '>') {
  538.             sysnext();
  539.             T_RETURN(ARROW_TOK);
  540.         }
  541.         else {
  542.             T_RETURN(MINUS_TOK);
  543.         }
  544.  
  545.  
  546.     case '*':    /* * or *= */
  547.  
  548.         sysnext();
  549.         if (ch == '=') {
  550.             sysnext();
  551.             T_RETURN(STAR_ASSN_TOK);
  552.         }
  553.         else {
  554.             T_RETURN(STAR_TOK);
  555.         }
  556.  
  557.  
  558.     case '/':    /* comment or / or /= */
  559.  
  560.         sysnext();
  561.         if (ch == '*') {
  562.             sysnext();
  563.             skip_comment();
  564.             goto rescan;
  565.         }
  566.         else if (ch == '=') {
  567.             sysnext();
  568.             T_RETURN(DIV_ASSN_TOK);
  569.         }
  570.         else {
  571.             T_RETURN(DIV_TOK);
  572.         }
  573.  
  574.  
  575.     case '%':    /* % or %= */
  576.  
  577.         sysnext();
  578.         if (ch == '=') {
  579.             sysnext();
  580.             T_RETURN(MOD_ASSN_TOK);
  581.         }
  582.         else {
  583.             T_RETURN(MOD_TOK);
  584.         }
  585.  
  586.  
  587.     case '>':    /* > or >= or >> or >>= */
  588.  
  589.         sysnext();
  590.         if (ch == '>') {
  591.             sysnext();
  592.             if (ch == '=') {
  593.                 sysnext();
  594.                 T_RETURN(RSHIFT_ASSN_TOK);
  595.             }
  596.             else {
  597.                 T_RETURN(RSHIFT_TOK);
  598.             }
  599.         }
  600.         else if (ch == '=') {
  601.             sysnext();
  602.             T_RETURN(GE_TOK);
  603.         }
  604.         else {
  605.             T_RETURN(GT_TOK);
  606.         }
  607.  
  608.  
  609.     case '<':    /* < or or <= or << or <<= */
  610.  
  611.         sysnext();
  612.         if (ch == '<') {
  613.             sysnext();
  614.             if (ch == '=') {
  615.                 sysnext();
  616.                 T_RETURN(LSHIFT_ASSN_TOK);
  617.             }
  618.             else {
  619.                 T_RETURN(LSHIFT_TOK);
  620.             }
  621.         }
  622.         else if (ch == '=') {
  623.             sysnext();
  624.             T_RETURN(LE_TOK);
  625.         }
  626.         else {
  627.             T_RETURN(LT_TOK);
  628.         }
  629.  
  630.  
  631.     case '!':    /* ! or != */
  632.  
  633.         sysnext();
  634.         if (ch == '=') {
  635.             sysnext();
  636.             T_RETURN(NE_TOK);
  637.         }
  638.         else {
  639.             T_RETURN(NOT_TOK);
  640.         }
  641.             
  642.  
  643.     case '|':    /* | or |= or || */
  644.  
  645.         sysnext();
  646.         if (ch == '=') {
  647.             sysnext();
  648.             T_RETURN(OR_ASSN_TOK);
  649.         }
  650.         else if (ch == '|') {
  651.             sysnext();
  652.             T_RETURN(LOR_TOK);
  653.         }
  654.         else {
  655.             T_RETURN(OR_TOK);
  656.         }
  657.  
  658.  
  659.     case '&':    /* & or &= or && */
  660.  
  661.         sysnext();
  662.         if (ch == '=') {
  663.             sysnext();
  664.             T_RETURN(AND_ASSN_TOK);
  665.         }
  666.         else if (ch == '&') {
  667.             sysnext();
  668.             T_RETURN(LAND_TOK);
  669.         }
  670.         else {
  671.             T_RETURN(AND_TOK);
  672.         }
  673.  
  674.  
  675.     case '^':    /* ^ or ^= */
  676.  
  677.         sysnext();
  678.         if (ch == '=') {
  679.             sysnext();
  680.             T_RETURN(XOR_ASSN_TOK);
  681.         }
  682.         else {
  683.             T_RETURN(XOR_TOK);
  684.         }
  685.  
  686.  
  687.     case '?':    sysnext();    T_RETURN(QUESTION_TOK);
  688.     case ':':    sysnext();    T_RETURN(COLON_TOK);
  689.  
  690.     case '~':    sysnext();    T_RETURN(TILDE_TOK);
  691.     case ',':    sysnext();    T_RETURN(COMMA_TOK);
  692.     case '(':    sysnext();    T_RETURN(LPAREN_TOK);
  693.     case ')':    sysnext();    T_RETURN(RPAREN_TOK);
  694.     case '[':    sysnext();    T_RETURN(LBRACK_TOK);
  695.     case ']':    sysnext();    T_RETURN(RBRACK_TOK);
  696.     case '{':    sysnext();    T_RETURN(LCURLY_TOK);
  697.     case '}':    sysnext();    T_RETURN(RCURLY_TOK);
  698.     case ';':    sysnext();    T_RETURN(SEMICOLON_TOK);
  699.  
  700.     default:
  701.  
  702.         strcpy(mesgbuf, "Character error: ");
  703.         cbuf [0] = ch;
  704.         cbuf [1] = '\0';
  705.         strcat(mesgbuf, cbuf);
  706.         error(mesgbuf);
  707.         sysnext();
  708.         goto rescan;
  709.     }
  710. }
  711.  
  712. #undef T_RETURN
  713.  
  714. /*
  715.     Do beginning of line processing.
  716.     Look for preprocessor directives only if flag is TRUE.
  717. */
  718. void
  719. begin_line(flag)
  720. bool flag;
  721. {
  722.     TRACEPB("begin_line", printf("t_line: %d\n", t_line));
  723.  
  724.     for (;;) {
  725.         if (com_flag) {
  726.             copy_ws(TRUE);
  727.         }
  728.         else {
  729.             skip_ws(TRUE);
  730.         }
  731.  
  732.         /* PP directives are not allowed as the result of macro expansion. */
  733.         if (flag && ch == '#' && !m_flag) {
  734.             sysnext();
  735.             do_pp();
  736.         }
  737.         else {
  738.             break;
  739.         }
  740.     }
  741.  
  742.     RETURN_VOID("begin_line");
  743. }
  744.  
  745. /*
  746.     Bump the line number of the current file.
  747. */
  748. void
  749. bump_line()
  750. {
  751.     t_line++;
  752.     TRACEP("bump_line", printf("t_line = %d\n", t_line));
  753. }
  754.