Subversion Repositories wimsdev

Rev

Rev 12247 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*  Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18.  /* This program translates oef format exercises into wims internal data format. */
  19.  
  20. #define MAX_TITLEN 80
  21.  
  22. #define MAX_PARM 10
  23. #define MAX_PARAM 1024
  24. #define MAX_DEFINE 1024
  25. #define MAX_FLEN 199999
  26.  
  27. #define VERSION "3.22"
  28.  
  29.  
  30. #include "../Lib/libwims.h"
  31. #include "oef2wims.h"
  32.  
  33. FILE *outf;
  34. int choicecnt=0, answercnt=0, feedbackcnt=0, varcnt=0, conditioncnt=0, condans=0, has_plot=0;
  35. char *primitive_dir="oef";
  36. int has_help=0;
  37. int posttag=0, prevarcnt=-1, post=0, deftag, prevars;
  38. int start_varcnt=0;
  39. int step_defined=0;
  40. int embedcnt=0;
  41. char *badpar=NULL;
  42. char *mdef; /* external definition */
  43. char *format="html";
  44.  
  45. int ao[256];
  46. int aocnt=0;
  47.  
  48. struct param param[MAX_PARAM+32];
  49.  
  50. char *inpbuf, *inpend;
  51. char outfname[1024];
  52.  
  53. enum {t_tit, t_head, t_head2, t_lang, t_def, t_wims, t_form, t_main, t_plot, t_hint,
  54.       t_ans, t_choi, t_cond, t_cond2, t_sol, t_feedback, t_help, t_step, t_latex};
  55.  
  56. struct {
  57.   char *name;
  58.   int type, parmcnt;
  59.   void (*processor)(char *p[MAX_PARM]);
  60. } directives[]={
  61.   {"answer", t_ans, 5, p_answer},
  62.   {"author", t_head2, 1, p_header},
  63.   {"choice", t_choi, 5, p_choice},
  64.   {"complex", t_def, 2, p_complex},
  65.   {"computeanswer", t_head, 1, p_computeanswer},
  66.   {"condition", t_cond, 4, p_condition},
  67.   {"conditions", t_cond2, 1, p_conditions},
  68.   {"credits", t_def, 2, p_credits},
  69.   {"css", t_head, 1, p_css},
  70.   {"description", t_head, 1, p_description},
  71.   {"else", t_def, 0, p_else},
  72.   {"email", t_head2, 1, p_header},
  73.   {"endif", t_def, 0, p_endif},
  74.   {"endwhile", t_def, 0, p_endwhile},
  75.   {"feedback", t_feedback, 2, p_feedback},
  76.   {"for", t_def, 1, p_for},
  77.   {"format", t_form, 1, empty},
  78.   {"function", t_def, 2, p_func},
  79.   {"help", t_help, 1, p_help},
  80.   {"hint", t_hint, 1, p_hint},
  81.   {"if", t_def, 1, p_if},
  82.   {"ifval", t_def, 1, p_ifval},
  83.   {"int", t_def, 2, p_int},
  84.   {"integer", t_def, 2, p_int},
  85.   {"keywords", t_head2, 1, p_header},
  86.   {"language", t_head, 1, p_language},
  87.   {"latex", t_latex, 1, p_latex},
  88.   {"matrix", t_def, 2, p_matrix},
  89.   {"mdef", t_def, 2, p_mdef},
  90.   {"next", t_def, 0, p_next},
  91.   {"nextstep", t_step, 1, p_nextstep},
  92.   {"observation", t_head, 1, p_observation},
  93.   {"parameter", t_def, 2, p_parm},
  94.   {"plot", t_plot, 3, p_plot},
  95.   {"precision", t_head, 1, p_precision},
  96.   {"range", t_head, 1, p_range},
  97.   {"rational", t_def, 2, p_rational},
  98.   {"real", t_def, 2, p_real},
  99.   {"reply", t_ans, 5, p_answer},
  100.   {"solution", t_sol, 1, p_solution},
  101.   {"statement", t_main, 1, p_statement},
  102.   {"steps", t_step, 1, p_steps},
  103.   {"text", t_def, 2, p_text},
  104.   {"title", t_tit, 1, empty},
  105.   {"title_ca", t_lang, 1, p_header},
  106.   {"title_cn", t_lang, 1, p_header},
  107.   {"title_en", t_lang, 1, p_header},
  108.   {"title_es", t_lang, 1, p_header},
  109.   {"title_fr", t_lang, 1, p_header},
  110.   {"title_it", t_lang, 1, p_header},
  111.   {"title_nl", t_lang, 1, p_header},
  112.   {"title_si", t_lang, 1, p_header},
  113.   {"variable", t_def, 2, p_parm},
  114.   {"while", t_def, 1, p_while},
  115.   {"wims", t_wims, 1, p_wims}
  116. };
  117.  
  118. #define dir_no (sizeof(directives)/sizeof(directives[0]))
  119.  
  120. struct {
  121.   char *parm[MAX_PARM];
  122.   short int type, tag;
  123. } define[MAX_DEFINE];
  124. int define_no, title_no=-1, statement_no=-1;
  125.  
  126. /* Debug output */
  127. void oef_debug(void)
  128. {
  129.   int i,j,n;
  130.   for(i=0;i<define_no;i++) {
  131.     printf("%s: ",directives[define[i].type].name);
  132.     n=directives[define[i].type].parmcnt;
  133.     for(j=0;j<n;j++) {
  134.       printf("%s",define[i].parm[j]);
  135.       if(j<n-1) printf(", ");
  136.     }
  137.     printf("\n");
  138.   }
  139. }
  140.  
  141. /* get one input file */
  142. long int getinp(char fname[])
  143. {
  144.   FILE *input;
  145.   long int siz;
  146.   int i;
  147.  
  148.   input=fopen(fname,"r");
  149.   if(input==NULL) return 0;
  150.   fseek(input,0L,SEEK_END); siz=ftell(input);
  151.   if(siz<=0 || siz>=MAX_FLEN) {
  152.     fclose(input);
  153.     if(siz==0) return 0; else return -1;
  154.   }
  155.   fseek(input,0L,SEEK_SET);
  156.   inpbuf=xmalloc(siz+10);
  157.   siz=fread(inpbuf,1,siz,input); fclose(input);
  158.   if(siz<=0) return -1;
  159.   inpend=inpbuf+siz; *inpend=0;
  160.   for(i=0;i<siz;i++)
  161.     if(inpbuf[i]==13 || (inpbuf[i]>=0 && inpbuf[i]<=6)) inpbuf[i]=' ';
  162.   return siz;
  163. }
  164.  
  165. /* Processes input file */
  166. void process(void)
  167. {
  168.   char *p, *pe, *pp;
  169.   int i,j;
  170.  
  171.   for(p=inpbuf,define_no=0;define_no<MAX_DEFINE && p<inpend;p++) {
  172.     if(*p!='\\' && *p!='{' && (*p>6 || *p<0)) continue;
  173.     if(*p>0 && *p<=6) {
  174.       pe="";
  175.       switch(*p) {
  176.         case elsechar: pe="else"; break;
  177.         case endifchar: pe="endif"; break;
  178.         case nextchar: pe="next"; break;
  179.         case whilechar: pe="endwhile"; break;
  180.       }
  181.       define[define_no].tag=posttag;
  182.       define[define_no++].type=search_list(directives,dir_no,sizeof(directives[0]),pe);
  183.       continue;
  184.     }
  185.     if(*p=='{') {
  186.       if((p=find_matching(p+1,'}'))==NULL) oef_error("Unmatched parentheses???");
  187.       continue;
  188.     }
  189.     p++;
  190.     for(pe=p;isalnum(*pe) || *pe=='_'; pe++);
  191.     pp=find_word_start(pe);
  192.     if(*pp!='{') {
  193.       if(pp>p) p=pp-1;
  194.         continue;
  195.     }
  196. /*c=*pe; */*pe=0;
  197.     i=search_list(directives,dir_no,sizeof(directives[0]),p);
  198.     if(i<0) {
  199.       if(wordchr(mdef,p)!=NULL) {
  200.         pe=find_matching(pp+1,'}'); if(pe==NULL) oef_error("Unmatched parentheses?");
  201.         *pe=0;define[define_no].type=
  202.               search_list(directives,dir_no,sizeof(directives[0]),"mdef");
  203.         replace_newline(pp+1);
  204.         define[define_no].tag=posttag;
  205.         define[define_no].parm[0]=p;
  206.         define[define_no].parm[1]=pp+1;
  207.         define_no++; p=pe;
  208.         continue;
  209.       }
  210.       if((p=find_matching(pp+1,'}'))==NULL) oef_error("Unmatched parentheses?");
  211.         continue;
  212.     }
  213.     define[define_no].type=i;
  214.     define[define_no].tag=posttag;
  215.     for(j=0;j<MAX_PARM && j<directives[i].parmcnt;j++,pp=find_word_start(pe+1)) {
  216.       if(j>0 && *pp!='{') break;
  217.       if((pe=find_matching(pp+1,'}'))==NULL) oef_error("Unmatched parentheses?");
  218.       *pe=0; replace_newline(pp+1);
  219.       define[define_no].parm[j]=pp+1;
  220.     }
  221.     for(;j<MAX_PARM;j++) define[define_no].parm[j]="";
  222.     switch(directives[i].type) {
  223.       case t_tit: {
  224.         title_no=define_no; break;
  225.       }
  226.       case t_head2: case t_lang: {
  227.         define[define_no].parm[1]=directives[i].name;
  228.         break;
  229.       }
  230.       case t_ans: {
  231.         if(aocnt<256) ao[aocnt++]=t_ans;
  232.         answercnt++; goto checkeq;
  233.       }
  234.       case t_step: {
  235.         if(step_defined) oef_error("Multiple definition of steps.");
  236.         step_defined=1; break;
  237.       }
  238.       case t_def: {
  239.         char *pt;
  240.         if(directives[i].parmcnt<2) {
  241.           char *pt2, *pt3;
  242.           pt=find_word_start(pe+1); pt3="";
  243.           if(*pt!='{') pt2=pt;
  244.           else {
  245.             *pt=' '; pt2=find_matching(pt,'}');
  246.             if(pt2==NULL) oef_error("Unmatched parentheses?");
  247.             pt3=find_word_start(pt2+1);
  248.           }
  249.           if(strcmp(directives[i].name,"if")==0 || strcmp(directives[i].name,"ifval")==0) {
  250.             if(*pt3=='{') {
  251.               *pt2=elsechar; *pt3=' ';
  252.               pt2=find_matching(pt3,'}');
  253.               if(pt2==NULL) oef_error("Unmatched parentheses?");
  254.             }
  255.             *pt2=endifchar;
  256.           }
  257.           else {
  258.             if(strcmp(directives[i].name,"while")==0) *pt2=whilechar;
  259.             else {
  260.               varcnt++; *pt2=nextchar;
  261.             }
  262.           }
  263.           break;
  264.         }
  265.         varcnt++;
  266.         checkeq:
  267.         if(*(define[define_no].parm[1])==0 &&
  268.            (pt=strchr(define[define_no].parm[0],'='))!=NULL) {
  269.           if(*(pt-1)==':') *(pt-1)=0;
  270.           *pt=0; define[define_no].parm[1]=pt+1;
  271.         }
  272.         break;
  273.       }
  274.       case t_choi: {
  275.         if(aocnt<256) ao[aocnt++]=t_choi;
  276.         choicecnt++; break;
  277.       }
  278.       case t_cond: {
  279.         conditioncnt++; break;
  280.       }
  281.       case t_main: {
  282.         if(posttag) oef_error("Multiple definition of statement.");
  283.         posttag=1; if(prevarcnt<0) prevarcnt=varcnt;
  284.         statement_no=define_no; break;
  285.       }
  286.       case t_plot: {
  287.         has_plot=1; break;
  288.       }
  289.       case t_form: {
  290.         char *s=define[define_no].parm[0];
  291.         s=find_word_start(s);*find_word_end(s)=0;
  292.         if(strcasecmp(s,"html")==0) format="html";
  293.         if(strcasecmp(s,"tex")==0) format="tex";
  294.         break;
  295.       }
  296.       case t_feedback: {
  297.         feedbackcnt++; break;
  298.       }
  299.     }
  300.     define_no++; p=pe;
  301.   }
  302. }
  303.  
  304. /* Output one category */
  305. void _out(int typ)
  306. {
  307.   int i, t;
  308.   for(i=0;i<define_no;i++) {
  309.     t=define[i].type;
  310.     if(directives[t].type!=typ) continue;
  311.     if(typ==t_def && define[i].tag!=deftag) continue;
  312.     directives[t].processor(define[i].parm);
  313.   }
  314. }
  315.  
  316. /* Output the result */
  317. void output(void)
  318. {
  319.   int i,k;
  320. /* no statement, nothing to do */
  321.   if(statement_no<0) oef_error("No statement defined.");
  322.   outf=fopen(outfname,"w"); if(outf==NULL) oef_error("Unable to open output file.");
  323.   if(title_no>=0 && *(define[title_no].parm[0])!=0) {
  324.     char *p=define[title_no].parm[0];
  325.     if(strlen(p)>MAX_TITLEN) *(p+MAX_TITLEN)=0;
  326.     fprintf(outf,"!set title=%s\n",p);
  327.   }
  328.   else {
  329.     fprintf(outf,"!set title=No title\n");
  330.   }
  331.   fprintf(outf,"!if $wims_read_parm!=$empty\n\
  332. !goto $wims_read_parm\n\
  333. !endif\n");
  334.   fprintf(outf,"oef2wims_version=%s\n",VERSION);
  335.   _out(t_head2);
  336.   _out(t_head);
  337.   _out(t_lang);
  338.   if(aocnt>0) {
  339.     int i;
  340.     fprintf(outf,"\nansorder=");
  341.     for(i=0;i<aocnt;i++) {
  342.       if(ao[i]==t_ans) fprintf(outf,"r");
  343.       else fprintf(outf,"c");
  344.       if(i<aocnt-1) fprintf(outf,",");
  345.     }
  346.   }
  347.   if(prevarcnt<varcnt) post=varcnt-prevarcnt; else post=0;
  348.   fprintf(outf,"\n\
  349. varcnt=%d\n\
  350. prevarcnt=%d\n\
  351. postvarcnt=%d\n\
  352. replycnt=%d\n\
  353. choicecnt=%d\n\
  354. conditioncnt=%d\n\
  355. feedbackcnt=%d\n\
  356. format=%s\n\n\
  357. val1=$imagedir\n\
  358. val2=$confparm1\n\
  359. val3=$confparm2\n\
  360. val4=$confparm3\n\
  361. val5=$confparm4\n\n\
  362. !if $testcondition=yes\n\
  363. !goto test\n\
  364. !endif\n\
  365. !if $status=waiting\n\
  366. !exit\n\
  367. !endif\n\n",varcnt+1,prevarcnt,post,answercnt,choicecnt,
  368.           conditioncnt,feedbackcnt,format);
  369.   varcnt=start_varcnt; deftag=0;
  370.   _out(t_def);
  371.   _out(t_step);
  372. /*    _out(t_wims); */
  373.   _out(t_plot);
  374.   answercnt=1; _out(t_ans);
  375.   choicecnt=1; _out(t_choi);
  376.   deftag=1; prevars=varcnt;
  377.   _out(t_main);
  378.   _out(t_hint);
  379.   _out(t_help);
  380.   _out(t_sol);
  381.   _out(t_latex);
  382.   fprintf(outf,"\n!goto stat\n");
  383. /* second run to output execution codes */
  384.   p_statement(NULL);
  385.   p_hint(NULL);
  386.   p_help(NULL);
  387.   p_solution(NULL);
  388.   p_latex(NULL);
  389.   if(post) {
  390.     fprintf(outf,"\n!exit\n\n:postdef\n"); _out(t_def);
  391.   }
  392.   fprintf(outf,"\n!exit\n\n:feedback\n");
  393.   _out(t_feedback);
  394.   fprintf(outf,"\n!exit\n\n:test\n");
  395.   _out(t_cond2); conditioncnt=1; _out(t_cond);
  396.   fprintf(outf,"\n!exit\n\n:stat\nvsavelist=");
  397.   for(k=0,i=1;i<prevars;i++) {
  398.     if(param[i].save==0) continue;
  399.     if(k>0) fprintf(outf,",");
  400.     k++;
  401.     fprintf(outf,"%d",i);
  402.   }
  403.   fprintf(outf,"\nembedcnt=%d\n",embedcnt);
  404.   fclose(outf);
  405. }
  406.  
  407. int main(int argc, char *argv[])
  408. {
  409.   int t;
  410.   sp_error=oef_error;
  411.   substitute=substit;
  412.   if(argc<=1) return 0; /* no input file */
  413.   if(argc==2 && strcmp(argv[1],"table")==0) {
  414.     if(verify_order(directives, dir_no, sizeof(directives[0]))) return -1;
  415.     if(verify_order(specialfn, specialfn_no, sizeof(specialfn[0]))) return -1;
  416.     puts("Table orders OK."); return 0;
  417.   }
  418.   if(argc>2) snprintf(outfname,sizeof(outfname),"%s",argv[2]);
  419.   else {
  420.     char *fe;
  421.     snprintf(outfname,sizeof(outfname)-10,"%s",argv[1]);
  422.     fe=outfname+strlen(outfname)-strlen(".oef");
  423.     if(strcasecmp(fe,".oef")==0) *fe=0;
  424.     strcat(fe,".def");
  425.   }
  426.   mdef=getenv("oef2wims_mdef"); if(mdef==NULL) mdef="";
  427.   printf("%s..",argv[1]);
  428.   t=getinp(argv[1]);
  429.   if(t<0) oef_error("Source file bad or too long.");
  430.   if(t==0) oef_error("Empty source file.");
  431.   if(checkparentheses(inpbuf,1)!=0) oef_error("Unmatched parentheses");
  432.   outf=fopen(outfname,"w"); if(outf==NULL) oef_error("Unable to open output file.");
  433.   fclose(outf); remove(outfname);
  434.   vbuf_statement[0]=vbuf_hint[0]=vbuf_help[0]=vbuf_solution[0]=0;
  435.   param[1].name="imagedir";param[1].type=pt_text;
  436.   param[2].name="confparm1";param[2].type=pt_text;
  437.   param[3].name="confparm2";param[3].type=pt_text;
  438.   param[4].name="confparm3";param[4].type=pt_text;
  439.   param[5].name="confparm4";param[5].type=pt_text;
  440.   start_varcnt=6;
  441.   process();
  442.   output();
  443.   printf(" -> %s\n",outfname);
  444.   return 0;
  445. }
  446.