File:  [LON-CAPA] / capa / capa51 / pProj / capaGrammarDef.y
Revision 1.5: download - view: text, annotated - select for diffs
Wed Oct 20 19:57:37 1999 UTC (24 years, 9 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
-Modified analyze set to show strings with frequency info

    1: /* ========================================================================== */
    2: /*            capaGrammarDef.y    created by Isaac Tsai                       */
    3: /*                                1998, 1999 copyrighted by Isaac Tsai        */
    4: /* no longer there is a length constrain on string concatenation July 13 1998 */
    5: /* /RMAP() function */
    6: /* TODO: new mechanism to collect answer informations */
    7: /*****************************************************************************/
    8: /*****************************************************************************/
    9: /*****************************************************************************/
   10: %{
   11: #include <stdio.h>
   12: #include <ctype.h>
   13: #include <string.h>
   14: #include <math.h>
   15: #include "capaParser.h"   /* _symbol structure def */
   16: #include "capaCommon.h"
   17: #include "capaFunction.h"
   18: #include "capaRQO.h"
   19: #ifdef __hpux
   20: #include <stdlib.h>
   21: #include <alloca.h>
   22: #endif
   23: 
   24: #ifdef   YACC_DBUG
   25: #define  YYDBUG_PR1(xx)        { printf(xx);    fflush(stdout); }
   26: #define  YYDBUG_PR2(xx,yy)     { printf(xx,yy); fflush(stdout); }
   27: #define  YYDBUG_PR3(xx,yy,zz)  { printf(xx,yy,zz); fflush(stdout); }
   28: #define  YYDBUG_PR4(xx,yy,zz,aa)  { printf(xx,yy,zz,aa); fflush(stdout); }
   29: #define  YYDBUG_SYM(xx)        { switch((xx)->s_type) { \
   30:                                      case IDENTIFIER: \
   31:                                               printf("ID(%s)\n",(xx)->s_name);  break; \
   32:                                      case I_VAR:  case I_CONSTANT: \
   33:                                               printf("INT(%d)\n",(xx)->s_int);  break; \
   34:                                      case R_VAR:  case R_CONSTANT: \
   35:                                               printf("REAL(%.16g)\n",(xx)->s_real); break; \
   36:                                      case S_VAR:  case S_CONSTANT: \
   37:                                               printf("STR(%s)\n",(xx)->s_str); break; \
   38:                                } }
   39: #else
   40: #define  YYDBUG_PR1(xx)        { }
   41: #define  YYDBUG_PR2(xx,yy)     { }
   42: #define  YYDBUG_PR3(xx,yy,zz)  { }
   43: #define  YYDBUG_PR4(xx,yy,zz,aa)  { }
   44: #define  YYDBUG_SYM(xx)        { }
   45: #endif
   46: 
   47: int   yylex();
   48: void  yyerror(char*);
   49: void  free_calc_expr(Symbol*);
   50: /******************************************************************************/
   51: /* GLOBAL VARIABLES                                                           */
   52: /******************************************************************************/
   53: int                Lexi_qnum;
   54: 
   55: extern int         Lexi_line;
   56: extern int         Lexi_pos[MAX_OPENED_FILE];
   57: extern char        Opened_filename[MAX_OPENED_FILE][QUARTER_K];
   58: extern int         Input_idx;
   59: int                Current_line[MAX_OPENED_FILE];
   60: extern int         Func_idx;
   61: extern Symbol      FuncStack[MAX_FUNC_NEST];
   62: extern int         IFstatus[MAX_FUNC_NEST];
   63: extern int         IFcount;
   64: extern int         gUnitError;
   65: 
   66: int                Parsemode_f;    /* Parser mode flag */
   67: 
   68: Problem_t         *FirstProblem_p; /* First problem                    */
   69: Problem_t         *LastProblem_p;  /* Last problem                     */
   70: Problem_t         *LexiProblem_p;  /* Current problem                  */
   71: char              *EndText_p;
   72: char              *StartText_p;
   73: char              *ErrorMsg_p;
   74: int                ErrorMsg_count;
   75: WarnMsg_t         *WarnMsg_p;
   76: int                WarnMsg_count;
   77: int                Answer_infospec;
   78: void              (*Status_Func)();
   79: AnswerInfo_t       CurrAnsInfo;
   80: 
   81: RandQO_t          *QuestionOrder;
   82: PointsList_t      *CurrPtsList;
   83: PointsList_t      *LastPtsList;
   84: 
   85: 
   86: 
   87: 
   88: #ifdef  YYSTYPE
   89: #undef  YYSTYPE
   90: #endif
   91: #define YYSTYPE  Symbol_p
   92: 
   93: 
   94: #define ADD_op          1
   95: #define SUB_op          2
   96: #define MUL_op          3
   97: #define DIV_op          4
   98: #define IDIV_op         5
   99: #define NOT_DEFINED_op  9
  100: 
  101: /*#define  yyerror  printf*/
  102: 
  103: %}
  104: %token       NEW_ID
  105: %token       I_CONSTANT  R_CONSTANT     S_CONSTANT
  106: %token       I_VAR       R_VAR          S_VAR
  107: 
  108: %token       IDENTIFIER  FUNCTION_ID    ARRAY_ID
  109: %token       HINT_LINE   EXPLAIN_LINE   TEXT_LINE    IMPORT_LINE
  110: %token       CAPA_LET  CAPA_DEF  CAPA_DIS   CAPA_END   CAPA_VAR
  111: %token       CAPA_ESC  CAPA_MAP  CAPA_FIG   CAPA_ANS   CAPA_RMAP
  112: %token       CAPA_IF   CAPA_ELSE CAPA_ENDIF CAPA_SUBJ  CAPA_WHILE
  113: %token       CAPA_RQO  CAPA_ENDWHILE        CAPA_START 
  114: %token       ANS_AND         ANS_BOX_SHOW    ANS_CALC        ANS_CI          ANS_COMPARE       ANS_CS
  115: %token       ANS_EVAL        ANS_EXPLAIN     ANS_EXTERNAL    ANS_FMT
  116: %token       ANS_FORMULA     ANS_HINT        ANS_MC          ANS_MINUS
  117: %token       ANS_OFF         ANS_ON          ANS_OR          ANS_ORDERED
  118: %token       ANS_PATH        ANS_PCREDIT     ANS_PLUS        ANS_RANGE       
  119: %token       ANS_SHOW_BR     ANS_SIG         ANS_TOLERANCE   ANS_TRY         ANS_TYPE
  120: %token       ANS_UNFMT       ANS_UNIT        ANS_WEIGHT 
  121: %token       VAR_RANGE       VERBATIM
  122: %token       SLASH           FORMAT
  123: %token       EQ_op  NE_op  GT_op  GE_op  LT_op  LE_op  AND_op  OR_op   EoL    
  124: 
  125: %start       prob_set
  126: 
  127: %%
  128: 
  129: prob_set     :  startQ  questions  CAPA_END  { YYDBUG_PR1(" prob_set := startQ questions END\n\n"); }
  130:              ;
  131: 
  132: questions    :  a_line                  { YYDBUG_PR1(" questions <= a_line");
  133:                                           if (Status_Func != NULL) Status_Func();
  134:                                         }
  135:              |  questions  a_line       { YYDBUG_PR1(" questions <= questions a_line");
  136:                                           if (Status_Func != NULL) Status_Func();
  137:                                         }
  138:              ;
  139:              
  140: startL       :  CAPA_LET                { YYDBUG_PR1("\n begin_let::"); } 
  141:              ;
  142:              
  143: startV       :  CAPA_VAR                { YYDBUG_PR1(" begin_var"); } 
  144:              ;
  145:              
  146: startA       :  CAPA_ANS                { YYDBUG_PR1("\n START ANSWER(/ANS)::\n"); 
  147:                                           init_answerinfo(); 
  148:                                         }
  149:              ;
  150: 
  151: startSA      :  CAPA_SUBJ               { YYDBUG_PR1("\n START SUBJECT ANSWER(/SUBJECTIVE)::\n");
  152:                                           init_answerinfo();
  153:                                         }
  154:              ;
  155:              
  156: startM       :  CAPA_MAP                { YYDBUG_PR1("\n begin_map::"); } 
  157:              ;
  158: 
  159: startR       :  CAPA_RMAP               { YYDBUG_PR1("\n begin_rmap::"); } 
  160:              ;
  161: 
  162: startRQO     :  CAPA_RQO                { YYDBUG_PR1("\n begin_rqo::"); } 
  163:              ;
  164: 
  165: ans_and_op   :  ANS_AND                 { add_answer_cnt(ANS_AND); YYDBUG_PR1("(AND ,new an answer info)"); }
  166:              ;
  167:              
  168: ans_or_op    :  ANS_OR                  { add_answer_cnt(ANS_OR); YYDBUG_PR1("(OR ,new an answer info)");  }
  169:              ;
  170: 
  171: a_line       :  startL  statement EoL   { YYDBUG_PR1(" a_line <= startL statement CR\n");  }
  172:              | CAPA_END                 { YYDBUG_PR1(" a_line <=  END\n\n"); }
  173:              |  startRQO rqo_def EoL     { YYDBUG_PR1(" aline <= CAPA_RQO\n");
  174:                                           rqo_finish();
  175:                                         }
  176:              |  CAPA_START              { YYDBUG_PR1(" aline <= CAPA_START\n");
  177: 					  start_question_over();
  178: 	                                }
  179:              |  HINT_LINE               { append_hint($1->s_str); 
  180:                                           YYDBUG_PR2(" a_line <= Hint_line(%s)\n",$1->s_str);
  181:                                           capa_mfree($1->s_str); capa_mfree((char *)$1);
  182:                                         }
  183:              |  EXPLAIN_LINE            { append_explain($1->s_str); 
  184:                                           YYDBUG_PR2(" a_line <= Explain_line(%s)\n",$1->s_str);
  185:                                           capa_mfree($1->s_str); capa_mfree((char*)$1);
  186:                                         }
  187:              |  IMPORT_LINE  EoL        { YYDBUG_PR1(" a_line <= import_line CR\n");  }
  188:              |  q_text EoL              { YYDBUG_PR1(" a_line <= Qtext CR\n"); append_text("\n");  }
  189:              |  answer_expr             { YYDBUG_PR1(" a_line <= answer_expr (init a new prob) CR\n"); 
  190:                                           init_new_prob(); }
  191:              |  if_expr                 { YYDBUG_PR1(" a_line <= if_expr\n");  }
  192:              |  while_expr              { YYDBUG_PR1(" a_line <= while_expr\n");  }
  193:              |  map_expr   EoL          { YYDBUG_PR1(" a_line <= map_expr CR\n");  }
  194:              |  EoL                     { YYDBUG_PR1(" a_line <= (CR)\n");  }
  195:              |  VERBATIM                { YYDBUG_PR1(" a_line <= (VERBATIM)\n");
  196: 	                                  switch(Parsemode_f) {
  197: 					  case TeX_MODE: append_text("\\begin{verbatim}");
  198: 					    break;
  199: 					  case HTML_MODE: append_text("<PRE>");
  200: 					    break;
  201: 					  }
  202:                                           append_text($1->s_str);
  203:                                           capa_mfree($1->s_str); capa_mfree((char *)$1);
  204: 	                                  switch(Parsemode_f) {
  205: 					  case TeX_MODE: append_text("\\end{verbatim}\n");
  206: 					    break;
  207: 					  case HTML_MODE: append_text("</PRE>\n");
  208: 					    break;
  209: 					  }
  210:                                         }
  211:              |  error EoL               { char  warn_msg[WARN_MSG_LENGTH]; 
  212:                                           YYDBUG_PR1(" a_line := ERROR(CR)\n");
  213:                                           sprintf(warn_msg," Question %d: Syntax error.\n", Lexi_qnum+1);
  214:                                           capa_msg(MESSAGE_ERROR,warn_msg); 
  215:                                           begin_text();
  216:                                         }
  217:              
  218:              ;
  219:              
  220: statement    :  IDENTIFIER '=' calc_expr 
  221:                                         { char  warn_msg[WARN_MSG_LENGTH];
  222:                                           
  223: 					if ( $1 != $3 ) { /* /LET a = a */
  224:                                           switch($1->s_type) {
  225:                                              case IDENTIFIER:
  226:                                              case I_VAR: case I_CONSTANT:
  227:                                              case R_VAR: case R_CONSTANT: break;
  228:                                              case S_VAR: case S_CONSTANT: 
  229:                                                     capa_mfree($1->s_str); $1->s_str = NULL; break;
  230:                                              default:    break;
  231:                                           }
  232:                                           switch($3->s_type) {
  233:                                             case IDENTIFIER:
  234:                                                  sprintf(warn_msg,"var \"%s\" not defined before use.\n",$3->s_name);
  235:                                                  capa_msg(MESSAGE_ERROR,warn_msg);
  236:                                                  break;
  237:                                             case I_VAR:  case I_CONSTANT: 
  238:                                                  $1->s_type = I_VAR;
  239:                                                  $1->s_int = $3->s_int; 
  240:                                                  break;
  241:                                             case R_VAR:  case R_CONSTANT:
  242:                                                  $1->s_type = R_VAR;
  243:                                                  $1->s_real = $3->s_real; 
  244:                                                  break;
  245:                                             case S_VAR:  case S_CONSTANT:
  246:                                                  $1->s_type = S_VAR;
  247:                                                  $1->s_str = strsave($3->s_str);
  248:                                                  break;
  249:                                           }
  250:                                           YYDBUG_PR1(" statement <=    ID = calc_expr:: "); YYDBUG_SYM($3);
  251: 					  free_calc_expr($3);
  252: 					}
  253:                                         }
  254:              |  ARRAY_ID '[' calc_expr ']' '=' calc_expr
  255:                                         {    Symbol  *s_p;
  256:                                              char     warn_msg[WARN_MSG_LENGTH];
  257: 
  258: 					     s_p = get_array_symbol($1,$3,1);
  259:                                              switch(s_p->s_type) {
  260:                                                case IDENTIFIER:
  261:                                                case I_VAR: case I_CONSTANT:
  262:                                                case R_VAR: case R_CONSTANT: break;
  263:                                                case S_VAR: case S_CONSTANT: 
  264:                                                     capa_mfree(s_p->s_str); s_p->s_str = NULL; break;
  265:                                                default:    break;
  266:                                              }
  267:                                              switch($6->s_type) {
  268:                                                case IDENTIFIER:
  269:                                                  sprintf(warn_msg,"var \"%s\" not defined before use.\n",$6->s_name);
  270:                                                  capa_msg(MESSAGE_ERROR,warn_msg);
  271:                                                  break;
  272:                                                case I_VAR:  case I_CONSTANT: 
  273:                                                  s_p->s_type = I_VAR;
  274:                                                  s_p->s_int = $6->s_int;
  275:                                                  break;
  276:                                                case R_VAR:  case R_CONSTANT:
  277:                                                  s_p->s_type = R_VAR;
  278:                                                  s_p->s_real = $6->s_real; 
  279:                                                  break;
  280:                                                case S_VAR:  case S_CONSTANT:
  281:                                                  s_p->s_type = S_VAR;
  282:                                                  s_p->s_str = strsave($6->s_str);
  283:                                                  break;
  284:                                              }
  285:                                              free_calc_expr($6);
  286:                                         }
  287:              ;
  288: 
  289: rqo_def      :  rqo_speca             { rqo_1spec(); }
  290:              |  rqo_speca "," rqo_def { rqo_2spec(); }
  291:              ;
  292: 
  293: rqo_speca    : an_integer                 {start_rqo_type(SINGLE);append_rqo($1);}
  294:              | an_integer "!"             {start_rqo_type(IMMOBILE);append_rqo($1);}
  295:              | an_integer "-" an_integer  {start_rqo_type(RANGE);append_rqo($1);
  296:                                            append_rqo($3);
  297:                                           }
  298:              | an_integer "~" rqo_specb   {prefix_rqo($1);}
  299:              | an_integer "+" rqo_specc   {prefix_rqo($1);}
  300:              ;
  301: 
  302: rqo_specb    : an_integer                 {start_rqo_type(ALL_MIX);append_rqo($1);}
  303:              | an_integer "~" rqo_specb   {prefix_rqo($1);}
  304:              | an_integer "+" an_integer  {start_rqo_type(LAST_FIXED);append_rqo($1);
  305:                                            append_rqo($3);}
  306:              ;
  307: 
  308: rqo_specc    : an_integer                 {start_rqo_type(ALL_FIXED);append_rqo($1);}
  309:              | an_integer "+" rqo_specd   {prefix_rqo($1);}
  310:              | an_integer "~" rqo_spece   {prefix_rqo($1);}
  311:              ;
  312: 
  313: rqo_specd    : an_integer                 {start_rqo_type(ALL_FIXED);append_rqo($1);}
  314:              | an_integer "+" rqo_specd   {prefix_rqo($1);}
  315:              ;
  316: 
  317: rqo_spece    : an_integer                 {start_rqo_type(FIRST_FIXED);append_rqo($1);}
  318:              | an_integer "~" rqo_spece   {prefix_rqo($1);}
  319:              | an_integer "+" an_integer  {start_rqo_type(BOTH_FIXED);append_rqo($1);
  320:                                            append_rqo($3);}
  321:              ;
  322: 
  323: 
  324: q_text       :  TEXT_LINE               { append_text($1->s_str);
  325:                                           capa_mfree($1->s_str); capa_mfree((char *)$1);
  326:                                         }
  327:              |  var_expr                {   }
  328:              |  q_text var_expr         {   }
  329:              |  q_text TEXT_LINE        { append_text($2->s_str); 
  330:                                           capa_mfree($2->s_str); capa_mfree((char *)$2);
  331:                                         }
  332:              ;
  333:              
  334: if_expr      :  CAPA_IF '(' calc_expr  ')'
  335:                                         { int leng=0; /* begin_next_line(); no use, can be get rid of */
  336:                                           YYDBUG_PR2("(IF expr <IFcount=%d>)\n",IFcount);
  337:                                           switch($3->s_type) {
  338:                                             case IDENTIFIER: 
  339:                                                    IFstatus[IFcount] = IF_FALSE;
  340:                                                    begin_next_line();
  341:                                                    break;
  342:                                             case I_CONSTANT: case I_VAR: 
  343:                                                    if(!$3->s_int) {
  344:                                                       IFstatus[IFcount] = IF_FALSE;
  345:                                                       begin_if_skip();
  346:                                                    } else {
  347:                                                       IFstatus[IFcount] = IF_TRUE;
  348:                                                       begin_next_line();
  349:                                                    } 
  350:                                                    break;
  351:                                             case R_CONSTANT: case R_VAR:
  352:                                                    if($3->s_real == 0.0) {
  353:                                                       IFstatus[IFcount] = IF_FALSE;
  354:                                                       begin_if_skip();
  355:                                                    }else{
  356:                                                       IFstatus[IFcount] = IF_TRUE;
  357:                                                       begin_next_line();
  358:                                                    }
  359:                                                    break;
  360:                                             case S_CONSTANT: 
  361: 					           if ( $3->s_str) {
  362: 						      leng = strlen($3->s_str);
  363:                                                       capa_mfree($3->s_str);
  364:                                                    } 
  365:                                                    if(leng == 0) {
  366:                                                       IFstatus[IFcount] = IF_FALSE;
  367:                                                       begin_if_skip();
  368:                                                    }else{
  369:                                                       IFstatus[IFcount] = IF_TRUE;
  370:                                                       begin_next_line();
  371:                                                    }
  372:                                                    break;
  373:                                             case S_VAR:
  374: 					           if ( $3->s_str) {
  375: 						      leng = strlen($3->s_str);
  376:                                                       capa_mfree($3->s_str);
  377:                                                    }
  378: 						   if(leng == 0) {
  379:                                                       IFstatus[IFcount] = IF_FALSE;
  380:                                                       begin_if_skip();
  381:                                                    }else{
  382:                                                       IFstatus[IFcount] = IF_TRUE;
  383:                                                       begin_next_line();
  384:                                                    }
  385:                                                    break;
  386:                                           }
  387: 					  capa_mfree((char*)$3);
  388:                                         }
  389:              ;
  390: 
  391: while_expr   :  CAPA_WHILE '(' calc_expr  ')'
  392:                                         {
  393:                                           int leng; 
  394:                                           YYDBUG_PR1("(WHILE expr)\n");
  395:                                           switch($3->s_type) {
  396:                                             case IDENTIFIER: /* undefined identifier regarded as false */
  397:                                                    begin_while_skip();
  398:                                                    break;
  399:                                             case I_CONSTANT: case I_VAR: 
  400:                                                    if(!$3->s_int) {
  401:                                                       begin_while_skip();
  402:                                                    } else {
  403:                                                       begin_next_line(); /* skip to EoL and begin S_TEXT */
  404:                                                    } 
  405:                                                    break;
  406:                                             case R_CONSTANT: case R_VAR:
  407:                                                    if($3->s_real == 0.0) {
  408:                                                       begin_while_skip();
  409:                                                    }else{
  410:                                                       begin_next_line(); /* skip to EoL and begin S_TEXT */
  411:                                                    }
  412:                                                    break;
  413:                                             case S_CONSTANT: 
  414:                                                    leng = strlen($3->s_str);
  415:                                                    capa_mfree($3->s_str);
  416:                                                    if(leng == 0) {
  417:                                                       begin_while_skip();
  418:                                                    }else{
  419:                                                       begin_next_line(); /* skip to EoL and begin S_TEXT */
  420:                                                    }
  421:                                                    break;
  422:                                             case S_VAR:
  423:                                                    leng = strlen($3->s_str);
  424:                                                    if(leng == 0) {
  425:                                                       begin_while_skip();
  426:                                                    }else{
  427:                                                       begin_next_line(); /* skip to EoL and begin S_TEXT */
  428:                                                    }
  429:                                                    break;
  430:                                           }
  431: 					  capa_mfree((char*)$3);
  432:                                         }
  433:              ;
  434: 
  435: var_expr     :  startV '(' formated_ans  ')'
  436:                                         { display_var( $3 ) ; }
  437:              ;
  438:              
  439: answer_expr  : answer_spec              { finish_answer_info(); 
  440:                                         }
  441:              | answer_expr ans_and_op  answer_spec
  442:                                         { finish_answer_info(); 
  443:                                           YYDBUG_PR1(" answer_expr <-- AND answers (copy answerinfo)\n"); }
  444:              | answer_expr ans_or_op   answer_spec
  445:                                         { finish_answer_info(); 
  446:                                           YYDBUG_PR1(" answer_expr <-- OR answers (copy answerinfo)\n"); 
  447: }             | startSA  '(' answer_info ')'
  448:                                         { YYDBUG_PR1("\n subjective answer\n");
  449: 					  finish_answer_info();
  450:                                           LexiProblem_p->ans_type = ANSWER_IS_SUBJECTIVE;
  451:                                         }
  452:              | startSA  '(' ')'
  453:                                         { YYDBUG_PR1("\n subjective answer\n");
  454: 					  finish_answer_info();
  455:                                           LexiProblem_p->ans_type = ANSWER_IS_SUBJECTIVE;
  456:                                         }
  457:              
  458:              ;
  459:              
  460: answer_spec  : startA '(' formated_ans  ')'
  461:                                         { assign_answer( $3 );
  462:                                           YYDBUG_PR1("\nASSIGN Answer\n");
  463:                                         }
  464:              | startA '(' formated_ans ',' answer_info ')'
  465:                                         { assign_answer( $3 );
  466:                                           YYDBUG_PR1("\nASSIGN Answers + Answer Info\n");
  467:                                         }
  468:              ;
  469: 	     
  470: answer_info  : ans_infospec
  471: 	     | answer_info ',' ans_infospec
  472: 	     ;
  473: 
  474: 
  475: ans_infospec : ANS_TOLERANCE '=' a_number
  476:                                        { YYDBUG_PR1(" ans_infospec:= TOL=a_number");
  477:                                          assign_tolerance(TOL_ABSOLUTE,$3);
  478:                                        }
  479:              | ANS_TOLERANCE '=' IDENTIFIER
  480:                                        { assign_tolerance(TOL_ABSOLUTE,$3);
  481:                                        }
  482:              | ANS_TOLERANCE '=' IDENTIFIER '%'
  483:                                        { assign_tolerance(TOL_PERCENTAGE,$3);
  484:                                        }
  485:              | ANS_TOLERANCE '=' a_number '%'
  486:                                        { assign_tolerance(TOL_PERCENTAGE,$3);
  487:                                        }
  488: 	     | ANS_COMPARE '=' answer_comp {       }
  489: 	     | ANS_SIG '='  answer_sig     {       }
  490: 	     | ANS_WEIGHT '=' an_integer
  491: 	                               {  assign_weight( $3 );
  492: 	                               }
  493: 	     | ANS_WEIGHT '=' IDENTIFIER
  494: 	                               {  assign_weight( $3 );
  495: 	                               }
  496: 	     | ANS_HINT '=' an_integer {  assign_hint( $3 );
  497: 	                               }
  498: 	     | ANS_HINT '=' IDENTIFIER {  assign_hint( $3 );
  499: 	                               }
  500: 	     | ANS_PCREDIT '=' ANS_ON  {  LexiProblem_p->partial_cdt = 1;
  501: 	                               }
  502: 	     | ANS_PCREDIT '=' ANS_OFF {  LexiProblem_p->partial_cdt = 0;
  503: 	                               }
  504: 	     | ANS_SHOW_BR '=' ANS_ON  {  LexiProblem_p->show_br = DO_SHOW;
  505: 	                               }
  506: 	     | ANS_SHOW_BR '=' ANS_OFF {  LexiProblem_p->show_br = DONOT_SHOW;
  507: 	                               }
  508: 	     | ANS_BOX_SHOW '=' ANS_ON {  LexiProblem_p->show_ans_box  = DO_SHOW;
  509: 	                               }
  510: 	     | ANS_BOX_SHOW '=' ANS_OFF {  LexiProblem_p->show_ans_box = DONOT_SHOW;
  511: 	                               }                          
  512: 	     | ANS_CALC '=' ANS_FMT    {  CurrAnsInfo.ans_calc = CALC_FORMATED;
  513: 	                               }
  514: 	     | ANS_CALC '=' ANS_UNFMT  {  CurrAnsInfo.ans_calc = CALC_UNFORMATED;
  515: 	                               } 
  516: 	     | ANS_TRY '=' an_integer  {  assign_try_limits( $3 );
  517: 	                               }
  518: 	     | ANS_TRY '=' IDENTIFIER  {  assign_try_limits( $3 );
  519: 	                               }
  520: 	     | ANS_UNIT '=' S_CONSTANT {  assign_units( $3 ); capa_mfree($3->s_str); capa_mfree((char *)$3);
  521: 	                               }
  522: 	     | ANS_UNIT '=' IDENTIFIER {  assign_units( $3 );
  523: 	                               }
  524: 	     | ANS_EVAL '=' var_range {  CurrAnsInfo.ans_pts_list = CurrPtsList; 
  525: 	                                 CurrPtsList=NULL; LastPtsList = NULL;  
  526: 	                               }
  527: 	     ;
  528: 
  529: 
  530: var_range    :  '<' S_CONSTANT '@'  pt_list  '>'     { assign_id_list( $2 ); 
  531:                                                        capa_mfree($2->s_str); 
  532:                                                        capa_mfree((char *)$2);
  533:                                                      }
  534:              |  '<' IDENTIFIER '@'  pt_list  '>'     { assign_id_list( $2 );  }
  535:              ;
  536: 
  537: pt_list      :   pt_list  ','  point_coord          { int idx;
  538:                                                       idx = LastPtsList->pts_idx; idx++;
  539:                                                       LastPtsList->pts_next = new_ptslist( $3 );
  540:                                                       LastPtsList = LastPtsList->pts_next;
  541:                                                       LastPtsList->pts_idx = idx;
  542:                                                       CurrPtsList->pts_idx = idx;
  543:                                                       if( $3->s_type == S_CONSTANT ) {
  544:                                                         capa_mfree($3->s_str); capa_mfree((char *)$3);
  545:                                                       }
  546:                                                     }
  547:              |   pt_list  ','  pt_range             { }
  548:              |   point_coord                        { CurrPtsList = new_ptslist( $1 );  
  549:                                                       LastPtsList = CurrPtsList;
  550:                                                       if( $1->s_type == S_CONSTANT ) {
  551:                                                         capa_mfree($1->s_str); capa_mfree((char *)$1);
  552:                                                       }
  553:                                                     }
  554:              |   pt_range                           { }
  555:              ;
  556: 
  557: pt_range     :   point_coord   ':'  point_coord  '#'  IDENTIFIER   { PointsList_t *pt;
  558: 
  559:                                                                      if( LastPtsList != NULL ) {
  560:                                                                         LastPtsList->pts_next = gen_ptslist( $1, $3, $5 );
  561:                                                                         pt = LastPtsList->pts_next;
  562:                                                                         while( pt->pts_next != NULL ) {
  563:                                                                            pt = pt->pts_next;
  564:                                                                         }
  565:                                                                         LastPtsList = pt;
  566:                                                                      } else {
  567:                                                                         CurrPtsList = gen_ptslist( $1, $3, $5 );
  568:                                                                         LastPtsList = CurrPtsList;
  569:                                                                      }
  570:                                                                      if( $1->s_type == S_CONSTANT ) {
  571:                                                                          capa_mfree($1->s_str); capa_mfree((char *)$1);
  572:                                                                      }
  573:                                                                      if( $3->s_type == S_CONSTANT ) {
  574:                                                                          capa_mfree($3->s_str); capa_mfree((char *)$3);
  575:                                                                      }
  576:                                                                    }
  577:              |   point_coord   ':'  point_coord  '#'  a_number     { PointsList_t *pt;
  578: 
  579:                                                                      if( LastPtsList != NULL ) {
  580:                                                                         LastPtsList->pts_next = gen_ptslist( $1, $3, $5 );
  581:                                                                         pt = LastPtsList->pts_next;
  582:                                                                         while( pt->pts_next != NULL ) {
  583:                                                                            pt = pt->pts_next;
  584:                                                                         }
  585:                                                                         LastPtsList = pt;
  586:                                                                      } else {
  587:                                                                         CurrPtsList = gen_ptslist( $1, $3, $5 );
  588:                                                                         LastPtsList = CurrPtsList;
  589:                                                                      }
  590:                                                                      if( $1->s_type == S_CONSTANT ) {
  591:                                                                          capa_mfree($1->s_str); capa_mfree((char *)$1);
  592:                                                                      }
  593:                                                                      if( $3->s_type == S_CONSTANT ) {
  594:                                                                          capa_mfree($3->s_str); capa_mfree((char *)$3);
  595:                                                                      }
  596:                                                                      if( $5->s_type == I_CONSTANT || $5->s_type == R_CONSTANT) {
  597:                                                                          capa_mfree((char *)$5);
  598:                                                                      }
  599:                                                                    }
  600:              ;
  601: 
  602: 
  603: point_coord  :   IDENTIFIER            { $$ = $1;  }
  604:              |   S_CONSTANT            { $$ = $1;  }
  605:              ;
  606: 
  607: 
  608: 	     
  609: formated_ans : calc_expr               { $1->s_distype = DEFAULT_FORMAT;
  610:                                          $$ = $1;
  611:                                          $1->s_format = NULL;
  612:                                          YYDBUG_PR2(" formated_ans := calc_expr (type %d)",$1->s_type);
  613:                                        }
  614:              | calc_expr FORMAT        { $1->s_distype = $2->s_distype;
  615:                                          $1->s_format  = strsave($2->s_str); /* **** */
  616:                                          capa_mfree($2->s_str); capa_mfree((char *)$2);
  617:                                          $$ = $1;
  618:                                          YYDBUG_PR1(" formated_ans <= calc_expr FORMAT");
  619:                                        }
  620:              ;
  621:              
  622:              
  623: 
  624: answer_sig   : an_integer              { assign_sigs( $1->s_int,$1->s_int);
  625:                                          capa_mfree((char *)$1);
  626: 	                               }
  627:              | an_integer ANS_PLUS  an_integer
  628:                                        { assign_sigs($1->s_int,$1->s_int + $3->s_int);
  629:                                          capa_mfree((char *)$1);  capa_mfree((char *)$3);
  630: 	                               }
  631:              | an_integer ANS_MINUS an_integer
  632:                                        { assign_sigs($1->s_int - $3->s_int,$1->s_int);
  633:                                          capa_mfree((char *)$1);  capa_mfree((char *)$3);
  634: 	                               }
  635:              | an_integer ANS_PLUS  an_integer ANS_MINUS an_integer
  636:                                        { assign_sigs($1->s_int - $5->s_int,$1->s_int + $3->s_int);
  637:                                          capa_mfree((char *)$1);  capa_mfree((char *)$3); capa_mfree((char *)$5);
  638: 	                               }
  639: 	     | an_integer ANS_MINUS  an_integer ANS_PLUS an_integer
  640:                                        { assign_sigs($1->s_int - $3->s_int,$1->s_int + $5->s_int);
  641:                                          capa_mfree((char *)$1);  capa_mfree((char *)$3); capa_mfree((char *)$5);
  642: 	                               }
  643:              ;
  644:              
  645: answer_comp  : ANS_CS                  {  CurrAnsInfo.ans_type = ANSWER_IS_STRING_CS; }
  646:              | ANS_CI                  {  CurrAnsInfo.ans_type = ANSWER_IS_STRING_CI; }
  647:              | ANS_MC                  {  CurrAnsInfo.ans_type = ANSWER_IS_CHOICE;    }
  648:              | ANS_FORMULA             {  CurrAnsInfo.ans_type = ANSWER_IS_FORMULA;   }
  649:              | ANS_EXTERNAL            {  CurrAnsInfo.ans_type = ANSWER_IS_EXTERNAL;  }
  650:              ;
  651: 
  652: 
  653: map_expr     : startM '(' basic_constr ';' var_list ';' arg_list ')'
  654:                                       { char   key[SMALL_LINE_BUFFER];
  655:                                         char   warn_msg[WARN_MSG_LENGTH];
  656:                                         int    result=0;
  657: 
  658:                                         YYDBUG_PR1(" map_expr body executed\n");
  659:                                         sprintf(key,"%ld",$3->s_int);
  660:                                         if( $5->s_argc ==  $7->s_argc ) {
  661:                                           result=do_map(key, $5->s_argp, $7->s_argp, $5->s_argc, FORWARD_MAP);
  662: 					} else {
  663: 					  if ($5->s_argc==1) {
  664: 					    Symbol *a_sp;
  665: 					    a_sp=build_array_list($5,$7->s_argc);
  666: 					    result=do_map(key, a_sp->s_argp, $7->s_argp, a_sp->s_argc, FORWARD_MAP);
  667: 					    free_arglist(a_sp->s_argp);
  668: 					  } else {
  669: 					    sprintf(warn_msg,"/MAP arg. counts are not matched.\n");
  670: 					    capa_msg(MESSAGE_ERROR,warn_msg);
  671: 					  }
  672:                                         }
  673: 					if (result!=0) {
  674: 					    sprintf(warn_msg,
  675: 						    "/MAP had invalid arguments.\n");
  676: 					    capa_msg(MESSAGE_ERROR,warn_msg);
  677: 					}
  678:                                         free_arglist($5->s_argp);
  679:                                         free_arglist($7->s_argp);
  680:                                       }
  681:              | startR '(' basic_constr ';' var_list ';' arg_list ')'
  682:                                       { char   key[SMALL_LINE_BUFFER];
  683:                                         char   warn_msg[WARN_MSG_LENGTH];
  684: 					int    result=0;
  685: 
  686:                                         YYDBUG_PR1(" rmap_expr body executed\n");
  687:                                         sprintf(key,"%ld",$3->s_int);
  688:                                         if( $5->s_argc ==  $7->s_argc ) {
  689:                                           result=do_map(key, $5->s_argp, $7->s_argp, $5->s_argc, REVERSE_MAP);
  690:                                           
  691:                                         } else {
  692: 					  if ($5->s_argc==1) {
  693: 					    Symbol *a_sp;
  694: 					    a_sp=build_array_list($5,$7->s_argc);
  695: 					    result=do_map(key, a_sp->s_argp, $7->s_argp, a_sp->s_argc, FORWARD_MAP);
  696: 					    free_arglist(a_sp->s_argp);
  697: 					  } else {
  698: 					    sprintf(warn_msg,"/RMAP arg. counts are not matched.\n");
  699: 					    capa_msg(MESSAGE_ERROR,warn_msg);
  700: 					  }
  701:                                         }
  702: 					if (result!=0) {
  703: 					    sprintf(warn_msg,
  704: 						    "/MAP had invalid arguments.\n");
  705: 					    capa_msg(MESSAGE_ERROR,warn_msg);
  706: 					}
  707:                                         free_arglist($5->s_argp);
  708:                                         free_arglist($7->s_argp);
  709:                                       }
  710:              ;
  711: 
  712: 
  713: 
  714: calc_expr    : calc_expr EQ_op  block  { $$ = symbols_op($1, $3, EQ_op);  }
  715:              | calc_expr NE_op  block  { $$ = symbols_op($1, $3, NE_op);  }
  716:              | calc_expr GE_op  block  { $$ = symbols_op($1, $3, GE_op);  }
  717:              | calc_expr GT_op  block  { $$ = symbols_op($1, $3, GT_op);  }
  718:              | calc_expr LE_op  block  { $$ = symbols_op($1, $3, LE_op);  }
  719:              | calc_expr LT_op  block  { $$ = symbols_op($1, $3, LT_op);  }
  720:              | calc_expr AND_op block  { $$ = symbols_op($1, $3, AND_op); }
  721:              | calc_expr OR_op  block  { $$ = symbols_op($1, $3, OR_op);  }
  722:              | block                   { $$ = $1; 
  723:                                          YYDBUG_PR1(" calc_expr <= block "); YYDBUG_SYM($1);   }
  724:              ;
  725: 
  726: block        : block '+' term          { $$ = symbols_op($1, $3, ADD_op); YYDBUG_PR1("block <= block '+' term "); YYDBUG_SYM($$); }
  727:              | block '-' term          { $$ = symbols_op($1, $3, SUB_op); }
  728:              | term                    { $$ = $1; YYDBUG_PR2(" block <= term YYSTATE(%d) ",yystate); YYDBUG_SYM($1);   }
  729:              ;
  730: 
  731: term         : term '*' basic_constr   { $$ = symbols_op($1, $3, MUL_op); }
  732:              | term '/' basic_constr   { $$ = symbols_op($1, $3, DIV_op); }
  733:              | term '%' basic_constr   { $$ = symbols_op($1, $3, IDIV_op); }
  734:              | basic_constr            { $$ = $1; 
  735:                                          YYDBUG_PR1(" term <= basic_constr "); YYDBUG_SYM($1);   }
  736:              ;
  737: 
  738: basic_constr : FUNCTION_ID '('  ')'   {  int tmp;
  739:                                          
  740:                                          Func_idx--;
  741:                                          if(Func_idx >= 0 ) {
  742:                                            tmp = match_function(FuncStack[Func_idx].s_name,0);
  743:                                            $$ = do_function(tmp, 0, NULL );
  744:                                            capa_mfree(FuncStack[Func_idx].s_name);
  745:                                          }
  746:                                          
  747:                                       }
  748:              | FUNCTION_ID '(' arg_list ')'
  749:                                       {  int  tmp;
  750:                                       
  751:                                          Func_idx--;
  752:                                          YYDBUG_PR4(" basic_constr <= FUNCTION<%s><argc=%d> YYSTATE(%d) ",
  753:                                              FuncStack[Func_idx].s_name,$3->s_argc,yystate);
  754:                                          
  755:                                          if(Func_idx >= 0 ) {
  756:                                            tmp = match_function(FuncStack[Func_idx].s_name,$3->s_argc);
  757: 					   $$ = do_function(tmp, $3->s_argc, $3->s_argp);
  758: 					   capa_mfree(FuncStack[Func_idx].s_name);
  759: 					   free_arglist($3->s_argp);
  760:                                          }
  761:                                          YYDBUG_PR1(" basic_constr <= RETURN FUNCT "); YYDBUG_SYM($$);
  762:                                          
  763:                                       }
  764:              | an_array               {   $$ = $1;   }                         
  765:              | IDENTIFIER             { /* do not free identifier */ 
  766:                                           $$ = $1;
  767:                                       }
  768:              | '-' basic_constr       { $$ = $2;
  769:                                           switch($2->s_type) {
  770:                                             case I_VAR:      $$ = (Symbol *)capa_malloc(sizeof(Symbol),1);
  771:                                                              $$->s_type = I_CONSTANT;
  772:                                             case I_CONSTANT: $$->s_int =    - $2->s_int; break;
  773:                                             case R_VAR: $$ = (Symbol *)capa_malloc(sizeof(Symbol),1);
  774:                                                         $$->s_type = R_CONSTANT;
  775:                                             case R_CONSTANT: $$->s_real =   (-1.0)*($2->s_real); 
  776:                                                              break;
  777:                                             case S_VAR:
  778:                                             case S_CONSTANT: break;
  779:                                             default:         break;
  780:                                           }
  781:                                         }
  782:              | '+' basic_constr         { $$ = $2; }
  783:              | S_CONSTANT               { $$ = $1; }
  784:              | a_number                 { $$ = $1; }
  785:              | '(' calc_expr ')'        { $$ = $2; }
  786:              ;
  787: 
  788: arg_list     : arg_list ',' calc_expr   { $$ = $1;
  789:                                           $$->s_argc++;
  790:                                           $$->s_argp = addto_arglist($1->s_argp, $3); 
  791:                                         }
  792:              | calc_expr                { $$ = $1;
  793:                                           $$->s_argc = 1;
  794:                                           $$->s_argp = new_arglist($1);
  795:                                         }
  796:              ;
  797: 
  798: 
  799: var_list     : IDENTIFIER               { /* do not free identifier */
  800:                                           YYDBUG_PR1(" var_list <= ID");
  801:                                           $$ = $1;
  802:                                           $$->s_argc = 1;
  803:                                           $$->s_argp = new_arglist($1);
  804:                                         }
  805:              | ARRAY_ID '[' calc_expr ']'{
  806:                                           YYDBUG_PR1(" var_list <= ARRAYID,calc");
  807:                                           $$ = get_array_symbol($1,$3,1);
  808:                                           $$->s_argc = 1;
  809:                                           $$->s_argp = new_arglist($$);
  810: 	                                 }
  811:              | var_list ',' ARRAY_ID '[' calc_expr ']' {
  812:                                           YYDBUG_PR1(" var_list <= var_list,ARRAYID,calc");
  813: 	                                  $$ = $1;
  814: 					  $$->s_argc++;
  815: 					  $$->s_argp = addto_arglist($1->s_argp, 
  816: 							    get_array_symbol($3,$5,1));
  817:                                         }
  818:              | var_list ',' IDENTIFIER  { /* do not free identifier */
  819:                                           YYDBUG_PR1(" var_list <= var_list,ID");
  820:                                           $$ = $1;
  821:                                           $$->s_argc++;
  822:                                           $$->s_argp = addto_arglist($1->s_argp, $3); 
  823:                                         }
  824:              ;
  825: 
  826: 
  827: a_number     : an_integer               { $$ = $1; }
  828:              | a_real                   { $$ = $1; }
  829:              ;
  830:              
  831: an_integer   : I_CONSTANT               { $$ = $1; }
  832:              ;
  833:              
  834: a_real       : R_CONSTANT               { $$ = $1; } 
  835:              ;
  836: 
  837: an_array     : ARRAY_ID '[' calc_expr ']'     {   $$=get_array_symbol($1,$3,1);   } 
  838:              ;
  839: 
  840: startQ       :                  { /* first matching will occur before first line of input text */
  841:                                   YYDBUG_PR1(" startQ := begin_question\n");
  842:                                   begin_question(); Answer_infospec = 0; 
  843:                                 }
  844:              ;
  845: 
  846: 
  847: 
  848: %%
  849: /* ============================================================================  */
  850: ExpNode_p
  851: mk_node(op, left, right) int op; ExpNode_p left; ExpNode_p right;
  852: { 
  853:   ExpNode     *np;
  854:   
  855:   np = (ExpNode* )malloc(sizeof(ExpNode));
  856:   np->e_type       = op;
  857:   np->e_lsibp      = left;
  858:   np->e_rsibp      = right;
  859:   left->e_parentp  = np;
  860:   right->e_parentp = np;
  861:   return (np);
  862: }
  863: 
  864: ExpNode_p
  865: mk_leaf(type, valp) int type; Symbol_p valp;
  866: {
  867:   ExpNode     *np;
  868:   
  869:   np = (ExpNode*)malloc(sizeof(ExpNode));
  870:   np->e_type = IDENTIFIER;
  871:   np->e_sp = valp;
  872:   return (np);
  873:   
  874: }
  875: 
  876: /* ------------------------------------------------------------- */
  877: void free_calc_expr(Symbol *expr)
  878: {
  879:   switch(expr->s_type) {
  880:   case I_CONSTANT:
  881:   case R_CONSTANT: capa_mfree((char *)expr); break;
  882:   case S_CONSTANT: capa_mfree(expr->s_str); capa_mfree((char *)expr); break;
  883:   default: break;
  884:   }
  885: }
  886: 
  887: /* this is the entry point to array symbol retrieval */
  888: /* array main name and index are  used to locate the symbol */
  889: /* name of the array is used to retrieve the array symbol */
  890: 
  891: Symbol* get_array_symbol ( name,index,free_symbols ) 
  892: Symbol *name,*index;int free_symbols;
  893: {
  894:   Symbol  *s_p, *a_p;
  895:   char    *key, *tmp;
  896:   int      leng, idx_len;
  897:   leng = strlen(name->s_name)+8; /* [ ] */
  898:   
  899:   switch(index->s_type) {
  900:     case I_VAR:
  901:     case I_CONSTANT: tmp = (char *)capa_malloc(64,1);
  902:       sprintf(tmp,"%ld",index->s_int);
  903:       break;
  904:     case R_VAR: 
  905:     case R_CONSTANT: tmp = (char *)capa_malloc(64,1);
  906:       sprintf(tmp,"%g",index->s_real);
  907:       break;
  908:     case S_VAR:
  909:     case S_CONSTANT: idx_len = strlen(index->s_str); tmp = (char *)capa_malloc(idx_len+4,1);
  910:       sprintf(tmp,"\"%s\"",index->s_str); /* string array index is a bit different from integer one */
  911:       break;
  912:     default:         break;
  913:   }
  914:   idx_len = strlen(tmp);
  915:   
  916:   key = (char *)capa_malloc(idx_len+leng,1);
  917:   sprintf(key,"%s[%s]",name->s_name,tmp);
  918:   
  919:   a_p = find_arrayid(name->s_name);   /* use the array name to search array tree */
  920:                                       /* */
  921:   s_p = find_array_by_index(a_p,key); /* use the index portion to search along array linked list */
  922:   capa_mfree((char *)tmp); capa_mfree((char *)key);
  923:   
  924:   if (free_symbols) { /* free both the name symbol and index symbol */
  925:     if( (index->s_type == I_CONSTANT) || (index->s_type == R_CONSTANT) ) 
  926:       capa_mfree((char *)index);
  927:     if(index->s_type == S_CONSTANT) {
  928:       capa_mfree(index->s_str); capa_mfree((char *)index); 
  929:     }
  930:     capa_mfree(name->s_name);  capa_mfree((char *)name);
  931:   }
  932:   return (s_p);
  933: }
  934: 
  935: Symbol * build_array_list(ar_name,num_elem)
  936: Symbol *ar_name;int num_elem;
  937: {
  938:   int     i;
  939:   Symbol *arg_list,*a_p;
  940:   char    idx_str[MAX_BUFFER_SIZE];
  941:   
  942:   a_p = find_arrayid(ar_name->s_name);
  943:   i = 1;
  944:   sprintf(idx_str,"%s[%d]",ar_name->s_name,i); /* create array elements with integer index */
  945:   arg_list = find_array_by_index(a_p,idx_str); /* will create a new element if not found */
  946:   arg_list->s_argc=1;
  947:   arg_list->s_argp=new_arglist(arg_list);
  948:   
  949:   for (i=2;i<=num_elem;i++) {
  950:       sprintf(idx_str,"%s[%d]",ar_name->s_name,i);
  951:       arg_list->s_argc++;
  952:       arg_list->s_argp=addto_arglist(arg_list->s_argp,find_array_by_index(a_p,idx_str));
  953:   }
  954:   return arg_list;
  955: }
  956: 
  957: 
  958: 
  959: 
  960: 
  961: 
  962: 
  963: /* ------------------------------------------------------------- */
  964: void        
  965: append_text(str) char *str;  
  966: {            
  967:   char *q;  
  968:   int   i;  
  969:  
  970:   if (!LexiProblem_p->question) {
  971:       if (!(q = capa_malloc(strlen(str)+1,1)))  printf("No room to append.");
  972:       strncpy(q,str,strlen(str)+1);
  973:   } else {
  974:       i =  strlen(LexiProblem_p->question);
  975:       i += (strlen(str)+1);
  976:       q =  capa_malloc(i,1);  /* *** */
  977:       if (!q)  printf("No room to append().");
  978:       strcat(strncpy(q,LexiProblem_p->question, strlen(LexiProblem_p->question)+1), str);
  979:       capa_mfree(LexiProblem_p->question);
  980:   }
  981:   LexiProblem_p->question=q;
  982: }
  983:  
  984: /******************************************************************************/
  985: /* ADD A STRING TO THE CURRENT HINT TEXT BLOCK                                */
  986: /******************************************************************************/
  987: void             /* RETURNS: nothing */
  988: append_hint(str) /* ARGUMENTS:       */
  989: char *str;       /*    String to add */
  990: {                /* LOCAL VARIABLES: */
  991:    char *q;      /*    New string    */
  992:  
  993:    if (!LexiProblem_p->hint) {
  994:       if (!(q = capa_malloc(strlen(str)+1,1)))
  995:          printf("no room");
  996:       strncpy(q,str,strlen(str)+1);
  997:    } else {
  998:       if (!(q = capa_malloc(strlen(LexiProblem_p->hint)+strlen(str)+1,1)))
  999:          printf("no room");
 1000:       strcat(strncpy(q,LexiProblem_p->hint,strlen(LexiProblem_p->hint)), str);
 1001:       capa_mfree(LexiProblem_p->hint);
 1002:    }
 1003:    LexiProblem_p->hint=q;
 1004:    /* printf("APPEND HINT: %s\n", str); */
 1005: }
 1006: /******************************************************************************/
 1007: /* ADD A STRING TO THE CURRENT EXPLAIN TEXT BLOCK                                */
 1008: /******************************************************************************/
 1009: void             /* RETURNS: nothing */
 1010: append_explain(str) /* ARGUMENTS:       */
 1011: char *str;       /*    String to add */
 1012: {                /* LOCAL VARIABLES: */
 1013:    char *q;      /*    New string    */
 1014:  
 1015:    if (!LexiProblem_p->explain) {
 1016:       if (!(q = capa_malloc(strlen(str)+1,1)))
 1017:          printf("no room");
 1018:       strncpy(q,str, strlen(str)+1);
 1019:    } else {
 1020:       if (!(q = capa_malloc(strlen(LexiProblem_p->explain)+strlen(str)+1,1)))
 1021:          printf("no room");
 1022:       strcat(strncpy(q,LexiProblem_p->explain,strlen(LexiProblem_p->explain)+1), str);
 1023:       capa_mfree(LexiProblem_p->explain);
 1024:    }
 1025:    LexiProblem_p->explain=q;
 1026:    /* printf("APPEND EXPLAIN: %s\n", str); */
 1027: }
 1028: 
 1029: void        
 1030: append_error(str) char *str;  
 1031: {            
 1032:   char *q;  
 1033:   int   i;  
 1034: 
 1035:   ErrorMsg_count++;
 1036:   if (!ErrorMsg_p) {
 1037:       if (!(q = capa_malloc(strlen(str)+1,1)))  printf("No room in append.");
 1038:       strncpy(q,str,strlen(str)+1);
 1039:   } else {
 1040:       i =  strlen(ErrorMsg_p);
 1041:       i += (strlen(str)+1);
 1042:       q =  capa_malloc(i,1);  /* *** */
 1043:       if (!q)  printf("No room in append()");
 1044:       strcat(strncpy(q,ErrorMsg_p, strlen(ErrorMsg_p)+1), str);
 1045:       capa_mfree(ErrorMsg_p);
 1046:   }
 1047:   ErrorMsg_p=q;
 1048:   /* printf("APPEND ERROR: %s\n", str); */
 1049: }
 1050: void        
 1051: append_warn(type,str) int type;char *str;  
 1052: {            
 1053:   WarnMsg_t  *p, *t;
 1054:   char       *q;  
 1055: 
 1056:   WarnMsg_count++;
 1057:   if (!WarnMsg_p) {
 1058:       if (!(p = (WarnMsg_t *)capa_malloc(sizeof(WarnMsg_t),1)))  printf("No room in create WarnMsg_t.");
 1059:       if (!(q = capa_malloc(strlen(str)+1,1)))      printf("No room in allocating space for warn msg.");
 1060:       strncpy(q,str,strlen(str)+1);
 1061:       p->warn_next = NULL;
 1062:       p->warn_type = type;
 1063:       p->warn_str = q;
 1064:       WarnMsg_p=p;
 1065:   } else {
 1066:       for(t=WarnMsg_p;t->warn_next;t=t->warn_next) {   } /* do nothing within for loop */
 1067:       if (!(p = (WarnMsg_t *)capa_malloc(sizeof(WarnMsg_t),1)))  printf("No room in create WarnMsg_t.");
 1068:       if (!(q = capa_malloc(strlen(str)+1,1)))      printf("No room in allocating space for warn msg.");
 1069:       strncpy(q,str,strlen(str)+1);
 1070:       p->warn_next = NULL;
 1071:       p->warn_type = type;
 1072:       p->warn_str = q;
 1073:       t->warn_next = p;
 1074:   }
 1075: }
 1076: 
 1077: /*****************************************************************************/
 1078: /*********** if *b is a constant symbol, destroy (free) b ********************/
 1079: /*********** if *a is a var symbol, create a new symbol **********************/
 1080: /*                 do not free(*a)     */
 1081: /*           */
 1082: Symbol *
 1083: symbols_op(a, b, op) Symbol *a; Symbol *b; int op;
 1084: {
 1085:   int     type,  new, leng;
 1086:   long    tmp_i, tmp_j;
 1087:   double  tmp_p, tmp_q;
 1088:   char    a_str[QUARTER_K], *b_str=NULL, *r_strp;
 1089:   char    warn_msg[ONE_K];
 1090:   Symbol *a_symp;
 1091:   
 1092: if( a->s_type == IDENTIFIER || b->s_type == IDENTIFIER ) {
 1093:    if(a->s_type == IDENTIFIER) { /* a is IDENTIFIER */
 1094:      sprintf(warn_msg,"var \"%s\" not defined before use.\n", a->s_name);
 1095:      capa_msg(MESSAGE_ERROR,warn_msg);
 1096:      return (b);
 1097:    } else { /* b is IDENTIFIER */
 1098:      sprintf(warn_msg,
 1099:       "var \"%s\" not defined before use.\n",b->s_name);
 1100:      capa_msg(MESSAGE_ERROR,warn_msg);
 1101:      return (a);
 1102:    }
 1103:  } else {  /* a and b are neither identifiers */
 1104:   if( (a->s_type == I_VAR) ||
 1105:       (a->s_type == R_VAR) ||
 1106:       (a->s_type == S_VAR) )  {
 1107:         a_symp = (Symbol *)capa_malloc(sizeof(Symbol),1);  /* *** */
 1108:         new = 1;
 1109:   } else {
 1110:         new = 0;
 1111:         a_symp = a; /* re-use symbol *a */
 1112:   }
 1113:   if( ((a->s_type == I_CONSTANT)||(a->s_type == I_VAR)) && 
 1114:       ((b->s_type == I_CONSTANT)||(b->s_type == I_VAR)) ) { /* both a and b are integer */
 1115:     type = I_CONSTANT;
 1116:     switch( op ) {
 1117:       case ADD_op: a_symp->s_int = a->s_int +  b->s_int ; break;
 1118:       case SUB_op: a_symp->s_int = a->s_int -  b->s_int ; break;
 1119:       case MUL_op: a_symp->s_int = a->s_int *  b->s_int ; break;
 1120:       case DIV_op: if(b->s_int != 0) {
 1121:                      a_symp->s_int = a->s_int /  b->s_int ; 
 1122:                    } else {
 1123:                      sprintf(warn_msg,"division (/) by zero!\n");
 1124:                      capa_msg(MESSAGE_ERROR,warn_msg);
 1125:                    } break;
 1126:       case IDIV_op: if(b->s_int != 0) {
 1127:                       a_symp->s_int = (a->s_int %  b->s_int );
 1128:                     } else {
 1129:                       sprintf(warn_msg,"integer division (%%) by zero!\n");
 1130:                       capa_msg(MESSAGE_ERROR,warn_msg);
 1131:                     } break;
 1132:       case EQ_op:   a_symp->s_int = ((a->s_int ==  b->s_int)? 1: 0); break;
 1133:       case NE_op:   a_symp->s_int = ((a->s_int ==  b->s_int)? 0: 1); break;
 1134:       case GT_op:   a_symp->s_int = ((a->s_int >   b->s_int)? 1: 0); break;
 1135:       case GE_op:   a_symp->s_int = ((a->s_int >=  b->s_int)? 1: 0); break;
 1136:       case LT_op:   a_symp->s_int = ((a->s_int <   b->s_int)? 1: 0); break;
 1137:       case LE_op:   a_symp->s_int = ((a->s_int <=  b->s_int)? 1: 0); break;
 1138:       case AND_op:  a_symp->s_int = ((a->s_int &&  b->s_int)? 1: 0); break;
 1139:       case OR_op:   a_symp->s_int = ((a->s_int ||  b->s_int)? 1: 0); break;
 1140:     }
 1141:   } else {  /* a, b neither are integers */
 1142:     if( (a->s_type == S_VAR) || (a->s_type == S_CONSTANT) || 
 1143:         (b->s_type == S_VAR) || (b->s_type == S_CONSTANT) ) { /* either a or b is a string */
 1144:       type = S_CONSTANT;  /* the return type is a string */
 1145:       if( (a->s_type == S_VAR) || (a->s_type == S_CONSTANT) ) { /* a is a string */
 1146: 	if (a->s_str == NULL || 
 1147: 	    (((b->s_type == S_VAR) || (b->s_type == S_CONSTANT)) && b->s_str == NULL)) {
 1148: 	  if (a->s_str == NULL) {
 1149: 	    sprintf(warn_msg,"variable %s has not yet been assigned a value.\n",a->s_name);
 1150: 	    capa_msg(MESSAGE_ERROR,warn_msg);
 1151: 	  }
 1152: 	  if (((b->s_type == S_VAR) || (b->s_type == S_CONSTANT)) && b->s_str == NULL) {
 1153: 	    sprintf(warn_msg,"variable %s has not yet been assigned a value.\n",a->s_name);
 1154: 	    capa_msg(MESSAGE_ERROR,warn_msg);
 1155: 	  }
 1156: 	} else { /* a is a valid string */
 1157: 	  switch( b->s_type ) {
 1158: 	  case I_VAR:
 1159: 	  case I_CONSTANT:
 1160: 	    leng = SMALL_LINE_BUFFER; /* assuming a long integer does not exceed 128 digits*/
 1161: 	    b_str= capa_malloc(sizeof(char), leng);
 1162: 	    sprintf(b_str,"%ld", b->s_int);
 1163: 	    break;
 1164: 	  case R_VAR:
 1165: 	  case R_CONSTANT:
 1166: 	    leng = SMALL_LINE_BUFFER;/*assuming a double does not exceed128chars*/
 1167: 	    b_str= capa_malloc(sizeof(char), leng);
 1168: 	    sprintf(b_str,"%.15g", b->s_real);
 1169: 	    break;
 1170: 	  case S_VAR:
 1171: 	  case S_CONSTANT: /* DONE: get rid of limitations on b_str[] */
 1172: 	    leng =  strlen( b->s_str ) +  1;
 1173: 	    b_str= capa_malloc(sizeof(char), leng);
 1174: 	    sprintf(b_str,"%s",b->s_str);
 1175: 	    /*if(b->s_type == S_CONSTANT)  capa_mfree(b->s_str);*/
 1176: 	    break;
 1177: 	  }
 1178: 	  switch( op ) {
 1179: 	  case ADD_op:
 1180: 	    leng =  strlen( a->s_str ) + strlen(b_str) + 1;
 1181: 	    r_strp = capa_malloc(sizeof(char), leng);    /* **** */
 1182: 	    strcat(r_strp, a->s_str);
 1183: 	    strcat(r_strp, b_str);  /* concatenate two strings together */
 1184: 	    if( !new )   capa_mfree(a->s_str);  
 1185: 	    a_symp->s_str = r_strp;
 1186: 	    break;
 1187: 	  case SUB_op:
 1188: 	  case MUL_op:
 1189: 	  case DIV_op:
 1190: 	  case IDIV_op:
 1191: 	    if( !new )   capa_mfree(a->s_str);
 1192: 	    a_symp->s_str = strsave("<<Op NOT DEFINED>>");
 1193: 	    sprintf(warn_msg,"integer division (%%) cannot accept string operand!\n");
 1194: 	    capa_msg(MESSAGE_ERROR,warn_msg);
 1195: 	    break;
 1196: 	  case EQ_op: a_symp->s_int = (strcmp(a->s_str, b_str) == 0? 1: 0);
 1197: 	    type = I_CONSTANT;  break;
 1198: 	  case NE_op: a_symp->s_int = (strcmp(a->s_str, b_str) == 0? 0: 1);
 1199: 	    type = I_CONSTANT;  break;
 1200: 	  case GT_op: a_symp->s_int = (strcmp(a->s_str, b_str) > 0? 1: 0);
 1201: 	    type = I_CONSTANT;  break;
 1202: 	  case GE_op: a_symp->s_int = (strcmp(a->s_str, b_str) >= 0? 1: 0);
 1203: 	    type = I_CONSTANT;  break;
 1204: 	  case LT_op: a_symp->s_int = (strcmp(a->s_str, b_str) < 0? 1: 0);
 1205: 	    type = I_CONSTANT;  break;
 1206: 	  case LE_op: a_symp->s_int = (strcmp(a->s_str, b_str) <= 0? 1: 0);
 1207: 	    type = I_CONSTANT;  break;
 1208: 	  case AND_op: 
 1209: 	    if( (a->s_str[0] != 0) && (b_str[0] != 0)) {
 1210: 	      a_symp->s_int = 1;
 1211: 	    } else {
 1212: 	      a_symp->s_int = 0;
 1213: 	    } 
 1214: 	    type = I_CONSTANT;  break;
 1215: 	  case OR_op: 
 1216: 	    if( (a->s_str[0] != 0) || (b_str[0] != 0)) {
 1217: 	      a_symp->s_int = 1;
 1218: 	    } else {
 1219: 	      a_symp->s_int = 0;
 1220: 	    } 
 1221: 	    type = I_CONSTANT;  break;
 1222: 	  }
 1223: 	}
 1224: 	if (b_str!=NULL) capa_mfree(b_str);
 1225:       } else {  /* b is string and a is either integer or real */
 1226:         switch( a->s_type ) {
 1227:          case I_VAR:
 1228:          case I_CONSTANT:
 1229:                    sprintf(a_str,"%ld", a->s_int);     break;
 1230:          case R_VAR:
 1231:          case R_CONSTANT:
 1232:                    sprintf(a_str,"%.15g", a->s_real);  break;
 1233:         }
 1234:         switch( op ) {
 1235:          case ADD_op:
 1236:                    leng =  strlen( b->s_str ) + strlen(a_str) + 1;
 1237:                    r_strp = capa_malloc(sizeof(char), leng);   /* *** */
 1238:                    strcat(r_strp, a_str);
 1239:                    strcat(r_strp, b->s_str);
 1240:                    /*if( b->s_type == S_CONSTANT )  capa_mfree(b->s_str);*/
 1241:                    a_symp->s_str = r_strp;              break;
 1242:          case SUB_op:
 1243:          case MUL_op:
 1244:          case DIV_op:
 1245:          case IDIV_op:
 1246:                    a_symp->s_str = strsave("<<Op NOT DEFINED>>");
 1247:                    sprintf(warn_msg,"integer division (%%) cannot accept string operand!\n");
 1248:                    capa_msg(MESSAGE_ERROR,warn_msg);
 1249:                    break;
 1250:          case EQ_op: a_symp->s_int = (strcmp(a_str, b->s_str) == 0? 1: 0);
 1251:                      type = I_CONSTANT;  break;
 1252:          case NE_op: a_symp->s_int = (strcmp(a_str, b->s_str) == 0? 0: 1);
 1253:                      type = I_CONSTANT;  break;
 1254:          case GT_op: a_symp->s_int = (strcmp(a_str, b->s_str) > 0? 1: 0);
 1255:                      type = I_CONSTANT;  break;
 1256:          case GE_op: a_symp->s_int = (strcmp(a_str, b->s_str) >= 0? 1: 0);
 1257:                      type = I_CONSTANT;  break;
 1258:          case LT_op: a_symp->s_int = (strcmp(a_str, b->s_str) < 0? 1: 0);
 1259:                      type = I_CONSTANT;  break;
 1260:          case LE_op: a_symp->s_int = (strcmp(a_str,b->s_str) <= 0? 1: 0);
 1261:                      type = I_CONSTANT;  break;
 1262:          case AND_op: if( (a_str[0] != 0) && (b->s_str[0] != 0)) {
 1263:                        a_symp->s_int = 1;
 1264:                       } else {
 1265:                        a_symp->s_int = 0;
 1266:                       } 
 1267:                      type = I_CONSTANT;  break;
 1268:          case OR_op: if( (a_str[0] != 0) || (b_str[0] != 0)) {
 1269:                        a_symp->s_int = 1;
 1270:                       } else {
 1271:                        a_symp->s_int = 0;
 1272:                       } 
 1273:                      type = I_CONSTANT;  break;
 1274:         }
 1275:       }
 1276:       
 1277:     } else { /* both a and b are real */
 1278:       type = R_CONSTANT;
 1279:       if( (a->s_type == R_CONSTANT)||(a->s_type == R_VAR) ) {
 1280:         tmp_p = a->s_real;
 1281:       } else {
 1282:         tmp_p = (double)a->s_int;
 1283:       }
 1284:       if( (b->s_type == R_CONSTANT)||(b->s_type == R_VAR) ) {
 1285:         tmp_q = b->s_real;
 1286:       } else {
 1287:         tmp_q = (double)b->s_int;
 1288:       }
 1289:       switch( op ) {
 1290:         case ADD_op: a_symp->s_real =  tmp_p + tmp_q ; break;
 1291:         case SUB_op: a_symp->s_real =  tmp_p - tmp_q ; break;
 1292:         case MUL_op: a_symp->s_real =  tmp_p * tmp_q ; break;
 1293:         case DIV_op: if(tmp_q != 0.0) {
 1294:                        a_symp->s_real =  tmp_p / tmp_q ; 
 1295:                      } else {
 1296:                        /* printf("FDIVISION by ZERO\n"); */
 1297:                        sprintf(warn_msg,"division (/) by zero!\n");
 1298:                        capa_msg(MESSAGE_ERROR,warn_msg);
 1299:                      }
 1300:                      break;
 1301:         case IDIV_op: if(tmp_q != 0.0 ) {
 1302:                         tmp_i =  (long)tmp_p;
 1303:                         tmp_j =  (long)tmp_q;
 1304:                         a_symp->s_int = tmp_i % tmp_j;
 1305:                         type = I_CONSTANT;
 1306:                      } else {
 1307:                        /* printf("DIVISION by ZERO\n"); */
 1308:                        sprintf(warn_msg,"division (/) by zero!\n");
 1309:                        capa_msg(MESSAGE_ERROR,warn_msg);
 1310:                      }
 1311:                       break;
 1312:         case EQ_op:   type = I_CONSTANT;
 1313:                       a_symp->s_int = ((tmp_p ==  tmp_q)? 1: 0); break;
 1314:         case NE_op:   type = I_CONSTANT;
 1315:                       a_symp->s_int = ((tmp_p ==  tmp_q)? 0: 1); break;
 1316:         case GT_op:   type = I_CONSTANT;
 1317:                       a_symp->s_int = ((tmp_p >   tmp_q)? 1: 0); break;
 1318:         case GE_op:   type = I_CONSTANT;
 1319:                       a_symp->s_int = ((tmp_p >=  tmp_q)? 1: 0); break;
 1320:         case LT_op:   type = I_CONSTANT;
 1321:                       a_symp->s_int = ((tmp_p <   tmp_q)? 1: 0); break;
 1322:         case LE_op:   type = I_CONSTANT;
 1323:                       a_symp->s_int = ((tmp_p <=  tmp_q)? 1: 0); break;
 1324:         case AND_op:  type = I_CONSTANT;
 1325:                       a_symp->s_int = ((tmp_p &&  tmp_q)? 1: 0); break;
 1326:         case OR_op:   type = I_CONSTANT;
 1327:                       a_symp->s_int = ((tmp_p ||  tmp_q)? 1: 0); break;
 1328:       }
 1329:     }
 1330:   }
 1331:   if( (b->s_type == I_CONSTANT) ||
 1332:       (b->s_type == R_CONSTANT) )    capa_mfree((char *)b);     /* free symbol *b only */
 1333:   if( (b->s_type == S_CONSTANT) ) {  
 1334:     capa_mfree((char *)b->s_str);  
 1335:     capa_mfree((char *)b); 
 1336:   }
 1337:   a_symp->s_type =  type;
 1338:   return (a_symp);
 1339:  } 
 1340: }
 1341: 
 1342: /* ------------------------------------------------------ */
 1343: char *
 1344: format_toTeX( real ) char *real;
 1345: {
 1346:   int     idx, length, fraclength, i_exp;
 1347:   char   *expo_p, fracS[SMALL_LINE_BUFFER], result[ONE_K], *areal;
 1348:   char    warn_msg[WARN_MSG_LENGTH];
 1349:   
 1350:   length = strlen(real);
 1351:   if( index( real, 'e' ) == NULL ) {
 1352:     if( index( real, 'E' ) == NULL ) {
 1353:       sprintf(result,"%s", real);
 1354:     } else {
 1355:       expo_p = index(real, 'E'); /*** hpux complained */
 1356:       fraclength = length - strlen(expo_p);
 1357:       expo_p++; if(expo_p[0] == '+') expo_p++;
 1358:       sscanf(expo_p,"%d",&i_exp);
 1359:       for(idx=0;idx<fraclength;idx++) fracS[idx] = real[idx];
 1360:       fracS[fraclength] = 0;
 1361:       if(i_exp == 0 ) {
 1362:         sprintf(result,"$%s$", fracS);
 1363:       } else {
 1364:         sprintf(result,"$%s \\times 10^{%d}$", fracS, i_exp);
 1365:       }
 1366:     }
 1367:   } else {
 1368:     if( index( real, 'E' ) == NULL ) {
 1369:       expo_p = index(real, 'e'); /*** hpux complained */
 1370:       fraclength = length - strlen(expo_p);
 1371:       expo_p++; if(expo_p[0] == '+') expo_p++;
 1372:       sscanf(expo_p,"%d",&i_exp);
 1373:       for(idx=0;idx<fraclength;idx++) fracS[idx] = real[idx];
 1374:       fracS[fraclength] = 0;
 1375:       if(i_exp == 0 ) {
 1376:         sprintf(result,"$%s$", fracS);
 1377:       } else {
 1378:         sprintf(result,"$%s \\times 10^{%d}$", fracS, i_exp);
 1379:       }
 1380:     } else {
 1381:       sprintf(result,"<<Ill-formed REAL>>");
 1382:       sprintf(warn_msg,"number %s is not a valid real number!\n",real);
 1383:       capa_msg(MESSAGE_ERROR,warn_msg);
 1384:     }
 1385:   }
 1386:   areal = (char *) capa_malloc(strlen(result)+1, 1);
 1387:   strcpy(areal,result);
 1388:   return (areal);
 1389: }
 1390: /* ------------------------------------------------------ */
 1391: char *
 1392: format_toHTML( real ) char *real;
 1393: {
 1394:   int     idx, length, fraclength, i_exp;
 1395:   char   *expo_p, fracS[SMALL_LINE_BUFFER], result[ONE_K], *areal;
 1396:   char    warn_msg[WARN_MSG_LENGTH];
 1397:   
 1398:   length = strlen(real);
 1399:   if( index( real, 'e' ) == NULL ) {
 1400:     if( index( real, 'E' ) == NULL ) {
 1401:       sprintf(result,"%s", real);
 1402:     } else {
 1403:       expo_p = index(real, 'E'); /*** hpux complained */
 1404:       fraclength = length - strlen(expo_p);
 1405:       expo_p++; if(expo_p[0] == '+') expo_p++;
 1406:       sscanf(expo_p,"%d",&i_exp);
 1407:       for(idx=0;idx<fraclength;idx++) fracS[idx] = real[idx];
 1408:       fracS[fraclength] = 0;
 1409:       if(i_exp == 0 ) {
 1410:         sprintf(result,"%s", fracS);
 1411:       } else {
 1412:         sprintf(result,"%s&#215;10<sup>%d</sup>", fracS, i_exp); /* &#215 is code for x */
 1413:       }
 1414:     }
 1415:   } else { /* the string contains 'e' char */
 1416:     if( index( real, 'E' ) == NULL ) {
 1417:       expo_p = index(real, 'e'); /*** hpux complained */
 1418:       fraclength = length - strlen(expo_p);
 1419:       expo_p++; if(expo_p[0] == '+') expo_p++;
 1420:       sscanf(expo_p,"%d",&i_exp);
 1421:       for(idx=0;idx<fraclength;idx++) fracS[idx] = real[idx];
 1422:       fracS[fraclength] = 0;
 1423:       if(i_exp == 0 ) {
 1424:         sprintf(result,"%s", fracS);
 1425:       } else {
 1426:         sprintf(result,"%s&#215;10<sup>%d</sup>", fracS, i_exp); /* &#215 is code for x */
 1427:       }
 1428:     } else {
 1429:       sprintf(result,"<<Ill-formed REAL>>");
 1430:       sprintf(warn_msg,"number %s is not a valid real number!\n",real);
 1431:       capa_msg(MESSAGE_ERROR,warn_msg);
 1432:     }
 1433:   }
 1434:   areal = (char *) capa_malloc(strlen(result)+1, 1);
 1435:   strcpy(areal,result);
 1436:   return (areal);
 1437: }
 1438: /* -- This routine is called when a /ANS is encountered -- */
 1439: void
 1440: init_answerinfo()
 1441: {
 1442: 
 1443:   CurrAnsInfo.ans_str      = NULL;
 1444:   CurrAnsInfo.ans_type     = 0;
 1445:   CurrAnsInfo.ans_calc     = CALC_DEFAULT;
 1446:   CurrAnsInfo.ans_tol_type = TOL_ABSOLUTE;
 1447:   CurrAnsInfo.ans_tol      = TOL_DEFAULT;
 1448:   CurrAnsInfo.ans_sig_ub   = SIG_UB_DEFAULT;
 1449:   CurrAnsInfo.ans_sig_lb   = SIG_LB_DEFAULT;
 1450:   CurrAnsInfo.ans_id_list  = NULL;
 1451:   CurrAnsInfo.ans_pts_list = NULL;
 1452:   CurrAnsInfo.ans_fmt[0]      = '\0';
 1453:   CurrAnsInfo.ans_unit_str[0] = '\0';
 1454:   CurrAnsInfo.ans_unit     = NULL;
 1455:   CurrAnsInfo.ans_next     = NULL;
 1456: }
 1457: /* when encountered a /DIS(variable)  */
 1458: void
 1459: display_var( s )Symbol *s;
 1460: {
 1461:   char    *aline;
 1462:   char    *tmp_p;
 1463:   char    warn_msg[WARN_MSG_LENGTH];
 1464: 
 1465:                           
 1466:   switch(s->s_type) {
 1467:     case IDENTIFIER:
 1468:            aline = (char *)capa_malloc(sizeof(char)*ONE_K,1);
 1469:            sprintf(aline,"VAR \"%s\" NOT DEFINED!", s->s_name);
 1470:            sprintf(warn_msg,"display var \"%s\" not defined before use.\n",s->s_name);
 1471:            capa_msg(MESSAGE_ERROR,warn_msg);
 1472:           break;
 1473:     case I_VAR:  case I_CONSTANT:
 1474:            aline = (char *)capa_malloc(sizeof(char)*ONE_K,1);
 1475:            sprintf(aline, "%ld", s->s_int);
 1476:           break;
 1477:     case R_VAR:  case R_CONSTANT:
 1478:            aline = (char *)capa_malloc(sizeof(char)*ONE_K,1);
 1479:            if(Parsemode_f == TeX_MODE) {
 1480:              if(s->s_distype == DEFAULT_FORMAT ) {
 1481:                 sprintf(aline,"%.15g",s->s_real);
 1482:              } else {
 1483:                 sprintf(aline,s->s_format,s->s_real);
 1484:              }
 1485:              tmp_p = format_toTeX(aline);
 1486:              sprintf(aline,"%s",tmp_p);
 1487:              capa_mfree( (char *)tmp_p);
 1488:                                                       
 1489:            } else {
 1490:              if(Parsemode_f == HTML_MODE ) {
 1491:                 if(s->s_distype == DEFAULT_FORMAT ) {
 1492:                    sprintf(aline,"%.15g",s->s_real);
 1493:                 } else {
 1494:                    sprintf(aline,s->s_format,s->s_real);
 1495:                 }
 1496:                 tmp_p = format_toHTML(aline);
 1497:                 sprintf(aline,"%s",tmp_p);
 1498:                 capa_mfree( (char *)tmp_p);
 1499:               } else {
 1500:                 if(s->s_distype == DEFAULT_FORMAT ) {
 1501:                   sprintf(aline,"%.15g",s->s_real);
 1502:                 } else {
 1503:                   sprintf(aline,s->s_format,s->s_real);   
 1504:                 }
 1505:               }
 1506:             }
 1507:            break;
 1508:      case S_VAR:  case S_CONSTANT:  
 1509:             if (s->s_str == NULL) {
 1510: 	      sprintf(warn_msg,"variable %s has not yet been assigned a value.\n",
 1511: 		      s->s_name);
 1512: 	      capa_msg(MESSAGE_ERROR,warn_msg);
 1513: 	      aline=(char *)capa_malloc(9,1);
 1514: 	      sprintf(aline,"NO VALUE");
 1515:             } else {
 1516: 	      aline = (char *)capa_malloc(strlen(s->s_str)+1,1);
 1517: 	      sprintf(aline,"%s",s->s_str);
 1518: 	    }
 1519:            break;
 1520:    }
 1521:    append_text(aline);
 1522:    capa_mfree((char *)aline);
 1523:    if(s->s_format) { capa_mfree((char *)s->s_format); }
 1524:    s->s_format = NULL;
 1525:    switch(s->s_type) { /* free up spaces taken by constants */
 1526:      case I_CONSTANT:
 1527:      case R_CONSTANT: capa_mfree((char *)s); break;
 1528:      case S_CONSTANT: capa_mfree(s->s_str); capa_mfree((char *)s); break;
 1529:      default:  break;
 1530:    }
 1531: 
 1532: }
 1533: 
 1534: /* Assign the correct answer to CurrAnsInfo first */
 1535: void
 1536: assign_answer( s ) Symbol *s;
 1537: {
 1538:   char    aline[QUARTER_K];
 1539:   char    warn_msg[WARN_MSG_LENGTH];
 1540:                                           
 1541:   /*problem_default(LexiProblem_p);*/
 1542:   switch(s->s_type) {
 1543:     case IDENTIFIER:
 1544:             sprintf(warn_msg,"File %s, Line %3d: in /ANS, var %s not defined before use.\n",
 1545:               Opened_filename[Input_idx],Current_line[Input_idx],s->s_name);
 1546:             capa_msg(MESSAGE_ERROR,warn_msg);
 1547:             CurrAnsInfo.ans_str = strsave("ANSWER NOT DEFINED!");
 1548:             CurrAnsInfo.ans_type = ANSWER_IS_STRING_CI;
 1549:             sprintf(CurrAnsInfo.ans_fmt,"%%s");
 1550: 	    if (CurrAnsInfo.ans_tol == 0.0) {
 1551: 		sprintf(warn_msg, "File %s, Line %3d: answer has a numerical value of %ld and an implicit zero tolerance.\n",
 1552: 		  Opened_filename[Input_idx],Current_line[Input_idx],s->s_int);
 1553: 		capa_msg(MESSAGE_WARN,warn_msg);
 1554: 	    }
 1555: 	break;
 1556:      case I_VAR:  case I_CONSTANT:
 1557:             sprintf(aline, "%ld", s->s_int);
 1558:             CurrAnsInfo.ans_str = strsave(aline);
 1559:             CurrAnsInfo.ans_type = ANSWER_IS_INTEGER;
 1560:             sprintf(CurrAnsInfo.ans_fmt,"%%ld");
 1561:         break;
 1562:      case R_VAR:  case R_CONSTANT:
 1563:             if(s->s_distype == DEFAULT_FORMAT ) {
 1564:                sprintf(aline,"%.15g",s->s_real);
 1565:                sprintf(CurrAnsInfo.ans_fmt,"%%.15g");
 1566:             } else {
 1567:                sprintf(aline,"%.15g",s->s_real);
 1568:                strcpy(CurrAnsInfo.ans_fmt,s->s_format);  
 1569:             }
 1570:             CurrAnsInfo.ans_str = strsave(aline);
 1571:             CurrAnsInfo.ans_type = ANSWER_IS_FLOAT;
 1572:             if( CurrAnsInfo.ans_tol == 0.0 ) {
 1573:                 sprintf(warn_msg,"File %s, Line %3d: answer has a numerical value of %s and a zero tolerance.\n",
 1574:                         Opened_filename[Input_idx],Current_line[Input_idx],aline);
 1575:                 capa_msg(MESSAGE_WARN,warn_msg);
 1576:             }
 1577:          break;
 1578:      case S_VAR:  case S_CONSTANT:
 1579:             CurrAnsInfo.ans_str = strsave(s->s_str);
 1580:             if (s->s_str!=NULL && (strlen(s->s_str)>ANSWER_STRING_LENG-1)) {
 1581: 	      sprintf(warn_msg,"File %s, Line %3d: answer is too long, max allowed length is %d, current answer is %d\n",
 1582: 		      Opened_filename[Input_idx],Current_line[Input_idx],
 1583: 		      ANSWER_STRING_LENG-1, strlen(s->s_str));
 1584: 	      capa_msg(MESSAGE_ERROR,warn_msg);
 1585: 	      CurrAnsInfo.ans_str[ANSWER_STRING_LENG-1]='\0';
 1586: 	    }
 1587:             if ( !CurrAnsInfo.ans_type ) { /* not yet specified by str=  answer info */ 
 1588:               CurrAnsInfo.ans_type = ANSWER_IS_STRING_CI;
 1589:             }
 1590:             sprintf(CurrAnsInfo.ans_fmt,"%%s");
 1591:          break;
 1592:    }
 1593:    if(s->s_format) { 
 1594:        capa_mfree((char *)s->s_format);
 1595:    }
 1596:    s->s_format = NULL;
 1597:    switch(s->s_type) {
 1598:       case I_CONSTANT:
 1599:       case R_CONSTANT: capa_mfree((char *)s); break;
 1600:       case S_CONSTANT: capa_mfree(s->s_str); capa_mfree((char *)s); break;
 1601:      default:  break;
 1602:    }
 1603: 
 1604: }
 1605: 
 1606: /* Assign tolerance to CurrAnsInfo first */
 1607: void
 1608: assign_tolerance(tol_type, s) int tol_type; Symbol *s;
 1609: {
 1610:   char  warn_msg[WARN_MSG_LENGTH];
 1611:   
 1612:   CurrAnsInfo.ans_tol_type  = tol_type;
 1613:   switch( s->s_type ) {
 1614:       case IDENTIFIER:
 1615:             sprintf(warn_msg,"TOL = var, \"%s\" not defined before use.\n",s->s_name);
 1616:             capa_msg(MESSAGE_ERROR,warn_msg);
 1617:             CurrAnsInfo.ans_tol = 0.0;
 1618:           break;
 1619:        case I_VAR: case I_CONSTANT: 
 1620:            CurrAnsInfo.ans_tol =(double)s->s_int;
 1621:           break;
 1622:        case R_VAR: case R_CONSTANT:
 1623:            CurrAnsInfo.ans_tol = s->s_real;
 1624:           break;
 1625:        case S_VAR: case S_CONSTANT: CurrAnsInfo.ans_tol = 0.0;
 1626:           break;
 1627:    }
 1628:   free_calc_expr(s);
 1629: }
 1630: 
 1631: /* Problem weight is per problem based */
 1632: void
 1633: assign_weight( s ) Symbol *s;
 1634: { char warn_msg[WARN_MSG_LENGTH];
 1635:   YYDBUG_PR1(" weight = identifier\n");
 1636:   switch( s->s_type ) {
 1637:     case IDENTIFIER:
 1638:             sprintf(warn_msg,"WGT = var, \"%s\" not defined before use.\n", s->s_name);
 1639:             capa_msg(MESSAGE_ERROR,warn_msg);
 1640:             LexiProblem_p->weight = WEIGHT_DEFAULT;
 1641:            break;
 1642:     case I_VAR: case I_CONSTANT:
 1643:             if( s->s_int < 0 ) {
 1644:               sprintf(warn_msg,"WGT = %ld, weight cannot be less than zero.\n", s->s_int);
 1645: 	      capa_msg(MESSAGE_ERROR,warn_msg);
 1646: 	      LexiProblem_p->weight = WEIGHT_DEFAULT;
 1647:             } else {
 1648:               LexiProblem_p->weight = s->s_int; 
 1649:             }
 1650:             break;
 1651:      case R_VAR: case R_CONSTANT:
 1652:             if( s->s_real < 0.0 ) {
 1653:                sprintf(warn_msg,"WGT = %g, weight cannot be less than zero.\n", s->s_real);
 1654: 	       capa_msg(MESSAGE_ERROR,warn_msg);
 1655: 	       LexiProblem_p->weight = WEIGHT_DEFAULT;
 1656:             } else {
 1657:                LexiProblem_p->weight = (int)(s->s_real); 
 1658:             }
 1659:             break;
 1660:       case S_VAR: case S_CONSTANT: LexiProblem_p->weight = WEIGHT_DEFAULT; break;
 1661:     }
 1662:   free_calc_expr(s);
 1663: }
 1664: /* Answer try limit is per problem based */
 1665: void
 1666: assign_try_limits( s ) Symbol *s;
 1667: { char warn_msg[WARN_MSG_LENGTH];
 1668:   switch( s->s_type ) {
 1669:     case IDENTIFIER:
 1670: 	    sprintf(warn_msg,"TRY = var, \"%s\" not defined before use.\n",s->s_name);
 1671:             capa_msg(MESSAGE_ERROR,warn_msg);
 1672:             LexiProblem_p->tries = MAX_TRIES;
 1673:            break;
 1674:     case I_VAR: case I_CONSTANT:
 1675:             if(s->s_int <= 0) {
 1676: 	       sprintf(warn_msg,"TRIES = %ld, tries cannot be less than or equal to zero.\n",s->s_int);
 1677: 	       capa_msg(MESSAGE_ERROR,warn_msg);
 1678: 	       LexiProblem_p->tries = MAX_TRIES;
 1679: 	    } else {
 1680: 	       LexiProblem_p->tries = s->s_int;
 1681: 	    }
 1682: 	   break;
 1683:      case R_VAR:  case R_CONSTANT:
 1684:             if(s->s_real <= 0.0) {
 1685: 	       sprintf(warn_msg,"TRIES = %g, tries cannot be less than or equal to zero.\n",s->s_real);
 1686: 	       capa_msg(MESSAGE_ERROR,warn_msg);
 1687: 	       LexiProblem_p->tries = MAX_TRIES;
 1688: 	     } else {
 1689: 	       LexiProblem_p->tries = (int)(s->s_real);
 1690: 	     }
 1691:             break;
 1692:       case S_VAR: case S_CONSTANT: LexiProblem_p->tries = MAX_TRIES; break;
 1693:    }	    
 1694:   free_calc_expr(s);
 1695: }
 1696: /* Answer hint is per problem based */
 1697: void
 1698: assign_hint( s ) Symbol *s;
 1699: {  char warn_msg[WARN_MSG_LENGTH];
 1700: 	                                 
 1701:     switch( s->s_type ) {
 1702:       case IDENTIFIER:
 1703:                sprintf(warn_msg,"HINT = var, \"%s\" not defined before use.\n", s->s_name);
 1704:                capa_msg(MESSAGE_ERROR,warn_msg);
 1705:                LexiProblem_p->show_hint = SHOW_HINT_DEFAULT;
 1706:              break;
 1707:       case I_VAR: case I_CONSTANT:
 1708:                if( s->s_int < 0 ) {
 1709:                   sprintf(warn_msg,"HINT = %ld, show hint cannot be less than zero.\n", s->s_int);
 1710: 	          capa_msg(MESSAGE_ERROR,warn_msg);
 1711: 	          LexiProblem_p->show_hint = SHOW_HINT_DEFAULT;
 1712:                } else {
 1713:                   LexiProblem_p->show_hint = s->s_int; 
 1714:                }
 1715:              break;
 1716:        case R_VAR: case R_CONSTANT:
 1717:                if( s->s_real < 0.0 ) {
 1718:                   sprintf(warn_msg,"HINT = %g, show hint cannot be less than zero.\n", s->s_real);
 1719: 	          capa_msg(MESSAGE_ERROR,warn_msg);
 1720: 	          LexiProblem_p->show_hint = SHOW_HINT_DEFAULT;
 1721:                } else {
 1722:                   LexiProblem_p->weight = (int)(s->s_real); 
 1723:                }
 1724:              break;
 1725:        case S_VAR: case S_CONSTANT: LexiProblem_p->show_hint = SHOW_HINT_DEFAULT; break;
 1726:     }
 1727:   free_calc_expr(s);
 1728: }
 1729: 
 1730: /* Assign answer units string to CurrAnsInfo first */
 1731: void
 1732: assign_units( s ) Symbol *s;
 1733: {
 1734:   char    symb_str[ONE_TWO_EIGHT];
 1735:   char    warn_msg[WARN_MSG_LENGTH];
 1736:   
 1737:   switch( s->s_type ) {
 1738:     case IDENTIFIER:
 1739:            sprintf(warn_msg,"UNIT = var, \"%s\" not defined before use.\n", s->s_name);
 1740:            capa_msg(MESSAGE_ERROR,warn_msg);
 1741:            break;
 1742:     case I_VAR: case I_CONSTANT:
 1743:            sprintf(warn_msg,"UNIT = %ld, unit cannot be a number.\n", s->s_int);
 1744:            capa_msg(MESSAGE_ERROR,warn_msg);
 1745:            break;
 1746:     case R_VAR: case R_CONSTANT:
 1747:            sprintf(warn_msg,"UNIT = %g, unit cannot be a number.\n", s->s_real);
 1748: 	   capa_msg(MESSAGE_ERROR,warn_msg);
 1749:            break;
 1750:     case S_VAR: case S_CONSTANT:
 1751:            strcpy(symb_str,s->s_str);
 1752: 	   strcpy(CurrAnsInfo.ans_unit_str,symb_str);
 1753: 	   CurrAnsInfo.ans_unit = u_parse_unit(symb_str);
 1754: 	   if (gUnitError) {
 1755: 	      sprintf(warn_msg,"Error in unit specified: %s\n",symb_str);
 1756: 	      capa_msg(MESSAGE_ERROR,warn_msg);
 1757: 	   }
 1758: 	break;
 1759:   }
 1760: }
 1761: void
 1762: assign_sigs( lb, ub ) int lb; int ub;
 1763: {
 1764:   CurrAnsInfo.ans_sig_lb = lb;
 1765:   CurrAnsInfo.ans_sig_ub = ub;
 1766: }
 1767: 
 1768: void
 1769: assign_id_list( s ) Symbol *s;
 1770: {
 1771:   char    warn_msg[WARN_MSG_LENGTH];
 1772:   
 1773:   switch( s->s_type ) {
 1774:     case IDENTIFIER:
 1775:            sprintf(warn_msg,"Eval = < ID @ Pts >, \"%s\" not defined before use.\n", s->s_name);
 1776:            capa_msg(MESSAGE_ERROR,warn_msg);
 1777:            break;
 1778:     case I_VAR: case I_CONSTANT:
 1779:            sprintf(warn_msg,"Eval = < %ld @ Pts >, ID cannot be a number.\n", s->s_int);
 1780:            capa_msg(MESSAGE_ERROR,warn_msg);
 1781:            break;
 1782:     case R_VAR: case R_CONSTANT:
 1783:            sprintf(warn_msg,"Eval = < %.16g @ Pts >, ID cannot be a number.\n", s->s_real);
 1784: 	   capa_msg(MESSAGE_ERROR,warn_msg);
 1785:            break;
 1786:     case S_VAR: case S_CONSTANT:
 1787: 	   CurrAnsInfo.ans_id_list = strsave(s->s_str);
 1788: 	   break;
 1789:   }
 1790: }
 1791: 
 1792: /* =========================================================================== */
 1793: 
 1794: 
 1795: 
 1796: 
 1797: 
 1798: 
 1799: /* =========================================================================== */
 1800: 
 1801: void start_question_over()
 1802: {
 1803:   free_problems(LexiProblem_p);
 1804:   LexiProblem_p = (Problem_t *) capa_malloc(sizeof(Problem_t),1); 
 1805:   problem_default(LexiProblem_p);
 1806:   begin_question();
 1807: }
 1808: 
 1809: void
 1810: init_new_prob()
 1811: {
 1812:   if (LastProblem_p) {
 1813:      LastProblem_p->next = LexiProblem_p;
 1814:   } else {
 1815:      FirstProblem_p      = LexiProblem_p;
 1816:   }
 1817:   LastProblem_p = LexiProblem_p;
 1818:   Lexi_qnum++;  
 1819:   LexiProblem_p = (Problem_t *) capa_malloc(sizeof(Problem_t),1); /* *** */
 1820:   problem_default(LexiProblem_p);
 1821: }
 1822: void
 1823: add_answer_cnt(op)int op;
 1824: {
 1825:   LexiProblem_p->ans_cnt++;
 1826:   if(LexiProblem_p->ans_op == 0) { /* the very first /AND or /OR */
 1827:     LexiProblem_p->ans_op = op;
 1828:   } else {
 1829:     if( LexiProblem_p->ans_op != op ) { char    warn_msg[WARN_MSG_LENGTH];
 1830:       sprintf(warn_msg,"When specifying multiple answers, either /AND or /OR can be used, but not both.\n");
 1831:       capa_msg(MESSAGE_ERROR,warn_msg);
 1832:     }
 1833:   }
 1834: }
 1835: 
 1836: /* -- called when forming answer_expr */
 1837: void
 1838: finish_answer_info()
 1839: {
 1840:   AnswerInfo_t  *ai;
 1841:   
 1842:   if( LexiProblem_p->ans_cnt == 1 ) {  /* Only one answer is defined */
 1843:       LexiProblem_p->answer    = CurrAnsInfo.ans_str;
 1844:       LexiProblem_p->ans_type  = CurrAnsInfo.ans_type;
 1845:       LexiProblem_p->calc      = CurrAnsInfo.ans_calc;
 1846:       LexiProblem_p->tol_type  = CurrAnsInfo.ans_tol_type;
 1847:       LexiProblem_p->tolerance = CurrAnsInfo.ans_tol;
 1848:       LexiProblem_p->sig_ubound= CurrAnsInfo.ans_sig_ub;
 1849:       LexiProblem_p->sig_lbound= CurrAnsInfo.ans_sig_lb;
 1850:       LexiProblem_p->id_list   = CurrAnsInfo.ans_id_list;
 1851:       LexiProblem_p->pts_list  = CurrAnsInfo.ans_pts_list;
 1852:       strcpy(LexiProblem_p->ans_fmt,CurrAnsInfo.ans_fmt);
 1853:       strcpy(LexiProblem_p->unit_str,CurrAnsInfo.ans_unit_str);
 1854:       LexiProblem_p->ans_unit  = CurrAnsInfo.ans_unit;
 1855:   } else {
 1856:       ai = (AnswerInfo_t  *)capa_malloc(sizeof(AnswerInfo_t),1);
 1857:       ai->ans_str       = CurrAnsInfo.ans_str;
 1858:       ai->ans_type      = CurrAnsInfo.ans_type;
 1859:       ai->ans_calc      = CurrAnsInfo.ans_calc;
 1860:       ai->ans_tol_type  = CurrAnsInfo.ans_tol_type;
 1861:       ai->ans_tol       = CurrAnsInfo.ans_tol;
 1862:       ai->ans_sig_ub    = CurrAnsInfo.ans_sig_ub;
 1863:       ai->ans_sig_lb    = CurrAnsInfo.ans_sig_lb;
 1864:       ai->ans_id_list   = CurrAnsInfo.ans_id_list;
 1865:       ai->ans_pts_list  = CurrAnsInfo.ans_pts_list;
 1866:       strcpy(ai->ans_fmt,CurrAnsInfo.ans_fmt);
 1867:       strcpy(ai->ans_unit_str,CurrAnsInfo.ans_unit_str);
 1868:       ai->ans_unit      = CurrAnsInfo.ans_unit;
 1869:       ai->ans_next      = NULL;
 1870:       if(LexiProblem_p->ans_cnt == 2) {
 1871:         LexiProblem_p->ans_list = ai;
 1872:       } else {
 1873:         (LexiProblem_p->ans_list_last)->ans_next = ai;
 1874:       }
 1875:       LexiProblem_p->ans_list_last = ai;
 1876:   }
 1877: 
 1878: }
 1879: 
 1880: /* === End of capaGrammarDef.y ============================================= */
 1881: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>