home *** CD-ROM | disk | FTP | other *** search
/ Graphics 16,000 / graphics-16000.iso / msdos / animutil / pvquan / animdat / scanner.c < prev    next >
C/C++ Source or Header  |  1992-11-30  |  10KB  |  388 lines

  1. /*--------------------------------------------------------------*/
  2. /*            ANIMDAT 1.1                */
  3. /*        copyright 1992 - TODD SANKEY            */
  4. /*                                */
  5. /*  The author hereby grants permission for the use and sharing    */
  6. /* of both source code end executable versions of this software    */
  7. /* at no charge. This software is not for sale and no other    */
  8. /* shall charge for it without the expressed consent of the    */
  9. /* author.                            */
  10. /*                                */
  11. /*  The source code can be freely modified, but it must retain    */
  12. /* the original copyright notice, and the author must be    */
  13. /* notified of these changes if the altered code is to be    */
  14. /* distributed.                            */
  15. /*--------------------------------------------------------------*/
  16. /*------------------------------------------------------*/
  17. /* scanner.c    Scans and tokenizes a source buffer.    */
  18. /*------------------------------------------------------*/
  19.  
  20. #define scanner_c
  21.  
  22. #include <ctype.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include "common.h"
  26.  
  27. #define MAX_LINE_LENGTH    256
  28. #define EOB_CHAR    0
  29. #define SPECIAL        1
  30. #define LETTER        2
  31. #define    DIGIT        3
  32.  
  33. /* globals */
  34. TOKEN_CODE    token;
  35. char        word_string[MAX_LINE_LENGTH];
  36. double        literal_value;
  37. char *token_names[]={"No token","Identifier","Number","String","^","*",
  38.             "(",")","-","+","=","<",">","<=",">=","<>","/",",",
  39.             "OR","AND","SIN","COS","TAN","EXP","LOG","RND","ATAN",
  40.             "ASIN","ACOS","#","quote",
  41.             "ERROR","NUMSCENE","%","END OF BUFFER"};
  42.  
  43. /* variable used inside scanner module */
  44. static int    ch;        /* current input character from source buffer */
  45. static char    *buffer_offset;    /* offset into source buffer */
  46. static char    *bufferp;    /* start of source buffer */
  47. static char    token_string[MAX_LINE_LENGTH];
  48. static char    *tokenp = token_string;
  49. static int    digit_count;
  50. static char    char_table[256];
  51.  
  52. static char    rw_2[]={'o','r',OR,0};
  53. static char    rw_3[]={'a','n','d',AND,
  54.             's','i','n',SIN,
  55.             'c','o','s',COS,
  56.             't','a','n',TAN,
  57.             'e','x','p',EXP,
  58.             'l','o','g',LOG,
  59.             'r','n','d',RND,0};
  60. static char    rw_4[]={'a','t','a','n',ATAN,
  61.             'a','s','i','n',ASIN,
  62.             'a','c','o','s',ACOS,0};
  63. static char    rw_10[]={'n','u','m','_','s','c','e','n','e','s',NUMSCENE,0};
  64.  
  65. static char    *rsvd_word_table[] = { NULL, NULL, rw_2, rw_3, rw_4,NULL,NULL,NULL,NULL,NULL, rw_10 };
  66. #define MAX_RESERVED_WORD_LENGTH 10
  67. #define MIN_RESERVED_WORD_LENGTH 2
  68.  
  69.  
  70. /* Local procedures */
  71. void get_char(void);
  72. void skip_comment(void);
  73. void skip_blanks(void);
  74. void get_word(void);
  75. void get_number(void);
  76. void get_special(void);
  77. void get_quote(void);
  78. void downshift_word(void);
  79. int  is_reserved_word(void);
  80.  
  81.  
  82. #define char_code(ch) char_table[ch]
  83.  
  84.  
  85.     /********************************/
  86.     /*                */
  87.     /* Initialization routines    */
  88.     /*                */
  89.     /********************************/
  90.  
  91.  
  92. /*----------------------------------------------------------------------*/
  93. /* init_scanner        Initialize the scanner globals and start the    */
  94. /*            scanner at the specified point.            */
  95. /*----------------------------------------------------------------------*/
  96.  
  97. void init_scanner(char *source_buffer)
  98. {
  99.  ch = 0;
  100.  token = NO_TOKEN;
  101.  word_string[0] = 0;
  102.  literal_value = 0.0;
  103.  token_string[0] = 0;
  104.  tokenp = token_string;
  105.  digit_count = 0;
  106.  bufferp = source_buffer;
  107.  buffer_offset = bufferp;
  108.  
  109.  for (ch = 0; ch<256; ch++) char_table[ch] = SPECIAL;
  110.  for (ch = '0'; ch <='9'; ch++) char_table[ch] = DIGIT;
  111.  for (ch = 'a'; ch <='z'; ch++) char_table[ch] = LETTER;
  112.  for (ch = 'A'; ch <='Z'; ch++) char_table[ch] = LETTER;
  113.  char_table[0] = EOB_CHAR;
  114.  
  115.  get_char();    /* Get first character of source buffer */
  116.  get_token();    /* initialize to first token in buffer */
  117. }
  118.  
  119.  
  120.  
  121.     /********************************/
  122.     /*                */
  123.     /*    Character routines    */
  124.     /*                */
  125.     /********************************/
  126.  
  127. /*----------------------------------------------------------------------*/
  128. /* get_char        Set ch to the next character from the source    */
  129. /*            buffer.                        */
  130. /*----------------------------------------------------------------------*/
  131.  
  132. void get_char(void)
  133. {
  134.  ch = *buffer_offset++;
  135.  switch (ch) {
  136.     case '\0' :
  137.         buffer_offset--;
  138.         break;
  139.     case '\t' :            /* Make tab and new-line characters */
  140.     case '\n' :            /* appear as spaces. */
  141.         ch = ' ';
  142.         break;
  143.  
  144.     case '{' :            /* Ignore comment and make it appear */
  145.         skip_comment();        /* as a space. */
  146.         ch = ' ';
  147.         break;
  148.     }
  149. }
  150.  
  151.  
  152. /*----------------------------------------------------------------------*/
  153. /* skip_comment        Skip over a comment. Set ch to '}'        */
  154. /*----------------------------------------------------------------------*/
  155.  
  156. void skip_comment()
  157. {
  158.  do {
  159.     get_char();
  160.     } while ( (ch != '}') && (ch != EOB_CHAR) );
  161. }
  162.  
  163.  
  164. /*----------------------------------------------------------------------*/
  165. /* skip_blanks        Skip over white space                */
  166. /*----------------------------------------------------------------------*/
  167.  
  168. void skip_blanks()
  169. {
  170.  while (ch == ' ') get_char();
  171. }
  172.  
  173.  
  174.  
  175.     /********************************/
  176.     /*                */
  177.     /*    Token routines        */
  178.     /*                */
  179.     /********************************/
  180. /* Note: after a token has been extracted, ch is the first character after
  181.    the token. */
  182.  
  183. /*----------------------------------------------------------------------*/
  184. /* get_token        Extract the next token from the source buffer.    */
  185. /*----------------------------------------------------------------------*/
  186.  
  187. void get_token()
  188. {
  189.  skip_blanks();
  190.  tokenp = token_string;
  191.  
  192.  switch (char_code(ch)) {
  193.     case LETTER:    get_word();        break;
  194.     case DIGIT:    get_number();        break;
  195.     case EOB_CHAR:    token = END_OF_FILE;    break;
  196.     default:    get_special();        break;
  197.     }
  198. }
  199.  
  200.  
  201. /*----------------------------------------------------------------------*/
  202. /* get_word        Extract a word token and downshift its        */
  203. /*            characters. Check if its a reserved word. Set    */
  204. /*            token to IDENTIFIER if it's not.        */
  205. /*----------------------------------------------------------------------*/
  206.  
  207. void get_word()
  208. {
  209.  while ( (char_code(ch) == LETTER) || (char_code(ch) == DIGIT)
  210.         || (ch == '_') || (ch == '.') ) {
  211.     *tokenp++ = ch;
  212.     get_char();
  213.     }
  214.  *tokenp = '\0';
  215.  downshift_word();
  216.  if (!is_reserved_word() )
  217.     token = IDENTIFIER;
  218. }
  219.  
  220.  
  221. /*----------------------------------------------------------------------*/
  222. /* get_number        Extract a number token and set literal_value to    */
  223. /*            its value. Set token to NUMBER.            */
  224. /*----------------------------------------------------------------------*/
  225.  
  226. void get_number()
  227. {
  228.  double    real_part = 0.0, temp_real, tenths;
  229.  long    whole_part = 0;
  230.  
  231.  /* Accumulate whole number part */
  232.  while ( char_code(ch) == DIGIT) {
  233.     whole_part = (10*whole_part) + (ch - '0');
  234.     *tokenp++ = ch;
  235.     get_char();
  236.     }
  237.  
  238.  if (ch == '.') {
  239.     tenths = 10.0;
  240.     *tokenp++ = ch;
  241.     get_char();
  242.     while ( char_code(ch) == DIGIT) {
  243.         temp_real = (double)(ch - '0');
  244.         temp_real /= tenths;
  245.         real_part+= temp_real;
  246.         tenths *= 10.0;
  247.         *tokenp++ = ch;
  248.         get_char();
  249.         }
  250.     }
  251.  
  252.  *tokenp = '\0';
  253.  real_part += (double)whole_part;
  254.  token = NUMBER;
  255.  literal_value = real_part;
  256. }
  257.  
  258.  
  259.  
  260. /*----------------------------------------------------------------------*/
  261. /* get_quote        Extract the literal contents between two    */
  262. /*            quotation marks.                */
  263. /*----------------------------------------------------------------------*/
  264.  
  265. void get_quote(void)
  266. {
  267.  int count;
  268.  
  269.  ch = *buffer_offset++;
  270.  for (count=0 ; (count < MAX_LINE_LENGTH) && (ch != '"'); count++) {
  271.     word_string[count] = ch;
  272.     ch = *buffer_offset++;
  273.     }
  274.  if (count >= MAX_LINE_LENGTH)
  275.     error(LINE_TOO_LONG,cur_line);
  276.  
  277.  word_string[count] = '\0';
  278.  get_char();
  279. }
  280.  
  281.  
  282. /*----------------------------------------------------------------------*/
  283. /* get_special        Extract a special token. Some are single    */
  284. /*            character and some are double. Set token    */
  285. /*            appropriately.                    */
  286. /*----------------------------------------------------------------------*/
  287.  
  288. void get_special()
  289. {
  290.  *tokenp++ = ch;
  291.  switch (ch) {
  292.     case '^':    token = CARET;        get_char();    break;
  293.     case '*':    token = STAR;        get_char();    break;
  294.     case '(':    token = LPAREN;        get_char();    break;
  295.     case ')':    token = RPAREN;        get_char();    break;
  296.     case '-':    token = MINUS;        get_char();    break;
  297.     case '+':    token = PLUS;        get_char();    break;
  298.     case '/':    token = SLASH;        get_char();    break;
  299.     case '=':    token = EQUAL;        get_char();    break;
  300.     case ',':    token = COMMA;        get_char();    break;
  301.     case '#':    token = POUND;        get_char();    break;
  302.     case '"':    token = QUOTE;        get_quote();    break;
  303.     case '%':    token = PERCENT;    get_char();    break;
  304.     case '<':    get_char();
  305.             if (ch == '=') {    /* <= */
  306.                 *tokenp++ = ch;
  307.                 token = LE;
  308.                 get_char();
  309.                 }
  310.             else if (ch == '>') {    /* <> */
  311.                 *tokenp++ = ch;
  312.                 token = NE;
  313.                 get_char();
  314.                 }
  315.             else
  316.                 token = LT;
  317.             break;
  318.  
  319.     case '>':    get_char();
  320.             if (ch == '=') {    /* >= */
  321.                 *tokenp++ = ch;
  322.                 token = GE;
  323.                 get_char();
  324.                 }
  325.             else
  326.                 token = GT;
  327.             break;
  328.  
  329.     case '!':    get_char();
  330.             if (ch == '=') {
  331.                 *tokenp++ = ch;
  332.                 token = NE;
  333.                 get_char();
  334.                 }
  335.             else
  336.                 token = ERROR;
  337.             break;
  338.  
  339.     default:    token = ERROR;
  340.             get_char();
  341.             break;
  342.     }
  343.  *tokenp = '\0';
  344. }
  345.  
  346.  
  347. /*----------------------------------------------------------------------*/
  348. /* downshift_word    Copy a word token into word_string with all    */
  349. /*            characters converted to lower case.        */
  350. /*----------------------------------------------------------------------*/
  351.  
  352. void downshift_word()
  353. {
  354.  char    *wp = word_string;
  355.  char    *tp = token_string;
  356.  
  357.  do {
  358.     *wp++ = (*tp++);
  359.     } while ( (*tp) != '\0' );
  360.  *wp = '\0';
  361. }
  362.  
  363.  
  364. /*----------------------------------------------------------------------*/
  365. /* is_reserved_word    Checks if a word token is a reserved word. If    */
  366. /*            so, set token appropriately and return 1.    */
  367. /*            Otherwise return 0.                */
  368. /*----------------------------------------------------------------------*/
  369.  
  370. int is_reserved_word()
  371. {
  372.  int word_length;
  373.  char *rwp;
  374.  
  375.  word_length = strlen(word_string);
  376.  if (word_length >= MIN_RESERVED_WORD_LENGTH && word_length <= MAX_RESERVED_WORD_LENGTH) {
  377.     for (rwp = rsvd_word_table[word_length];
  378.         (rwp != NULL) && (*rwp != '\0') ;
  379.         rwp += (word_length+1) ) {
  380.         if (!strncmp(word_string,rwp,word_length) ) {
  381.             token=(TOKEN_CODE)( *(rwp+word_length));
  382.             return (1);
  383.             }
  384.         }
  385.     }
  386.  return (0);
  387. }
  388.