Back to index

wims  3.65+svn20090927
oef2wims.c
Go to the documentation of this file.
00001 /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
00002  *
00003  *  This program is free software; you can redistribute it and/or modify
00004  *  it under the terms of the GNU General Public License as published by
00005  *  the Free Software Foundation; either version 2 of the License, or
00006  *  (at your option) any later version.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00016  */
00017 
00018  /* This program translates oef format exercises into wims internal data format. */
00019 
00020 #define MAX_TITLEN  40
00021 #define MAX_PROMPTLEN 40
00022 #define MAX_PARM    10
00023 #define MAX_PARAM   1024
00024 #define MAX_DEFINE  1024
00025 #define MAX_FLEN 199999
00026 #define elsechar '\001'
00027 #define endifchar '\002'
00028 #define nextchar '\003'
00029 #define whilechar '\004'
00030 #define VERSION "3.22"
00031 #define executed_str "__EXECUTED_1692754_EXERCISE__"
00032 
00033 #include "../Lib/libwims.h"
00034 
00035 FILE *outf;
00036 int choicecnt=0, answercnt=0, feedbackcnt=0, varcnt=0, conditioncnt=0, condans=0, has_plot=0;
00037 char *primitive_dir="oef";
00038 int has_help=0;
00039 int posttag=0, prevarcnt=-1, post=0, deftag, prevars;
00040 int start_varcnt=0;
00041 int step_defined=0;
00042 int embedcnt=0;
00043 char *badpar=NULL;
00044 char *mdef;   /* external definition */
00045 char *format="html";
00046 
00047 int ao[256];
00048 int aocnt=0;
00049 
00050 struct {
00051     char *name;
00052     int serial;
00053     short int type, save;
00054 } param[MAX_PARAM+32];
00055 
00056 char *inpbuf, *inpend;
00057 char outfname[1024];
00058 
00059 #include "lines.c"
00060 #include "compare.c"
00061 #include "outexec.c"
00062 #include "process.c"
00063 
00064 enum {t_tit, t_head, t_def, t_wims, t_form, t_main, t_plot, t_hint, 
00065       t_ans, t_choi, t_cond, t_cond2, t_sol, t_feedback, t_help, t_step};
00066 
00067 struct {
00068     char *name;
00069     int  type, parmcnt;
00070     void (*processor)(char *p[MAX_PARM]);
00071 } directives[]={
00072       {"answer",     t_ans ,5,     p_answer},
00073       {"author",     t_head,1,     p_author},
00074       {"choice",     t_choi,5,     p_choice},
00075       {"complex",    t_def ,2,     p_complex},
00076       {"computeanswer",     t_head,1,     p_computeanswer},
00077       {"condition",  t_cond,4,     p_condition},
00078       {"conditions", t_cond2,1,    p_conditions},
00079       {"css",        t_head,1,     p_css},
00080       {"else",              t_def,0,      p_else},
00081       {"email",             t_head,1,     p_email},
00082       {"endif",             t_def,0,      p_endif},
00083       {"endwhile",   t_def,0,      p_endwhile},
00084       {"feedback",   t_feedback,2,   p_feedback},
00085       {"for",        t_def,1,      p_for},
00086       {"format",     t_form,1,     empty},
00087       {"function",   t_def ,2,     p_func},
00088       {"help",              t_help,1,     p_help},
00089       {"hint",              t_hint,1,     p_hint},
00090       {"if",         t_def,1,      p_if},
00091       {"int",        t_def ,2,     p_int},
00092       {"integer",    t_def ,2,     p_int},
00093       {"language",   t_head,1,     p_language},
00094       {"matrix",     t_def ,2,     p_matrix},
00095       {"mdef",              t_def, 2,     p_mdef},
00096       {"next",              t_def,0,      p_next},
00097       {"nextstep",   t_step, 1,    p_nextstep},
00098       {"parameter",  t_def ,2,     p_parm},
00099       {"plot",              t_plot,3,     p_plot},
00100       {"precision",  t_head,1,     p_precision},
00101       {"range",             t_head,1,     p_range},
00102       {"rational",   t_def ,2,     p_rational},
00103       {"real",              t_def ,2,     p_real},
00104       {"reply",             t_ans ,5,     p_answer},
00105       {"solution",   t_sol, 1,     p_solution},
00106       {"statement",  t_main,1,     p_statement},
00107       {"steps",             t_step, 1,    p_steps},
00108       {"text",              t_def ,2,     p_text},
00109       {"title",             t_tit ,1,     empty},
00110       {"variable",   t_def ,2,     p_parm},
00111       {"while",             t_def,1,      p_while},
00112       {"wims",              t_wims,1,     p_wims}
00113 };
00114 
00115 #define dir_no (sizeof(directives)/sizeof(directives[0]))
00116 
00117 struct {
00118     char *parm[MAX_PARM];
00119     short int type, tag;
00120 } define[MAX_DEFINE];
00121 int define_no, title_no=-1, statement_no=-1;
00122 
00123        /* Debug output */
00124 void debug(void)
00125 {
00126     int i,j,n;
00127     for(i=0;i<define_no;i++) {
00128        printf("%s:   ",directives[define[i].type].name);
00129        n=directives[define[i].type].parmcnt;
00130        for(j=0;j<n;j++) {
00131            printf("%s",define[i].parm[j]);
00132            if(j<n-1) printf(", ");
00133        }
00134        printf("\n");
00135     }
00136 }
00137 
00138        /* get one input file */
00139 long int getinp(char fname[])
00140 {
00141     FILE *input;
00142     long int siz;
00143     int i;
00144     
00145     input=fopen(fname,"r");
00146     if(input==NULL) return 0;
00147     fseek(input,0L,SEEK_END); siz=ftell(input);
00148     if(siz<=0 || siz>=MAX_FLEN) {
00149        fclose(input);
00150        if(siz==0) return 0; else return -1;
00151     }
00152     fseek(input,0L,SEEK_SET);
00153     inpbuf=xmalloc(siz+10);
00154     siz=fread(inpbuf,1,siz,input); fclose(input);
00155     if(siz<=0) return -1;
00156     inpend=inpbuf+siz; *inpend=0;
00157     for(i=0;i<siz;i++) 
00158       if(inpbuf[i]==13 || (inpbuf[i]>=0 && inpbuf[i]<=6)) inpbuf[i]=' ';
00159     return siz;
00160 }
00161 
00162        /* Processes input file */
00163 void process(void)
00164 {
00165     char *p, *pe, *pp, c;
00166     int i,j;
00167     
00168     for(p=inpbuf,define_no=0;define_no<MAX_DEFINE && p<inpend;p++) {
00169        if(*p!='\\' && *p!='{' && (*p>6 || *p<0)) continue;
00170        if(*p>0 && *p<=6) {
00171            pe=""; switch(*p) {
00172               case elsechar: pe="else"; break;
00173               case endifchar: pe="endif"; break;
00174               case nextchar: pe="next"; break;
00175               case whilechar: pe="endwhile"; break;
00176            }
00177            define[define_no].tag=posttag;
00178            define[define_no++].type=
00179              search_list(directives,dir_no,sizeof(directives[0]),pe);
00180            continue;
00181        }
00182        if(*p=='{') {
00183            if((p=find_matching(p+1,'}'))==NULL) error("Unmatched parentheses???");
00184            continue;
00185        }
00186        p++;
00187        for(pe=p;isalnum(*pe) || *pe=='_'; pe++);
00188        pp=find_word_start(pe);
00189        if(*pp!='{') {
00190            if(pp>p) p=pp-1;
00191            continue;
00192        }
00193        c=*pe; *pe=0;
00194        i=search_list(directives,dir_no,sizeof(directives[0]),p);
00195        if(i<0) {
00196            if(wordchr(mdef,p)!=NULL) {
00197               pe=find_matching(pp+1,'}'); if(pe==NULL) error("Unmatched parentheses?");
00198               *pe=0;define[define_no].type=
00199                 search_list(directives,dir_no,sizeof(directives[0]),"mdef");
00200               replace_newline(pp+1);
00201               define[define_no].tag=posttag;
00202               define[define_no].parm[0]=p;
00203               define[define_no].parm[1]=pp+1;
00204               define_no++; p=pe;
00205               continue;
00206            }
00207            if((p=find_matching(pp+1,'}'))==NULL) error("Unmatched parentheses?");
00208            continue;
00209        }
00210        define[define_no].type=i;
00211        define[define_no].tag=posttag;
00212        for(j=0;j<MAX_PARM && j<directives[i].parmcnt;j++,pp=find_word_start(pe+1)) {
00213            if(j>0 && *pp!='{') break;
00214            if((pe=find_matching(pp+1,'}'))==NULL) error("Unmatched parentheses?");
00215            *pe=0; replace_newline(pp+1);
00216            define[define_no].parm[j]=pp+1;
00217        }
00218        for(;j<MAX_PARM;j++) define[define_no].parm[j]="";
00219        switch(directives[i].type) {
00220            case t_tit: {
00221               title_no=define_no; break;
00222            }
00223            case t_ans: {
00224               if(aocnt<256) ao[aocnt++]=t_ans;
00225               answercnt++; goto checkeq;
00226            }
00227            case t_step: {
00228               if(step_defined) error("Multiple definition of steps.");
00229               step_defined=1;      break;
00230            }
00231            case t_def: {
00232               char *pt;
00233               if(directives[i].parmcnt<2) {
00234                   char *pt2, *pt3;
00235                   pt=find_word_start(pe+1); pt3="";
00236                   if(*pt!='{') pt2=pt;
00237                   else {
00238                      *pt=' '; pt2=find_matching(pt,'}');
00239                      if(pt2==NULL) error("Unmatched parentheses?");
00240                      pt3=find_word_start(pt2+1);
00241                   }
00242                   if(strcmp(directives[i].name,"if")==0) {
00243                      if(*pt3=='{') {
00244                          *pt2=elsechar; *pt3=' ';
00245                          pt2=find_matching(pt3,'}');
00246                          if(pt2==NULL) error("Unmatched parentheses?");
00247                      }
00248                      *pt2=endifchar;
00249                   }
00250                   else {
00251                      if(strcmp(directives[i].name,"while")==0) *pt2=whilechar;
00252                      else {
00253                          varcnt++; *pt2=nextchar;
00254                      }
00255                   }
00256                   break;
00257               }
00258               varcnt++;
00259               checkeq:
00260               if(*(define[define_no].parm[1])==0 && 
00261                  (pt=strchr(define[define_no].parm[0],'='))!=NULL) {
00262                   if(*(pt-1)==':') *(pt-1)=0;
00263                   *pt=0; define[define_no].parm[1]=pt+1;
00264               }
00265               break;
00266            }
00267            case t_choi: {
00268               if(aocnt<256) ao[aocnt++]=t_choi;
00269               choicecnt++; break;
00270            }
00271            case t_cond: {
00272               conditioncnt++; break;
00273            }
00274            case t_main: {
00275               if(posttag) error("Multiple definition of statement.");
00276               posttag=1; if(prevarcnt<0) prevarcnt=varcnt;
00277               statement_no=define_no; break;
00278            }
00279            case t_plot: {
00280               has_plot=1; break;
00281            }
00282            case t_form: {
00283               char *s=define[define_no].parm[0];
00284               s=find_word_start(s);*find_word_end(s)=0;
00285               if(strcasecmp(s,"html")==0) format="html";
00286               if(strcasecmp(s,"tex")==0) format="tex";
00287               break;
00288            }
00289            case t_feedback: {
00290               feedbackcnt++; break;
00291            }
00292        }
00293        define_no++; p=pe;
00294     }
00295 }
00296 
00297        /* Output one category */
00298 void _out(int typ)
00299 {
00300     int i, t;
00301     for(i=0;i<define_no;i++) {
00302        t=define[i].type;
00303        if(directives[t].type!=typ) continue;
00304        if(typ==t_def && define[i].tag!=deftag) continue;
00305        directives[t].processor(define[i].parm);
00306     }
00307 }
00308 
00309        /* Output the result */
00310 void output(void)
00311 {
00312     int i,k;
00313        /* no statement, nothing to do */
00314     if(statement_no<0) error("No statement defined.");
00315     outf=fopen(outfname,"w"); if(outf==NULL) error("Unable to open output file.");
00316     if(title_no>=0 && *(define[title_no].parm[0])!=0) {
00317        char *p=define[title_no].parm[0];
00318        if(strlen(p)>MAX_TITLEN) *(p+MAX_TITLEN)=0;
00319        fprintf(outf,"!set title=%s\n",p);
00320     }
00321     else {
00322        fprintf(outf,"!set title=No title\n");
00323     }
00324     fprintf(outf,"!if $wims_read_parm!=$empty\n\
00325  !goto $wims_read_parm\n\
00326 !endif\n");
00327     fprintf(outf,"oef2wims_version=%s\n",VERSION);
00328     _out(t_head);
00329     if(aocnt>0) {
00330        int i;
00331        fprintf(outf,"\nansorder=");
00332        for(i=0;i<aocnt;i++) {
00333            if(ao[i]==t_ans) fprintf(outf,"r");
00334            else fprintf(outf,"c");
00335            if(i<aocnt-1) fprintf(outf,",");
00336        }      
00337     }
00338     if(prevarcnt<varcnt) post=varcnt-prevarcnt; else post=0;
00339     fprintf(outf,"\n\
00340 varcnt=%d\n\
00341 prevarcnt=%d\n\
00342 postvarcnt=%d\n\
00343 replycnt=%d\n\
00344 choicecnt=%d\n\
00345 conditioncnt=%d\n\
00346 feedbackcnt=%d\n\
00347 format=%s\n\n\
00348 val1=$imagedir\n\
00349 val2=$confparm1\n\
00350 val3=$confparm2\n\
00351 val4=$confparm3\n\
00352 val5=$confparm4\n\n\
00353 !if $testcondition=yes\n\
00354  !goto test\n\
00355 !endif\n\
00356 !if $status=waiting\n\
00357  !exit\n\
00358 !endif\n\n",varcnt+1,prevarcnt,post,answercnt,choicecnt,
00359            conditioncnt,feedbackcnt,format);
00360     varcnt=start_varcnt; deftag=0;
00361     _out(t_def);
00362     _out(t_step);
00363 /*    _out(t_wims);  */
00364     _out(t_plot);
00365     answercnt=1; _out(t_ans);
00366     choicecnt=1; _out(t_choi);
00367     deftag=1; prevars=varcnt;
00368     _out(t_main);
00369     _out(t_hint);
00370     _out(t_help);
00371     _out(t_sol);
00372     fprintf(outf,"\n!goto stat\n");
00373        /* second run to output execution codes */
00374     p_statement(NULL);
00375     p_hint(NULL);
00376     p_help(NULL);
00377     p_solution(NULL);
00378     if(post) {
00379        fprintf(outf,"\n!exit\n\n:postdef\n"); _out(t_def);
00380     }
00381     fprintf(outf,"\n!exit\n\n:feedback\n");
00382     _out(t_feedback);
00383     fprintf(outf,"\n!exit\n\n:test\n");
00384     _out(t_cond2); conditioncnt=1; _out(t_cond);
00385     fprintf(outf,"\n!exit\n\n:stat\nvsavelist=");
00386     for(k=0,i=1;i<prevars;i++) {
00387        if(param[i].save==0) continue;
00388        if(k>0) fprintf(outf,","); k++;
00389        fprintf(outf,"%d",i);
00390     }
00391     fprintf(outf,"\nembedcnt=%d\n",embedcnt);
00392     fclose(outf);
00393 }
00394 
00395 int main(int argc, char *argv[])
00396 {
00397     int t;
00398     error1=error; error2=error; error3=error;
00399     substitute=substit;
00400     if(argc<=1) return 0; /* no input file */
00401     if(argc==2 && strcmp(argv[1],"table")==0) {
00402        if(verify_order(directives, dir_no, sizeof(directives[0]))) return -1;
00403        if(verify_order(specialfn, specialfn_no, sizeof(specialfn[0]))) return -1;
00404        puts("Table orders OK."); return 0;
00405     }
00406     if(argc>2) snprintf(outfname,sizeof(outfname),"%s",argv[2]);
00407     else {
00408        char *fe;
00409        snprintf(outfname,sizeof(outfname)-10,"%s",argv[1]);
00410        fe=outfname+strlen(outfname)-strlen(".oef");
00411        if(strcasecmp(fe,".oef")==0) *fe=0;
00412        strcat(fe,".def");
00413     }
00414     mdef=getenv("oef2wims_mdef"); if(mdef==NULL) mdef="";
00415     printf("%s..",argv[1]);
00416     t=getinp(argv[1]);
00417     if(t<0) error("Source file bad or too long.");
00418     if(t==0) error("Empty source file.");
00419     if(checkparentheses(inpbuf,1)!=0) error("Unmatched parentheses");
00420     outf=fopen(outfname,"w"); if(outf==NULL) error("Unable to open output file.");
00421     fclose(outf); remove(outfname);
00422     vbuf_statement[0]=vbuf_hint[0]=vbuf_help[0]=vbuf_solution[0]=0;
00423     param[1].name="imagedir";param[1].type=pt_text;
00424     param[2].name="confparm1";param[2].type=pt_text;
00425     param[3].name="confparm2";param[3].type=pt_text;
00426     param[4].name="confparm3";param[4].type=pt_text;
00427     param[5].name="confparm4";param[5].type=pt_text;
00428     start_varcnt=6;
00429     process();
00430     output();
00431     printf(" -> %s\n",outfname);
00432     return 0;
00433 }
00434