home *** CD-ROM | disk | FTP | other *** search
- /** parse.c
- ** Parser.
- **
- ** Written by and Copyright 1994 Asher Hoskins.
- **
- ** The author retains copyright on this implementation. Permission for
- ** educational and non-profit use is granted to all. If you're planning to
- ** make money with this or any code derived from it, check with the author
- ** first.
- **/
-
- #include <stdio.h>
- #include <ctype.h>
- #include "parse.h"
- #include "kvikmath.h"
-
- #define MAXNUMLENGTH 20
- #define TOKNUM 20
-
- static int get_number(char *, char *, int *);
- static int convert_num(char *);
- static int convert_bignum(char *);
-
- token_val_t get_token(char line[], int *offset)
- {
- static token_val_t ret;
- char num[MAXNUMLENGTH];
- int i, j, k, match, toklen;
-
- /* Define tokens */
-
- static token_def_t token_def[] = {
- T_NUMBER, ",XX",
- T_REGISTER, ".XX",
- T_DATA_POINTER, "/XX",
- T_PROGRAM_POINTER, ":XX",
- T_CONSTANT, "\"XX",
- T_UMINUS, "-XX",
- T_LESS_THAN, "(XX",
- T_GREATER_THAN, ")XX",
-
- T_ASSIGN, "(-X",
- T_POINTS_TO, "-)X",
- T_PREVIOUS, "((X",
- T_NEXT, "))X",
- T_MINUS, "--X",
- T_MULTIPLY, ")(X",
- T_EQUAL, "::X",
- T_LESS_THAN_OR_EQ, "(:X",
- T_GREATER_THAN_OR_EQ, "):X",
-
- T_PLUS, "-/-",
- T_DIVIDE, "-:-",
- T_NOT_EQUAL, ":/:"
- };
-
- /* Skip whitespace */
- while (line[*offset] == ' ')
- (*offset)++;
-
- /* Premature end of line */
-
- if (line[*offset] == '\0') {
- ret.token = T_ERROR;
- ret.val.errnum = PE_TRUNC;
- return(ret);
- }
-
- /* Legal end of line */
-
- if (line[*offset] == '\n') {
- ret.token = T_NEWLINE;
- return(ret);
- }
-
- /* Tokens that start with a digit */
-
- if (isdigit(line[*offset])) {
- if (get_number(num, line, offset)) {
- ret.token = T_ERROR;
- ret.val.errnum = PE_BADNUM;
- return(ret);
- }
-
- switch (line[*offset]) {
-
- case '/':
- (*offset)++;
- if (line[*offset] == ':') {
- ret.token = T_PROG_POINTER_STORE_DEF;
- (*offset)++;
- }
- else
- ret.token = T_DATA_POINTER_DEF;
- strncpy(ret.val.label, num, MAXLABELLENGTH);
- ret.val.label[MAXLABELLENGTH-1] = '\0';
- break;
- case ':':
- (*offset)++;
- ret.token = T_PROGRAM_POINTER_DEF;
- strncpy(ret.val.label, num, MAXLABELLENGTH);
- ret.val.label[MAXLABELLENGTH-1] = '\0';
- break;
- default:
- ret.token = T_BIGNUM;
- ret.val.num = convert_bignum(num);
- }
-
- return(ret);
- }
-
- /* Channels */
-
- if (line[*offset] == '(' && isdigit(line[*offset+1]) &&
- line[*offset+2] == ')') {
- ret.token = T_CHANNEL;
- ret.val.digit = line[*offset+1] - '0';
- *offset += 3;
- return(ret);
- }
-
- /* Everything else, there's probably a nicer way to do this... */
-
- ret.token = T_ERROR;
- ret.val.errnum = PE_BADTOK;
-
- toklen = 0;
- for (i=0; i<3; i++) {
- j = 0;
- do {
- match = 1;
- for (k=0; k<=i; k++)
- match = match && (line[*offset+k] == token_def[j].format[k]);
- j++;
- } while (!match && j<TOKNUM);
- if (match) {
- ret.token = token_def[j-1].token;
- toklen++;
- }
- }
- *offset += toklen;
-
- switch (ret.token) {
-
- case T_NUMBER:
- if (get_number(num, line, offset)) {
- ret.token = T_ERROR;
- ret.val.errnum = PE_BADNUM;
- }
- else
- ret.val.num = convert_num(num);
- break;
-
- case T_REGISTER: case T_DATA_POINTER: case T_PROGRAM_POINTER:
- case T_CONSTANT:
- if (isdigit(line[*offset]))
- ret.val.digit = line[*offset] - '0';
- else {
- ret.token = T_ERROR;
- ret.val.errnum = PE_BADDIGIT;
- }
- (*offset)++;
- }
-
- return(ret);
- }
-
- /** Read a number from 'line', increment 'offset'. Return it as a string
- ** in 'num'.
- **/
-
- static int get_number(char num[], char line[], int *offset)
- {
- int i=0;
-
- while (i<MAXNUMLENGTH-1 && isdigit(line[*offset])) {
- num[i] = line[*offset];
- (*offset)++;
- i++;
- }
-
- num[i] = '\0';
-
- return(isdigit(line[*offset]));
- }
-
- /** Convert a number from a string into kvik's internal format.
- **/
-
- static int convert_num(char *num)
- {
- return(str2kvik(num));
- }
-
- /** Convert an integer in a string into an integer.
- **/
-
- static int convert_bignum(char *num)
- {
- int n;
-
- num[4] = '\0';
- sscanf(num, "%d", &n);
- return(n);
- }
-
-