Rev 11123 | Rev 13380 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9095 | bpr | 1 | /* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis |
10 | reyssat | 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 |
||
9095 | bpr | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | reyssat | 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 | |||
9095 | bpr | 20 | #define MAX_TITLEN 60 |
8135 | bpr | 21 | |
9095 | bpr | 22 | #define MAX_PARM 10 |
23 | #define MAX_PARAM 1024 |
||
24 | #define MAX_DEFINE 1024 |
||
10 | reyssat | 25 | #define MAX_FLEN 199999 |
8135 | bpr | 26 | |
10 | reyssat | 27 | #define VERSION "3.22" |
28 | |||
8135 | bpr | 29 | |
10 | reyssat | 30 | #include "../Lib/libwims.h" |
8135 | bpr | 31 | #include "oef2wims.h" |
10 | reyssat | 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; |
||
7677 | bpr | 42 | char *mdef; /* external definition */ |
10 | reyssat | 43 | char *format="html"; |
44 | |||
45 | int ao[256]; |
||
46 | int aocnt=0; |
||
47 | |||
8135 | bpr | 48 | struct param param[MAX_PARAM+32]; |
10 | reyssat | 49 | |
50 | char *inpbuf, *inpend; |
||
51 | char outfname[1024]; |
||
52 | |||
9095 | bpr | 53 | enum {t_tit, t_head, t_head2, t_lang, t_def, t_wims, t_form, t_main, t_plot, t_hint, |
2656 | bpr | 54 | t_ans, t_choi, t_cond, t_cond2, t_sol, t_feedback, t_help, t_step, t_latex}; |
10 | reyssat | 55 | |
56 | struct { |
||
12247 | bpr | 57 | char *name; |
58 | int type, parmcnt; |
||
59 | void (*processor)(char *p[MAX_PARM]); |
||
10 | reyssat | 60 | } directives[]={ |
12247 | bpr | 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} |
||
10 | reyssat | 116 | }; |
117 | |||
118 | #define dir_no (sizeof(directives)/sizeof(directives[0])) |
||
119 | |||
120 | struct { |
||
12247 | bpr | 121 | char *parm[MAX_PARM]; |
122 | short int type, tag; |
||
10 | reyssat | 123 | } define[MAX_DEFINE]; |
124 | int define_no, title_no=-1, statement_no=-1; |
||
125 | |||
7677 | bpr | 126 | /* Debug output */ |
8918 | bpr | 127 | void oef_debug(void) |
10 | reyssat | 128 | { |
12247 | bpr | 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(", "); |
||
10 | reyssat | 136 | } |
12247 | bpr | 137 | printf("\n"); |
138 | } |
||
10 | reyssat | 139 | } |
140 | |||
7677 | bpr | 141 | /* get one input file */ |
10 | reyssat | 142 | long int getinp(char fname[]) |
143 | { |
||
12247 | bpr | 144 | FILE *input; |
145 | long int siz; |
||
146 | int i; |
||
7677 | bpr | 147 | |
12247 | bpr | 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; |
||
10 | reyssat | 163 | } |
164 | |||
7677 | bpr | 165 | /* Processes input file */ |
10 | reyssat | 166 | void process(void) |
167 | { |
||
12247 | bpr | 168 | char *p, *pe, *pp; |
169 | int i,j; |
||
7677 | bpr | 170 | |
12247 | bpr | 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; |
||
7677 | bpr | 180 | } |
12247 | bpr | 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 | } |
||
7677 | bpr | 196 | /*c=*pe; */*pe=0; |
12247 | bpr | 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= |
||
7677 | bpr | 202 | search_list(directives,dir_no,sizeof(directives[0]),"mdef"); |
12247 | bpr | 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; |
||
7677 | bpr | 209 | } |
12247 | bpr | 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; |
||
7677 | bpr | 225 | } |
12247 | bpr | 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); |
||
7677 | bpr | 248 | } |
12247 | bpr | 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; |
||
7677 | bpr | 256 | } |
12247 | bpr | 257 | else { |
258 | if(strcmp(directives[i].name,"while")==0) *pt2=whilechar; |
||
259 | else { |
||
260 | varcnt++; *pt2=nextchar; |
||
7677 | bpr | 261 | } |
262 | } |
||
12247 | bpr | 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; |
||
7677 | bpr | 273 | } |
12247 | bpr | 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 | } |
||
10 | reyssat | 299 | } |
12247 | bpr | 300 | define_no++; p=pe; |
301 | } |
||
10 | reyssat | 302 | } |
303 | |||
7677 | bpr | 304 | /* Output one category */ |
10 | reyssat | 305 | void _out(int typ) |
306 | { |
||
12247 | bpr | 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 | } |
||
10 | reyssat | 314 | } |
315 | |||
7677 | bpr | 316 | /* Output the result */ |
10 | reyssat | 317 | void output(void) |
318 | { |
||
12247 | bpr | 319 | int i,k; |
7677 | bpr | 320 | /* no statement, nothing to do */ |
12247 | bpr | 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\ |
||
10 | reyssat | 332 | !goto $wims_read_parm\n\ |
333 | !endif\n"); |
||
12247 | bpr | 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,","); |
||
10 | reyssat | 345 | } |
12247 | bpr | 346 | } |
347 | if(prevarcnt<varcnt) post=varcnt-prevarcnt; else post=0; |
||
348 | fprintf(outf,"\n\ |
||
10 | reyssat | 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, |
||
7677 | bpr | 368 | conditioncnt,feedbackcnt,format); |
12247 | bpr | 369 | varcnt=start_varcnt; deftag=0; |
370 | _out(t_def); |
||
371 | _out(t_step); |
||
7677 | bpr | 372 | /* _out(t_wims); */ |
12247 | bpr | 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"); |
||
7677 | bpr | 383 | /* second run to output execution codes */ |
12247 | bpr | 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); |
||
10 | reyssat | 405 | } |
406 | |||
407 | int main(int argc, char *argv[]) |
||
408 | { |
||
12247 | bpr | 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; |
||
10 | reyssat | 445 | } |