/* main CAPA parser Copyright (C) 1992-2000 Michigan State University The CAPA system is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The CAPA system is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the CAPA system; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, you have permission to link this program with the TtH/TtM library and distribute executables, as long as you follow the requirements of the GNU GPL in regard to all of the software in the executable aside from TtH/TtM. */ /* ========================================================================== */ /* capaGrammarDef.y created by Isaac Tsai */ /* 1998, 1999 by Isaac Tsai */ /* no longer there is a length constrain on string concatenation July 13 1998 */ /* /RMAP() function */ /* TODO: new mechanism to collect answer informations */ /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ %{ #include #include #include #include #include "capaParser.h" /* _symbol structure def */ #include "capaCommon.h" #include "capaFunction.h" #include "capaRQO.h" #ifdef __hpux #include #include #endif #ifdef YACC_DBUG #define YYDBUG_PR1(xx) { printf(xx); fflush(stdout); } #define YYDBUG_PR2(xx,yy) { printf(xx,yy); fflush(stdout); } #define YYDBUG_PR3(xx,yy,zz) { printf(xx,yy,zz); fflush(stdout); } #define YYDBUG_PR4(xx,yy,zz,aa) { printf(xx,yy,zz,aa); fflush(stdout); } #define YYDBUG_SYM(xx) { switch((xx)->s_type) { \ case IDENTIFIER: \ printf("ID(%s)\n",(xx)->s_name); break; \ case I_VAR: case I_CONSTANT: \ printf("INT(%d)\n",(xx)->s_int); break; \ case R_VAR: case R_CONSTANT: \ printf("REAL(%.16g)\n",(xx)->s_real); break; \ case S_VAR: case S_CONSTANT: \ printf("STR(%s)\n",(xx)->s_str); break; \ } } #else /* YACC_DBUG */ #define YYDBUG_PR1(xx) { } #define YYDBUG_PR2(xx,yy) { } #define YYDBUG_PR3(xx,yy,zz) { } #define YYDBUG_PR4(xx,yy,zz,aa) { } #define YYDBUG_SYM(xx) { } #endif /* YACC_DBUG */ int yylex(); void yyerror(char*); void free_calc_expr(Symbol*); void assign_pts (Symbol *, Symbol *, Symbol *); /******************************************************************************/ /* GLOBAL VARIABLES */ /******************************************************************************/ int Lexi_qnum; extern int Lexi_line; extern int Lexi_pos[MAX_OPENED_FILE]; extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K]; extern int Input_idx; int Current_line[MAX_OPENED_FILE]; extern int Func_idx; extern Symbol FuncStack[MAX_FUNC_NEST]; extern int IFstatus[MAX_FUNC_NEST]; extern int IFcount; extern int gUnitError; int Parsemode_f; /* Parser mode flag */ Problem_t *FirstProblem_p; /* First problem */ Problem_t *LastProblem_p; /* Last problem */ Problem_t *LexiProblem_p; /* Current problem */ char *EndText_p; char *StartText_p; char *ErrorMsg_p; int ErrorMsg_count; WarnMsg_t *WarnMsg_p; int WarnMsg_count; int Answer_infospec; void (*Status_Func)(); AnswerInfo_t CurrAnsInfo; RandQO_t *QuestionOrder; PointsList_t *CurrPtsList; PointsList_t *LastPtsList; #ifdef YYSTYPE #undef YYSTYPE #endif #define YYSTYPE Symbol_p #define ADD_op 1 #define SUB_op 2 #define MUL_op 3 #define DIV_op 4 #define IDIV_op 5 #define NOT_DEFINED_op 9 /*#define yyerror printf*/ %} %token NEW_ID %token I_CONSTANT R_CONSTANT S_CONSTANT %token I_VAR R_VAR S_VAR %token IDENTIFIER FUNCTION_ID ARRAY_ID %token HINT_LINE EXPLAIN_LINE TEXT_LINE IMPORT_LINE %token CAPA_LET CAPA_DEF CAPA_DIS CAPA_END CAPA_VAR %token CAPA_ESC CAPA_MAP CAPA_FIG CAPA_ANS CAPA_RMAP %token CAPA_IF CAPA_ELSE CAPA_ENDIF CAPA_SUBJ CAPA_WHILE %token CAPA_RQO CAPA_ENDWHILE CAPA_START %token ANS_AND ANS_BOX_SHOW ANS_CALC ANS_CI ANS_COMPARE ANS_CS %token ANS_EVAL ANS_EXPLAIN ANS_EXTERNAL ANS_FMT %token ANS_FORMULA ANS_HINT ANS_MC ANS_MINUS %token ANS_OFF ANS_ON ANS_OR ANS_ORDERED %token ANS_PATH ANS_PCREDIT ANS_PLUS ANS_RANGE %token ANS_SHOW_BR ANS_SIG ANS_TOLERANCE ANS_TRY ANS_TYPE %token ANS_UNFMT ANS_UNIT ANS_VERBATIM ANS_WEIGHT %token VAR_RANGE VERBATIM %token SLASH FORMAT %token EQ_op NE_op GT_op GE_op LT_op LE_op AND_op OR_op EoL %start prob_set %% prob_set : startQ questions CAPA_END { YYDBUG_PR1(" prob_set := startQ questions END\n\n"); } ; questions : a_line { YYDBUG_PR1(" questions <= a_line"); if (Status_Func != NULL) Status_Func(); } | questions a_line { YYDBUG_PR1(" questions <= questions a_line"); if (Status_Func != NULL) Status_Func(); } ; startL : CAPA_LET { YYDBUG_PR1("\n begin_let::"); } ; startV : CAPA_VAR { YYDBUG_PR1(" begin_var"); } ; startA : CAPA_ANS { YYDBUG_PR1("\n START ANSWER(/ANS)::\n"); init_answerinfo(); } ; startSA : CAPA_SUBJ { YYDBUG_PR1("\n START SUBJECT ANSWER(/SUBJECTIVE)::\n"); init_answerinfo(); } ; startM : CAPA_MAP { YYDBUG_PR1("\n begin_map::"); } ; startR : CAPA_RMAP { YYDBUG_PR1("\n begin_rmap::"); } ; startRQO : CAPA_RQO { YYDBUG_PR1("\n begin_rqo::"); } ; ans_and_op : ANS_AND { add_answer_cnt(ANS_AND); YYDBUG_PR1("(AND ,new an answer info)"); } ; ans_or_op : ANS_OR { add_answer_cnt(ANS_OR); YYDBUG_PR1("(OR ,new an answer info)"); } ; a_line : startL statement EoL { YYDBUG_PR1(" a_line <= startL statement CR\n"); } | CAPA_END { YYDBUG_PR1(" a_line <= END\n\n"); } | startRQO rqo_def EoL { YYDBUG_PR1(" aline <= CAPA_RQO\n"); rqo_finish(); } | CAPA_START { YYDBUG_PR1(" aline <= CAPA_START\n"); start_question_over(); } | HINT_LINE { append_hint($1->s_str); YYDBUG_PR2(" a_line <= Hint_line(%s)\n",$1->s_str); capa_mfree($1->s_str); capa_mfree((char *)$1); } | EXPLAIN_LINE { append_explain($1->s_str); YYDBUG_PR2(" a_line <= Explain_line(%s)\n",$1->s_str); capa_mfree($1->s_str); capa_mfree((char*)$1); } | IMPORT_LINE EoL { YYDBUG_PR1(" a_line <= import_line CR\n"); } | q_text EoL { YYDBUG_PR1(" a_line <= Qtext CR\n"); append_text("\n"); } | answer_expr { YYDBUG_PR1(" a_line <= answer_expr (init a new prob) CR\n"); init_new_prob(); } | if_expr { YYDBUG_PR1(" a_line <= if_expr\n"); } | while_expr { YYDBUG_PR1(" a_line <= while_expr\n"); } | map_expr EoL { YYDBUG_PR1(" a_line <= map_expr CR\n"); } | EoL { YYDBUG_PR1(" a_line <= (CR)\n"); } | VERBATIM { YYDBUG_PR1(" a_line <= (VERBATIM)\n"); switch(Parsemode_f) { case TeX_MODE: append_text("\\begin{verbatim}"); break; case HTML_MODE: append_text("
");
					    break;
					  }
                                          append_text($1->s_str);
                                          capa_mfree($1->s_str); capa_mfree((char *)$1);
	                                  switch(Parsemode_f) {
					  case TeX_MODE: append_text("\\end{verbatim}\n");
					    break;
					  case HTML_MODE: append_text("
\n"); break; } } | error EoL { char warn_msg[WARN_MSG_LENGTH]; YYDBUG_PR1(" a_line := ERROR(CR)\n"); sprintf(warn_msg," Question %d: Syntax error.\n", Lexi_qnum+1); capa_msg(MESSAGE_ERROR,warn_msg); begin_text(); } ; statement : IDENTIFIER '=' calc_expr { char warn_msg[WARN_MSG_LENGTH]; if ( $1 != $3 ) { /* /LET a = a */ switch($1->s_type) { case IDENTIFIER: case I_VAR: case I_CONSTANT: case R_VAR: case R_CONSTANT: break; case S_VAR: case S_CONSTANT: /* free up original used spaces */ capa_mfree($1->s_str); $1->s_str = NULL; break; default: break; } switch($3->s_type) { case IDENTIFIER: sprintf(warn_msg,"var \"%s\" not defined before use.\n",$3->s_name); capa_msg(MESSAGE_ERROR,warn_msg); break; case I_VAR: case I_CONSTANT: $1->s_type = I_VAR; $1->s_int = $3->s_int; break; case R_VAR: case R_CONSTANT: $1->s_type = R_VAR; $1->s_real = $3->s_real; break; case S_VAR: case S_CONSTANT: $1->s_type = S_VAR; $1->s_str = strsave($3->s_str); break; } YYDBUG_PR1(" statement <= ID = calc_expr:: "); YYDBUG_SYM($3); free_calc_expr($3); } } | ARRAY_ID '[' calc_expr ']' '=' calc_expr { Symbol *s_p; char warn_msg[WARN_MSG_LENGTH]; s_p = get_array_symbol($1,$3,1); switch(s_p->s_type) { case IDENTIFIER: case I_VAR: case I_CONSTANT: case R_VAR: case R_CONSTANT: break; case S_VAR: case S_CONSTANT: capa_mfree(s_p->s_str); s_p->s_str = NULL; break; default: break; } switch($6->s_type) { case IDENTIFIER: sprintf(warn_msg,"var \"%s\" not defined before use.\n",$6->s_name); capa_msg(MESSAGE_ERROR,warn_msg); break; case I_VAR: case I_CONSTANT: s_p->s_type = I_VAR; s_p->s_int = $6->s_int; break; case R_VAR: case R_CONSTANT: s_p->s_type = R_VAR; s_p->s_real = $6->s_real; break; case S_VAR: case S_CONSTANT: s_p->s_type = S_VAR; s_p->s_str = strsave($6->s_str); break; } free_calc_expr($6); } ; rqo_def : rqo_speca { rqo_1spec(); } | rqo_speca ',' rqo_def { rqo_2spec(); } ; rqo_speca : an_integer {start_rqo_type(SINGLE);append_rqo($1);} | an_integer '!' {start_rqo_type(IMMOBILE);append_rqo($1);} | an_integer '-' an_integer {start_rqo_type(RANGE);append_rqo($1); append_rqo($3); } | an_integer '~' rqo_specb {prefix_rqo($1);} | an_integer '+' rqo_specc {prefix_rqo($1);} ; rqo_specb : an_integer {start_rqo_type(ALL_MIX);append_rqo($1);} | an_integer '~' rqo_specb {prefix_rqo($1);} | an_integer '+' an_integer {start_rqo_type(LAST_FIXED);append_rqo($1); append_rqo($3);} ; rqo_specc : an_integer {start_rqo_type(ALL_FIXED);append_rqo($1);} | an_integer '+' rqo_specd {prefix_rqo($1);} | an_integer '~' rqo_spece {prefix_rqo($1);} ; rqo_specd : an_integer {start_rqo_type(ALL_FIXED);append_rqo($1);} | an_integer '+' rqo_specd {prefix_rqo($1);} ; rqo_spece : an_integer {start_rqo_type(FIRST_FIXED);append_rqo($1);} | an_integer '~' rqo_spece {prefix_rqo($1);} | an_integer '+' an_integer {start_rqo_type(BOTH_FIXED);append_rqo($1); append_rqo($3);} ; q_text : TEXT_LINE { append_text($1->s_str); capa_mfree($1->s_str); capa_mfree((char *)$1); } | var_expr { } | q_text var_expr { } | q_text TEXT_LINE { append_text($2->s_str); capa_mfree($2->s_str); capa_mfree((char *)$2); } ; if_expr : CAPA_IF '(' calc_expr ')' { int leng=0; /* begin_next_line(); no use, can be get rid of */ YYDBUG_PR2("(IF expr )\n",IFcount); switch($3->s_type) { case IDENTIFIER: IFstatus[IFcount] = IF_FALSE; begin_next_line(); break; case I_CONSTANT: case I_VAR: if(!$3->s_int) { IFstatus[IFcount] = IF_FALSE; begin_if_skip(); } else { IFstatus[IFcount] = IF_TRUE; begin_next_line(); } break; case R_CONSTANT: case R_VAR: if($3->s_real == 0.0) { IFstatus[IFcount] = IF_FALSE; begin_if_skip(); }else{ IFstatus[IFcount] = IF_TRUE; begin_next_line(); } break; case S_CONSTANT: if ( $3->s_str) { leng = strlen($3->s_str); capa_mfree($3->s_str); } if(leng == 0) { IFstatus[IFcount] = IF_FALSE; begin_if_skip(); }else{ IFstatus[IFcount] = IF_TRUE; begin_next_line(); } break; case S_VAR: if ( $3->s_str) { leng = strlen($3->s_str); capa_mfree($3->s_str); } if(leng == 0) { IFstatus[IFcount] = IF_FALSE; begin_if_skip(); }else{ IFstatus[IFcount] = IF_TRUE; begin_next_line(); } break; } capa_mfree((char*)$3); } ; while_expr : CAPA_WHILE '(' calc_expr ')' { int leng; YYDBUG_PR1("(WHILE expr)\n"); switch($3->s_type) { case IDENTIFIER: /* undefined identifier regarded as false */ begin_while_skip(); break; case I_CONSTANT: case I_VAR: if(!$3->s_int) { begin_while_skip(); } else { begin_next_line(); /* skip to EoL and begin S_TEXT */ } break; case R_CONSTANT: case R_VAR: if($3->s_real == 0.0) { begin_while_skip(); }else{ begin_next_line(); /* skip to EoL and begin S_TEXT */ } break; case S_CONSTANT: leng = strlen($3->s_str); capa_mfree($3->s_str); if(leng == 0) { begin_while_skip(); }else{ begin_next_line(); /* skip to EoL and begin S_TEXT */ } break; case S_VAR: leng = strlen($3->s_str); if(leng == 0) { begin_while_skip(); }else{ begin_next_line(); /* skip to EoL and begin S_TEXT */ } break; } capa_mfree((char*)$3); } ; var_expr : startV '(' formated_ans ')' { display_var( $3 ) ; } ; answer_expr : answer_spec { finish_answer_info(); } | answer_expr ans_and_op answer_spec { finish_answer_info(); YYDBUG_PR1(" answer_expr <-- AND answers (copy answerinfo)\n"); } | answer_expr ans_or_op answer_spec { finish_answer_info(); YYDBUG_PR1(" answer_expr <-- OR answers (copy answerinfo)\n"); } | startSA '(' answer_info ')' { YYDBUG_PR1("\n subjective answer\n"); finish_answer_info(); LexiProblem_p->ans_type = ANSWER_IS_SUBJECTIVE; } | startSA '(' ')' { YYDBUG_PR1("\n subjective answer\n"); finish_answer_info(); LexiProblem_p->ans_type = ANSWER_IS_SUBJECTIVE; } ; answer_spec : startA '(' formated_ans ')' { assign_answer( $3 ); YYDBUG_PR1("\nASSIGN Answer\n"); } | startA '(' formated_ans ',' answer_info ')' { assign_answer( $3 ); YYDBUG_PR1("\nASSIGN Answers + Answer Info\n"); } ; answer_info : ans_infospec | answer_info ',' ans_infospec ; ans_infospec : ANS_TOLERANCE '=' a_number { YYDBUG_PR1(" ans_infospec:= TOL=a_number"); assign_tolerance(TOL_ABSOLUTE,$3); } | ANS_TOLERANCE '=' IDENTIFIER { assign_tolerance(TOL_ABSOLUTE,$3); } | ANS_TOLERANCE '=' IDENTIFIER '%' { assign_tolerance(TOL_PERCENTAGE,$3); } | ANS_TOLERANCE '=' a_number '%' { assign_tolerance(TOL_PERCENTAGE,$3); } | ANS_COMPARE '=' answer_comp { } | ANS_SIG '=' answer_sig { } | ANS_WEIGHT '=' an_integer { assign_weight( $3 ); } | ANS_WEIGHT '=' IDENTIFIER { assign_weight( $3 ); } | ANS_HINT '=' an_integer { assign_hint( $3 ); } | ANS_HINT '=' IDENTIFIER { assign_hint( $3 ); } | ANS_PCREDIT '=' ANS_ON { LexiProblem_p->partial_cdt = 1; } | ANS_PCREDIT '=' ANS_OFF { LexiProblem_p->partial_cdt = 0; } | ANS_SHOW_BR '=' ANS_ON { LexiProblem_p->show_br = DO_SHOW; } | ANS_SHOW_BR '=' ANS_OFF { LexiProblem_p->show_br = DONOT_SHOW; } | ANS_VERBATIM '=' ANS_ON { LexiProblem_p->verbatim = DO_VERBATIM; } | ANS_VERBATIM '=' ANS_OFF { LexiProblem_p->verbatim = DONOT_VERBATIM; } | ANS_BOX_SHOW '=' ANS_ON { LexiProblem_p->show_ans_box = DO_SHOW; } | ANS_BOX_SHOW '=' ANS_OFF { LexiProblem_p->show_ans_box = DONOT_SHOW; } | ANS_CALC '=' ANS_FMT { CurrAnsInfo.ans_calc = CALC_FORMATED; } | ANS_CALC '=' ANS_UNFMT { CurrAnsInfo.ans_calc = CALC_UNFORMATED; } | ANS_TRY '=' an_integer { assign_try_limits( $3 ); } | ANS_TRY '=' IDENTIFIER { assign_try_limits( $3 ); } | ANS_UNIT '=' S_CONSTANT { assign_units( $3 ); capa_mfree($3->s_str); capa_mfree((char *)$3); } | ANS_UNIT '=' IDENTIFIER { assign_units( $3 ); } | ANS_EVAL '=' var_range { CurrAnsInfo.ans_pts_list = CurrPtsList; CurrPtsList=NULL; LastPtsList = NULL; } ; var_range : '<' S_CONSTANT '@' pt_list '>' { assign_id_list( $2 ); capa_mfree($2->s_str); capa_mfree((char *)$2); } | '<' IDENTIFIER '@' pt_list '>' { assign_id_list( $2 ); } ; pt_list : pt_list ',' point_coord { int idx; idx = LastPtsList->pts_idx; idx++; LastPtsList->pts_next = new_ptslist( $3 ); LastPtsList = LastPtsList->pts_next; LastPtsList->pts_idx = idx; CurrPtsList->pts_idx = idx; if( $3->s_type == S_CONSTANT ) { capa_mfree($3->s_str); capa_mfree((char *)$3); } } | pt_list ',' pt_range { } | point_coord { CurrPtsList = new_ptslist( $1 ); LastPtsList = CurrPtsList; if( $1->s_type == S_CONSTANT ) { capa_mfree($1->s_str); capa_mfree((char *)$1); } } | pt_range { } ; pt_range : point_coord ':' point_coord '#' IDENTIFIER { assign_pts($1,$3,$5); /*PointsList_t *pt; if( LastPtsList != NULL ) { LastPtsList->pts_next = gen_ptslist( $1, $3, $5 ); pt = LastPtsList->pts_next; while( pt->pts_next != NULL ) { pt = pt->pts_next; } LastPtsList = pt; } else { CurrPtsList = gen_ptslist( $1, $3, $5 ); LastPtsList = CurrPtsList; } if( $1->s_type == S_CONSTANT ) { capa_mfree($1->s_str); capa_mfree((char *)$1); } if( $3->s_type == S_CONSTANT ) { capa_mfree($3->s_str); capa_mfree((char *)$3); } */ } | point_coord ':' point_coord '#' ARRAY_ID '[' calc_expr ']' { assign_pts($1,$3,get_array_symbol($5,$7,1)); } | point_coord ':' point_coord '#' a_number { assign_pts($1,$3,$5); /*PointsList_t *pt; if( LastPtsList != NULL ) { LastPtsList->pts_next = gen_ptslist( $1, $3, $5 ); pt = LastPtsList->pts_next; while( pt->pts_next != NULL ) { pt = pt->pts_next; } LastPtsList = pt; } else { CurrPtsList = gen_ptslist( $1, $3, $5 ); LastPtsList = CurrPtsList; } if( $1->s_type == S_CONSTANT ) { capa_mfree($1->s_str); capa_mfree((char *)$1); } if( $3->s_type == S_CONSTANT ) { capa_mfree($3->s_str); capa_mfree((char *)$3); } if( $5->s_type == I_CONSTANT || $5->s_type == R_CONSTANT) { capa_mfree((char *)$5); } */ } ; point_coord : IDENTIFIER { $$ = $1; } | ARRAY_ID '[' calc_expr ']' { $$ = get_array_symbol($1,$3,1); } | S_CONSTANT { $$ = $1; } ; formated_ans : calc_expr { $1->s_distype = DEFAULT_FORMAT; $$ = $1; $1->s_format = NULL; YYDBUG_PR2(" formated_ans := calc_expr (type %d)",$1->s_type); } | calc_expr FORMAT { $1->s_distype = $2->s_distype; $1->s_format = strsave($2->s_str); /* **** */ capa_mfree($2->s_str); capa_mfree((char *)$2); $$ = $1; YYDBUG_PR1(" formated_ans <= calc_expr FORMAT"); } ; answer_sig : an_integer { assign_sigs( $1->s_int,$1->s_int); capa_mfree((char *)$1); } | an_integer ANS_PLUS an_integer { assign_sigs($1->s_int,$1->s_int + $3->s_int); capa_mfree((char *)$1); capa_mfree((char *)$3); } | an_integer ANS_MINUS an_integer { assign_sigs($1->s_int - $3->s_int,$1->s_int); capa_mfree((char *)$1); capa_mfree((char *)$3); } | an_integer ANS_PLUS an_integer ANS_MINUS an_integer { assign_sigs($1->s_int - $5->s_int,$1->s_int + $3->s_int); capa_mfree((char *)$1); capa_mfree((char *)$3); capa_mfree((char *)$5); } | an_integer ANS_MINUS an_integer ANS_PLUS an_integer { assign_sigs($1->s_int - $3->s_int,$1->s_int + $5->s_int); capa_mfree((char *)$1); capa_mfree((char *)$3); capa_mfree((char *)$5); } ; answer_comp : ANS_CS { CurrAnsInfo.ans_type = ANSWER_IS_STRING_CS; } | ANS_CI { CurrAnsInfo.ans_type = ANSWER_IS_STRING_CI; } | ANS_MC { CurrAnsInfo.ans_type = ANSWER_IS_CHOICE; } | ANS_FORMULA { CurrAnsInfo.ans_type = ANSWER_IS_FORMULA; } | ANS_EXTERNAL { CurrAnsInfo.ans_type = ANSWER_IS_EXTERNAL; } ; map_expr : startM '(' basic_constr ';' var_list ';' arg_list ')' { char key[SMALL_LINE_BUFFER]; char warn_msg[WARN_MSG_LENGTH]; int result=0; YYDBUG_PR1(" map_expr body executed\n"); sprintf(key,"%ld",$3->s_int); if( $5->s_argc == $7->s_argc ) { result=do_map(key, $5->s_argp, $7->s_argp, $5->s_argc, FORWARD_MAP); } else { if ($5->s_argc==1) { Symbol *a_sp; a_sp=build_array_list($5,$7->s_argc); result=do_map(key, a_sp->s_argp, $7->s_argp, a_sp->s_argc, FORWARD_MAP); free_arglist(a_sp->s_argp); a_sp->s_argp=NULL; } else { sprintf(warn_msg,"/MAP arg. counts are not matched.\n"); capa_msg(MESSAGE_ERROR,warn_msg); } } if (result!=0) { sprintf(warn_msg, "/MAP had invalid arguments.\n"); capa_msg(MESSAGE_ERROR,warn_msg); } free_arglist($5->s_argp); $5->s_argp=NULL; free_arglist($7->s_argp); $7->s_argp=NULL; } | startR '(' basic_constr ';' var_list ';' arg_list ')' { char key[SMALL_LINE_BUFFER]; char warn_msg[WARN_MSG_LENGTH]; int result=0; YYDBUG_PR1(" rmap_expr body executed\n"); sprintf(key,"%ld",$3->s_int); if( $5->s_argc == $7->s_argc ) { result=do_map(key, $5->s_argp, $7->s_argp, $5->s_argc, REVERSE_MAP); } else { if ($5->s_argc==1) { Symbol *a_sp; a_sp=build_array_list($5,$7->s_argc); result=do_map(key, a_sp->s_argp, $7->s_argp, a_sp->s_argc, FORWARD_MAP); free_arglist(a_sp->s_argp); a_sp->s_argp=NULL; } else { sprintf(warn_msg,"/RMAP arg. counts are not matched.\n"); capa_msg(MESSAGE_ERROR,warn_msg); } } if (result!=0) { sprintf(warn_msg, "/MAP had invalid arguments.\n"); capa_msg(MESSAGE_ERROR,warn_msg); } free_arglist($5->s_argp); $5->s_argp=NULL; free_arglist($7->s_argp); $7->s_argp=NULL; } ; calc_expr : calc_expr EQ_op block { $$ = symbols_op($1, $3, EQ_op); } | calc_expr NE_op block { $$ = symbols_op($1, $3, NE_op); } | calc_expr GE_op block { $$ = symbols_op($1, $3, GE_op); } | calc_expr GT_op block { $$ = symbols_op($1, $3, GT_op); } | calc_expr LE_op block { $$ = symbols_op($1, $3, LE_op); } | calc_expr LT_op block { $$ = symbols_op($1, $3, LT_op); } | calc_expr AND_op block { $$ = symbols_op($1, $3, AND_op); } | calc_expr OR_op block { $$ = symbols_op($1, $3, OR_op); } | block { $$ = $1; YYDBUG_PR1(" calc_expr <= block "); YYDBUG_SYM($1); } ; block : block '+' term { $$ = symbols_op($1, $3, ADD_op); YYDBUG_PR1("block <= block '+' term "); YYDBUG_SYM($$); } | block '-' term { $$ = symbols_op($1, $3, SUB_op); } | term { $$ = $1; YYDBUG_PR2(" block <= term YYSTATE(%d) ",yystate); YYDBUG_SYM($1); } ; term : term '*' basic_constr { $$ = symbols_op($1, $3, MUL_op); } | term '/' basic_constr { $$ = symbols_op($1, $3, DIV_op); } | term '%' basic_constr { $$ = symbols_op($1, $3, IDIV_op); } | basic_constr { $$ = $1; YYDBUG_PR1(" term <= basic_constr "); YYDBUG_SYM($1); } ; basic_constr : FUNCTION_ID '(' ')' { int tmp; Func_idx--; if(Func_idx >= 0 ) { tmp = match_function(FuncStack[Func_idx].s_name,0); $$ = do_function(tmp, 0, NULL ); capa_mfree(FuncStack[Func_idx].s_name); } } | FUNCTION_ID '(' arg_list ')' { int tmp; Func_idx--; YYDBUG_PR4(" basic_constr <= FUNCTION<%s> YYSTATE(%d) ", FuncStack[Func_idx].s_name,$3->s_argc,yystate); if(Func_idx >= 0 ) { tmp = match_function(FuncStack[Func_idx].s_name,$3->s_argc); $$ = do_function(tmp, $3->s_argc, $3->s_argp); capa_mfree(FuncStack[Func_idx].s_name); free_arglist($3->s_argp); $3->s_argp=NULL; } YYDBUG_PR1(" basic_constr <= RETURN FUNCT "); YYDBUG_SYM($$); } | an_array { $$ = $1; } | IDENTIFIER { /* do not free identifier */ $$ = $1; } | '-' basic_constr { $$ = $2; switch($2->s_type) { case I_VAR: $$ = (Symbol *)capa_malloc(sizeof(Symbol),1); $$->s_type = I_CONSTANT; case I_CONSTANT: $$->s_int = - $2->s_int; break; case R_VAR: $$ = (Symbol *)capa_malloc(sizeof(Symbol),1); $$->s_type = R_CONSTANT; case R_CONSTANT: $$->s_real = (-1.0)*($2->s_real); break; case S_VAR: case S_CONSTANT: break; default: break; } } | '+' basic_constr { $$ = $2; } | S_CONSTANT { $$ = $1; } | a_number { $$ = $1; } | '(' calc_expr ')' { $$ = $2; } ; arg_list : arg_list ',' calc_expr { $$ = $1; $$->s_argc++; $$->s_argp = addto_arglist($1->s_argp, $3); } | calc_expr { $$ = $1; $$->s_argc = 1; $$->s_argp = new_arglist($1); } ; var_list : IDENTIFIER { /* do not free identifier */ YYDBUG_PR1(" var_list <= ID"); $$ = $1; $$->s_argc = 1; $$->s_argp = new_arglist($1); } | ARRAY_ID '[' calc_expr ']'{ YYDBUG_PR1(" var_list <= ARRAYID,calc"); $$ = get_array_symbol($1,$3,1); $$->s_argc = 1; $$->s_argp = new_arglist($$); } | var_list ',' ARRAY_ID '[' calc_expr ']' { YYDBUG_PR1(" var_list <= var_list,ARRAYID,calc"); $$ = $1; $$->s_argc++; $$->s_argp = addto_arglist($1->s_argp, get_array_symbol($3,$5,1)); } | var_list ',' IDENTIFIER { /* do not free identifier */ YYDBUG_PR1(" var_list <= var_list,ID"); $$ = $1; $$->s_argc++; $$->s_argp = addto_arglist($1->s_argp, $3); } ; a_number : an_integer { $$ = $1; } | a_real { $$ = $1; } ; an_integer : I_CONSTANT { $$ = $1; } ; a_real : R_CONSTANT { $$ = $1; } ; an_array : ARRAY_ID '[' calc_expr ']' { YYDBUG_PR1(" an_array <= ARRAY_ID '['calc_expr ']' "); $$=get_array_symbol($1,$3,1); } ; startQ : { /* first matching will occur before first line of input text */ YYDBUG_PR1(" startQ := begin_question\n"); begin_question(); Answer_infospec = 0; } ; %% /* ============================================================================ */ ExpNode_p mk_node(op, left, right) int op; ExpNode_p left; ExpNode_p right; { ExpNode *np; np = (ExpNode* )malloc(sizeof(ExpNode)); np->e_type = op; np->e_lsibp = left; np->e_rsibp = right; left->e_parentp = np; right->e_parentp = np; return (np); } ExpNode_p mk_leaf(type, valp) int type; Symbol_p valp; { ExpNode *np; np = (ExpNode*)malloc(sizeof(ExpNode)); np->e_type = IDENTIFIER; np->e_sp = valp; return (np); } /* ------------------------------------------------------------- */ void free_calc_expr(Symbol *expr) { switch(expr->s_type) { case I_CONSTANT: case R_CONSTANT: capa_mfree((char *)expr); break; case S_CONSTANT: capa_mfree(expr->s_str); capa_mfree((char *)expr); break; default: break; } } /* this is the entry point to array symbol retrieval */ /* array main name and index are used to locate the symbol */ /* name of the array is used to retrieve the array symbol */ Symbol* get_array_symbol ( name,index,free_symbols ) Symbol *name,*index;int free_symbols; { Symbol *s_p, *a_p; char *key, *tmp; int leng, idx_len; leng = strlen(name->s_name)+8; /* [ ] */ switch(index->s_type) { case I_VAR: case I_CONSTANT: tmp = (char *)capa_malloc(64,1); sprintf(tmp,"%ld",index->s_int); break; case R_VAR: case R_CONSTANT: tmp = (char *)capa_malloc(64,1); sprintf(tmp,"%g",index->s_real); break; case S_VAR: case S_CONSTANT: idx_len = strlen(index->s_str); tmp = (char *)capa_malloc(idx_len+4,1); sprintf(tmp,"\"%s\"",index->s_str); /* string array index is a bit different from integer one */ break; default: break; } idx_len = strlen(tmp); key = (char *)capa_malloc(idx_len+leng,1); sprintf(key,"%s[%s]",name->s_name,tmp); a_p = (Symbol *)NULL; a_p = find_arrayid(name->s_name); /* use the array name to search array tree */ if( a_p == NULL ) { return NULL; } /* did not check for error! */ s_p = find_array_by_index(a_p,key); /* use the index portion to search along array linked list */ capa_mfree((char *)tmp); capa_mfree((char *)key); if (free_symbols) { /* free both the name symbol and index symbol */ if( (index->s_type == I_CONSTANT) || (index->s_type == R_CONSTANT) ) capa_mfree((char *)index); if(index->s_type == S_CONSTANT) { capa_mfree(index->s_str); capa_mfree((char *)index); } capa_mfree(name->s_name); capa_mfree((char *)name); } return (s_p); } Symbol * build_array_list(ar_name,num_elem) Symbol *ar_name;int num_elem; { int i; Symbol *arg_list,*a_p; char idx_str[MAX_BUFFER_SIZE]; a_p = find_arrayid(ar_name->s_name); i = 1; sprintf(idx_str,"%s[%d]",ar_name->s_name,i); /* create array elements with integer index */ arg_list = find_array_by_index(a_p,idx_str); /* will create a new element if not found */ arg_list->s_argc=1; arg_list->s_argp=new_arglist(arg_list); for (i=2;i<=num_elem;i++) { sprintf(idx_str,"%s[%d]",ar_name->s_name,i); arg_list->s_argc++; arg_list->s_argp=addto_arglist(arg_list->s_argp,find_array_by_index(a_p,idx_str)); } return arg_list; } /* ------------------------------------------------------------- */ void append_text(str) char *str; { char *q; int i; if (!LexiProblem_p->question) { if (!(q = capa_malloc(strlen(str)+1,1))) printf("No room to append."); strncpy(q,str,strlen(str)+1); } else { i = strlen(LexiProblem_p->question); i += (strlen(str)+1); q = capa_malloc(i,1); /* *** */ if (!q) printf("No room to append()."); strcat(strncpy(q,LexiProblem_p->question, strlen(LexiProblem_p->question)+1), str); capa_mfree(LexiProblem_p->question); } LexiProblem_p->question=q; } /******************************************************************************/ /* ADD A STRING TO THE CURRENT HINT TEXT BLOCK */ /******************************************************************************/ void /* RETURNS: nothing */ append_hint(str) /* ARGUMENTS: */ char *str; /* String to add */ { /* LOCAL VARIABLES: */ char *q; /* New string */ if (!LexiProblem_p->hint) { if (!(q = capa_malloc(strlen(str)+1,1))) printf("no room"); strncpy(q,str,strlen(str)+1); } else { if (!(q = capa_malloc(strlen(LexiProblem_p->hint)+strlen(str)+1,1))) printf("no room"); strcat(strncpy(q,LexiProblem_p->hint,strlen(LexiProblem_p->hint)), str); capa_mfree(LexiProblem_p->hint); } LexiProblem_p->hint=q; /* printf("APPEND HINT: %s\n", str); */ } /******************************************************************************/ /* ADD A STRING TO THE CURRENT EXPLAIN TEXT BLOCK */ /******************************************************************************/ void /* RETURNS: nothing */ append_explain(str) /* ARGUMENTS: */ char *str; /* String to add */ { /* LOCAL VARIABLES: */ char *q; /* New string */ if (!LexiProblem_p->explain) { if (!(q = capa_malloc(strlen(str)+1,1))) printf("no room"); strncpy(q,str, strlen(str)+1); } else { if (!(q = capa_malloc(strlen(LexiProblem_p->explain)+strlen(str)+1,1))) printf("no room"); strcat(strncpy(q,LexiProblem_p->explain,strlen(LexiProblem_p->explain)+1), str); capa_mfree(LexiProblem_p->explain); } LexiProblem_p->explain=q; /* printf("APPEND EXPLAIN: %s\n", str); */ } void append_error(str) char *str; { char *q; int i; ErrorMsg_count++; if (!ErrorMsg_p) { if (!(q = capa_malloc(strlen(str)+1,1))) printf("No room in append."); strncpy(q,str,strlen(str)+1); } else { i = strlen(ErrorMsg_p); i += (strlen(str)+1); q = capa_malloc(i,1); /* *** */ if (!q) printf("No room in append()"); strcat(strncpy(q,ErrorMsg_p, strlen(ErrorMsg_p)+1), str); capa_mfree(ErrorMsg_p); } ErrorMsg_p=q; /* printf("APPEND ERROR: %s\n", str); */ } void append_warn(type,str) int type;char *str; { WarnMsg_t *p, *t; char *q; WarnMsg_count++; if (!WarnMsg_p) { if (!(p = (WarnMsg_t *)capa_malloc(sizeof(WarnMsg_t),1))) printf("No room in create WarnMsg_t."); if (!(q = capa_malloc(strlen(str)+1,1))) printf("No room in allocating space for warn msg."); strncpy(q,str,strlen(str)+1); p->warn_next = NULL; p->warn_type = type; p->warn_str = q; WarnMsg_p=p; } else { for(t=WarnMsg_p;t->warn_next;t=t->warn_next) { } /* do nothing within for loop */ if (!(p = (WarnMsg_t *)capa_malloc(sizeof(WarnMsg_t),1))) printf("No room in create WarnMsg_t."); if (!(q = capa_malloc(strlen(str)+1,1))) printf("No room in allocating space for warn msg."); strncpy(q,str,strlen(str)+1); p->warn_next = NULL; p->warn_type = type; p->warn_str = q; t->warn_next = p; } } /*****************************************************************************/ /*********** if *b is a constant symbol, destroy (free) b ********************/ /*********** if *a is a var symbol, create a new symbol **********************/ /* do not free(*a) */ /* If either a or b is invalid it propagates the error up the parse tree */ Symbol * symbols_op(a, b, op) Symbol *a; Symbol *b; int op; { int type, new, leng; long tmp_i, tmp_j; double tmp_p, tmp_q; char a_str[QUARTER_K], *b_str=NULL, *r_strp; char warn_msg[ONE_K]; Symbol *a_symp; if( a->s_type == IDENTIFIER || b->s_type == IDENTIFIER ) { if(a->s_type == IDENTIFIER) { /* a is IDENTIFIER */ sprintf(warn_msg,"var \"%s\" not defined before use.\n", a->s_name); capa_msg(MESSAGE_ERROR,warn_msg); return (a); } else { /* b is IDENTIFIER */ sprintf(warn_msg,"var \"%s\" not defined before use.\n",b->s_name); capa_msg(MESSAGE_ERROR,warn_msg); return (b); } } else { /* a and b are neither identifiers */ if( (a->s_type == I_VAR) || (a->s_type == R_VAR) || (a->s_type == S_VAR) ) { a_symp = (Symbol *)capa_malloc(sizeof(Symbol),1); /* *** */ new = 1; } else { new = 0; a_symp = a; /* re-use symbol *a */ } if( ((a->s_type == I_CONSTANT)||(a->s_type == I_VAR)) && ((b->s_type == I_CONSTANT)||(b->s_type == I_VAR)) ) { /* both a and b are integer */ type = I_CONSTANT; switch( op ) { case ADD_op: a_symp->s_int = a->s_int + b->s_int ; break; case SUB_op: a_symp->s_int = a->s_int - b->s_int ; break; case MUL_op: a_symp->s_int = a->s_int * b->s_int ; break; case DIV_op: if(b->s_int != 0) { a_symp->s_int = a->s_int / b->s_int ; } else { sprintf(warn_msg,"division (/) by zero!\n"); capa_msg(MESSAGE_ERROR,warn_msg); } break; case IDIV_op: if(b->s_int != 0) { a_symp->s_int = (a->s_int % b->s_int ); } else { sprintf(warn_msg,"integer division (%%) by zero!\n"); capa_msg(MESSAGE_ERROR,warn_msg); } break; case EQ_op: a_symp->s_int = ((a->s_int == b->s_int)? 1: 0); break; case NE_op: a_symp->s_int = ((a->s_int == b->s_int)? 0: 1); break; case GT_op: a_symp->s_int = ((a->s_int > b->s_int)? 1: 0); break; case GE_op: a_symp->s_int = ((a->s_int >= b->s_int)? 1: 0); break; case LT_op: a_symp->s_int = ((a->s_int < b->s_int)? 1: 0); break; case LE_op: a_symp->s_int = ((a->s_int <= b->s_int)? 1: 0); break; case AND_op: a_symp->s_int = ((a->s_int && b->s_int)? 1: 0); break; case OR_op: a_symp->s_int = ((a->s_int || b->s_int)? 1: 0); break; } } else { /* a, b neither are integers */ if( (a->s_type == S_VAR) || (a->s_type == S_CONSTANT) || (b->s_type == S_VAR) || (b->s_type == S_CONSTANT) ) { /* either a or b is a string */ type = S_CONSTANT; /* the return type is a string */ if( (a->s_type == S_VAR) || (a->s_type == S_CONSTANT) ) { /* a is a string */ if (a->s_str == NULL || (((b->s_type == S_VAR) || (b->s_type == S_CONSTANT)) && b->s_str == NULL)) { if (a->s_str == NULL) { sprintf(warn_msg,"variable %s has not yet been assigned a value.\n",a->s_name); capa_msg(MESSAGE_ERROR,warn_msg); } if (((b->s_type == S_VAR) || (b->s_type == S_CONSTANT)) && b->s_str == NULL) { sprintf(warn_msg,"variable %s has not yet been assigned a value.\n",a->s_name); capa_msg(MESSAGE_ERROR,warn_msg); } } else { /* a is a valid string */ switch( b->s_type ) { case I_VAR: case I_CONSTANT: leng = SMALL_LINE_BUFFER; /* assuming a long integer does not exceed 128 digits*/ b_str= capa_malloc(sizeof(char), leng); sprintf(b_str,"%ld", b->s_int); break; case R_VAR: case R_CONSTANT: leng = SMALL_LINE_BUFFER;/*assuming a double does not exceed128chars*/ b_str= capa_malloc(sizeof(char), leng); sprintf(b_str,"%.15g", b->s_real); break; case S_VAR: case S_CONSTANT: /* DONE: get rid of limitations on b_str[] */ leng = strlen( b->s_str ) + 1; b_str= capa_malloc(sizeof(char), leng); sprintf(b_str,"%s",b->s_str); /*if(b->s_type == S_CONSTANT) capa_mfree(b->s_str);*/ break; } switch( op ) { case ADD_op: leng = strlen( a->s_str ) + strlen(b_str) + 1; r_strp = capa_malloc(sizeof(char), leng); /* **** */ strcat(r_strp, a->s_str); strcat(r_strp, b_str); /* concatenate two strings together */ if( !new ) capa_mfree(a->s_str); a_symp->s_str = r_strp; break; case SUB_op: case MUL_op: case DIV_op: case IDIV_op: if( !new ) capa_mfree(a->s_str); a_symp->s_str = strsave("<>"); sprintf(warn_msg,"integer division (%%) cannot accept string operand!\n"); capa_msg(MESSAGE_ERROR,warn_msg); break; case EQ_op: a_symp->s_int = (strcmp(a->s_str, b_str) == 0? 1: 0); type = I_CONSTANT; break; case NE_op: a_symp->s_int = (strcmp(a->s_str, b_str) == 0? 0: 1); type = I_CONSTANT; break; case GT_op: a_symp->s_int = (strcmp(a->s_str, b_str) > 0? 1: 0); type = I_CONSTANT; break; case GE_op: a_symp->s_int = (strcmp(a->s_str, b_str) >= 0? 1: 0); type = I_CONSTANT; break; case LT_op: a_symp->s_int = (strcmp(a->s_str, b_str) < 0? 1: 0); type = I_CONSTANT; break; case LE_op: a_symp->s_int = (strcmp(a->s_str, b_str) <= 0? 1: 0); type = I_CONSTANT; break; case AND_op: if( (a->s_str[0] != 0) && (b_str[0] != 0)) { a_symp->s_int = 1; } else { a_symp->s_int = 0; } type = I_CONSTANT; break; case OR_op: if( (a->s_str[0] != 0) || (b_str[0] != 0)) { a_symp->s_int = 1; } else { a_symp->s_int = 0; } type = I_CONSTANT; break; } } if (b_str!=NULL) capa_mfree(b_str); } else { /* b is string and a is either integer or real */ switch( a->s_type ) { case I_VAR: case I_CONSTANT: sprintf(a_str,"%ld", a->s_int); break; case R_VAR: case R_CONSTANT: sprintf(a_str,"%.15g", a->s_real); break; } switch( op ) { case ADD_op: leng = strlen( b->s_str ) + strlen(a_str) + 1; r_strp = capa_malloc(sizeof(char), leng); /* *** */ strcat(r_strp, a_str); strcat(r_strp, b->s_str); /*if( b->s_type == S_CONSTANT ) capa_mfree(b->s_str);*/ a_symp->s_str = r_strp; break; case SUB_op: case MUL_op: case DIV_op: case IDIV_op: a_symp->s_str = strsave("<>"); sprintf(warn_msg,"integer division (%%) cannot accept string operand!\n"); capa_msg(MESSAGE_ERROR,warn_msg); break; case EQ_op: a_symp->s_int = (strcmp(a_str, b->s_str) == 0? 1: 0); type = I_CONSTANT; break; case NE_op: a_symp->s_int = (strcmp(a_str, b->s_str) == 0? 0: 1); type = I_CONSTANT; break; case GT_op: a_symp->s_int = (strcmp(a_str, b->s_str) > 0? 1: 0); type = I_CONSTANT; break; case GE_op: a_symp->s_int = (strcmp(a_str, b->s_str) >= 0? 1: 0); type = I_CONSTANT; break; case LT_op: a_symp->s_int = (strcmp(a_str, b->s_str) < 0? 1: 0); type = I_CONSTANT; break; case LE_op: a_symp->s_int = (strcmp(a_str,b->s_str) <= 0? 1: 0); type = I_CONSTANT; break; case AND_op: if( (a_str[0] != 0) && (b->s_str[0] != 0)) { a_symp->s_int = 1; } else { a_symp->s_int = 0; } type = I_CONSTANT; break; case OR_op: if( (a_str[0] != 0) || (b_str[0] != 0)) { a_symp->s_int = 1; } else { a_symp->s_int = 0; } type = I_CONSTANT; break; } } } else { /* both a and b are real */ type = R_CONSTANT; if( (a->s_type == R_CONSTANT)||(a->s_type == R_VAR) ) { tmp_p = a->s_real; } else { tmp_p = (double)a->s_int; } if( (b->s_type == R_CONSTANT)||(b->s_type == R_VAR) ) { tmp_q = b->s_real; } else { tmp_q = (double)b->s_int; } switch( op ) { case ADD_op: a_symp->s_real = tmp_p + tmp_q ; break; case SUB_op: a_symp->s_real = tmp_p - tmp_q ; break; case MUL_op: a_symp->s_real = tmp_p * tmp_q ; break; case DIV_op: if(tmp_q != 0.0) { a_symp->s_real = tmp_p / tmp_q ; } else { /* printf("FDIVISION by ZERO\n"); */ sprintf(warn_msg,"division (/) by zero!\n"); capa_msg(MESSAGE_ERROR,warn_msg); } break; case IDIV_op: if(tmp_q != 0.0 ) { tmp_i = (long)tmp_p; tmp_j = (long)tmp_q; a_symp->s_int = tmp_i % tmp_j; type = I_CONSTANT; } else { /* printf("DIVISION by ZERO\n"); */ sprintf(warn_msg,"division (/) by zero!\n"); capa_msg(MESSAGE_ERROR,warn_msg); } break; case EQ_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p == tmp_q)? 1: 0); break; case NE_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p == tmp_q)? 0: 1); break; case GT_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p > tmp_q)? 1: 0); break; case GE_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p >= tmp_q)? 1: 0); break; case LT_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p < tmp_q)? 1: 0); break; case LE_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p <= tmp_q)? 1: 0); break; case AND_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p && tmp_q)? 1: 0); break; case OR_op: type = I_CONSTANT; a_symp->s_int = ((tmp_p || tmp_q)? 1: 0); break; } } } if( (b->s_type == I_CONSTANT) || (b->s_type == R_CONSTANT) ) capa_mfree((char *)b); /* free symbol *b only */ if( (b->s_type == S_CONSTANT) ) { capa_mfree((char *)b->s_str); capa_mfree((char *)b); } a_symp->s_type = type; return (a_symp); } } /* ------------------------------------------------------ */ char * format_toTeX( real ) char *real; { int idx, length, fraclength, i_exp; char *expo_p, fracS[SMALL_LINE_BUFFER], result[ONE_K], *areal; char warn_msg[WARN_MSG_LENGTH]; length = strlen(real); if( index( real, 'e' ) == NULL ) { if( index( real, 'E' ) == NULL ) { sprintf(result,"%s", real); } else { expo_p = index(real, 'E'); /*** hpux complained */ fraclength = length - strlen(expo_p); expo_p++; if(expo_p[0] == '+') expo_p++; sscanf(expo_p,"%d",&i_exp); for(idx=0;idx>"); sprintf(warn_msg,"number %s is not a valid real number!\n",real); capa_msg(MESSAGE_ERROR,warn_msg); } } areal = (char *) capa_malloc(strlen(result)+1, 1); strcpy(areal,result); return (areal); } /* ------------------------------------------------------ */ char * format_toHTML( real ) char *real; { int idx, length, fraclength, i_exp; char *expo_p, fracS[SMALL_LINE_BUFFER], result[ONE_K], *areal; char warn_msg[WARN_MSG_LENGTH]; length = strlen(real); if( index( real, 'e' ) == NULL ) { if( index( real, 'E' ) == NULL ) { sprintf(result,"%s", real); } else { expo_p = index(real, 'E'); /*** hpux complained */ fraclength = length - strlen(expo_p); expo_p++; if(expo_p[0] == '+') expo_p++; sscanf(expo_p,"%d",&i_exp); for(idx=0;idx%d", fracS, i_exp); /* × is code for x */ } } } else { /* the string contains 'e' char */ if( index( real, 'E' ) == NULL ) { expo_p = index(real, 'e'); /*** hpux complained */ fraclength = length - strlen(expo_p); expo_p++; if(expo_p[0] == '+') expo_p++; sscanf(expo_p,"%d",&i_exp); for(idx=0;idx%d", fracS, i_exp); /* × is code for x */ } } else { sprintf(result,"<>"); sprintf(warn_msg,"number %s is not a valid real number!\n",real); capa_msg(MESSAGE_ERROR,warn_msg); } } areal = (char *) capa_malloc(strlen(result)+1, 1); strcpy(areal,result); return (areal); } /* -- This routine is called when a /ANS is encountered -- */ void init_answerinfo() { CurrAnsInfo.ans_str = NULL; CurrAnsInfo.ans_type = 0; CurrAnsInfo.ans_calc = CALC_DEFAULT; CurrAnsInfo.ans_tol_type = TOL_ABSOLUTE; CurrAnsInfo.ans_tol = TOL_DEFAULT; CurrAnsInfo.ans_sig_ub = SIG_UB_DEFAULT; CurrAnsInfo.ans_sig_lb = SIG_LB_DEFAULT; CurrAnsInfo.ans_id_list = NULL; CurrAnsInfo.ans_pts_list = NULL; CurrAnsInfo.ans_fmt[0] = '\0'; CurrAnsInfo.ans_unit_str[0] = '\0'; CurrAnsInfo.ans_unit = NULL; CurrAnsInfo.ans_next = NULL; } /* when encountered a /DIS(variable) */ void display_var( s )Symbol *s; { char *aline; char *tmp_p; char warn_msg[WARN_MSG_LENGTH]; switch(s->s_type) { case IDENTIFIER: aline = (char *)capa_malloc(sizeof(char)*ONE_K,1); sprintf(aline,"VAR \"%s\" NOT DEFINED!", s->s_name); sprintf(warn_msg,"display var \"%s\" not defined before use.\n",s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); break; case I_VAR: case I_CONSTANT: aline = (char *)capa_malloc(sizeof(char)*ONE_K,1); sprintf(aline, "%ld", s->s_int); break; case R_VAR: case R_CONSTANT: aline = (char *)capa_malloc(sizeof(char)*ONE_K,1); if(Parsemode_f == TeX_MODE) { if(s->s_distype == DEFAULT_FORMAT ) { sprintf(aline,"%.15g",s->s_real); } else { sprintf(aline,s->s_format,s->s_real); } tmp_p = format_toTeX(aline); sprintf(aline,"%s",tmp_p); capa_mfree( (char *)tmp_p); } else { if(Parsemode_f == HTML_MODE ) { if(s->s_distype == DEFAULT_FORMAT ) { sprintf(aline,"%.15g",s->s_real); } else { sprintf(aline,s->s_format,s->s_real); } tmp_p = format_toHTML(aline); sprintf(aline,"%s",tmp_p); capa_mfree( (char *)tmp_p); } else { if(s->s_distype == DEFAULT_FORMAT ) { sprintf(aline,"%.15g",s->s_real); } else { sprintf(aline,s->s_format,s->s_real); } } } break; case S_VAR: case S_CONSTANT: if (s->s_str == NULL) { sprintf(warn_msg,"variable %s has not yet been assigned a value.\n", s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); aline=(char *)capa_malloc(9,1); sprintf(aline,"NO VALUE"); } else { aline = (char *)capa_malloc(strlen(s->s_str)+1,1); sprintf(aline,"%s",s->s_str); } break; } append_text(aline); capa_mfree((char *)aline); if(s->s_format) { capa_mfree((char *)s->s_format); } s->s_format = NULL; switch(s->s_type) { /* free up spaces taken by constants */ case I_CONSTANT: case R_CONSTANT: capa_mfree((char *)s); break; case S_CONSTANT: capa_mfree(s->s_str); capa_mfree((char *)s); break; default: break; } } /* Assign the correct answer to CurrAnsInfo first */ void assign_answer( s ) Symbol *s; { char aline[QUARTER_K]; char warn_msg[WARN_MSG_LENGTH]; /*problem_default(LexiProblem_p);*/ switch(s->s_type) { case IDENTIFIER: sprintf(warn_msg,"File %s, Line %3d: in /ANS, var %s not defined before use.\n", Opened_filename[Input_idx],Current_line[Input_idx],s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); CurrAnsInfo.ans_str = strsave("ANSWER NOT DEFINED!"); CurrAnsInfo.ans_type = ANSWER_IS_STRING_CI; sprintf(CurrAnsInfo.ans_fmt,"%%s"); if (CurrAnsInfo.ans_tol == 0.0) { sprintf(warn_msg, "File %s, Line %3d: answer has a numerical value of %ld and an implicit zero tolerance.\n", Opened_filename[Input_idx],Current_line[Input_idx],s->s_int); capa_msg(MESSAGE_WARN,warn_msg); } break; case I_VAR: case I_CONSTANT: sprintf(aline, "%ld", s->s_int); CurrAnsInfo.ans_str = strsave(aline); CurrAnsInfo.ans_type = ANSWER_IS_INTEGER; sprintf(CurrAnsInfo.ans_fmt,"%%ld"); break; case R_VAR: case R_CONSTANT: if(s->s_distype == DEFAULT_FORMAT ) { sprintf(aline,"%.15g",s->s_real); sprintf(CurrAnsInfo.ans_fmt,"%%.15g"); } else { sprintf(aline,"%.15g",s->s_real); strcpy(CurrAnsInfo.ans_fmt,s->s_format); } CurrAnsInfo.ans_str = strsave(aline); CurrAnsInfo.ans_type = ANSWER_IS_FLOAT; if( CurrAnsInfo.ans_tol == 0.0 ) { sprintf(warn_msg,"File %s, Line %3d: answer has a numerical value of %s and a zero tolerance.\n", Opened_filename[Input_idx],Current_line[Input_idx],aline); capa_msg(MESSAGE_WARN,warn_msg); } break; case S_VAR: case S_CONSTANT: CurrAnsInfo.ans_str = strsave(s->s_str); if (s->s_str!=NULL && (strlen(s->s_str)>ANSWER_STRING_LENG-1)) { sprintf(warn_msg,"File %s, Line %3d: answer is too long, max allowed length is %d, current answer is %d\n", Opened_filename[Input_idx],Current_line[Input_idx], ANSWER_STRING_LENG-1, strlen(s->s_str)); capa_msg(MESSAGE_ERROR,warn_msg); CurrAnsInfo.ans_str[ANSWER_STRING_LENG-1]='\0'; } if ( !CurrAnsInfo.ans_type ) { /* not yet specified by str= answer info */ CurrAnsInfo.ans_type = ANSWER_IS_STRING_CI; } sprintf(CurrAnsInfo.ans_fmt,"%%s"); break; } if(s->s_format) { capa_mfree((char *)s->s_format); } s->s_format = NULL; switch(s->s_type) { case I_CONSTANT: case R_CONSTANT: capa_mfree((char *)s); break; case S_CONSTANT: capa_mfree(s->s_str); capa_mfree((char *)s); break; default: break; } } /* Assign tolerance to CurrAnsInfo first */ void assign_tolerance(tol_type, s) int tol_type; Symbol *s; { char warn_msg[WARN_MSG_LENGTH]; CurrAnsInfo.ans_tol_type = tol_type; switch( s->s_type ) { case IDENTIFIER: sprintf(warn_msg,"TOL = var, \"%s\" not defined before use.\n",s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); CurrAnsInfo.ans_tol = 0.0; break; case I_VAR: case I_CONSTANT: CurrAnsInfo.ans_tol =(double)s->s_int; break; case R_VAR: case R_CONSTANT: CurrAnsInfo.ans_tol = s->s_real; break; case S_VAR: case S_CONSTANT: CurrAnsInfo.ans_tol = 0.0; break; } free_calc_expr(s); } /* Problem weight is per problem based */ void assign_weight( s ) Symbol *s; { char warn_msg[WARN_MSG_LENGTH]; YYDBUG_PR1(" weight = identifier\n"); switch( s->s_type ) { case IDENTIFIER: sprintf(warn_msg,"WGT = var, \"%s\" not defined before use.\n", s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->weight = WEIGHT_DEFAULT; break; case I_VAR: case I_CONSTANT: if( s->s_int < 0 ) { sprintf(warn_msg,"WGT = %ld, weight cannot be less than zero.\n", s->s_int); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->weight = WEIGHT_DEFAULT; } else { LexiProblem_p->weight = s->s_int; } break; case R_VAR: case R_CONSTANT: if( s->s_real < 0.0 ) { sprintf(warn_msg,"WGT = %g, weight cannot be less than zero.\n", s->s_real); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->weight = WEIGHT_DEFAULT; } else { LexiProblem_p->weight = (int)(s->s_real); } break; case S_VAR: case S_CONSTANT: LexiProblem_p->weight = WEIGHT_DEFAULT; break; } free_calc_expr(s); } /* Answer try limit is per problem based */ void assign_try_limits( s ) Symbol *s; { char warn_msg[WARN_MSG_LENGTH]; switch( s->s_type ) { case IDENTIFIER: sprintf(warn_msg,"TRY = var, \"%s\" not defined before use.\n",s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->tries = MAX_TRIES; break; case I_VAR: case I_CONSTANT: if(s->s_int <= 0) { sprintf(warn_msg,"TRIES = %ld, tries cannot be less than or equal to zero.\n",s->s_int); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->tries = MAX_TRIES; } else { LexiProblem_p->tries = s->s_int; } break; case R_VAR: case R_CONSTANT: if(s->s_real <= 0.0) { sprintf(warn_msg,"TRIES = %g, tries cannot be less than or equal to zero.\n",s->s_real); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->tries = MAX_TRIES; } else { LexiProblem_p->tries = (int)(s->s_real); } break; case S_VAR: case S_CONSTANT: LexiProblem_p->tries = MAX_TRIES; break; } free_calc_expr(s); } /* Answer hint is per problem based */ void assign_hint( s ) Symbol *s; { char warn_msg[WARN_MSG_LENGTH]; switch( s->s_type ) { case IDENTIFIER: sprintf(warn_msg,"HINT = var, \"%s\" not defined before use.\n", s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->show_hint = SHOW_HINT_DEFAULT; break; case I_VAR: case I_CONSTANT: if( s->s_int < 0 ) { sprintf(warn_msg,"HINT = %ld, show hint cannot be less than zero.\n", s->s_int); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->show_hint = SHOW_HINT_DEFAULT; } else { LexiProblem_p->show_hint = s->s_int; } break; case R_VAR: case R_CONSTANT: if( s->s_real < 0.0 ) { sprintf(warn_msg,"HINT = %g, show hint cannot be less than zero.\n", s->s_real); capa_msg(MESSAGE_ERROR,warn_msg); LexiProblem_p->show_hint = SHOW_HINT_DEFAULT; } else { LexiProblem_p->weight = (int)(s->s_real); } break; case S_VAR: case S_CONSTANT: LexiProblem_p->show_hint = SHOW_HINT_DEFAULT; break; } free_calc_expr(s); } /* Assign answer units string to CurrAnsInfo first */ void assign_units( s ) Symbol *s; { char symb_str[ONE_TWO_EIGHT]; char warn_msg[WARN_MSG_LENGTH]; switch( s->s_type ) { case IDENTIFIER: sprintf(warn_msg,"UNIT = var, \"%s\" not defined before use.\n", s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); break; case I_VAR: case I_CONSTANT: sprintf(warn_msg,"UNIT = %ld, unit cannot be a number.\n", s->s_int); capa_msg(MESSAGE_ERROR,warn_msg); break; case R_VAR: case R_CONSTANT: sprintf(warn_msg,"UNIT = %g, unit cannot be a number.\n", s->s_real); capa_msg(MESSAGE_ERROR,warn_msg); break; case S_VAR: case S_CONSTANT: strcpy(symb_str,s->s_str); strcpy(CurrAnsInfo.ans_unit_str,symb_str); CurrAnsInfo.ans_unit = u_parse_unit(symb_str); if (gUnitError) { sprintf(warn_msg,"Error in unit specified: %s\n",symb_str); capa_msg(MESSAGE_ERROR,warn_msg); } break; } } void assign_sigs( lb, ub ) int lb; int ub; { CurrAnsInfo.ans_sig_lb = lb; CurrAnsInfo.ans_sig_ub = ub; } void assign_id_list( s ) Symbol *s; { char warn_msg[WARN_MSG_LENGTH]; switch( s->s_type ) { case IDENTIFIER: sprintf(warn_msg,"Eval = < ID @ Pts >, \"%s\" not defined before use.\n", s->s_name); capa_msg(MESSAGE_ERROR,warn_msg); break; case I_VAR: case I_CONSTANT: sprintf(warn_msg,"Eval = < %ld @ Pts >, ID cannot be a number.\n", s->s_int); capa_msg(MESSAGE_ERROR,warn_msg); break; case R_VAR: case R_CONSTANT: sprintf(warn_msg,"Eval = < %.16g @ Pts >, ID cannot be a number.\n", s->s_real); capa_msg(MESSAGE_ERROR,warn_msg); break; case S_VAR: case S_CONSTANT: CurrAnsInfo.ans_id_list = strsave(s->s_str); break; } } /* void assign_pts ( Symbol* coord1, Symbol* coord2, Symbol* num) { */ void assign_pts (coord1, coord2, num)Symbol *coord1;Symbol *coord2;Symbol *num; { PointsList_t *pt; if( LastPtsList != NULL ) { LastPtsList->pts_next = gen_ptslist( coord1, coord2, num ); pt = LastPtsList->pts_next; while( pt->pts_next != NULL ) { pt = pt->pts_next; } LastPtsList = pt; } else { CurrPtsList = gen_ptslist( coord1, coord2, num ); LastPtsList = CurrPtsList; } if(coord1->s_type == S_CONSTANT) { capa_mfree(coord1->s_str); capa_mfree((char *)coord1); } if(coord2->s_type == S_CONSTANT) { capa_mfree(coord2->s_str); capa_mfree((char *)coord2); } if(num->s_type == I_CONSTANT || num->s_type == R_CONSTANT) { capa_mfree((char *)num); } } /* =========================================================================== */ /* =========================================================================== */ void start_question_over() { free_problems(LexiProblem_p); LexiProblem_p = (Problem_t *) capa_malloc(sizeof(Problem_t),1); problem_default(LexiProblem_p); begin_question(); } void init_new_prob() { if (LastProblem_p) { LastProblem_p->next = LexiProblem_p; } else { FirstProblem_p = LexiProblem_p; } LastProblem_p = LexiProblem_p; Lexi_qnum++; LexiProblem_p = (Problem_t *) capa_malloc(sizeof(Problem_t),1); /* *** */ problem_default(LexiProblem_p); } void add_answer_cnt(op)int op; { LexiProblem_p->ans_cnt++; if(LexiProblem_p->ans_op == 0) { /* the very first /AND or /OR */ LexiProblem_p->ans_op = op; } else { if( LexiProblem_p->ans_op != op ) { char warn_msg[WARN_MSG_LENGTH]; sprintf(warn_msg,"When specifying multiple answers, either /AND or /OR can be used, but not both.\n"); capa_msg(MESSAGE_ERROR,warn_msg); } } } /* -- called when forming answer_expr */ void finish_answer_info() { AnswerInfo_t *ai; if( LexiProblem_p->ans_cnt == 1 ) { /* Only one answer is defined */ LexiProblem_p->answer = CurrAnsInfo.ans_str; LexiProblem_p->ans_type = CurrAnsInfo.ans_type; LexiProblem_p->calc = CurrAnsInfo.ans_calc; LexiProblem_p->tol_type = CurrAnsInfo.ans_tol_type; LexiProblem_p->tolerance = CurrAnsInfo.ans_tol; LexiProblem_p->sig_ubound= CurrAnsInfo.ans_sig_ub; LexiProblem_p->sig_lbound= CurrAnsInfo.ans_sig_lb; LexiProblem_p->id_list = CurrAnsInfo.ans_id_list; LexiProblem_p->pts_list = CurrAnsInfo.ans_pts_list; strcpy(LexiProblem_p->ans_fmt,CurrAnsInfo.ans_fmt); strcpy(LexiProblem_p->unit_str,CurrAnsInfo.ans_unit_str); LexiProblem_p->ans_unit = CurrAnsInfo.ans_unit; } else { ai = (AnswerInfo_t *)capa_malloc(sizeof(AnswerInfo_t),1); ai->ans_str = CurrAnsInfo.ans_str; ai->ans_type = CurrAnsInfo.ans_type; ai->ans_calc = CurrAnsInfo.ans_calc; ai->ans_tol_type = CurrAnsInfo.ans_tol_type; ai->ans_tol = CurrAnsInfo.ans_tol; ai->ans_sig_ub = CurrAnsInfo.ans_sig_ub; ai->ans_sig_lb = CurrAnsInfo.ans_sig_lb; ai->ans_id_list = CurrAnsInfo.ans_id_list; ai->ans_pts_list = CurrAnsInfo.ans_pts_list; strcpy(ai->ans_fmt,CurrAnsInfo.ans_fmt); strcpy(ai->ans_unit_str,CurrAnsInfo.ans_unit_str); ai->ans_unit = CurrAnsInfo.ans_unit; ai->ans_next = NULL; if(LexiProblem_p->ans_cnt == 2) { LexiProblem_p->ans_list = ai; } else { (LexiProblem_p->ans_list_last)->ans_next = ai; } LexiProblem_p->ans_list_last = ai; } } /* === End of capaGrammarDef.y ============================================= */