home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / kvik / src / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-21  |  3.8 KB  |  207 lines  |  [TEXT/MPS ]

  1. /** parse.c
  2.  ** Parser.
  3.  **
  4.  ** Written by and Copyright 1994 Asher Hoskins.
  5.  **
  6.  ** The author retains copyright on this implementation. Permission for
  7.  ** educational and non-profit use is granted to all. If you're planning to
  8.  ** make money with this or any code derived from it, check with the author
  9.  ** first.
  10.  **/
  11.  
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include "parse.h"
  15. #include "kvikmath.h"
  16.  
  17. #define MAXNUMLENGTH 20
  18. #define TOKNUM 20
  19.  
  20. static int get_number(char *, char *, int *);
  21. static int convert_num(char *);
  22. static int convert_bignum(char *);
  23.  
  24. token_val_t get_token(char line[], int *offset)
  25. {
  26.     static token_val_t ret;
  27.     char num[MAXNUMLENGTH];
  28.     int i, j, k, match, toklen;
  29.  
  30.     /* Define tokens */
  31.  
  32.     static token_def_t token_def[] = {
  33.         T_NUMBER, ",XX",
  34.         T_REGISTER, ".XX",
  35.         T_DATA_POINTER, "/XX",
  36.         T_PROGRAM_POINTER, ":XX",
  37.         T_CONSTANT, "\"XX",
  38.         T_UMINUS, "-XX",
  39.         T_LESS_THAN, "(XX",
  40.         T_GREATER_THAN, ")XX",
  41.  
  42.         T_ASSIGN, "(-X",
  43.         T_POINTS_TO, "-)X",
  44.         T_PREVIOUS, "((X",
  45.         T_NEXT, "))X",
  46.         T_MINUS, "--X",
  47.         T_MULTIPLY, ")(X",
  48.         T_EQUAL, "::X",
  49.         T_LESS_THAN_OR_EQ, "(:X",
  50.         T_GREATER_THAN_OR_EQ, "):X",
  51.  
  52.         T_PLUS, "-/-",
  53.         T_DIVIDE, "-:-",
  54.         T_NOT_EQUAL, ":/:"
  55.     };
  56.  
  57.     /* Skip whitespace */
  58.     while (line[*offset] == ' ')
  59.         (*offset)++;
  60.  
  61.     /* Premature end of line */
  62.  
  63.     if (line[*offset] == '\0') {
  64.         ret.token = T_ERROR;
  65.         ret.val.errnum = PE_TRUNC;
  66.         return(ret);
  67.     }
  68.  
  69.     /* Legal end of line */
  70.  
  71.     if (line[*offset] == '\n') {
  72.         ret.token = T_NEWLINE;
  73.         return(ret);
  74.     }
  75.  
  76.     /* Tokens that start with a digit */
  77.  
  78.     if (isdigit(line[*offset])) {
  79.         if (get_number(num, line, offset)) {
  80.             ret.token = T_ERROR;
  81.             ret.val.errnum = PE_BADNUM;
  82.             return(ret);
  83.         }
  84.  
  85.         switch (line[*offset]) {
  86.  
  87.         case '/':
  88.             (*offset)++;
  89.             if (line[*offset] == ':') {
  90.                 ret.token = T_PROG_POINTER_STORE_DEF;
  91.                 (*offset)++;
  92.             }
  93.             else
  94.                 ret.token = T_DATA_POINTER_DEF;
  95.             strncpy(ret.val.label, num, MAXLABELLENGTH);
  96.             ret.val.label[MAXLABELLENGTH-1] = '\0';
  97.             break;
  98.         case ':':
  99.             (*offset)++;
  100.             ret.token = T_PROGRAM_POINTER_DEF;
  101.             strncpy(ret.val.label, num, MAXLABELLENGTH);
  102.             ret.val.label[MAXLABELLENGTH-1] = '\0';
  103.             break;
  104.         default:
  105.             ret.token = T_BIGNUM;
  106.             ret.val.num = convert_bignum(num);
  107.         }
  108.  
  109.         return(ret);
  110.     }
  111.  
  112.     /* Channels */
  113.  
  114.     if (line[*offset] == '(' && isdigit(line[*offset+1]) &&
  115.         line[*offset+2] == ')') {
  116.         ret.token = T_CHANNEL;
  117.         ret.val.digit = line[*offset+1] - '0';
  118.         *offset += 3;
  119.         return(ret);
  120.     }
  121.  
  122.     /* Everything else, there's probably a nicer way to do this... */
  123.  
  124.     ret.token = T_ERROR;
  125.     ret.val.errnum = PE_BADTOK;
  126.  
  127.     toklen = 0;
  128.     for (i=0; i<3; i++) {
  129.         j = 0;
  130.         do {
  131.             match = 1;
  132.             for (k=0; k<=i; k++)
  133.                 match = match && (line[*offset+k] == token_def[j].format[k]);
  134.             j++;
  135.         } while (!match && j<TOKNUM);
  136.         if (match) {
  137.             ret.token = token_def[j-1].token;
  138.             toklen++;
  139.         }
  140.     }
  141.     *offset += toklen;
  142.  
  143.     switch (ret.token) {
  144.  
  145.     case T_NUMBER:
  146.         if (get_number(num, line, offset)) {
  147.             ret.token = T_ERROR;
  148.             ret.val.errnum = PE_BADNUM;
  149.         }
  150.         else
  151.             ret.val.num = convert_num(num);
  152.         break;
  153.  
  154.     case T_REGISTER: case T_DATA_POINTER: case T_PROGRAM_POINTER:
  155.     case T_CONSTANT:
  156.         if (isdigit(line[*offset]))
  157.             ret.val.digit = line[*offset] - '0';
  158.         else {
  159.             ret.token = T_ERROR;
  160.             ret.val.errnum = PE_BADDIGIT;
  161.         }
  162.         (*offset)++;
  163.     }
  164.  
  165.     return(ret);
  166. }
  167.  
  168. /** Read a number from 'line', increment 'offset'. Return it as a string
  169.  ** in 'num'.
  170.  **/
  171.  
  172. static int get_number(char num[], char line[], int *offset)
  173. {
  174.     int i=0;
  175.  
  176.     while (i<MAXNUMLENGTH-1 && isdigit(line[*offset])) {
  177.         num[i] = line[*offset];
  178.         (*offset)++;
  179.         i++;
  180.     }
  181.  
  182.     num[i] = '\0';
  183.  
  184.     return(isdigit(line[*offset]));
  185. }
  186.  
  187. /** Convert a number from a string into kvik's internal format.
  188.  **/
  189.  
  190. static int convert_num(char *num)
  191. {
  192.     return(str2kvik(num));
  193. }
  194.  
  195. /** Convert an integer in a string into an integer.
  196.  **/
  197.  
  198. static int convert_bignum(char *num)
  199. {
  200.     int n;
  201.  
  202.     num[4] = '\0';
  203.     sscanf(num, "%d", &n);
  204.     return(n);
  205. }
  206.  
  207.