/* File: token.c Support utilities for the parser. */ #include #include #include #include "token.h" /* Internal function */ static int SkipSpaces(char *, int) ; /* Initialize input */ input_t *ReadInput(void) { input_t *rec ; int length ; /* make space for rec */ rec = (input_t *) malloc(sizeof(input_t)) ; if (rec == NULL) { printf("ReadInput: could not malloc!\n") ; exit(1) ; } /* Get user input */ fgets(rec->str, BUFLEN, stdin) ; /* includes '\n' */ length = strlen(rec->str) ; rec->str[length-1] = '\0' ; /* kill trailing '\n' */ /* Initialize input indices */ rec->pos = SkipSpaces(rec->str, 0) ; /* skip leading spaces */ rec->last = length - 2 ; /* Haven't looked ahead */ rec->looked = 0 ; rec->lookahead_pos = rec->pos ; rec->lookahead.kind = UNDEF ; return rec ; } /* Return index of next non-space character */ int SkipSpaces(char *str, int i) { while(isspace(str[i])) i++ ; return i ; } /* Return the next token in the input string. Just looking, do not consume the token. Assumptions: input->pos is the index of the beginning of the next token (leading spaces should have been skipped) input->last is the index of the last character of the input string ('\0' is beyond the last character). input->looked says whether we've looked ahead before. input->lookahead_pos, if we've looked ahead, points to the beginning of the token after the look ahead token input->lookahead is the lookahead token, if we've looked ahead before. */ token_t LookAhead(input_t *rec) { token_t token ; char *str ; int val, i ; /* Previously looked ahead? */ if (rec->looked) return rec->lookahead ; /* Look for the next token, mark that we looked ahead */ rec->looked = 1 ; i = rec->pos ; str = rec->str ; /* Bogus input position */ if (i < 0) { token.kind = UNDEF ; rec->lookahead = token ; rec->looked = 0 ; return token ; } /* Past end of input ? */ if (rec->pos > rec->last) { token.kind = EOL ; rec->lookahead = token ; rec->lookahead_pos = i ; return token ; } /* it's a decimal number */ if (isdigit(str[i])) { val = 0 ; do { val = 10*val + str[i] - '0' ; i++ ; } while (isdigit(str[i])) ; token.kind = NUMBER ; token.value = val ; rec->lookahead = token ; rec->lookahead_pos = SkipSpaces(str,i) ; return token ; } /* Single character cases */ switch(str[i]) { case '+' : token.kind = PLUS ; break ; case '-' : token.kind = MINUS ; break ; case '*' : token.kind = TIMES ; break ; case '/' : token.kind = DIVIDE ; break ; case '(' : token.kind = L_PAREN ; break ; case ')' : token.kind = R_PAREN ; break ; default : token.kind = UNDEF ; rec->lookahead = token ; rec->lookahead_pos = i ; return token ; } rec->lookahead = token ; rec->lookahead_pos = SkipSpaces(str, i+1) ; return token ; } /* Consume the next token. Read documentation for LookAhead(). */ void EatToken(input_t *rec) { /* Must have looked ahead previously. Update input accordingly */ if (rec->looked) { rec->pos = rec->lookahead_pos ; rec->looked = 0 ; return ; } else { printf ("EatToken: Internal error, must call LookAhead() first\n") ; exit(1) ; } } /* Print error message and point to where the syntax error occurred. */ void PrintError(input_t *rec) { int i ; printf("%s\n", rec->str) ; for (i = 0 ; i < rec->pos ; i++) { printf(" ") ; } printf("^--- syntax error\n") ; }