home *** CD-ROM | disk | FTP | other *** search
- /*
- * token.c -- tokenizer to go with YACC/Bison pov scanner
- *
- * (c) 1993, 1994 by Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
-
- #include "ray.h"
- #include "extern.h"
- #include "proto.h"
- #include "parse.h"
-
-
- #if defined MSDOS || defined __MSDOS__ || defined msdos || defined __msdos__
- #include "rayparse.h"
- #else
- #include "rayparse.tab.h"
- #endif
-
-
- #define INDICATORCOUNT 25
-
- /***************************************************************************
- * PROTOS *
- ***************************************************************************/
-
- PRIVATE int inputlines;
- PUBLIC struct declare_tab *the_dectab;
-
- /* file stack, for INCLUDES */
- struct file_stack_entry {
- FILE *fp;
- int lineno;
- struct file_stack_entry *prev;
- };
-
-
- PRIVATE struct file_stack_entry *current_file; /* info of the file we're
- * reading */
- PRIVATE FILE *infile; /* the filepointer. */
- PRIVATE int maxkey; /* number of keywords + 1 */
-
- struct keyword_ent { /* for the keyword table */
- char *name;
- int tokcode;
- };
-
- PRIVATE struct keyword_ent keyword_tab[] =
- {
- "algebraic", ALGEBRAIC_T,
- "alpha", ALPHA,
- "ambient", AMBIENT,
- "antialias", ANTIALIAS,
- "aspect", ASPECT,
- "atmosphere", ATMOSPHERE,
- "attenuation", ATTENUATION,
- "background", BACKGROUND,
- "blue", BLUE,
- "bounded_by", BOUNDED_BY,
- "box", BOX_T,
- "brilliance", BRILLIANCE,
- "camera", CAMERA_T,
- "clipped_by", CLIPPED_BY,
- "closed", CLOSEDCURVE,
- "color", COLOR,
- "colour", COLOR, /* just to be pov compatible */
- "composite", COMPOSITE_T,
- "cutoff", CUTOFF,
- "cylinder", CYLINDER_T,
- "declare", DECLARE,
- "default", DEFAULTTEXT,
- "depth", DEPTH,
- "diffuse", DIFFUSE,
- "direction", DIRECTION,
- "disc", DISC_T,
- "extrusion", EXTRUSION_T,
- "fov", FOV,
- "gif", GIF,
- "green", GREEN,
- "image_map", IMAGE_MAP,
- "include", INCLUDE,
- "interpolate", INTERPOLATE,
- "intersection", INTERSECTION,
- "inverse", INVERSE,
- "ior", IOR,
- "iterations", ITERATIONS,
- "light_source", LIGHT_SOURCE_T,
- "location", LOCATION,
- "look_at", LOOK_AT,
- "map_type", MAPTYPE,
- "object", OBJECT,
- "once", ONCE,
- "open", OPEN,
- "options", OPTIONS,
- "plane", PLANE_T,
- "point_at", POINT_AT,
- "polygon", POLYGON_T,
- "quadric", QUADRIC_T,
- "radius", RADIUS,
- "red", RED,
- "reflect_angle", REFLECT_ANGLE,
- "reflection", REFLECTION,
- "refract_angle", REFRACT_ANGLE,
- "refraction", REFRACTION,
- "rgb", RGB,
- "rotate", ROTATE,
- "roughness", ROUGHNESS,
- "scale", SCALE,
- "sky", SKY,
- "smooth_triangle", SMOOTH_TRIANGLE_T,
- "specular", SPECULAR,
- "speed", SPEED,
- "sphere", SPHERE_T,
- "spotlight", SPOTLIGHT,
- "sturm", STURM,
- "superq", SUPERQ_T,
- "texture", TEXTURE,
- "tga", TARGA,
- "tightness", TIGHTNESS,
- "time", TIME,
- "tolerance", TOLERANCE,
- "torus", TORUS_T,
- "translate", TRANSLATE,
- "triangle", TRIANGLE_T,
- "union", UNION,
- "uvoffset", UVOFFSET,
- "uvrange", UVRANGE,
- "uvswap", UVSWAP,
- "x", X_T,
- "y", Y_T,
- "z", Z_T,
- NULL, 0
- };
-
-
- /*
- * PROTOS
- */
- PRIVATE void free_declare_tab(void);
- PRIVATE void new_file(char *fn);
- PRIVATE void get_quotedstring(char *s);
- PRIVATE void get_word(char *cp);
- PRIVATE void eat_junk(void);
- PRIVATE void pushc(int c);
- PRIVATE int popc(void);
- PRIVATE void eat_comment(void);
- PRIVATE void eat_linecomment(void);
-
- /***************************************************************************
- * PUBLICS *
- ***************************************************************************/
-
-
- /* prints an error message with linenumber to stdout and then dies */
- PUBLIC void
- errormsg(char *format,...)
- {
- char s1[100],
- s2[100];
- va_list arglist;
-
- if (infile != NULL) /* line number appropriate? */
- sprintf(s1, "\nerror (line %d): ", inputlines);
- else
- sprintf(s1, "\nerror: ");
-
- va_start(arglist, format);
- vsprintf(s2, format, arglist);
- va_end(arglist);
-
- fprintf(error_out, "%s%s\n", s1, s2);
-
- exit(1);
- }
-
- /* prints a warning with linenumber to stdout */
- PUBLIC void
- warning(char *format,...)
- {
- char s1[100],
- s2[100];
- va_list arglist;
-
- if (infile != NULL)
- sprintf(s1, "\nwarning (line %d): ", inputlines);
- else
- sprintf(s1, "\nwarning: ");
-
- va_start(arglist, format);
- vsprintf(s2, format, arglist);
- va_end(arglist);
-
- fprintf(error_out, "%s%s\n", s1, s2);
- }
-
-
- /* initialize this module */
- PUBLIC void
- set_input(char *fname)
- {
- current_file = NULL;
- infile = NULL;
- for (maxkey = 0; keyword_tab[maxkey].name; maxkey++);
-
- new_file(fname);
- }
-
- /* and leave it behind. */
- PUBLIC void
- close_input(void)
- {
- free_declare_tab();
- }
-
- /***************************************************************************
- * PRIVATES *
- ***************************************************************************/
-
- /*
- * read the #include "xxx" part
- */
- PRIVATE void
- handle_include(void)
- {
- char fn[100];
-
- get_quotedstring(fn);
-
- new_file(fn);
- }
-
- /* push stuff to filestack */
- PRIVATE void
- new_file(char *fn)
- {
- struct file_stack_entry *prev;
-
- infile = fopen(fn, "rt");
- if (infile == NULL)
- errormsg("can't open %s\n", fn);
-
- if (current_file != NULL)
- current_file->lineno = inputlines;
-
- prev = current_file;
-
- current_file = ALLOC(struct file_stack_entry);
-
- CHECK_MEM(current_file, "file info");
-
- current_file->prev = prev;
- current_file->fp = infile;
- inputlines = current_file->lineno = 1;
- printf("[%s ", fn);
- }
-
- /* pop from file stack */
- PRIVATE void
- exit_file(void)
- {
- struct file_stack_entry *p;
-
- if (current_file != NULL) { /* we're not finished */
- printf("]"); /* show that we closing */
- fclose(current_file->fp);
-
- /* pop the stack */
- p = current_file;
- current_file = current_file->prev;
- free(p);
-
- if (current_file == NULL) { /* this was the Mother of all
- * includes */
- printf("<end of scene>\n");
- infile = NULL;
- } else {
- inputlines = current_file->lineno;
- infile = current_file->fp;
- }
- }
- }
-
-
- PRIVATE long dotcount = 0;
-
- PRIVATE void
- free_declare_tab(void)
- {
- struct declare_tab *p,
- *next;
-
- for (p = the_dectab; p != NULL; p = next) {
- next = p->next;
- free(p->name);
- switch (p->type) {
- case IDENTIFIER:
- assert(FALSE);
- case FLOAT_IDENTIFIER:
- free_float(p->data);
- break;
- case TEXTURE_IDENTIFIER:
- free_texture(p->data);
- break;
- case IMAGEMAP_IDENTIFIER:
- free_image_map(p->data);
- break;
- case COLOR_IDENTIFIER:
- free_color(p->data);
- break;
- case CAMERA_IDENTIFIER:
- free_camera(p->data);
- break;
- case VECTOR_IDENTIFIER:
- free_vector(p->data);
- break;
-
- case QUADRIC_IDENTIFIER:
- case SPHERE_IDENTIFIER:
- case PLANE_IDENTIFIER:
- case LIGHT_IDENTIFIER:
- case BOX_IDENTIFIER:
- case COMPOSITE_IDENTIFIER:
- case UNION_IDENTIFIER:
- case INTERSECTION_IDENTIFIER:
- case TRIANGLE_IDENTIFIER:
- case TORUS_IDENTIFIER:
- case ALGEBRAIC_IDENTIFIER:
- case SUPERQ_IDENTIFIER:
- case POLYGON_IDENTIFIER:
- case OBJECT_IDENTIFIER:
- free_object((object *) p->data);
- break;
- default:
- assert(FALSE);
- }
- free(p);
- }
- the_dectab = NULL;
-
- }
-
- PUBLIC void
- print_dectab(void)
- {
- #ifdef DEBUG
- struct declare_tab *p;
-
- for (p = the_dectab; p != NULL; p = p->next) {
- printf("\n\t\"%s\": ", p->name);
- switch (p->type) {
- case IDENTIFIER:
- assert(FALSE);
- case FLOAT_IDENTIFIER:
- printf("%lf\n", *(double *) p->data);
- break;
- case COLOR_IDENTIFIER:
- print_c("", *(color *) p->data);
- break;
- case VECTOR_IDENTIFIER:
- print_v("", *(vector *) p->data);
- break;
- case TEXTURE_IDENTIFIER:
- print_texture(p->data);
- break;
- case IMAGEMAP_IDENTIFIER:
- print_image_map(p->data);
- break;
- case CAMERA_IDENTIFIER:
- print_camera(p->data);
- break;
-
- case QUADRIC_IDENTIFIER:
- case SPHERE_IDENTIFIER:
- case PLANE_IDENTIFIER:
- case LIGHT_IDENTIFIER:
- case BOX_IDENTIFIER:
- case COMPOSITE_IDENTIFIER:
- case UNION_IDENTIFIER:
- case TORUS_IDENTIFIER:
- case INTERSECTION_IDENTIFIER:
- case ALGEBRAIC_IDENTIFIER:
- case SUPERQ_IDENTIFIER:
- case POLYGON_IDENTIFIER:
- print_object((object *) p->data);
- break;
-
- case OBJECT_IDENTIFIER:
- printf("GENERIC OBJECT: ");
- print_object((object *) p->data);
- break;
-
- default:
- assert(FALSE);
- }
- }
-
- #endif
- }
-
-
- PRIVATE struct declare_tab *
- add_declare(char *name)
- {
- struct declare_tab *p;
-
- p = the_dectab;
-
- /* alloc one */
- the_dectab = ALLOC(struct declare_tab);
-
- CHECK_MEM(the_dectab, "declaration");
-
- /* link it in */
- the_dectab->next = p;
-
- /* copy the string */
- the_dectab->name = malloc(strlen(name) + 1);
- CHECK_MEM(the_dectab->name, "identifier name");
- strcpy(the_dectab->name, name);
-
- /* init the declare */
- the_dectab->type = IDENTIFIER;
- the_dectab->data = NULL;
-
- return the_dectab;
- }
-
- PRIVATE int
- search_keyword(char *s)
- {
- int lo,
- hi,
- cmp,
- result;
-
- lo = 0;
- hi = maxkey;
-
- /* binary search */
- do {
- cmp = (lo + hi) / 2;
-
- result = strcmp(s, keyword_tab[cmp].name);
-
- if (result < 0)
- hi = cmp;
- else
- lo = cmp;
-
- }
- while (hi - lo > 1);
- if (!strcmp(s, keyword_tab[lo].name))
- return lo;
- else
- return -1; /* not found */
- }
-
- /* search declaration table for string s, return pointer to decl info. */
- PRIVATE struct declare_tab *
- search_declare(char *s)
- {
- struct declare_tab *p;
-
- for (p = the_dectab; p != NULL; p = p->next)
- if (!strcmp(p->name, s))
- return p;
- return NULL;
- }
-
- /*
- * The main tokenizer function. It's a bit hairy, but it's simple
- *
- * get a char: is it an letter ([a-zA-Z_]), then read a word. *is it a
- * keyword? yes: is it include ? yes: handle include, and call yylex()
- * recursively no: return token code no: it's an identifier. Is it new?
- * yes: add a declaration, no: return pointer to info
- */
-
- PUBLIC int
- yylex(void)
- {
- int c,
- t;
- char s[100];
-
- eat_junk(); /* eat up comments, and whitespace */
- c = popc(); /* look at important char */
-
- if (isalpha(c) || c == '_') { /* were looking at a word */
- pushc(c);
- get_word(s);
- t = search_keyword(s);
- if (t != -1) { /* reserved word? */
- if (keyword_tab[t].tokcode == INCLUDE) { /* includes shouldn't be
- * seen by the parser */
- handle_include();
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("INCLUDE");
- #endif
- return yylex();
- } else {
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("\nKEYWORD \"%s\"\n", s);
- #endif
- return keyword_tab[t].tokcode; /* a real keyword */
- }
- } else {
- if ((yylval.dectabptr = search_declare(s)) == NULL) { /* unknown identifer */
- yylval.dectabptr = add_declare(s);
-
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("NEW ");
- #endif
-
- }
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("IDENTIFIER: \"%s\"\n", s);
- #endif
- return yylval.dectabptr->type;
- }
- } else if (isdigit(c) || c == '.') { /* number */
- pushc(c);
- if (fscanf(infile, "%lf", &(yylval.doubleval)) != 1)
- assert(FALSE);
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("\nread %lf\n", yylval.doubleval);
- #endif
-
- return FLOAT_CONST;
- }
- if (c == EOF) {
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("<EOF>");
- #endif
-
- if (infile == NULL)
- return 0;
-
- exit_file();
- return yylex();
- }
- if (c == '\"') {
- pushc('\"');
- get_quotedstring(yylval.stringval);
-
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("STRING %s\n", yylval.stringval);
- #endif
-
- return STRING;
- }
- /* not a string, not a number, so it's a char; return it. */
-
- #ifdef DEBUG
- if (debug_options & DEBUGTOK)
- printf("CHAR %c\n", c);
- #endif
-
- return c;
-
- }
-
- /*
- * read a quoted string like "ad sfj54%$%$5439yties" gobble the quotes.
- */
- PRIVATE void
- get_quotedstring(char *s)
- {
- int c;
-
- eat_junk();
- if ((c = popc()) != '\"')
- errormsg("\" expected");
-
- while ((c = popc()) != EOF && c != '\"')
- *s++ = c;
-
-
- if (c != '\"')
- errormsg("\" expected");
- *s = 0;
- }
-
- /* handle word; _ is a char too */
- PRIVATE void
- get_word(char *cp)
- {
- int c;
-
- while (1) {
- c = popc();
- if (!(isalnum(c) || c == '_')) { /* OK, end of word */
- *cp = 0;
- pushc(c);
- return;
- }
- *cp++ = c;
- }
- }
-
- /* strip comments, spaces etc */
- PRIVATE void
- eat_junk(void)
- {
- int c;
-
- while (1) {
- c = popc();
- if (c == '#' || c == '\r') /* ignore '#' */
- continue;
-
- if (c == '/') { /* is this a comment? */
- c = popc();
- if (c == '*')
- eat_comment();
- else if (c == '/')
- eat_linecomment();
- else { /* not a comment */
- pushc(c);
- pushc('/');
- return;
- }
- } else if (!isspace(c)) {
- pushc(c);
- return;
- }
- }
-
- }
-
- /* eat a comment */
- PRIVATE void
- eat_comment(void)
- {
- int c;
-
- while (1) {
- c = popc();
- if (c == EOF)
- return;
-
- if (c == '/') {
- c = popc();
- if (c != '*')
- continue;
- eat_comment();
- } else if (c == '*')
- if ((c = popc()) == '/')
- return;
- else
- pushc(c);
- }
- }
-
- /* eat a // comment */
- PRIVATE void
- eat_linecomment(void)
- {
- int c;
-
- while (1) {
- c = popc();
- if (c == '\n' || c == EOF)
- return;
- }
- }
-
-
- /* i'm too lazy to type getc(infile); */
- PRIVATE int
- popc(void)
- {
- int c;
-
- if (current_file == NULL)
- return EOF;
-
- c = getc(infile);
-
- if (c == '\n') {
- if (!(dotcount++ % INDICATORCOUNT))
- printf(".");
- inputlines++;
- }
- return c;
- }
-
- /* push back a char to the current infile */
- PRIVATE void
- pushc(int c)
- {
- if (current_file == NULL)
- return;
-
- if (c == '\n')
- inputlines--;
- ungetc(c, infile);
- }
-