/* 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 <stdio.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include "capaParser.h" /* _symbol structure def */
#include "capaCommon.h"
#include "capaFunction.h"
#include "capaRQO.h"
#ifdef __hpux
#include <stdlib.h>
#include <alloca.h>
#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("<PRE>");
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("</PRE>\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 <IFcount=%d>)\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><argc=%d> 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 = find_arrayid(name->s_name); /* use the array name to search array tree */
/* 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("<<Op NOT DEFINED>>");
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("<<Op NOT DEFINED>>");
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<fraclength;idx++) fracS[idx] = real[idx];
fracS[fraclength] = 0;
if(i_exp == 0 ) {
sprintf(result,"$%s$", fracS);
} else {
sprintf(result,"$%s \\times 10^{%d}$", fracS, i_exp);
}
}
} else {
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<fraclength;idx++) fracS[idx] = real[idx];
fracS[fraclength] = 0;
if(i_exp == 0 ) {
sprintf(result,"$%s$", fracS);
} else {
sprintf(result,"$%s \\times 10^{%d}$", fracS, i_exp);
}
} else {
sprintf(result,"<<Ill-formed REAL>>");
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<fraclength;idx++) fracS[idx] = real[idx];
fracS[fraclength] = 0;
if(i_exp == 0 ) {
sprintf(result,"%s", fracS);
} else {
sprintf(result,"%s×10<sup>%d</sup>", 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<fraclength;idx++) fracS[idx] = real[idx];
fracS[fraclength] = 0;
if(i_exp == 0 ) {
sprintf(result,"%s", fracS);
} else {
sprintf(result,"%s×10<sup>%d</sup>", fracS, i_exp); /* × is code for x */
}
} else {
sprintf(result,"<<Ill-formed REAL>>");
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 ============================================= */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>