#include #include #include #include #include "vecmath.h" #include "tokens.h" /* Functions in this file implement parsing operations for each object type. The main function to be called is Parse(). Each parsing function assigns values retrieved from the file to a set of local variables that can be used to create objects. Parsing stops at the first error and the program exits through function Error() defined in tokens.c, after printing the current line number and an error message. (A real parser would have better error recovery, but this simple approach greatly simplifies the code and is sufficient for our purposes). Although this code runs, it requires additions to make it fully functional. Search for comments starting with TODO to find places requiring modification. */ /* a collection of functions for syntax verification */ void ParseLeftAngle() { GetToken(); if(Token.id != T_LEFT_ANGLE ) Error("Expected <"); } void ParseRightAngle() { GetToken(); if(Token.id != T_RIGHT_ANGLE ) Error("Expected >"); } double ParseDouble() { GetToken(); if(Token.id != T_DOUBLE ) Error("Expected a number"); return Token.double_value; } void ParseLeftCurly() { GetToken(); if(Token.id != T_LEFT_CURLY ) Error("Expected {"); } void ParseRightCurly() { GetToken(); if(Token.id != T_RIGHT_CURLY ) Error("Expected }"); } void ParseComma() { GetToken(); if(Token.id != T_COMMA ) Error("Expected ,"); } void ParseVector(struct Vector* v) { ParseLeftAngle(); v->x = ParseDouble(); ParseComma(); v->y = ParseDouble(); ParseComma(); v->z = ParseDouble(); ParseRightAngle(); } void ParseMatrix( struct Matrix4d* m) { SetIdentity4d(m); ParseLeftAngle(); m->val[4*0] = ParseDouble(); ParseComma(); m->val[4*1] = ParseDouble(); ParseComma(); m->val[4*2] = ParseDouble(); ParseComma(); m->val[4*0+1] = ParseDouble(); ParseComma(); m->val[4*1+1] = ParseDouble(); ParseComma(); m->val[4*2+1] = ParseDouble(); ParseComma(); m->val[4*0+2] = ParseDouble(); ParseComma(); m->val[4*1+2] = ParseDouble(); ParseComma(); m->val[4*2+2] = ParseDouble(); ParseComma(); m->val[4*0+3] = ParseDouble(); ParseComma(); m->val[4*1+3] = ParseDouble(); ParseComma(); m->val[4*2+3] = ParseDouble(); ParseRightAngle(); } void ParseTransform(struct Matrix4d* transf) { /* if there is nothing to parse, this is not our problem: this should be handled by the caller */ struct Vector v; struct Matrix4d m; while(1) { GetToken(); switch( Token.id ) { case T_SCALE: ParseVector(&v); /* TODO: add code to initialize scaling matrix here */ ScaleMatrix4d(transf, &v); break; case T_ROTATE: ParseVector(&v); /* TODO: add code to initialize rotation matrix here */ RotateMatrix4d(transf, &v); break; case T_TRANSLATE: ParseVector(&v); TranslateMatrix4d(transf, &v); /* TODO: add code to initialize translation matrix here */ break; /* once we run into an unknown token, we assume there are no more transforms to parse and we return to caller */ case T_MATRIX: ParseMatrix(&m); MultMatrix4d(transf, &m, transf); break; default: UngetToken(); return; } } } void ParseCamera() { /* these are variables where we store the information about the camera; they can be used in the end of the function to assign fields in the camera object */ struct Vector location, right, up, direction, look_at; double angle; struct Matrix4d transform; int done = FALSE; SetIdentity4d(&transform); /* default values */ SetVect(&location, 0.0, 0.0,0.0); SetVect(&right, 1.0, 0.0, 0.0); SetVect(&up, 0.0,1.0,0.0); SetVect(&direction, 0.0,0.0,1.0); angle = 60.0*M_PI/180.0; ParseLeftCurly(); /* parse camera parameters */ while(!done) { GetToken(); switch(Token.id) { case T_LOCATION: ParseVector(&location); break; case T_RIGHT: ParseVector(&right); break; case T_UP: ParseVector(&up); break; case T_DIRECTION: ParseVector(&direction); break; case T_LOOK_AT: ParseVector(&look_at); break; case T_ANGLE: angle = M_PI*ParseDouble()/180.0; break; default: done = TRUE; UngetToken(); break; } } ParseTransform(&transform); ParseRightCurly(); /* TODO: assignment to the camera object fields should happen here; for now, we just print the values */ printf("camera { \n"); printf("\tlocation "); PrintVect(location); printf("\n"); printf("\tright "); PrintVect(right); printf("\n"); printf("\tup "); PrintVect(up); printf("\n"); printf("\tdirection "); PrintVect(direction); printf("\n"); printf("\tangle %.3g\n", angle*180.0/M_PI); printf("\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } void ParsePolygon() { /* these three variables store information about the polygon */ int num_vertices; struct Vector* vertices; struct Matrix4d transform; int vert_cnt; int done = FALSE; int i; SetIdentity4d(&transform); num_vertices = 0; vertices = 0; ParseLeftCurly(); num_vertices = (int)ParseDouble(); if( num_vertices < 3 ) Error("Polygon must have at least 3 vertices"); vertices = (struct Vector*)malloc( sizeof(struct Vector)*num_vertices); ParseComma(); for( vert_cnt = 0; vert_cnt < num_vertices; vert_cnt++) { ParseVector(&(vertices[vert_cnt])); if( vert_cnt < num_vertices-1 ) ParseComma(); } ParseTransform(&transform); ParseRightCurly(); /* TODO: assignment to the polygon object fields should happen here; for now, we just print the values */ printf("polygon {\n"); printf("\t%d,\n\t", num_vertices); for( i = 0; i < num_vertices-1; i++) { PrintVect(vertices[i]); printf(","); } PrintVect(vertices[num_vertices-1]); printf("\n\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } void ParseSphere() { struct Vector center; double radius; struct Matrix4d transform; SetIdentity4d(&transform); SetVect(¢er, 0,0,0); radius = 1.0; ParseLeftCurly(); ParseVector(¢er); ParseComma(); radius = ParseDouble(); ParseTransform(&transform); ParseRightCurly(); /* TODO: assignment to the sphere object fields should happen here; for now, we just print the values */ printf("sphere {\n\t"); PrintVect(center); printf(", %.3g\n", radius); printf("\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } void ParseBox() { struct Vector corner1, corner2; struct Matrix4d transform; SetIdentity4d(&transform); SetVect(&corner1, 0,0,0); SetVect(&corner2, 0,0,0); ParseLeftCurly(); ParseVector(&corner1); ParseComma(); ParseVector(&corner2); ParseTransform(&transform); ParseRightCurly(); /* TODO: assignment to the box object fields should happen here; for now, we just print the values */ printf("box {\n\t"); PrintVect(corner1); printf(", "); PrintVect(corner2); printf("\n\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } void ParseCylinder() { struct Vector base_point , cap_point ; double radius; struct Matrix4d transform; SetIdentity4d(&transform); SetVect(&base_point, 0,0,0); SetVect(&cap_point, 0,0,0); radius = 0; ParseLeftCurly(); ParseVector(&base_point); ParseComma(); ParseVector(&cap_point); ParseComma(); radius = ParseDouble(); ParseTransform(&transform); ParseRightCurly(); /* TODO: assignment to the cylinder object fields should happen here; for now, we just print the values */ printf("cylinder {\n\t"); PrintVect(base_point); printf(", "); PrintVect(cap_point); printf(", %.3g\n", radius); printf("\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } void ParseCone() { struct Vector base_point, cap_point; double base_radius, cap_radius; struct Matrix4d transform; SetIdentity4d(&transform); SetVect(&base_point, 0,0,0); SetVect(&cap_point, 0,0,0); base_radius = 0; cap_radius = 0; ParseLeftCurly(); ParseVector(&base_point); ParseComma(); base_radius = ParseDouble(); ParseComma(); ParseVector(&cap_point); ParseComma(); cap_radius = ParseDouble(); ParseTransform(&transform); ParseRightCurly(); /* TODO: assignment to the cone object fields should happen here; for now, we just print the values */ printf("cone {\n\t"); PrintVect(base_point); printf(", %.3g, ", base_radius); PrintVect(cap_point); printf(", %.3g\n", cap_radius); printf("\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } void ParseQuadric() { struct Vector ABC, DEF, GHI; double J; struct Matrix4d transform; SetIdentity4d(&transform); SetVect(&ABC, 0,0,0); SetVect(&DEF, 0,0,0); SetVect(&GHI, 0,0,0); J = 0; ParseLeftCurly(); ParseVector(&ABC); ParseComma(); ParseVector(&DEF); ParseComma(); ParseVector(&GHI); ParseComma(); J = ParseDouble(); ParseTransform(&transform); ParseRightCurly(); printf("quadric {\n\t"); PrintVect(ABC); printf(", "); PrintVect(DEF); printf(", "); PrintVect(GHI); printf(", %.3g\n", J); printf("\tmatrix "); PrintMatrix4d(transform); printf("\n}\n"); } /* main parsing function calling functions to parse each object; */ void Parse(FILE* infile) { InitializeToken(infile); GetToken(); while(Token.id != T_EOF) { switch(Token.id) { case T_CAMERA: ParseCamera(); break; case T_POLYGON: ParsePolygon(); break; case T_SPHERE: ParseSphere(); break; case T_BOX: ParseBox(); break; case T_CYLINDER: ParseCylinder(); break; case T_CONE: ParseCone(); break; case T_QUADRIC: ParseQuadric(); break; default: Error("Unknown statement"); } GetToken(); } }