/* displayb.y Display file Parser This is the YACC parser code for firework display files. Copyright (c) 1998, Mike Oliphant and Rob Clark */ %{ #include #include "pyro.h" #include #include /* parser specific stuff. */ struct vec { double x; double y; double z; }; typedef struct vec Vec; struct parser_fw_template { int type; Vec *start; Vec *dir; }; typedef struct parser_fw_template Fw; typedef struct stack Stack; struct stack { int type; int count; char *from; Stack *next; }; Stack *push(Stack *s, int type, int count, char* from); Stack *pop(Stack *s); int top_type(Stack *s); int top_count(Stack *s); char *top_from(Stack *s); int printfw(Fw *fw); int yyparse(); int yyerror(); int yylex(); static char *filestream=NULL; static char *cpos=NULL; static Stack *sstack=NULL; static double nextworktime; FILE *dispfile; static Fw *nextFwptr; int end=0; %} %union { double val; Vec *vec; Fw *fw; } %token NUM %token FWNAME %token REPEAT %token DONE %token LOOP %token WAIT %token ERR %token END %type val %type vec %type fw_template %type delay %type repeat %type done %left NEG %right '(' %left ')' %right ',' %% input: /* empty */ | input line ; line: '\n' | fw_template { nextFwptr=$1; YYACCEPT; } | LOOP { cpos=filestream; YYACCEPT; } | delay { nextworktime=$1; YYACCEPT; } | repeat { sstack=push(sstack,REPEAT,$1,cpos); YYACCEPT;} | done { if(top_count(sstack)>1) { sstack->count--; cpos=sstack->from;} else { sstack=pop(sstack); } } | ERR { yyerror("parse error"); YYERROR; } | error { yyerrok; } | END { cpos=filestream; end=1; YYACCEPT; } ; fw_template: FWNAME { $$=$1; } | FWNAME vec { $$=$1; $$->start=$2; } | FWNAME vec vec { $$=$1; $$->start=$2; $$->dir=$3; } ; delay: WAIT val { $$=$2; } ; repeat: REPEAT val { $$=$2; } ; done: DONE vec: '(' val ',' val ',' val ')' { $$=(Vec *)malloc(sizeof(Vec)); $$->x=$2; $$->y=$4; $$->z=$6; } ; val: NUM {$$=$1;} | '-' NUM %prec NEG {$$= -$2;} ; %% #include #include #include int yyerror (char *s) {printf ("%s\n", s); return 0;} int FindWork(char *name) { int work; for(work=0;workname)) return work; /* if(!STRCASECMP(name,"one")) return 1; if(!STRCASECMP(name,"two")) return 2; */ return -1; } int printfw(Fw *fw) { printf("\n"); printf("Firework: %d\n",fw->type); if(fw->start) printf(" start: (%f,%f,%f)\n",fw->start->x,fw->start->y,fw->start->z); if(fw->dir) printf(" dir: (%f,%f,%f)\n",fw->dir->x,fw->dir->y,fw->dir->z); printf("\n"); return 0; } #define FBUF 255 /* Functions main requires */ int ParseDisplayFile(char* filename) { int c; int len; int i; if((dispfile=fopen(filename,"r"))==NULL) { fprintf(stderr,"Failed to open display file: %s\n",filename); return -1; } len=FBUF; filestream=(char *)malloc(len+1); i=0; while((c=fgetc(dispfile))!=EOF) { if(i==len){ len+=FBUF; filestream=(char *)realloc(filestream, len+1); } if(c=='#') { while((c=fgetc(dispfile))!=EOF && c!='\n') ; c=fgetc(dispfile); } filestream[i++]=c; } filestream[i]='\0'; cpos=filestream; fclose(dispfile); return 0; } Firework *GetWork(void) { Firework *work=NULL; yyparse(); if(nextFwptr) { work=NewWork(Fireworks[nextFwptr->type]); if(nextFwptr->start) { work->x=nextFwptr->start->x; work->y=nextFwptr->start->y; work->z=nextFwptr->start->z; } if(nextFwptr->dir) { work->dx=nextFwptr->dir->x/40; work->dy=nextFwptr->dir->y/20; work->dz=nextFwptr->dir->z/40; } } nextFwptr=NULL; return work; } void UpdateDisplay(double elapsed) { nextworktime-=elapsed; } int CheckDisplay() { if(nextworktime<0.0) return 1; if(end) { end=0; return -1; } return 0; } void RestartDisplay(void) { cpos=filestream; } /* Stack stuff */ Stack *push(Stack *s, int type, int count, char* from) { Stack *n; n=(Stack *)malloc(sizeof(Stack)); n->type=type; n->count=count; n->from=from; n->next=s; return n; } Stack *pop(Stack *s) { Stack *n; if(s==NULL) fprintf(stderr,"Stack overflow.\n"); n=s->next; free(s); return n; } int top_type(Stack *s) { if(s==NULL) fprintf(stderr,"No Stack top.\n"); return s->type; } int top_count(Stack *s) { if(s==NULL) fprintf(stderr,"No Stack top.\n"); return s->count; } char *top_from(Stack *s) { if(s==NULL) fprintf(stderr,"No Stack top.\n"); return s->from; } /* yylex based on example in bison documentation */ int yylex() { int i; int c; int gotfw; /* skip whitespace */ while ((c = *cpos++) == ' ' || c == '\t'); if (c == '\0') { return END; } if (c == '.' || isdigit (c)){ cpos--; sscanf(cpos,"%lf%n", &yylval.val,&i); cpos+=i; return NUM; } if (isalpha (c)){ static char *symbuf = 0; static int length = 0; int i; if (length == 0) length = 40, symbuf = (char *)malloc (length + 1); i = 0; do{ if (i == length) { length *= 2; symbuf = (char *)realloc (symbuf, length + 1); } symbuf[i++] = c; c=*cpos++; } while (c != '\0' && isalnum (c)); cpos--; symbuf[i] = '\0'; if(!STRCASECMP(symbuf,"loop")) return LOOP; if(!STRCASECMP(symbuf,"end")) return END; if(!STRCASECMP(symbuf,"repeat")) return REPEAT; if(!STRCASECMP(symbuf,"done")) return DONE; if(!STRCASECMP(symbuf,"wait")) return WAIT; gotfw=FindWork(symbuf); if(gotfw!=-1){ yylval.fw= (Fw *) malloc (sizeof(Fw)); yylval.fw->type=gotfw; yylval.fw->start=NULL; yylval.fw->dir=NULL; return FWNAME; } /* unknown string */ return ERR; } /* character constant */ return c; }