home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics 16,000
/
graphics-16000.iso
/
msdos
/
animutil
/
pvquan
/
animdat
/
scanner.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-30
|
10KB
|
388 lines
/*--------------------------------------------------------------*/
/* ANIMDAT 1.1 */
/* copyright 1992 - TODD SANKEY */
/* */
/* The author hereby grants permission for the use and sharing */
/* of both source code end executable versions of this software */
/* at no charge. This software is not for sale and no other */
/* shall charge for it without the expressed consent of the */
/* author. */
/* */
/* The source code can be freely modified, but it must retain */
/* the original copyright notice, and the author must be */
/* notified of these changes if the altered code is to be */
/* distributed. */
/*--------------------------------------------------------------*/
/*------------------------------------------------------*/
/* scanner.c Scans and tokenizes a source buffer. */
/*------------------------------------------------------*/
#define scanner_c
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "common.h"
#define MAX_LINE_LENGTH 256
#define EOB_CHAR 0
#define SPECIAL 1
#define LETTER 2
#define DIGIT 3
/* globals */
TOKEN_CODE token;
char word_string[MAX_LINE_LENGTH];
double literal_value;
char *token_names[]={"No token","Identifier","Number","String","^","*",
"(",")","-","+","=","<",">","<=",">=","<>","/",",",
"OR","AND","SIN","COS","TAN","EXP","LOG","RND","ATAN",
"ASIN","ACOS","#","quote",
"ERROR","NUMSCENE","%","END OF BUFFER"};
/* variable used inside scanner module */
static int ch; /* current input character from source buffer */
static char *buffer_offset; /* offset into source buffer */
static char *bufferp; /* start of source buffer */
static char token_string[MAX_LINE_LENGTH];
static char *tokenp = token_string;
static int digit_count;
static char char_table[256];
static char rw_2[]={'o','r',OR,0};
static char rw_3[]={'a','n','d',AND,
's','i','n',SIN,
'c','o','s',COS,
't','a','n',TAN,
'e','x','p',EXP,
'l','o','g',LOG,
'r','n','d',RND,0};
static char rw_4[]={'a','t','a','n',ATAN,
'a','s','i','n',ASIN,
'a','c','o','s',ACOS,0};
static char rw_10[]={'n','u','m','_','s','c','e','n','e','s',NUMSCENE,0};
static char *rsvd_word_table[] = { NULL, NULL, rw_2, rw_3, rw_4,NULL,NULL,NULL,NULL,NULL, rw_10 };
#define MAX_RESERVED_WORD_LENGTH 10
#define MIN_RESERVED_WORD_LENGTH 2
/* Local procedures */
void get_char(void);
void skip_comment(void);
void skip_blanks(void);
void get_word(void);
void get_number(void);
void get_special(void);
void get_quote(void);
void downshift_word(void);
int is_reserved_word(void);
#define char_code(ch) char_table[ch]
/********************************/
/* */
/* Initialization routines */
/* */
/********************************/
/*----------------------------------------------------------------------*/
/* init_scanner Initialize the scanner globals and start the */
/* scanner at the specified point. */
/*----------------------------------------------------------------------*/
void init_scanner(char *source_buffer)
{
ch = 0;
token = NO_TOKEN;
word_string[0] = 0;
literal_value = 0.0;
token_string[0] = 0;
tokenp = token_string;
digit_count = 0;
bufferp = source_buffer;
buffer_offset = bufferp;
for (ch = 0; ch<256; ch++) char_table[ch] = SPECIAL;
for (ch = '0'; ch <='9'; ch++) char_table[ch] = DIGIT;
for (ch = 'a'; ch <='z'; ch++) char_table[ch] = LETTER;
for (ch = 'A'; ch <='Z'; ch++) char_table[ch] = LETTER;
char_table[0] = EOB_CHAR;
get_char(); /* Get first character of source buffer */
get_token(); /* initialize to first token in buffer */
}
/********************************/
/* */
/* Character routines */
/* */
/********************************/
/*----------------------------------------------------------------------*/
/* get_char Set ch to the next character from the source */
/* buffer. */
/*----------------------------------------------------------------------*/
void get_char(void)
{
ch = *buffer_offset++;
switch (ch) {
case '\0' :
buffer_offset--;
break;
case '\t' : /* Make tab and new-line characters */
case '\n' : /* appear as spaces. */
ch = ' ';
break;
case '{' : /* Ignore comment and make it appear */
skip_comment(); /* as a space. */
ch = ' ';
break;
}
}
/*----------------------------------------------------------------------*/
/* skip_comment Skip over a comment. Set ch to '}' */
/*----------------------------------------------------------------------*/
void skip_comment()
{
do {
get_char();
} while ( (ch != '}') && (ch != EOB_CHAR) );
}
/*----------------------------------------------------------------------*/
/* skip_blanks Skip over white space */
/*----------------------------------------------------------------------*/
void skip_blanks()
{
while (ch == ' ') get_char();
}
/********************************/
/* */
/* Token routines */
/* */
/********************************/
/* Note: after a token has been extracted, ch is the first character after
the token. */
/*----------------------------------------------------------------------*/
/* get_token Extract the next token from the source buffer. */
/*----------------------------------------------------------------------*/
void get_token()
{
skip_blanks();
tokenp = token_string;
switch (char_code(ch)) {
case LETTER: get_word(); break;
case DIGIT: get_number(); break;
case EOB_CHAR: token = END_OF_FILE; break;
default: get_special(); break;
}
}
/*----------------------------------------------------------------------*/
/* get_word Extract a word token and downshift its */
/* characters. Check if its a reserved word. Set */
/* token to IDENTIFIER if it's not. */
/*----------------------------------------------------------------------*/
void get_word()
{
while ( (char_code(ch) == LETTER) || (char_code(ch) == DIGIT)
|| (ch == '_') || (ch == '.') ) {
*tokenp++ = ch;
get_char();
}
*tokenp = '\0';
downshift_word();
if (!is_reserved_word() )
token = IDENTIFIER;
}
/*----------------------------------------------------------------------*/
/* get_number Extract a number token and set literal_value to */
/* its value. Set token to NUMBER. */
/*----------------------------------------------------------------------*/
void get_number()
{
double real_part = 0.0, temp_real, tenths;
long whole_part = 0;
/* Accumulate whole number part */
while ( char_code(ch) == DIGIT) {
whole_part = (10*whole_part) + (ch - '0');
*tokenp++ = ch;
get_char();
}
if (ch == '.') {
tenths = 10.0;
*tokenp++ = ch;
get_char();
while ( char_code(ch) == DIGIT) {
temp_real = (double)(ch - '0');
temp_real /= tenths;
real_part+= temp_real;
tenths *= 10.0;
*tokenp++ = ch;
get_char();
}
}
*tokenp = '\0';
real_part += (double)whole_part;
token = NUMBER;
literal_value = real_part;
}
/*----------------------------------------------------------------------*/
/* get_quote Extract the literal contents between two */
/* quotation marks. */
/*----------------------------------------------------------------------*/
void get_quote(void)
{
int count;
ch = *buffer_offset++;
for (count=0 ; (count < MAX_LINE_LENGTH) && (ch != '"'); count++) {
word_string[count] = ch;
ch = *buffer_offset++;
}
if (count >= MAX_LINE_LENGTH)
error(LINE_TOO_LONG,cur_line);
word_string[count] = '\0';
get_char();
}
/*----------------------------------------------------------------------*/
/* get_special Extract a special token. Some are single */
/* character and some are double. Set token */
/* appropriately. */
/*----------------------------------------------------------------------*/
void get_special()
{
*tokenp++ = ch;
switch (ch) {
case '^': token = CARET; get_char(); break;
case '*': token = STAR; get_char(); break;
case '(': token = LPAREN; get_char(); break;
case ')': token = RPAREN; get_char(); break;
case '-': token = MINUS; get_char(); break;
case '+': token = PLUS; get_char(); break;
case '/': token = SLASH; get_char(); break;
case '=': token = EQUAL; get_char(); break;
case ',': token = COMMA; get_char(); break;
case '#': token = POUND; get_char(); break;
case '"': token = QUOTE; get_quote(); break;
case '%': token = PERCENT; get_char(); break;
case '<': get_char();
if (ch == '=') { /* <= */
*tokenp++ = ch;
token = LE;
get_char();
}
else if (ch == '>') { /* <> */
*tokenp++ = ch;
token = NE;
get_char();
}
else
token = LT;
break;
case '>': get_char();
if (ch == '=') { /* >= */
*tokenp++ = ch;
token = GE;
get_char();
}
else
token = GT;
break;
case '!': get_char();
if (ch == '=') {
*tokenp++ = ch;
token = NE;
get_char();
}
else
token = ERROR;
break;
default: token = ERROR;
get_char();
break;
}
*tokenp = '\0';
}
/*----------------------------------------------------------------------*/
/* downshift_word Copy a word token into word_string with all */
/* characters converted to lower case. */
/*----------------------------------------------------------------------*/
void downshift_word()
{
char *wp = word_string;
char *tp = token_string;
do {
*wp++ = (*tp++);
} while ( (*tp) != '\0' );
*wp = '\0';
}
/*----------------------------------------------------------------------*/
/* is_reserved_word Checks if a word token is a reserved word. If */
/* so, set token appropriately and return 1. */
/* Otherwise return 0. */
/*----------------------------------------------------------------------*/
int is_reserved_word()
{
int word_length;
char *rwp;
word_length = strlen(word_string);
if (word_length >= MIN_RESERVED_WORD_LENGTH && word_length <= MAX_RESERVED_WORD_LENGTH) {
for (rwp = rsvd_word_table[word_length];
(rwp != NULL) && (*rwp != '\0') ;
rwp += (word_length+1) ) {
if (!strncmp(word_string,rwp,word_length) ) {
token=(TOKEN_CODE)( *(rwp+word_length));
return (1);
}
}
}
return (0);
}