home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / fweb153.zip / fweb-1.53 / web / eval.c < prev    next >
C/C++ Source or Header  |  1995-09-23  |  30KB  |  1,410 lines

  1. #if(0)
  2.   FTANGLE v1.53, created with UNIX on "Thursday, September 21, 1995 at 15:06."  \
  3.   COMMAND LINE: "web/ftangle web/eval -A -# --F -= 1.53/web/eval.c" \
  4.   RUN TIME: "Saturday, September 23, 1995 at 16:17." \
  5.   WEB FILE:    "web/eval.web" \
  6.   CHANGE FILE: (none)
  7. #endif
  8. #define _EVAL_h   \
  9.  
  10. #define BP_MARKER  1 \
  11.  
  12. #define PROPER_END(end) \
  13. end= (np+1)->byte_start; \
  14. if(*end==BP_MARKER&&np!=npmax)end= ((BP*)end)->byte_start \
  15.  
  16. #define MAX_ID_LENGTH  32 /* Truncated identifiers can't be longer than this. */ \
  17.  
  18. #define stringg  (eight_bits)02 /* Extended ASCII alpha should not appear. (The funny \
  19.     spelling is to avoid conflict with the VAX' \.{stdlib}.) */
  20. #define constant  (eight_bits)03 /* Numerical constant. */
  21. #define begin_Xmeta  or_or
  22. #define end_Xmeta  star_star
  23. #define cdir  (eight_bits)06 /* Brackets compiler directive.. */
  24. #define colon_colon  (eight_bits)011 /* \Cpp\ and \Fortran--90: `$\CF$'. */ \
  25.  
  26. #define join  (eight_bits)0177 /* |ASCII| delete will not appear. */ \
  27.  
  28. #define ID0  0200 /* $128 =$ end of the 7-bit ASCII codes. */
  29. #define TOKEN1(a)((a)<ID0)/* Is |a|~a single-byte token? */ \
  30.  
  31. #define MACRO_ARGUMENT  0377 /* See the related definition and discussion of \
  32.                 |MOD0|. */
  33. #define BASE2  0400 /* |0xFF + 1 = 0x100 = 256| */ \
  34.  
  35. #define MODULE_NAME  10240 /* |024000= 10240 = (0250-0200)*0400| */
  36. #define MODULE_NUM  20480 /* |050000 = 20480 = (0320-0200)*0400| */
  37. #define LINE_NUM  53248L /* |0150000==0320*0400| */ \
  38.  
  39. #define IDENTIFIER(left,right) \
  40. ((sixteen_bits)(((left)-ID0)*BASE2+(sixteen_bits)(right))) \
  41. /* Construct two-byte token out of its constituents. */ \
  42.  
  43. #define LEFT(a,id)((eight_bits)(((a)/BASE2+(id))))/* Make left-hand byte out of \
  44.                     |sixteen_bits|. */
  45. #define RIGHT(a)((eight_bits)(((a)%BASE2)))/* Make right-hand byte. */ \
  46.  
  47. #define ignore  0 /* Control code of no interest to \.{TANGLE}. */ \
  48.  
  49. #define begin_comment0  (eight_bits)0376 /* Sent from |input_ln|; marker for long comment. */
  50. #define begin_comment1  (eight_bits)0375 /* As above; marker for short comment. */ \
  51.  
  52. #define module_number  (eight_bits)0201 /* Code returned by |get_output| for mod.\ numbers. */
  53. #define identifier  (eight_bits)0202 /* Code returned by |get_output| for identifiers. */
  54. #define id_keyword  (eight_bits)0203 /* As above, but for expandable keyword. */ \
  55.  
  56. #define L_switch  (eight_bits)0257 /* Control code for `\.{@L}'. */
  57. #define begin_FORTRAN  (eight_bits)0260
  58. #define begin_RATFOR  (eight_bits)0261
  59. #define begin_C  (eight_bits)0262
  60. #define begin_LITERAL  (eight_bits)0263 \
  61.  
  62. #define verbatim  (eight_bits)0264 /* Can't be~|02| as for \.{fweave}, because \
  63.                 |stringg| is defined to be that. */ \
  64.  
  65. #define invisible_cmnt  (eight_bits)0265 /* Control code for `\.{@\%}'. */
  66. #define compiler_directive  (eight_bits)0266 /* No longer used. */
  67. #define Compiler_Directive  (eight_bits)0267 /* Control code for `\.{@?}'. */
  68. #define no_index  (eight_bits)0300 /* Control code for `\.{@-}'. */
  69. #define yes_index  (eight_bits)0301 /* Control code for `\.{@+}'. */ \
  70.  
  71. #define ascii_constant  (eight_bits)0302 /* Control code for `\.{@'}'. */
  72. #define begin_vcmnt  (eight_bits)0303 /* Control code for `\.{@\slashstar}'. */
  73. #define big_line_break  (eight_bits)0304 /* Control code for `\.{@\#}'. */ \
  74.  
  75. #define begin_bp  (eight_bits)0305
  76. #define insert_bp  (eight_bits)0306 \
  77.  
  78. #define begin_meta  (eight_bits)017 /* Control code for |"@("|. */
  79. #define end_meta  (eight_bits)027 \
  80.  
  81. #define TeX_string  (eight_bits)0307
  82. #define xref_roman  (eight_bits)0310
  83. #define xref_typewriter  (eight_bits)0311
  84. #define xref_wildcard  (eight_bits)0312 \
  85.  
  86. #define control_text  (eight_bits)0313 /* Control code for `\.{@t}', `\.{@\^}', etc. */ \
  87.  
  88. #define begin_nuweb  (eight_bits)0314
  89. #define no_mac_expand  (eight_bits)0315 /* Control code for `\.{@\~}' */
  90. #define set_line_info  (eight_bits)0316 /* Expt'l control code for `\.{@Q}'. */ \
  91.  
  92. #define formatt  (eight_bits)0320 /* Control code for `\.{@f}'. */ \
  93.  
  94. #define limbo_text  (eight_bits)0323 /* Control code for `\.{@l}'. */
  95. #define op_def  (eight_bits)0324 /* Control code for `\.{@v}'. */
  96. #define macro_def  (eight_bits)0325 /* Control code for `\.{@W}'. */ \
  97.  
  98. #define ignore_defn  (eight_bits)0327 /* Stuff to here should be ignored when scanning defn. */ \
  99.  
  100. #define new_output_file  (eight_bits)0331 /* Control code for `\.{@o}'. */ \
  101.  
  102. #define definition  (eight_bits)0332 /* Control code for `\.{@d}'. */
  103. #define undefinition  (eight_bits)0333 /* Control code for `\.{@u}'. */
  104. #define WEB_definition  (eight_bits)0334 /* Control code for `\.{@m}'. */ \
  105.  
  106. #define m_ifdef  (eight_bits)0335
  107. #define m_ifndef  (eight_bits)0336
  108. #define m_if  (eight_bits)0337
  109. #define m_else  (eight_bits)0340
  110. #define m_elif  (eight_bits)0341
  111. #define m_endif  (eight_bits)0342
  112. #define m_for  (eight_bits)0343
  113. #define m_endfor  (eight_bits)0344
  114. #define m_line  (eight_bits)0345
  115. #define m_undef  (eight_bits)0346 \
  116.  
  117. #define end_of_buffer  (eight_bits)0347 \
  118.  
  119. #define begin_code  (eight_bits)0350 /* Control code for `\.{@a}'. */
  120. #define module_name  (eight_bits)0351 /* Control code for `\.{@<}'. */ \
  121.  
  122. #define new_module  (eight_bits)0352 /* Control code for `\.{@\ }' and `\.{@*}'. */ \
  123.  
  124. #define BINARY(l,token)switch(val0->type) \
  125. { \
  126. case Int: \
  127. val0->value.i= val0->value.i token val1->value.i; \
  128. break; \
  129.  \
  130. case Double: \
  131. val0->value.l= val0->value.d token val1->value.d; \
  132. break; \
  133.  \
  134. case Id: \
  135. misplaced_id(val0->value.id,val1->value.id); \
  136.  \
  137. default: \
  138.  \
  139. { \
  140. if(eval_msgs) \
  141. macro_err(OC("! Shouldn't have type Op here"),YES);longjmp(top_of_evaluate,1); \
  142. } \
  143. } \
  144.  
  145. #define ARITH(token)BINARY(d,token)break \
  146.  
  147. #define LOG(token)BINARY(i,token)val0->type= Int;break \
  148.  
  149. #define BIT(token)if(val0->type!=Int) \
  150. { \
  151. if(eval_msgs) \
  152. macro_err(OC("! Invalid type %s in bit \
  153. operation. (Macro not defined?)"),YES,stype(val0->type));longjmp(top_of_evaluate,1); \
  154. } \
  155. val0->value.i= val0->value.i token val1->value.i; \
  156. break \
  157.  
  158. #define DEFINED_TOKEN  (eight_bits)023
  159. #define UNARY_MINUS  (eight_bits)024 \
  160.  
  161. #define LOWEST_PRECEDENCE  1
  162. #define HIGHEST_PRECEDENCE  13 \
  163.  \
  164. /* In the following, the casting shouldn't be necessary, since according to \
  165. ANSI |enum|s behave like integers. But it's necessary to keep the |DSU| \
  166. compiler happy. */
  167. #define IS_UNARY(token)((int)precedence(token)>=(int)UNARY)
  168. #define IS_BINARY(token)((int)precedence(token)<(int)UNARY) \
  169.  
  170. #define TO_DOUBLE(v)CONVERT_TO(Double,d,double,v)
  171. #define TO_ID(v)CONVERT_TO(Id,id,sixteen_bits,v) \
  172.  
  173. #define CONVERT_TO(t,lhs,cast,v)if(v->type!=t) \
  174. { \
  175. v->value.lhs= (cast)v->value.i; \
  176. v->type= t; \
  177. } \
  178.  
  179.  
  180.  
  181. #include "typedefs.h"
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190. typedef struct
  191. {
  192. eight_bits HUGE*tok_start;/* Pointer into |tok_mem| (for a module or \
  193. regular macro).  For an internal macro, points to the internal function. */
  194. sixteen_bits text_link;/* Relates replacement texts  (0 for a macro). */
  195. boolean Language;/* Which language referenced this name. */
  196. eight_bits nargs;/* Number of macro arguments. */
  197. unsigned moffset:8,/* Offset to macro replacement text from start. */
  198. recursive:1,/* Is this macro allowed to be recursive? */
  199. var_args:1,/* Can it have variable number of arguments? */
  200. module_text:1,/* Distinguishes from preprocessor fragment. */
  201. built_in:1;/* Is it a built-in function (internal macro)? */
  202. }text;
  203.  
  204. typedef text HUGE*text_pointer;
  205.  
  206.  
  207.  
  208. #if(0)
  209. IN_COMMON boolean truncate_ids;/* Truncate identifers? */
  210. IN_COMMON unsigned short tr_max[];/* Truncate to this length. */
  211. IN_COMMON name_pointer npmax;/* |name_ptr - 1|. */
  212. #endif
  213.  
  214. /* Back-pointer structure points back to the original name in |name_dir|. */
  215. typedef struct Bp
  216. {
  217. ASCII c;/* Dummy byte that always remains~|BP_MARKER|. */
  218. LANGUAGE Language;
  219. CONST ASCII HUGE*byte_start,HUGE*byte_end;/* Points to original, \
  220. untruncated name. */
  221. struct Bp HUGE*next;/* Links to next back-pointer structure, in \
  222. case a truncated name came from more than one original name. */
  223. struct Trunc HUGE*Root;
  224. }BP;
  225.  
  226. /* Info about a truncated identifier. */
  227. typedef struct Trunc
  228. {
  229. boolean Language;/* All languages associated with this name. */
  230. size_t num[NUM_LANGUAGES];
  231. /* \# of instances of the truncated name. */
  232. ASCII HUGE*id,HUGE*id_end;/* Truncated variable name. */
  233. BP HUGE*first,HUGE*last;/* First and last back-pointer structures. */
  234. struct Trunc HUGE*next;/* Next structure in truncated chain. */
  235. }TRUNC;
  236.  
  237.  
  238.  
  239. /* Precedence of the various operators. */
  240. typedef enum{BAD_TOKEN,OR_OR,AND_AND,BIT_OR,BIT_XOR,BIT_AND,LOG_EQ,LOG_LT,
  241. BIT_SHIFT,PLUS_MINUS,TIMES,EXP,UNARY,HIGHEST_UNARY}PRECEDENCE;
  242.  
  243. /* An operator, together with its precedence. */
  244. typedef struct
  245. {
  246. eight_bits token;
  247. PRECEDENCE precedence;
  248. }OP;
  249.  
  250. /* The actual data value. */
  251. typedef union
  252. {
  253. long i;/* All integers are long, to humor the pc people. */
  254. double d;/* We handle just one floating-point type. */
  255. sixteen_bits id;/* An identifier token. */
  256. OP op;
  257. }VALUE;
  258.  
  259. /* Type of the data value. The relative order must be preserved here, \
  260. because it is used in the type promotion routine |promote|. */
  261. typedef enum{Int,Double,Id,Op}TYPE;
  262.  
  263. /* Complete data structure for the token; includes links to the next and \
  264. last |VAL| structures. */
  265. typedef struct val
  266. {
  267. VALUE value;/* The actual data value or operator token. */
  268. TYPE type;/* The type of value stored in |value|. */
  269. struct val HUGE*last,HUGE*next;/* Link to the last and next values. */
  270. }VAL;
  271.  
  272.  
  273.  
  274. /* A static heap of available |VAL| structures. */
  275. VAL HUGE*val_heap;/* Allocated at outer level of |evaluate|. */
  276. VAL HUGE*val_ptr;/* Next available |VAL| in heap. */
  277.  
  278.  
  279.  
  280.  
  281. #include "e_type.h" /* Function prototypes for \.{eval}. */
  282. #include "r_type.h" /* Prototypes for \.{ratfor}. */
  283.  
  284.  
  285.  
  286.  
  287. /* The shorter length here is primarily to keep the stack under control. \
  288. Now that |N_MSGBUF| is used  dynamically, maybe this statement isn't \
  289. necessary. */
  290. #ifdef SMALL_MEMORY
  291. #define N_MSGBUF 2000
  292. #else
  293. #define N_MSGBUF 10000
  294. #endif
  295.  
  296.  
  297.  
  298.  
  299.  
  300. EXTERN long max_texts;/* Number of replacement texts, must be $< 10240$. */
  301. EXTERN text HUGE*text_info;/* Dynamic array. */
  302. EXTERN text_pointer text_end;/* End of above. */
  303.  
  304. EXTERN long dtexts_max;/* Number of deferred replacement texts. */
  305. EXTERN text HUGE*txt_dinfo;/* Dynamic array. */
  306. EXTERN text_pointer textd_end;
  307.  
  308. EXTERN text_pointer text_ptr,txt_dptr;/* First unused position in |text_info| \
  309.                     and in |txt_dinfo|. */
  310.  
  311. EXTERN long max_toks;/* Number of bytes in compressed code. */
  312. EXTERN eight_bits HUGE*tok_mem;/* Dynamic array. */
  313. EXTERN eight_bits HUGE*tok_m_end;
  314.  
  315. EXTERN long max_dtoks;/* Number of bytes in deferred macros. */
  316. EXTERN eight_bits HUGE*tok_dmem;/* Dynamic array. */
  317. EXTERN eight_bits HUGE*tokd_end;
  318.  
  319. EXTERN eight_bits HUGE*tok_ptr,HUGE*tok_dptr;/* First unused position in \
  320.             |tok_mem| and in |tok_dmem|. */
  321. EXTERN eight_bits HUGE*mx_tok_ptr,HUGE*mx_dtok_ptr;/* Largest value \
  322.     assumed by |tok_ptr|  and |tok_ptrd|; for statistics. */
  323.  
  324. EXTERN text_pointer macro_text;
  325.  
  326.  
  327.  
  328. static jmp_buf top_of_evaluate;/* Environment for the |setjmp|--|longjmp|./ */
  329. boolean eval_msgs ESET(YES);/* Sometimes we want to suppress the msgs. */
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337. outer_char*stype FCN((type))
  338. TYPE type C1("Type whose name is desired.")
  339. {
  340. switch(type)
  341. {
  342. case Int:return OC("Int");
  343. case Double:return OC("Double");
  344. case Id:return OC("Id");
  345. case Op:return OC("Op");
  346. default:return OC("UNKNOWN");
  347. }
  348. }
  349.  
  350.  
  351. boolean eval FCN((p0,p1))
  352. CONST eight_bits HUGE*p0 C0("Beginning of tokens.")
  353. CONST eight_bits HUGE*p1 C1("End of tokens.")
  354. {
  355. VAL val;
  356.  
  357. EVALUATE(val,p0,p1);
  358.  
  359. switch(val.type)
  360. {
  361. case Int:return(boolean)(val.value.i!=0);
  362. case Double:return(boolean)(val.value.d!=0.0);
  363. default:
  364. if(eval_msgs)
  365. macro_err(OC("! Non-numeric type returned from eval \
  366. (undefined macro?); assumed FALSE"),YES);
  367. return 0;/* Error in evaluation. */
  368. }
  369. }
  370.  
  371.  
  372. int neval FCN((p0,p1))
  373. CONST eight_bits HUGE*p0 C0("Beginning of tokens.")
  374. CONST eight_bits HUGE*p1 C1("End of tokens.")
  375. {
  376. VAL val;
  377.  
  378. EVALUATE(val,p0,p1);
  379.  
  380. switch(val.type)
  381. {
  382. case Int:return(int)(val.value.i);
  383. case Double:return(int)(val.value.d);
  384. default:
  385. if(eval_msgs)
  386. macro_err(OC("! Non-numeric type returned from neval \
  387. (undefined macro?); assumed 0"),YES);
  388. return 0;/* Error in evaluation. */
  389. }
  390. }
  391.  
  392.  
  393. SRTN i_eval_ FCN((n,pargs))
  394. int n C0("")
  395. PARGS pargs C1("")
  396. {
  397. VAL val;
  398. eight_bits HUGE*p0;
  399.  
  400. CHK_ARGS("$EVAL",1);
  401.  
  402. p0= pargs[0]+1;
  403. EVALUATE(val,p0,pargs[1]);
  404.  
  405.  
  406. {
  407. MCHECK0(2,"expansion |constant|");
  408. /* Takes care of the two bracketing |constant|s. */
  409. *mp++= constant;/* Beginning of the |constant|. */
  410.  
  411. switch(val.type)
  412. {
  413. case Int:
  414.  
  415. nsprintf((outer_char*)mp,OC("%ld"),1,val.value.i);
  416. break;
  417.  
  418. case Double:
  419.  
  420. nsprintf((outer_char*)mp,OC("%#.*g"),2,DBL_DIG,val.value.d);
  421. /* Format guarantees a decimal point. */
  422. break;
  423.  
  424. case Id:
  425. MCHECK0(pargs[1]-p0,"Id");
  426. mp--;/* Backspace to beginning of |constant|. */
  427. while(p0<pargs[1])*mp++= *p0++;/* Copy it over. */
  428. return;
  429.  
  430. default:
  431. if(eval_msgs)
  432. macro_err(OC("! Invalid type returned from _eval_"),YES);
  433. return;
  434. }
  435.  
  436. fin_constant(val.type);
  437. }
  438.  
  439. ;
  440. }
  441.  
  442.  
  443. CONST eight_bits HUGE*evaluate FCN((val,p0,p1))
  444. VAL HUGE*val C0("Return the evaluated |DATA| structure here.")
  445. CONST eight_bits HUGE*p0 C0("Beginning of the input tokens.")
  446. CONST eight_bits HUGE*p1 C1("End of the input tokens.")
  447. {
  448. if(setjmp(top_of_evaluate)==0)return eval0(val,p0,p1,(eight_bits)'\0');
  449. /* Evaluate the expression. */
  450. else
  451. {/* Get here from |longjmp|. */
  452. val->type= Id;/* Flag for bad expression. */
  453. val->value.id= ignore;
  454. return p1;
  455. }
  456. }
  457.  
  458.  
  459. CONST eight_bits HUGE*eval0 FCN((val,p0,p1,delim))
  460. VAL HUGE*val C0("Return the evaluated |DATA| structure here.")
  461. CONST eight_bits HUGE*p0 C0("Beginning of the input tokens.")
  462. CONST eight_bits HUGE*p1 C0("End of the input tokens.")
  463. eight_bits delim C1("End the scan when this token is encountered.")
  464. {
  465. CONST eight_bits HUGE*p;
  466. eight_bits a;
  467. sixteen_bits id;
  468. VAL v_root,v_end;/* Dummies to help terminate the list. */
  469. VAL HUGE*v;/* Current |VAL|. */
  470. VAL HUGE*v0= &v_root,HUGE*v1= &v_end;/* Point to the first and \
  471.         last elements in the chain. */
  472. VAL HUGE*vlast,HUGE*vnext;/* Temporaries. */
  473. int prec;
  474. boolean at_start;/* Are we at start of list? */
  475. eight_bits last_op;/* The first of two consecutive operator tokens. Also \
  476.     used as a |boolean| operator; if it's non-zero, the last token was an \
  477.     operator. */
  478. int k,found_op[HIGHEST_PRECEDENCE+1];
  479.  
  480. /* Initialize the speed array. */
  481. for(k= LOWEST_PRECEDENCE;k<=HIGHEST_PRECEDENCE;k++)found_op[k]= 0;
  482.  
  483. /* Check for invalid, null expression. */
  484. if(p0>=p1||*p0==delim)
  485. {
  486. if(eval_msgs)
  487. macro_err(OC("! Null expression encountered during expression \
  488. evaluation; 0 assumed"),YES);
  489. val->type= Int;
  490. val->value.i= 0;
  491.  
  492. if(*p0==delim)return p0+1;
  493. else return p1;
  494. }
  495.  
  496.  
  497. {
  498. at_start= YES;/* In case of a leading unary minus. */
  499. last_op= ignore;
  500.  
  501. for(p= p0,vlast= v0,v= v0->next= ++val_ptr,v->last= vlast;p<p1;)
  502. {
  503. if(TOKEN1(a= *p++))
  504.  
  505. {
  506. if(a==delim)
  507. break;/* The token |delim| ends the scan. */
  508.  
  509. reswitch:
  510. switch(a)
  511. {
  512. case 050:
  513. last_op= ignore;
  514. p= eval0(v,p,p1,051);
  515. /* Recursively evaluate parenthesized expressions. */
  516. break;
  517.  
  518. case dot_const:
  519. {
  520. extern DOTS dots0[];
  521. DOTS*d;
  522. int num= *p++;
  523.  
  524. if(num>14)
  525. {
  526. if(eval_msgs)
  527. macro_err(OC("! May only use predefined dot \
  528. constants such as .AND. here"),YES);longjmp(top_of_evaluate,1);
  529. };
  530.  
  531. d= dots0+num;
  532.  
  533. if(d->cat==expr)
  534. {
  535. if(eval_msgs)
  536. macro_err(OC("! .FALSE. and .TRUE. are not handled \
  537. by the expression evaluator.  Please use 0 or 1 instead"),YES);longjmp(top_of_evaluate,1);
  538. }
  539. if(d->cat!=binop)
  540. {
  541. if(eval_msgs)
  542. macro_err(OC("! Invalid dot constant during \
  543. expression evaluation; was expecting binary operator"),YES);longjmp(top_of_evaluate,1);
  544. }
  545. a= d->token;/* The translation. */
  546. goto reswitch;
  547. }
  548.  
  549. case constant:
  550. last_op= ignore;
  551. p= vfill(v,p,p1);/* Convert constant to data. */
  552. break;
  553.  
  554. case stringg:
  555. while(*p++!=stringg);/* Skip over embedded string, to \
  556. overlook verbatim comments. */
  557. continue;
  558.  
  559. case 040:
  560. case tab_mark:
  561. continue;/* These sneak in during nuweb mode. */
  562.  
  563. case 055:
  564. if(last_op||at_start)a= UNARY_MINUS;
  565. last_op= ignore;/* Falls through to |default|. */
  566.  
  567. default:
  568. if((prec= (int)precedence(a))>0)
  569. {
  570. if(last_op&&((IS_UNARY(last_op)&&IS_UNARY(a))
  571. ||(IS_BINARY(last_op)&&IS_BINARY(a))))
  572.  
  573. {
  574. if(eval_msgs)
  575. macro_err(OC("! Adjacent operators \"%s %s\" \
  576. not allowed in expression"),YES,op_name(last_op),op_name(a));longjmp(top_of_evaluate,1);
  577. }
  578.  
  579. v->type= Op;
  580. last_op= v->value.op.token= a;
  581. found_op[(int)(v->value.op.precedence= (PRECEDENCE)prec)]++;
  582. }
  583. else
  584. {
  585. if(eval_msgs)
  586. macro_err(OC(_Xx("! Invalid token '%c' (0x%x) in \
  587. expression")),YES,a>=040?a:'?',a);longjmp(top_of_evaluate,1);
  588. }
  589. break;
  590. }
  591.  
  592. at_start= NO;
  593. }
  594.  
  595.  
  596. else
  597.  
  598. {
  599. at_start= NO;last_op= ignore;
  600.  
  601. if((id= IDENTIFIER(a,*p++))==id_defined)
  602. {
  603. v->type= Op;
  604. last_op= v->value.op.token= DEFINED_TOKEN;
  605. found_op[(int)(v->value.op.precedence= precedence(DEFINED_TOKEN))]++;
  606. }
  607. else
  608. {
  609. v->type= Id;/* This had better be the argument of |defined|. */
  610. v->value.id= id;
  611. }
  612. }
  613.  
  614.  
  615.  
  616. /* This statement is put here rather than as part of the |for| so we can \
  617. skip over it if we're skipping a string. */
  618. vlast= v;v= v->next= ++val_ptr;v->last= vlast;
  619. }
  620.  
  621. vlast->next= v1;/* Terminate the chain forward. */
  622. v1->last= vlast;
  623. }
  624.  
  625.  
  626.  
  627.  
  628. for(prec= (int)HIGHEST_UNARY;prec>=(int)UNARY;prec--)
  629. if(found_op[prec])
  630. for(v= v0->next;v!=v1;v= vnext)
  631. {
  632. vnext= v->next;
  633.  
  634. if(v->type==Op&&v->value.op.precedence==(PRECEDENCE)prec)
  635. {
  636. switch(v->value.op.token)
  637. {
  638. case DEFINED_TOKEN:
  639.  
  640. {
  641. text_pointer m;
  642.  
  643. if(vnext->type!=Id)
  644.  
  645. {
  646. if(eval_msgs)
  647. macro_err(OC("! 'defined' must act on identifier, not type %s"),NO,stype(vnext->type));longjmp(top_of_evaluate,1);
  648. }
  649. else v->value.i= ((m= mac_lookup(vnext->value.id))!=NULL&&!(m->built_in));
  650.  
  651. v->type= Int;
  652. }
  653.  
  654. ;break;
  655.  
  656. case 041:
  657.  
  658.  
  659. switch(vnext->type)
  660. {
  661. case Int:
  662. v->value.i= !(vnext->value.i);
  663. break;
  664.  
  665. case Double:
  666. v->value.i= !(vnext->value.d);
  667. break;
  668.  
  669. default:
  670.  
  671. {
  672. if(eval_msgs)
  673. macro_err(OC("! Can't negate type %s"),YES,stype(vnext->type));longjmp(top_of_evaluate,1);
  674. }
  675. }
  676.  
  677. v->type= Int
  678.  
  679.  
  680. ;break;
  681.  
  682. case 0176:
  683.  
  684.  
  685. if(vnext->type!=Int)
  686. {
  687. if(eval_msgs)
  688. macro_err(OC("! Can't take one's complement of type %s; \
  689. operand converted to integer"),YES,stype(vnext->type));
  690. v->value.i= (long)(vnext->value.d);
  691. }
  692.  
  693. v->type= Int;
  694. v->value.i= ~vnext->value.i
  695.  
  696. ;break;
  697.  
  698. case UNARY_MINUS:
  699.  
  700.  
  701. switch(v->type= vnext->type)
  702. {
  703. case Int:
  704. v->value.i= -(vnext->value.i);break;
  705.  
  706. case Double:
  707. v->value.d= -(vnext->value.d);break;
  708.  
  709. default:
  710.  
  711. {
  712. if(eval_msgs)
  713. macro_err(OC("! Missing or invalid operand of unary minus \
  714. has type %s"),NO,stype(v->type));longjmp(top_of_evaluate,1);
  715. }
  716. }
  717.  
  718. ;break;
  719. }
  720.  
  721. /* The value is now where the unary operator was; remove the original value \
  722. from the list. */
  723. v->next= vnext->next;
  724. v->next->last= v;
  725. vnext= v->next;
  726.  
  727. if(!(--found_op[prec]))break;
  728. }
  729. }
  730.  
  731.  
  732.  
  733. /* Traverse the chain beginning at~|v0| and ending at~|v1|, and reduce \
  734. binary operations according to precedence. */
  735. v0= eval1(v0,v1,(PRECEDENCE)LOWEST_PRECEDENCE,found_op);
  736. val->type= v0->type;
  737. val->value= v0->value;
  738.  
  739. for(k= LOWEST_PRECEDENCE;k<=HIGHEST_PRECEDENCE;k++)
  740. if(found_op[k])
  741.  
  742. {
  743. if(eval_msgs)
  744. macro_err(OC("! Missing operand(s) at precedence \
  745. level %d (null macro?)"),YES,k);longjmp(top_of_evaluate,1);
  746. };
  747.  
  748. return p;
  749. }
  750.  
  751.  
  752. CONST eight_bits HUGE*vfill FCN((v,p0,p1))
  753. VAL HUGE*v C0("To be filled.")
  754. CONST eight_bits HUGE*p0 C0("Start of expression.")
  755. CONST eight_bits HUGE*p1 C1("End of expression.")
  756. {
  757. CONST eight_bits HUGE*p;
  758. eight_bits a;
  759. ASCII temp[100];/* Should be error checked. */
  760. ASCII HUGE*t;
  761. TYPE type= Int;
  762.  
  763. /* Put the stuff between |constant| into a temporary buffer. */
  764. for(p= p0,t= temp;p<p1;)
  765. {
  766. if((a= *p++)==constant)break;/* Terminating delimiter found. */
  767.  
  768. if(a==056||a==0145||a==0105||a==0144||a==0104)type= Double;
  769.  
  770. *t++= a;
  771. }
  772.  
  773. *t= '\0';
  774.  
  775. /* Convert the buffer. */
  776. switch(v->type= type)
  777. {
  778. case Int:
  779. if(temp[0]==060)
  780. if(temp[1]==0170||temp[1]==0130)
  781. v->value.i= xtoi(temp,t);
  782. else if(temp[1]==0142||temp[1]==0102)
  783. v->value.i= btoi(temp,t);
  784. else v->value.i= otoi(temp,t);
  785. else v->value.i= ATOL(to_outer(temp));
  786. break;
  787.  
  788. case Double:
  789. v->value.d= ATOF(to_outer(temp));
  790. break;
  791.  
  792. default:
  793. CONFUSION("vfill","Type must be Int or Double here");
  794. }
  795.  
  796. return p;
  797. }
  798.  
  799.  
  800. VAL HUGE*eval1 FCN((v0,v1,prec0,found_op))
  801. CONST VAL HUGE*v0 C0("Start of list.")
  802. CONST VAL HUGE*v1 C0("End of list.")
  803. PRECEDENCE prec0 C0("Start scanning with this value of precedence.")
  804. int found_op[]C1("Array of flags---was an operator found at \
  805. each precedence level?")
  806. {
  807. int prec;
  808. VAL HUGE*v,
  809. HUGE*val0,HUGE*val1;/* Returned pointers from |eval1| to the \
  810. left and right operands of a binary operator. */
  811.  
  812. if(v0->next==v1->last)return v0->next;/* Reduced down to constant. */
  813.  
  814. for(prec= (int)prec0;prec<(int)UNARY;prec++)
  815. if(found_op[prec])
  816. for(v= v1->last;v!=v0;v= v->last)
  817. {
  818. if(v->type==Op&&v->value.op.precedence==(PRECEDENCE)prec)
  819. {
  820. val0= eval1(v0,v,(PRECEDENCE)LOWEST_PRECEDENCE,
  821. found_op);/* Left-hand expression. */
  822. val1= eval1(v,v1,(PRECEDENCE)(prec+1),found_op);
  823. /* Right-hand expression. */
  824. promote(val0,val1);
  825.  
  826.  
  827.  
  828. switch(v->value.op.token)
  829. {
  830. case star_star:
  831.  
  832.  
  833. switch(val0->type)
  834. {
  835. case Int:
  836. val0->value.i= 
  837. (long)pow((double)val0->value.i,(double)val1->value.i);
  838. break;
  839.  
  840. case Double:
  841. val0->value.d= pow(val0->value.d,val1->value.d);
  842. break;
  843.  
  844. default:
  845.  
  846. {
  847. if(eval_msgs)
  848. macro_err(OC("! Invalid operand of exponentiate has type %s"),NO,stype(val0->type));longjmp(top_of_evaluate,1);
  849. }
  850. }
  851.  
  852. ;break;
  853.  
  854. case 052:ARITH(*);
  855. case 057:chk_zero('/',val1);ARITH(/);
  856. case 045:chk_zero('%',val1);BIT(%);
  857.  
  858. case 053:ARITH(+);
  859. case 055:ARITH(-);
  860.  
  861. case lt_lt:BIT(<<);
  862. case gt_gt:BIT(>>);
  863.  
  864. case 074:LOG(<);
  865. case lt_eq:LOG(<=);
  866. case 076:LOG(>);
  867. case gt_eq:LOG(>=);
  868.  
  869. case eq_eq:LOG(==);
  870. case not_eq:LOG(!=);
  871.  
  872. case 046:BIT(&);
  873. case 0136:case neqv:BIT(^);
  874. case 0174:BIT(|);
  875.  
  876. case and_and:BIT(&&);
  877. case or_or:BIT(||);
  878. }
  879.  
  880.  
  881.  
  882.  
  883. found_op[prec]--;
  884. return val0;
  885. }
  886. }
  887.  
  888.  
  889. {
  890. if(eval_msgs)
  891. macro_err(OC("! Missing binary operator, or undefined macro"),YES);longjmp(top_of_evaluate,1);
  892. }
  893.  
  894. DUMMY_RETURN(NULL);
  895. }
  896.  
  897.  
  898. SRTN chk_zero FCN((c,pv))
  899. outer_char c C0("Operator.")
  900. CONST VAL HUGE*pv C1("Right-hand operand.")
  901. {
  902. boolean is_zero= NO;
  903.  
  904. switch(pv->type)
  905. {
  906. case Int:
  907. if(pv->value.i==0)is_zero= YES;
  908. break;
  909.  
  910. case Double:
  911. if(pv->value.d==0.0)is_zero= YES;
  912. break;
  913.  
  914. default:
  915.  
  916. {
  917. if(eval_msgs)
  918. macro_err(OC("! Right operand of '%c' must have type Int or \
  919. Double"),YES,c);longjmp(top_of_evaluate,1);
  920. }
  921. }
  922.  
  923. if(is_zero)
  924. {
  925. if(eval_msgs)
  926. macro_err(OC("! RIGHT OPERAND OF '%c' IS ZERO"),YES,c);longjmp(top_of_evaluate,1);
  927. }
  928. }
  929.  
  930.  
  931. SRTN misplaced_id FCN((a0,a1))
  932. sixteen_bits a0 C0("Left-hand token.")
  933. sixteen_bits a1 C1("Right-hand token.")
  934. {
  935. outer_char left_id[MAX_ID_LENGTH],right_id[MAX_ID_LENGTH];
  936.  
  937. STRCPY(left_id,name_of(a0));
  938. STRCPY(right_id,name_of(a1));
  939.  
  940.  
  941. {
  942. if(eval_msgs)
  943. macro_err(OC("! Identifier not allowed as binary operand:  \
  944. left = \"%s\" (%d), right = \"%s\" (%d).  (Undefined WEB macro?)"),NO,left_id,a0,right_id,a1);longjmp(top_of_evaluate,1);
  945. }
  946. }
  947.  
  948.  
  949. PRECEDENCE precedence FCN((token))
  950. eight_bits token C1("Operator token whose precedence is desired.")
  951. {
  952. switch(token)
  953. {
  954. case DEFINED_TOKEN:
  955. return HIGHEST_UNARY;
  956.  
  957. /* --- The unary operators: Logical negation, one's complement, unary minus. */
  958. case 041:
  959. case 0176:
  960. case UNARY_MINUS:
  961. return UNARY;
  962.  
  963. /* --- Exponentiation --- */
  964. case star_star:
  965. return EXP;
  966.  
  967. /* --- Multiplication, division, modulus --- */
  968. case 052:
  969. case 057:
  970. case 045:
  971. return TIMES;
  972.  
  973. /* --- Addition, subtraction --- */
  974. case 053:
  975. case 055:
  976. return PLUS_MINUS;
  977.  
  978. /* --- Bit shift --- */
  979. case lt_lt:
  980. case gt_gt:
  981. return BIT_SHIFT;
  982.  
  983. /* --- Less than, greater than --- */
  984. case 074:case lt_eq:
  985. case 076:case gt_eq:
  986. return LOG_LT;
  987.  
  988. /* --- Equals, not equals --- */
  989. case eq_eq:
  990. case not_eq:
  991. return LOG_EQ;
  992.  
  993. /* --- Bitwise AND --- */
  994. case 046:
  995. return BIT_AND;
  996.  
  997. /* --- Bitwise EXCLUSIVE OR --- */
  998. case 0136:
  999. case neqv:
  1000. return BIT_XOR;
  1001.  
  1002. /* --- Bitwise OR --- */
  1003. case 0174:
  1004. return BIT_OR;
  1005.  
  1006. /* --- Logical AND --- */
  1007. case and_and:
  1008. return AND_AND;
  1009.  
  1010. /* --- Logical OR --- */
  1011. case or_or:
  1012. return OR_OR;
  1013.  
  1014. default:
  1015. return BAD_TOKEN;
  1016. }
  1017. }
  1018.  
  1019.  
  1020.  
  1021. #define NAME(token,name) case token: return OC(name)
  1022.  
  1023. outer_char*op_name FCN((token))
  1024. eight_bits token C1("Operator token whose name is desired.")
  1025. {
  1026. switch(token)
  1027. {
  1028. NAME(DEFINED_TOKEN,"defined");
  1029. NAME(041,"!");
  1030. NAME(0176,"~");
  1031. NAME(UNARY_MINUS,"-");
  1032. NAME(star_star,"**");
  1033. NAME(052,"*");
  1034. NAME(057,"/");
  1035. NAME(045,"%");
  1036. NAME(053,"+");
  1037. NAME(055,"-");
  1038. NAME(lt_lt,"<<");
  1039. NAME(gt_gt,">>");
  1040. NAME(074,"<");
  1041. NAME(lt_eq,"<=");
  1042. NAME(076,">");
  1043. NAME(gt_eq,">=");
  1044. NAME(eq_eq,"==");
  1045. NAME(not_eq,"!=");
  1046. NAME(046,"&");
  1047. NAME(0136,"^");
  1048. NAME(neqv,"?=");
  1049. NAME(0174,"|");
  1050. NAME(and_and,"&&");
  1051. NAME(or_or,"||");
  1052.  
  1053. default:return OC("(UNKNOWN)");
  1054. }
  1055. }
  1056.  
  1057. #undef NAME
  1058.  
  1059.  
  1060. SRTN promote FCN((v0,v1))
  1061. VAL HUGE*v0 C0("Left-hand value.")
  1062. VAL HUGE*v1 C1("Right-hand value.")
  1063. {
  1064. if((int)v0->type>(int)v1->type)convert_to(v0->type,v0,v1);
  1065. else convert_to(v1->type,v0,v1);
  1066. }
  1067.  
  1068. SRTN convert_to FCN((type,v0,v1))
  1069. TYPE type C0("Type to be converted to.")
  1070. VAL HUGE*v0 C0("Left-hand value.")
  1071. VAL HUGE*v1 C1("Right-hand value.")
  1072. {
  1073. switch(type)
  1074. {
  1075. case Int:break;
  1076.  
  1077. case Double:
  1078. TO_DOUBLE(v0);
  1079. TO_DOUBLE(v1);
  1080. break;
  1081.  
  1082. case Id:
  1083. TO_ID(v0);
  1084. TO_ID(v1);
  1085. break;
  1086.  
  1087. default:
  1088.  
  1089. {
  1090. if(eval_msgs)
  1091. macro_err(OC("! Invalid data type %s in promotion"),NO,stype(type));longjmp(top_of_evaluate,1);
  1092. }
  1093. }
  1094. }
  1095.  
  1096.  
  1097. SRTN i_lang_ FCN((n,pargs))
  1098. int n C0("")
  1099. PARGS pargs C1("")
  1100. {
  1101. outer_char temp[5],*temp1= temp+1;
  1102. sixteen_bits l;/* The number of the language identifier. */
  1103.  
  1104. CHK_ARGS("$LANGUAGE",0);
  1105.  
  1106. /* Initialize to \Fortran--77. */
  1107. STRCPY(temp,"$N");/* Some compilers don't allow auto initialization. */
  1108.  
  1109. switch(language)
  1110. {
  1111. case C:
  1112. *temp1= 'C';break;
  1113.  
  1114. case C_PLUS_PLUS:
  1115. STRCPY(temp1,"CPP");break;
  1116.  
  1117. case RATFOR:
  1118. if(!RAT_OK("(_LANGUAGE)"))
  1119. CONFUSION("_lang_",
  1120. "Language shouldn't be Ratfor here");
  1121. *temp1= 'R';break;
  1122.  
  1123. case RATFOR_90:
  1124. if(!RAT_OK("(_LANGUAGE)"))
  1125. CONFUSION("_lang_",
  1126. "Language shouldn't be Ratfor here");
  1127. STRCPY(temp1,"R90");break;
  1128.  
  1129. case TEX:
  1130. *temp1= 'X';break;
  1131.  
  1132. case LITERAL:
  1133. *temp1= 'V';break;
  1134.  
  1135. case FORTRAN:
  1136. default:
  1137. *temp1= 'N';break;
  1138.  
  1139. case FORTRAN_90:
  1140. STRCPY(temp1,"N90");break;
  1141. }
  1142.  
  1143. to_ASCII(temp);
  1144. l= ID_NUM((ASCII HUGE*)temp,(ASCII HUGE*)(temp+STRLEN(temp)));
  1145. /* Get number of the language identifier. */
  1146. MCHECK0(2,"language token");
  1147. *mp++= LEFT(l,ID0);/* Return the language token. */
  1148. *mp++= RIGHT(l);
  1149. }
  1150.  
  1151.  
  1152. SRTN i_lnum_ FCN((n,pargs))
  1153. int n C0("")
  1154. PARGS pargs C1("")
  1155. {
  1156. num_to_mbuf(n,pargs,"$LANGUAGE_NUM",0,"language number",stnd_num(language));
  1157. }
  1158.  
  1159.  
  1160. unsigned stnd_num FCN((Language))
  1161. LANGUAGE Language C1("")
  1162. {
  1163. proper_language:
  1164. switch(Language)
  1165. {
  1166. case C:return 0;
  1167. case C_PLUS_PLUS:return 1;
  1168. case FORTRAN:return 2;
  1169. case FORTRAN_90:return 3;
  1170. case RATFOR:return 4;
  1171. case RATFOR_90:return 5;
  1172. case TEX:return 6;
  1173. case LITERAL:return 7;
  1174. default:
  1175. Language= global_language;
  1176. goto proper_language;
  1177. }
  1178. }
  1179.  
  1180.  
  1181. SRTN e_macros(VOID)
  1182. {
  1183.  
  1184.  
  1185. SAVE_MACRO("_EVAL(expr)$$EVAL(expr)");/* Expand the expression. */
  1186. SAVE_MACRO("$EVAL(expr)$$EVAL(expr)");/* Expand the expression. */
  1187.  
  1188.  
  1189.  
  1190. SAVE_MACRO("_POW(x,y)$EVAL((x)^^(y))");
  1191. SAVE_MACRO("$POW(x,y)$EVAL((x)^^(y))");
  1192.  
  1193.  
  1194.  
  1195. SAVE_MACRO("$PI(...)$$CONST(\"$PI\", \".31415926535897932384626433832795028\
  1196. 8419716939937510\",#.)");
  1197.  
  1198. SAVE_MACRO("$E(...)$$CONST(\"$E\", \".2718281828459045235360287471352662497\
  1199. 75724709369995\",#.)");
  1200.  
  1201. SAVE_MACRO("$EXP(x)$POW($E, x)");
  1202. SAVE_MACRO("$SQRT(x)$POW(x, 0.5)");
  1203.  
  1204.  
  1205.  
  1206. SAVE_MACRO("$LOG(x)$$LOG(0, x)");
  1207. SAVE_MACRO("$LOG10(x)$$LOG(1, x)");
  1208.  
  1209.  
  1210.  
  1211. SAVE_MACRO("_MIN(a,...)$$MIN_MAX(0, a, #.)");
  1212. SAVE_MACRO("$MIN(a,...)$$MIN_MAX(0, a, #.)");
  1213.  
  1214. SAVE_MACRO("_MAX(a,...)$$MIN_MAX(1, a, #.)");
  1215. SAVE_MACRO("$MAX(a,...)$$MIN_MAX(1, a, #.)");
  1216.  
  1217. ;
  1218. }
  1219.  
  1220.  
  1221.  
  1222. SRTN i_const_ FCN((n,pargs))
  1223. int n C0("")
  1224. PARGS pargs C1("")
  1225. {
  1226. VAL val;
  1227. int prec,carry;
  1228.  
  1229. if(n==2)
  1230. prec= DBL_DIG;
  1231. else
  1232. {
  1233. CHK_ARGS("$$CONST",3);
  1234. EVALUATE(val,pargs[2]+1,pargs[3]);
  1235. if(val.type!=Int)
  1236. {
  1237. if(eval_msgs)
  1238. macro_err(OC("! Precision argument of $PI or $E must be an \
  1239. integer; default precision of %d assumed"),YES,DBL_DIG);
  1240. prec= DBL_DIG;
  1241. }
  1242. else
  1243. {
  1244. prec= (int)MIN(val.value.i,49L);
  1245. prec= MAX(prec,0);
  1246. }
  1247. }
  1248.  
  1249. prec+= 2;/* Take account of the leading digit and the decimal point. */
  1250.  
  1251. MCHECK0(prec+2,"math constant");
  1252.  
  1253. *mp++= constant;
  1254. STRNCPY(mp,pargs[1]+3,prec+1);
  1255. /* The '3' accounts for comma, |constant|, and quote.  We get one \
  1256. extra so we can round. */
  1257.  
  1258. n= prec;
  1259. carry= (mp[n--]>=065);
  1260.  
  1261. while(carry)
  1262. {
  1263. mp[n]+= 1;
  1264.  
  1265. if(mp[n]>071)
  1266. mp[n--]= 060;
  1267. else
  1268. break;
  1269. }
  1270.  
  1271. mp[0]= mp[1];
  1272. mp[1]= 056;
  1273.  
  1274. mp+= prec;
  1275. *mp++= constant;
  1276. }
  1277.  
  1278.  
  1279. SRTN i_log_ FCN((n,pargs))
  1280. int n C0("")
  1281. PARGS pargs C1("")
  1282. {
  1283. int m;
  1284. VAL val;
  1285. double x,y;
  1286.  
  1287. m= *(pargs[0]+2)-060;
  1288. EVALUATE(val,pargs[1]+1,pargs[2]);
  1289.  
  1290. if(val.type==Int)
  1291. x= (double)val.value.i;
  1292. else if(val.type==Double)
  1293. x= val.value.d;
  1294. else
  1295. {
  1296. if(eval_msgs)
  1297. macro_err(OC("! Invalid argument to $LOG or $LOG10 (undefined \
  1298. macro?); expansion aborted"),YES);
  1299. return;
  1300. }
  1301.  
  1302. if(m==0)
  1303. y= log(x);
  1304. else
  1305. y= log10(x);
  1306.  
  1307. MCHECK0(DBL_DIG+2,"$$LOG");
  1308. *mp++= constant;
  1309. sprintf((char*)mp,"%#.*g",DBL_DIG,y);
  1310.  
  1311. fin_constant(Double);
  1312. }
  1313.  
  1314.  
  1315. SRTN fin_constant FCN((type))
  1316. TYPE type C1("")
  1317. {
  1318. int n= STRLEN(mp);
  1319.  
  1320. if(type==Double)
  1321. while(mp[n-1]==060)
  1322. {
  1323. if(mp[n-2]==056)
  1324. break;
  1325.  
  1326. n--;
  1327. }
  1328.  
  1329. to_ASCII(mp);
  1330. mp+= n;
  1331. *mp++= constant;
  1332. }
  1333.  
  1334.  
  1335. SRTN i_min_max_ FCN((n,pargs))
  1336. int n C0("")
  1337. PARGS pargs C1("")
  1338. {
  1339. int m= *(pargs[0]+2)-060;
  1340. long l= 0;/* Accumulator for integers. */
  1341. double z= 0;/* Acuumulator for floating point. */
  1342. double v= 0;
  1343. VAL val;
  1344. TYPE type;
  1345. int k;
  1346.  
  1347. EVALUATE(val,pargs[1]+1,pargs[2]);/* Obtain the first value. */
  1348.  
  1349. type= val.type;
  1350.  
  1351. if(type==Int)
  1352. l= val.value.i;
  1353. else
  1354. z= val.value.d;
  1355.  
  1356. for(k= 2;k<n;k++)
  1357. {
  1358. EVALUATE(val,pargs[k]+1,pargs[k+1]);
  1359.  
  1360. if(val.type==Double)
  1361. {
  1362. if(type==Int)
  1363. z= (double)l;/* From now, accumulate floating point. */
  1364.  
  1365. type= Double;
  1366. }
  1367.  
  1368. if(type==Double)
  1369. if(val.type==Int)
  1370. v= (double)val.value.i;
  1371. else
  1372. v= val.value.d;
  1373.  
  1374. if(type==Int)
  1375. if(m==0)
  1376. {
  1377. if(val.value.i<l)
  1378. l= val.value.i;
  1379. }
  1380. else
  1381. {
  1382. if(val.value.i>l)
  1383. l= val.value.i;
  1384. }
  1385. else
  1386. if(m==0)
  1387. {
  1388. if(v<z)
  1389. z= v;
  1390. }
  1391. else
  1392. {
  1393. if(v>z)
  1394. z= v;
  1395. }
  1396. }
  1397.  
  1398. MCHECK0(DBL_DIG+2,"min_max");
  1399. *mp++= constant;
  1400.  
  1401. if(type==Int)
  1402. sprintf((char*)mp,"%ld",l);
  1403. else
  1404. sprintf((char*)mp,"%#.*g",DBL_DIG,z);
  1405.  
  1406. fin_constant(type);
  1407. }
  1408.  
  1409.  
  1410.