home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 355_02 / slk2.exe / SPP / UTL.C < prev   
C/C++ Source or Header  |  1991-06-09  |  11KB  |  594 lines

  1. /*
  2.     New Sherlock Preprocessor -- utilities.
  3.  
  4.     Source:  utl.c
  5.     Started: October 7, 1985
  6.     Version:
  7.         July 15, 1988
  8.         February 16, 1989
  9.             Add function name to errors and warnings.
  10.             Fix bug in skip_ws that made it loop!
  11.         August 3, 1989 Version 1.5
  12.             added slc_flag sentinal for single-line-comments.
  13.             errors go to stderr
  14.     
  15.  
  16.     PUBLIC DOMAIN SOFTWARE
  17.  
  18.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  19.     the public domain on June 15, 1991, by its author,
  20.  
  21.         Edward K. Ream
  22.         166 North Prospect Ave.
  23.         Madison, WI 53705.
  24.         (608) 257-0802
  25.  
  26.     Sherlock may be used for any commercial or non-commercial purpose.
  27.  
  28.  
  29.     DISCLAIMER OF WARRANTIES
  30.  
  31.     Edward K. Ream (Ream) specifically disclaims all warranties,
  32.     expressed or implied, with respect to this computer software,
  33.     including but not limited to implied warranties of merchantability
  34.     and fitness for a particular purpose.  In no event shall Ream be
  35.     liable for any loss of profit or any commercial damage, including
  36.     but not limited to special, incidental consequential or other damages.
  37. */
  38.  
  39. #include "spp.h"
  40.  
  41. /*
  42.     Return the value of a character constant.
  43. */
  44. int
  45. char_val(s)
  46. register char *s;
  47. {
  48.     int val;
  49.  
  50.     if (*s != '\\') {
  51.         return (int) *s;
  52.     }
  53.     s++;
  54.     switch (*s) {
  55.     case 'b':    return '\b';
  56.     case 'f':    return '\f';
  57.     case 'n':    return '\n';
  58.     case 'r':    return '\r';
  59.     case 't':    return '\t';
  60.     case '\'':    return '\'';
  61.     case '\\':    return '\\';
  62.  
  63.     default:
  64.         if (*s < '0' || *s > '7') {
  65.             return (int)*s;
  66.         }
  67.         val = 0;
  68.         while (*s >= '0' && *s <= '7') {
  69.             val = val * 8 + (int)*s - '0';
  70.             s++;
  71.         }
  72.         return val;
  73.     }
  74. }
  75.  
  76. /*
  77.     Re-evaluate a string constant; this may shorten it
  78.  
  79.     Return its length; it may contain imbedded zeroes once processed
  80.  
  81.     CAUTION: if the string is transformed, it is always shortened.  Callers
  82.     of this routine may count on that fact.
  83. */
  84. unsigned int
  85. str_val(d)
  86. register unsigned char *d;
  87. {
  88.     register unsigned char val, *dd, *s;
  89.     TICK("str_val");
  90.  
  91.     /* outer loop to scan the string */
  92.     s = dd = d;
  93.     while (*s) {
  94.         if (*s != '\\') {
  95.             *d++ = *s++;
  96.             continue;
  97.         }
  98.         ++s;
  99.         switch (*s) {
  100.         case 'b':    *d++ = '\b'; ++s; break;
  101.         case 'f':    *d++ = '\f'; ++s; break;
  102.         case 'n':    *d++ = '\n'; ++s; break;
  103.         case 'r':    *d++ = '\r'; ++s; break;
  104.         case 't':    *d++ = '\t'; ++s; break;
  105.         case '\'':    *d++ = '\''; ++s; break;
  106.         case '\\':    *d++ = '\\'; ++s; break;
  107.  
  108.         default:
  109.             if (*s < '0' || *s > '7') {
  110.                 continue;
  111.             }
  112.             val = 0;
  113.             while (*s >= '0' && *s <= '7') {
  114.                 val = val * 8 + *s - '0';
  115.                 s++;
  116.             }
  117.             *d++ = val;
  118.         }
  119.     }
  120.     *d++ = '\0';
  121.     TRACEP("str_val", printf("returns length %d\n", (int)(d - dd)));
  122.     return (unsigned int)(d - dd);
  123. }
  124.  
  125. /*
  126.     Return the value of a string of digits in a given radix.
  127. */
  128. int
  129. conv2i(string, radix)
  130. char *string;
  131. int radix;
  132. {
  133.     register int value;
  134.     register int digit;
  135.  
  136.     TICK("conv2i");
  137.  
  138.     value = 0;
  139.     while (digit = *string++) {
  140.         if (digit >= 'a' && digit <= 'z') {
  141.             digit = digit - 'a' + 10;
  142.         }
  143.         else if (digit >= 'A' && digit <= 'Z') {
  144.             digit = digit - 'A' + 10;
  145.         }
  146.         else {
  147.             digit = digit - '0';
  148.         }
  149.         value = (value * radix) + digit;
  150.     }
  151.     return value;
  152. }
  153.  
  154. /*
  155.     Convert a signed integer n to a string s[].
  156.     The length of s must be large enough to hold the result.
  157. */
  158. void
  159. conv2s (a, s)
  160. int a;
  161. register char *s;
  162. {
  163.     register char *d, *ss;
  164.     register int sn;
  165.     register unsigned long n;
  166.     char temp [INT_DIGITS];
  167.  
  168.     TICK("conv2s");
  169.  
  170.     /* Do the sign and handle 0x8000 correctly */
  171.     if (a >= 0) {
  172.         sn = 0;
  173.         /* these casts ARE NOT redundant: DO NOT fix them! */
  174.         /* see note in lint.doc about unsigned extending casts */
  175.         n = (unsigned long) (long) a;
  176.     }
  177.     else {
  178.         sn = 1;
  179.         n = (unsigned long) (long) (-a);
  180.     }
  181.  
  182.     /* put digits in reverse order into temp */
  183.     d = &temp[0];
  184.     *d++ = 0;
  185.     if (n) while (n) {
  186.         /* NOTE: in assembly, we would divide once */
  187.         *d++ = (char)(n % 10) + '0';
  188.         n = n / 10;
  189.     }
  190.     else {
  191.         *d++ = '0';
  192.     }
  193.  
  194.     /* insert the sign */
  195.     if (sn) {
  196.         *d++ = '-';
  197.     }
  198.  
  199.     /* Reverse temp into s. */
  200.     ss = s;
  201.     while(*ss++ = *--d) {};
  202.  
  203.     TRACE("conv2s", printf("conv2s returns: %s\n", s));
  204. }
  205.  
  206. /*
  207.     Convert a long n to a string s[].
  208.     The length of s must be large enough to hold the result.
  209. */
  210. void
  211. convl2s (a, s)
  212. long a;
  213. register char *s;
  214. {
  215.     register char *d, *ss;
  216.     register int sn;
  217.     register unsigned long n;
  218.     char temp [LONG_DIGITS];
  219.  
  220.     TICK("convl2s");
  221.  
  222.     /* Do the sign and handle 0x80000000 correctly */
  223.     if (a >= 0) {
  224.         sn = 0;
  225.         n = (unsigned long) a;
  226.     }
  227.     else {
  228.         sn = 1;
  229.         n = (unsigned long) (-a);
  230.     }
  231.  
  232.     /* put digits in reverse order into temp */
  233.     d = &temp[0];
  234.     *d++ = 0;
  235.     if (n) while (n) {
  236.         /* NOTE: in assembly, we would divide once */
  237.         *d++ = (char)(n % 10) + '0';
  238.         n = n / 10;
  239.     }
  240.     else {
  241.         *d++ = '0';
  242.     }
  243.  
  244.     /* insert the sign */
  245.     if (sn) {
  246.         *d++ = '-';
  247.     }
  248.  
  249.     /* Reverse temp into s. */
  250.     ss = s;
  251.     while(*ss++ = *--d) {};
  252.  
  253.     TRACE("convl2s", printf("convl2s (%ld): %s\n", a, s));
  254. }
  255.  
  256. /*
  257.     Convert a long n to a string s[], minimum digit count c.
  258.     The length of s must be large enough to hold any result.
  259. */
  260. void
  261. conul2sc(n, s, c)
  262. register unsigned long n;
  263. register char *s;
  264. register int c;
  265. {
  266.     register char *d, *ss;
  267.     char temp [LONG_DIGITS];
  268.  
  269.     TICK("conul2sc");
  270.  
  271.     /* put digits in reverse order into temp */
  272.     d = &temp[0];
  273.     *d++ = 0;
  274.     while (n) {
  275.         /* NOTE: in assembly, we would divide once */
  276.         *d++ = (char)(n % 10) + '0';
  277.         n /= 10;
  278.         if (c > 0) {
  279.             c--;
  280.         }
  281.     }
  282.     while (c > 0) {
  283.         c--;
  284.         *d++ = '0';
  285.     }
  286.  
  287.     /* Reverse temp into s. */
  288.     ss = s;
  289.     while(*ss++ = *--d) {};
  290.  
  291.     TRACE("conul2sc", printf("conul2sc returns: %s\n", s));
  292. }
  293.  
  294. /*
  295.     Convert a long n to a hex string s[], minimum digit count c.
  296.     The length of s must be large enough to hold any result.
  297. */
  298. void
  299. conl2h(n, s, c)
  300. register unsigned long n;
  301. register char *s;
  302. register int c;
  303. {
  304.     register char *d, *ss;
  305.     char temp [LONG_DIGITS];
  306.  
  307.     TICK("conl2h");
  308.  
  309.     /* put digits in reverse order into temp */
  310.     d = &temp[0];
  311.     *d++ = 0;
  312.     while (n) {
  313.         *d = ((char)n & 15) + '0';
  314.         if (*d > '9') {
  315.             *d += 7;
  316.         }
  317.         d++;
  318.         n >>= 4;
  319.         if (c > 0) {
  320.             c--;
  321.         }
  322.     }
  323.     while (c > 0) {
  324.         c--;
  325.         *d++ = '0';
  326.     }
  327.  
  328.     /* Reverse temp into s. */
  329.     ss = s;
  330.     while(*ss++ = *--d) {};
  331.  
  332.     TRACE("conl2h", printf("conl2h returns: %s\n", s));
  333. }
  334.  
  335. /*
  336.     Skip blanks and tabs,  but not newlines.
  337. */
  338. void
  339. skip_bl()
  340. {
  341.     ENTER("skip_bl");
  342.  
  343.     while (ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f') {
  344.         sysnext();
  345.     }
  346.     
  347.     RETURN_VOID("skip_bl");
  348. }
  349.  
  350. /*
  351.     Skip characters up to but NOT including a newline.
  352. */
  353. void
  354. skip_1line()
  355. {
  356.     ENTER("skip_1line");
  357.  
  358.     while (ch != END_FILE && ch != '\n') {
  359.         sysnext();
  360.     }
  361.  
  362.     RETURN_VOID("skip_1line");
  363. }
  364.  
  365. /*
  366.     Skip characters up to and including a newline.
  367. */
  368. void
  369. skip_past()
  370. {
  371.     ENTER("skip_past");
  372.  
  373.     while (ch != END_FILE && ch != '\n') {
  374.         sysnext();
  375.     }
  376.  
  377.     if (ch == '\n') {
  378.         sysnext();
  379.         bump_line();
  380.     }
  381.  
  382.     RETURN_VOID("skip_past");
  383. }
  384.  
  385. /*
  386.     Skip to the end of the current preprocessor directive.
  387.     I.e., skip to the first newline not contained in a comment.
  388. */
  389. void
  390. skip_pp()
  391. {
  392.     ENTER("skip_pp");
  393.  
  394.     while (ch != '\n' && ch != END_FILE) {
  395.         if (ch == '/') {
  396.             /* Possible comment. */
  397.             sysnext();
  398.             if (ch == '*') {
  399.                 sysnext();
  400.                 skip_comment();
  401.             }
  402.             else if (slc_flag && ch == '/') {
  403.                 /* 8/3/89 Single-line comment */
  404.                 while (ch != END_FILE && ch != '\n') {
  405.                     sysnext();
  406.                 }
  407.                 RETURN_VOID("skip_pp");
  408.             }
  409.             else {
  410.                 syspushback(ch);
  411.                 ch = '/';
  412.                 syshflush();
  413.                 RETURN_VOID("skip_pp");
  414.             }
  415.         }
  416.         else {
  417.             sysnext();
  418.         }
  419.     }
  420.     syshflush();
  421.     RETURN_VOID("skip_pp");
  422. }
  423.  
  424. /*
  425.     Skip blanks, tabs, and comments.
  426.     Also skip newlines if nl_flag is TRUE;
  427. */
  428. void
  429. skip_ws(nl_flag)
  430. bool nl_flag;
  431. {
  432.     ENTER_TRACE("skip_ws", printf("(%s)\n", pr_bool(nl_flag)));
  433.  
  434.     for(;;) {
  435.  
  436.         switch(ch) {
  437.  
  438.         case ' ':
  439.         case '\t':
  440.         case '\f':
  441.         case '\v':
  442.             sysnext();
  443.             continue;
  444.  
  445.         case '\n':
  446.             if (nl_flag) {
  447.                 bump_line();
  448.                 sysnext();
  449.                 continue;
  450.             }
  451.             else {
  452.                 /* 2/16/89 */
  453.                 goto done;
  454.             }
  455.  
  456.         case '/':
  457.             sysnext();
  458.             if (ch == '*') {
  459.                 sysnext();
  460.                 skip_comment();
  461.                 continue;
  462.             }
  463.             else if (slc_flag && ch == '/') {
  464.                 /* 8/3/89 Single-line comment */
  465.                 while (ch != END_FILE && ch != '\n') {
  466.                     sysnext();
  467.                 }
  468.                 continue;
  469.             }
  470.             else {
  471.                 syspushback(ch);
  472.                 ch = '/';
  473.                 goto done;
  474.             }
  475.  
  476.         default:
  477.             goto done;
  478.         }
  479.     }
  480. done:
  481.     RETURN_VOID("skip_ws");
  482. }
  483.  
  484. /*
  485.     Allow a continuation of an error or warning message.
  486. */
  487. static int err_line = -1;
  488.  
  489. void
  490. err_cont()
  491. {
  492.     err_line = -1;
  493. }
  494.     
  495. /*
  496.     Process a non-fatal error messages.
  497. */
  498. void
  499. error(char *message)
  500. {
  501.     err3(message, "", "");
  502. }
  503.  
  504. void
  505. err2(char *mess1, char *mess2)
  506. {
  507.     err3(mess1, mess2, "");
  508. }
  509.  
  510. void
  511. err3(char *mess1, char *mess2, char *mess3)
  512. {
  513.     TICK("err3");
  514.     syscsts();
  515.     t_errcount++;
  516.  
  517.     /* Supress multiple messages on the line. */
  518.     if (err_line == t_line) {
  519.         return;
  520.     }
  521.     else {
  522.         err_line = t_line;
  523.     }
  524.  
  525.     if (t_inlevel == 0 && fn_name != NULL && !str_eq(fn_name, "")) {
  526.         fprintf(stderr, "%s %d (%s): %s%s%s.\n",
  527.             t_file, t_line, fn_name, mess1, mess2, mess3);
  528.     }
  529.     else {
  530.         fprintf(stderr, "%s %d: %s%s%s.\n",
  531.             t_file, t_line, mess1, mess2, mess3);
  532.     }
  533. }
  534. /*
  535.     Give an error message and exit.
  536. */
  537. void
  538. fatal(char * message)
  539. {
  540.     TICK("fatal");
  541.  
  542.     fprintf(stderr, "%s %d: %s.\n", t_file, t_line, message);
  543.     TRACE("dump", m_stat());
  544.     TRACE("dump", sl_dump());
  545.     sysabort();
  546.     
  547. }
  548.  
  549. void
  550. syserr(char *message)
  551. {
  552.     fprintf(stderr, "\nSPP internal error. Please report this problem...\n\n");
  553.     fatal(message);
  554. }
  555.  
  556. /*
  557.     Process a non-fatal warning message.
  558. */
  559. void
  560. warning(char *message)
  561. {
  562.     warn3(message, "", "");
  563. }
  564.  
  565. void
  566. warn2(char *mess1, char *mess2)
  567. {
  568.     warn3(mess1, mess2, "");
  569. }
  570.  
  571. void
  572. warn3(char *mess1, char *mess2, char *mess3)
  573. {
  574.     TICK("warn3");
  575.     syscsts();
  576.  
  577.     /* Supress multiple messages on the line. */
  578.     if (err_line == t_line) {
  579.         return;
  580.     }
  581.     else {
  582.         err_line = t_line;
  583.     }
  584.  
  585.     if (t_inlevel == 0 && fn_name != NULL && !str_eq(fn_name, "")) {
  586.         fprintf(stderr, "Warning: %s %d (%s): %s%s%s.\n",
  587.             t_file, t_line, fn_name, mess1, mess2, mess3);
  588.     }
  589.     else {
  590.         fprintf(stderr, "Warning: %s %d: %s%s%s.\n",
  591.             t_file, t_line, mess1, mess2, mess3);
  592.     }
  593. }
  594.