/[ascend]/trunk/base/generic/compiler/relation_io.c
ViewVC logotype

Contents of /trunk/base/generic/compiler/relation_io.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 708 - (show annotations) (download) (as text)
Tue Jun 27 07:34:31 2006 UTC (17 years, 11 months ago) by johnpye
File MIME type: text/x-csrc
File size: 45611 byte(s)
Replaced some references to ascmalloc with ASC_NEW_ARRAY
1 /*
2 * Relation Output Routines
3 * by Tom Epperly
4 * Created: 2/8/90
5 * Version: $Revision: 1.16 $
6 * Version control file: $RCSfile: relation_io.c,v $
7 * Date last modified: $Date: 1998/04/10 23:25:47 $
8 * Last modified by: $Author: ballan $
9 *
10 * This file is part of the Ascend Language Interpreter.
11 *
12 * Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
13 * Copyright (C) 1998 Benjamin Allan and Vicente Rico-Ramirez
14 *
15 * The Ascend Language Interpreter is free software; you can redistribute
16 * it and/or modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of the
18 * License, or (at your option) any later version.
19 *
20 * The Ascend Language Interpreter is distributed in hope that it will be
21 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with the program; if not, write to the Free Software Foundation,
27 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
28 * COPYING.
29 *
30 */
31
32 #include <stdarg.h>
33 #include <utilities/ascConfig.h>
34 #include <utilities/ascMalloc.h>
35 #include <utilities/ascPanic.h>
36 #include <general/list.h>
37 #include <general/pool.h>
38 #include <general/dstring.h>
39 #include <general/pretty.h>
40 #include "compiler.h"
41 #include "fractions.h"
42 #include "dimen.h"
43 #include "functype.h"
44 #include "func.h"
45 #include "expr_types.h"
46 #include "extcall.h"
47 #include "instance_enum.h"
48 #include "extfunc.h"
49 #include "mathinst.h"
50 #include "visitinst.h"
51 #include "parentchild.h"
52 #include "instquery.h"
53 #include "tmpnum.h"
54 #include "find.h"
55 #include "relation_type.h"
56 #include "relation.h"
57 #include "relation_util.h"
58 #include "relation_io.h"
59 #include "instance_io.h"
60
61 #ifndef lint
62 static CONST char RelationOutputRoutinesRCS[]="$Id: relation_io.c,v 1.16 1998/04/10 23:25:47 ballan Exp $";
63 #endif
64
65
66 static char g_shortbuf[256];
67 #define SB255 g_shortbuf
68
69 #ifdef ASC_NO_POOL
70 #define RELIO_USES_POOL FALSE
71 #else
72 #define RELIO_USES_POOL TRUE
73 #endif
74
75 /*
76 * stack entry for relation io conversion to infix.
77 */
78 struct rel_stack {
79 struct rel_stack *next;
80 unsigned long pos;
81 int first;
82 unsigned long lhs; /* used only for binary tokens with first = 2 */
83 };
84
85 /* default for other tokens. this will cause an array bounds read
86 * error if misused, which is nice if you assume purify.
87 */
88 /*
89 * THIS LOOKS LIKE A BUG.
90 * rel_stack.lhs is unsigned long, so assigning -1 appears wrong
91 * If the intent is to use the result of (unsigned long)-1, then
92 * that should at least be commented. (JDS 12/11/2005)
93 */
94 #define NOLHS -1
95
96 /* worklist */
97 static struct rel_stack *g_rel_stack=NULL;
98
99 /* recycle spaces */
100 static pool_store_t g_rel_stack_pool = NULL;
101 /* global for our memory manager */
102 /* aim for 4096 chunks including malloc overhead */
103 #define RSP_LEN 2
104 #if (SIZEOF_VOID_P == 8)
105 #define RSP_WID 10
106 #else
107 #define RSP_WID 20
108 #endif
109 /* retune rpwid if the size of struct name changes */
110 #define RSP_ELT_SIZE (sizeof(struct rel_stack))
111 #define RSP_MORE_ELTS 1
112 /*
113 * Number of slots filled if more elements needed.
114 * So if the pool grows, it grows by RSP_MORE_ELTS*RSP_WID elements at a time.
115 */
116 #define RSP_MORE_BARS 5
117 /* This is the number of pool bar slots to add during expansion.
118 not all the slots will be filled immediately. */
119
120 /* This function is called at compiler startup time and destroy at shutdown. */
121 void RelationIO_init_pool(void) {
122 if (g_rel_stack_pool != NULL ) {
123 Asc_Panic(2, NULL, "ERROR: RelationIO_init_pool called twice.\n");
124 }
125 g_rel_stack_pool = pool_create_store(RSP_LEN, RSP_WID, RSP_ELT_SIZE,
126 RSP_MORE_ELTS, RSP_MORE_BARS);
127 if (g_rel_stack_pool == NULL) {
128 Asc_Panic(2, NULL,
129 "ERROR: RelationIO_init_pool unable to allocate pool.\n");
130 }
131 }
132
133 void RelationIO_destroy_pool(void) {
134 if (g_rel_stack_pool==NULL) return;
135 pool_clear_store(g_rel_stack_pool);
136 pool_destroy_store(g_rel_stack_pool);
137 g_rel_stack_pool = NULL;
138 }
139
140 void RelationIO_report_pool(void)
141 {
142 if (g_rel_stack_pool==NULL) {
143 FPRINTF(ASCERR,"rel_stacksPool is empty\n");
144 }
145 FPRINTF(ASCERR,"rel_stacksPool ");
146 pool_print_store(ASCERR,g_rel_stack_pool,0);
147 }
148
149 #if RELIO_USES_POOL
150 #define RSPMALLOC ((struct rel_stack *)(pool_get_element(g_rel_stack_pool)))
151 /* get a token. Token is the size of the struct struct rel_stack */
152 #define RSPFREE(p) (pool_free_element(g_rel_stack_pool,((void *)p)))
153 /* return a struct rel_stack */
154
155 #else
156
157 #define RSPMALLOC ascmalloc(sizeof(struct rel_stack ))
158 #define RSPFREE(p) ascfree(p)
159
160 #endif /* RELIO_USES_POOL */
161
162 static
163 void WriteOp(FILE *f, enum Expr_enum t)
164 {
165 switch(t){
166 case e_plus: PUTC('+',f); break;
167 case e_uminus:
168 case e_minus: PUTC('-',f); break;
169 case e_times: PUTC('*',f); break;
170 case e_divide: PUTC('/',f); break;
171 case e_power: PUTC('^',f); break;
172 case e_ipower: PUTC('^',f); break;
173 case e_equal: PUTC('=',f); break;
174 case e_notequal: FPRINTF(f,"<>"); break;
175 case e_less: PUTC('<',f); break;
176 case e_greater: PUTC('>',f); break;
177 case e_lesseq: FPRINTF(f,"<="); break;
178 case e_greatereq: FPRINTF(f,">="); break;
179 case e_maximize: FPRINTF(f,"MAXIMIZE"); break;
180 case e_minimize: FPRINTF(f,"MINIMIZE"); break;
181 default:
182 Asc_Panic(2, NULL, "Unknown term in WriteOp.\n");
183 break;
184 }
185 }
186
187 /* appends operator to dynamic symbol */
188 static void WriteOpDS(Asc_DString *dsPtr, enum Expr_enum t,
189 enum rel_lang_format lang)
190 {
191 (void)lang; /* future use for relational operators in other langs. */
192 assert(dsPtr!=NULL);
193 switch(t){
194 case e_plus:
195 Asc_DStringAppend(dsPtr,"+",1);
196 break;
197 case e_uminus:
198 case e_minus:
199 Asc_DStringAppend(dsPtr,"-",1);
200 break;
201 case e_times:
202 Asc_DStringAppend(dsPtr,"*",1);
203 break;
204 case e_divide:
205 Asc_DStringAppend(dsPtr,"/",1);
206 break;
207 case e_power:
208 Asc_DStringAppend(dsPtr,"^",1);
209 break;
210 case e_ipower:
211 Asc_DStringAppend(dsPtr,"^",1);
212 break;
213 case e_equal:
214 Asc_DStringAppend(dsPtr,"=",1);
215 break;
216 case e_notequal:
217 Asc_DStringAppend(dsPtr,"<>",2);
218 break;
219 case e_less:
220 Asc_DStringAppend(dsPtr,"<",1);
221 break;
222 case e_greater:
223 Asc_DStringAppend(dsPtr,">",1);
224 break;
225 case e_lesseq:
226 Asc_DStringAppend(dsPtr,"<=",2);
227 break;
228 case e_greatereq:
229 Asc_DStringAppend(dsPtr,">=",2);
230 break;
231 case e_maximize:
232 Asc_DStringAppend(dsPtr,"MAXIMIZE",8);
233 break;
234 case e_minimize:
235 Asc_DStringAppend(dsPtr,"MINIMIZE",8);
236 break;
237 default:
238 FPRINTF(ASCERR,"Unknown term in WriteOpDS.\n");
239 Asc_DStringAppend(dsPtr,"ERROR",5);
240 break;
241 }
242 }
243
244 char *RelationVarXName(CONST struct relation *r,
245 unsigned long varnum,
246 struct RXNameData *rd)
247 {
248 unsigned long i;
249 struct RXNameData myrd = {"x",NULL,""};
250 (void)r;
251
252 if (varnum < 1) {
253 return NULL;
254 }
255 if (rd == NULL) {
256 rd = &myrd;
257 } else {
258 assert(rd->prefix!=NULL);
259 assert(rd->suffix!=NULL);
260 }
261 if (rd->indices == NULL) {
262 i = varnum;
263 } else {
264 i = (unsigned long)(rd->indices[varnum]);
265 }
266 sprintf(SB255,"%.110s%lu%.110s",rd->prefix,i,rd->suffix);
267 return SB255;
268 }
269
270 static
271 void WriteTerm(FILE *f,
272 CONST struct relation *rel,
273 CONST struct relation_term *term,
274 CONST struct Instance *inst)
275 {
276 struct Instance *cur_var;
277 switch(RelationTermType(term)){
278 case e_var:
279 cur_var = RelationVariable(rel,TermVarNumber(term));
280 WriteInstanceName(f,cur_var,inst);
281 break;
282 case e_func:
283 FPRINTF(f,FuncName(TermFunc(term)));
284 break;
285 case e_int:
286 FPRINTF(f,"%ld",TermInteger(term));
287 break;
288 case e_zero:
289 FPRINTF(f,"%g",0.0);
290 break;
291 case e_real:
292 FPRINTF(f,"%g",TermReal(term));
293 break;
294 case e_plus:
295 case e_minus:
296 case e_times:
297 case e_divide:
298 case e_power:
299 case e_ipower:
300 WriteOp(f,RelationTermType(term));
301 break;
302 case e_uminus:
303 FPRINTF(f,"NEG");
304 break;
305 default:
306 Asc_Panic(2, NULL, "Unknown term type in WriteTerm.\n");
307 break;
308 }
309 }
310
311 /* write out a postfix term */
312 static
313 void WriteTermDS(Asc_DString *dsPtr,
314 CONST struct relation *rel,
315 CONST struct relation_term *term,
316 CONST struct Instance *inst)
317 {
318 struct Instance *cur_var;
319 switch(RelationTermType(term)){
320 case e_var:
321 cur_var = RelationVariable(rel,TermVarNumber(term));
322 WriteInstanceNameDS(dsPtr,cur_var,inst);
323 break;
324 case e_func:
325 Asc_DStringAppend(dsPtr,FuncName(TermFunc(term)),-1);
326 break;
327 case e_int:
328 sprintf(SB255,"%ld",TermInteger(term));
329 Asc_DStringAppend(dsPtr,SB255,-1);
330 break;
331 case e_zero:
332 Asc_DStringAppend(dsPtr,"0.0",3);
333 break;
334 case e_real:
335 sprintf(SB255,"(double) %.18g",TermReal(term));
336 Asc_DStringAppend(dsPtr,SB255,-1);
337 break;
338 case e_plus:
339 case e_minus:
340 case e_times:
341 case e_divide:
342 case e_power:
343 case e_ipower:
344 WriteOpDS(dsPtr,RelationTermType(term),relio_ascend);
345 break;
346 case e_uminus:
347 Asc_DStringAppend(dsPtr,"NEG",3);
348 break; /* what is this anyway? */
349 default:
350 FPRINTF(ASCERR,"Unknown term in WriteTermDS.\n");
351 Asc_DStringAppend(dsPtr,"ERROR",5);
352 break;
353 }
354 }
355
356 static
357 void WriteSidePF(FILE *f,
358 CONST struct relation *r,
359 int side,
360 CONST struct Instance *ref)
361 {
362 unsigned c,len;
363 CONST struct relation_term *term;
364 len = RelationLength(r,side);
365 for(c=1;c<=len;c++){
366 term = RelationTerm(r,c,side);
367 WriteTerm(f,r,term,ref);
368 if(c<len) PUTC(' ',f);
369 }
370 }
371
372 static
373 void WriteSidePFDS(Asc_DString *dsPtr,
374 CONST struct relation *r,
375 int side,
376 CONST struct Instance *ref)
377 {
378 unsigned c,len;
379 CONST struct relation_term *term;
380 len = RelationLength(r,side);
381 for(c=1;c<=len;c++){
382 term = RelationTerm(r,c,side);
383 WriteTermDS(dsPtr,r,term,ref);
384 if(c<len) Asc_DStringAppend(dsPtr," ",1);
385 }
386 }
387
388 void WriteRelationPostfix(FILE *f,
389 CONST struct Instance *relinst,
390 CONST struct Instance *ref)
391 {
392 CONST struct relation *r;
393 enum Expr_enum type;
394
395 r = GetInstanceRelation(relinst,&type);
396 if (type!=e_token) {
397 FPRINTF(ASCERR,"Invalid relation type in WriteRelationPostfix\n");
398 return;
399 }
400
401 switch(RelationRelop(r)){
402 case e_equal:
403 case e_notequal:
404 case e_less:
405 case e_greater:
406 case e_lesseq:
407 case e_greatereq:
408 WriteSidePF(f,r,1,ref);
409 PUTC(' ',f);
410 WriteSidePF(f,r,0,ref);
411 PUTC(' ',f);
412 WriteOp(f,RelationRelop(r));
413 break;
414 case e_maximize:
415 case e_minimize:
416 WriteOp(f,RelationRelop(r));
417 PUTC(' ',f);
418 WriteSidePF(f,r,1,ref);
419 break;
420 default:
421 FPRINTF(ASCERR,"Unexpected Relop in WriteRelationPostfix\n");
422 break;
423 }
424 }
425
426 char *WriteRelationPostfixString( CONST struct Instance *relinst,
427 CONST struct Instance *ref)
428 {
429 CONST struct relation *r;
430 enum Expr_enum type;
431 char *result;
432 static Asc_DString ds;
433 Asc_DString *dsPtr;
434
435 r = GetInstanceRelation(relinst,&type);
436 if (type!=e_token) {
437 FPRINTF(ASCERR,"Invalid relation type in WriteRelationPostfixString\n");
438 result=ASC_NEW_ARRAY(char,60);
439 if (result==NULL) return result;
440 sprintf(result,"WriteRelationPostfixString called on non-token relation.");
441 return result;
442 }
443 dsPtr = &ds;
444 Asc_DStringInit(dsPtr);
445
446 switch(RelationRelop(r)){
447 case e_equal:
448 case e_notequal:
449 case e_less:
450 case e_greater:
451 case e_lesseq:
452 case e_greatereq:
453 WriteSidePFDS(dsPtr,r,1,ref);
454 Asc_DStringAppend(dsPtr," ",1);
455 WriteSidePFDS(dsPtr,r,0,ref);
456 Asc_DStringAppend(dsPtr," ",1);
457 WriteOpDS(dsPtr,RelationRelop(r),relio_ascend);
458 break;
459 case e_maximize:
460 case e_minimize:
461 WriteOpDS(dsPtr,RelationRelop(r),relio_ascend);
462 Asc_DStringAppend(dsPtr," ",1);
463 WriteSidePFDS(dsPtr,r,1,ref);
464 break;
465 default:
466 FPRINTF(ASCERR,"Unexpected Relop in WriteRelationPostfix\n");
467 break;
468 }
469 result = Asc_DStringResult(dsPtr);
470 Asc_DStringFree(dsPtr);
471 return result;
472 }
473
474 static
475 void ClearRelationStack(void)
476 {
477 struct rel_stack *next;
478 while(g_rel_stack!=NULL){
479 next = g_rel_stack->next;
480 RSPFREE(g_rel_stack);
481 g_rel_stack = next;
482 }
483 }
484
485 static
486 void PushRelation(unsigned long int pos, int first, unsigned long int lhs)
487 {
488 struct rel_stack *next;
489 next = g_rel_stack;
490 g_rel_stack = RSPMALLOC;
491 g_rel_stack->next = next;
492 g_rel_stack->pos = pos;
493 g_rel_stack->first = first;
494 g_rel_stack->lhs = lhs;
495 }
496
497 static
498 int NotEmptyStack(void)
499 {
500 return g_rel_stack!=NULL;
501 }
502
503 static
504 int FirstTop(void)
505 {
506 assert(g_rel_stack!=NULL);
507 return g_rel_stack->first;
508 }
509
510 static
511 int LHSTop(void)
512 {
513 assert(g_rel_stack!=NULL);
514 return g_rel_stack->lhs;
515 }
516
517 /*
518 * destroy top of stack and returns its pos value.
519 */
520 static
521 unsigned long PopRelation(void)
522 {
523 struct rel_stack *next;
524 unsigned long result;
525 assert(g_rel_stack!=NULL);
526 next = g_rel_stack->next;
527 result = g_rel_stack->pos;
528 RSPFREE((char *)g_rel_stack);
529 g_rel_stack = next;
530 return result;
531 }
532
533 /* Assumes relation array of the form [lhs tokens, rhstokens,postoken].
534 * Searches left starting from postoken given until it finds the pos
535 * preceding the ",". This pos is the top of the lhs tokens tree,
536 * if you think about things in tree terms. postoken is the top of
537 * the tree and is binary. lhs and rhs refer to left and right
538 * side of any binary operator.
539 * Calling this with an ill formed tree is likely to cause weird
540 * errors and overrun the array or underrun the result.
541 */
542 static
543 unsigned long LeftHandSide(CONST struct relation *r,
544 unsigned long int pos,
545 int side)
546 {
547 unsigned long depth=1;
548 CONST struct relation_term *term;
549 pos--;
550 while(depth){
551 term = RelationTerm(r,pos,side);
552 switch(RelationTermType(term)){
553 case e_int:
554 case e_zero:
555 case e_real:
556 case e_var:
557 depth--;
558 break;
559 case e_func:
560 case e_uminus:
561 break;
562 case e_plus:
563 case e_minus:
564 case e_times:
565 case e_divide:
566 case e_power:
567 case e_ipower:
568 depth++;
569 break;
570 default:
571 Asc_Panic(2, NULL,
572 "Don't know this type of relation type.\n"
573 "(%d) in function LeftHandSide\n",
574 RelationTermType(term));
575 break;
576 }
577 pos--;
578 }
579 return pos;
580 }
581
582 /* a little function to tell us about precedence */
583 static
584 unsigned Priority(enum Expr_enum t)
585 {
586 switch(t){
587 case e_zero:
588 case e_var:
589 case e_int:
590 case e_real:
591 case e_func:
592 return 0;
593
594 case e_plus:
595 case e_minus:
596 return 1;
597
598 case e_times:
599 case e_divide:
600 return 2;
601
602 case e_uminus:
603 return 3;
604
605 case e_power:
606 case e_ipower:
607 return 4;
608
609 default:
610 return 0; /* 0=good idea? */
611 }
612 /*NOTREACHED*/
613 }
614
615 int NeedParen(enum Expr_enum parent_op, enum Expr_enum child_op, int rhs)
616 {
617 unsigned parent_p,child_p;
618 switch(child_op){
619 case e_zero:
620 case e_var:
621 case e_int:
622 case e_real:
623 case e_func:
624 return 0;
625 default:
626 parent_p = Priority(parent_op);
627 child_p = Priority(child_op);
628 if (parent_p > child_p) return 1;
629 if (parent_p < child_p) return 0;
630 if ((parent_op == e_minus)&&rhs) return 1;
631 if ((parent_op == e_divide)&&rhs) return 1;
632 return 0;
633 }
634 }
635
636 static
637 void WriteSide(FILE *f,
638 CONST struct relation *r,
639 int side,
640 CONST struct Instance *ref)
641 {
642 unsigned long pos,lhs,oldlhs;
643 int first;
644 enum Expr_enum t;
645 CONST struct relation_term *term;
646 struct Instance *cur_var;
647 ClearRelationStack();
648 PushRelation(RelationLength(r,side),1,NOLHS);
649 while(NotEmptyStack()){
650 first = FirstTop(); /* check if this is the first visit */
651 oldlhs = LHSTop(); /* check for cached LHS position on binaries */
652 pos = PopRelation(); /* check the top */
653 term = RelationTerm(r,pos,side);
654 switch(t = RelationTermType(term)){
655 case e_var:
656 cur_var = RelationVariable(r,TermVarNumber(term));
657 WriteInstanceName(f,cur_var,ref);
658 break;
659 case e_int:
660 FPRINTF(f,"%ld",TermInteger(term));
661 break;
662 case e_zero:
663 FPRINTF(f,"0");
664 break;
665 case e_real:
666 FPRINTF(f,"%g",TermReal(term));
667 break;
668 case e_func:
669 if(first) {
670 FPRINTF(f,"%s(",FuncName(TermFunc(term)));
671 PushRelation(pos,0,NOLHS);
672 PushRelation(pos-1,1,NOLHS);
673 }
674 else{
675 PUTC(')',f);
676 }
677 break;
678 case e_plus:
679 case e_minus:
680 case e_times:
681 case e_divide:
682 case e_power:
683 case e_ipower:
684 switch(first){
685 case 1:
686 lhs = LeftHandSide(r,pos,side);
687 term = RelationTerm(r,lhs,side);
688 if (NeedParen(t,RelationTermType(term),0)) {
689 PUTC('(',f);
690 }
691 PushRelation(pos,2,lhs);
692 PushRelation(lhs,1,NOLHS);
693 break;
694 case 2:
695 term = RelationTerm(r,oldlhs,side);
696 if (NeedParen(t,RelationTermType(term),0)) {
697 PUTC(')',f);
698 }
699 PUTC(' ',f);
700 WriteOp(f,t);
701 PUTC(' ',f);
702 PushRelation(pos,0,NOLHS);
703 term = RelationTerm(r,pos-1,side);
704 if (NeedParen(t,RelationTermType(term),1))
705 PUTC('(',f);
706 PushRelation(pos-1,1,oldlhs);
707 break;
708 case 0:
709 term = RelationTerm(r,pos-1,side);
710 if (NeedParen(t,RelationTermType(term),1))
711 PUTC(')',f);
712 break;
713 }
714 break;
715 case e_uminus:
716 term = RelationTerm(r,pos-1,side);
717 if (first){
718 PUTC('-',f);
719 PushRelation(pos,0,NOLHS);
720 switch(RelationTermType(term)){
721 case e_power:
722 case e_ipower:
723 case e_zero:
724 case e_int:
725 case e_real:
726 case e_var:
727 case e_func:
728 case e_uminus:
729 break;
730 default:
731 PUTC('(',f);
732 break;
733 }
734 PushRelation(pos-1,1,NOLHS);
735 }
736 else{
737 switch(RelationTermType(term)){
738 case e_power:
739 case e_ipower:
740 case e_int:
741 case e_zero:
742 case e_real:
743 case e_var:
744 case e_func:
745 case e_uminus:
746 break;
747 default:
748 PUTC(')',f);
749 break;
750 }
751 }
752 break;
753 default:
754 Asc_Panic(2, NULL,
755 "Don't know this type of relation type: function WriteSide\n");
756 break;
757 }
758 }
759 }
760
761 /**
762 write a side in infix notation
763 */
764 static
765 void WriteSideDS(Asc_DString *dsPtr, CONST struct relation *r, int side,
766 CONST struct Instance *ref, WRSNameFunc func, void *userdata,
767 enum rel_lang_format lang)
768 {
769 unsigned long pos,lhs, oldlhs, rlen;
770 int first;
771 enum Expr_enum t;
772 CONST struct relation_term *term;
773 struct Instance *cur_var;
774 char *username;
775
776
777 ClearRelationStack();
778 rlen = RelationLength(r,side);
779 PushRelation(rlen,1,NOLHS);
780 while(NotEmptyStack()){
781 first = FirstTop(); /* check if this is the first visit */
782 oldlhs = LHSTop(); /* check if this is the first visit */
783 pos = PopRelation(); /* check the top */
784 term = RelationTerm(r,pos,side);
785 t = RelationTermType(term);
786 switch (t) {
787 case e_diff:
788 /*cur_var = RelationVariable(r,TermVarNumber(term));
789 Asc_DStringAppend(dsPtr,"DIFF(",-1);
790 WriteInstanceNameDS(dsPtr,cur_var,ref);
791 Asc_DStringAppend(dsPtr,")",-1);*/
792 Asc_DStringAppend(dsPtr,"DIFF(__something__)",-1);
793 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"e_diff relation term not implemented");
794 break;
795 case e_var:
796 if (func == NULL) {
797 cur_var = RelationVariable(r,TermVarNumber(term));
798 WriteInstanceNameDS(dsPtr,cur_var,ref);
799 } else {
800 username = (*func)(r,TermVarNumber(term),userdata);
801 Asc_DStringAppend(dsPtr,username,-1);
802 }
803 break;
804 case e_int:
805 if (lang == relio_C) {
806 if (pos == rlen /* don't check next term if at END */ ||
807 RelationTermType(RelationTerm(r,pos+1,side)) != e_ipower) {
808 /* don't want to provoke integer division, normally */
809 sprintf(SB255,"%ld.0",TermInteger(term));
810 } else {
811 /* ipow(expr,i) is the only legal way of seeing ipow )
812 * which in stack terms is [expr... , int , e_ipower]
813 */
814 sprintf(SB255,"%ld",TermInteger(term));
815 }
816 } else {
817 sprintf(SB255,"%ld",TermInteger(term));
818 }
819 Asc_DStringAppend(dsPtr,SB255,-1);
820 break;
821 case e_zero:
822 if (lang == relio_C) {
823 Asc_DStringAppend(dsPtr,"0.0",3);
824 /* don't want to provoke integer division */
825 } else {
826 Asc_DStringAppend(dsPtr,"0",1);
827 }
828 break;
829 case e_real:
830 if (lang == relio_C) {
831 sprintf(SB255,"(double) %.18g",TermReal(term));
832 } else {
833 sprintf(SB255,"%g",TermReal(term));
834 }
835 Asc_DStringAppend(dsPtr,SB255,-1);
836 break;
837 case e_func:
838 if(first) {
839 if (lang == relio_C) {
840 sprintf(SB255,"%s(",FuncCName(TermFunc(term)));
841 } else {
842 sprintf(SB255,"%s(",FuncName(TermFunc(term)));
843 }
844 Asc_DStringAppend(dsPtr,SB255,-1);
845 PushRelation(pos,0,NOLHS);
846 PushRelation(pos-1,1,NOLHS);
847 }
848 else{
849 Asc_DStringAppend(dsPtr,")",1);
850 }
851 break;
852 case e_power:
853 case e_ipower:
854 if (lang == relio_C) {
855 /* we assume the args to pow Always need () around them
856 * to keep , from confusing anything, so lhs not used.
857 */
858 switch(first) {
859 case 1:
860 /* seeing this binary token the first time */
861 if (t==e_power) {
862 Asc_DStringAppend(dsPtr,"pow((",5);
863 } else {
864 Asc_DStringAppend(dsPtr,"asc_ipow((",10);
865 }
866 PushRelation(pos,2,NOLHS);
867 lhs = LeftHandSide(r,pos,side);
868 PushRelation(lhs,1,NOLHS);
869 break;
870 case 2:
871 /* seeing this binary token the second time */
872 if (t==e_power) {
873 Asc_DStringAppend(dsPtr,") , (",5);
874 } else {
875 Asc_DStringAppend(dsPtr,") , ",4);
876 }
877 PushRelation(pos,0,NOLHS);
878 PushRelation(pos-1,1,NOLHS);
879 break;
880 case 0:
881 /* seeing binary token the third (last) time */
882 if (t==e_power) {
883 Asc_DStringAppend(dsPtr," ))",3);
884 } else {
885 Asc_DStringAppend(dsPtr,")",1);
886 }
887 break;
888 default: /* first */
889 Asc_Panic(2, "WriteSideDS", "Don't know this type of stack first");
890 break;
891 }
892 break;
893 }
894 /* else FALL THROUGH to usual binary operator treatment */
895 case e_plus:
896 case e_minus:
897 case e_times:
898 case e_divide:
899 switch(first){
900 case 1:
901 /* seeing this binary token the first time */
902 lhs = LeftHandSide(r,pos,side);
903 term = RelationTerm(r,lhs,side);
904 if (NeedParen(t,RelationTermType(term),0)) {
905 Asc_DStringAppend(dsPtr,"(",1);
906 }
907 PushRelation(pos,2,lhs);
908 PushRelation(lhs,1,NOLHS);
909 break;
910 case 2:
911 /* seeing this binary token the second time */
912 term = RelationTerm(r,oldlhs,side);
913 if (NeedParen(t,RelationTermType(term),0)) {
914 Asc_DStringAppend(dsPtr,")",1);
915 }
916 Asc_DStringAppend(dsPtr," ",1);
917 WriteOpDS(dsPtr,t,lang);
918 Asc_DStringAppend(dsPtr," ",1);
919 PushRelation(pos,0,NOLHS);
920 term = RelationTerm(r,pos-1,side);
921 if (NeedParen(t,RelationTermType(term),1)) {
922 Asc_DStringAppend(dsPtr,"(",1);
923 }
924 PushRelation(pos-1,1,NOLHS);
925 break;
926 case 0:
927 /* seeing binary token the third (last) time */
928 term = RelationTerm(r,pos-1,side);
929 if (NeedParen(t,RelationTermType(term),1))
930 Asc_DStringAppend(dsPtr,")",1);
931 break;
932 }
933 break;
934 case e_uminus:
935 term = RelationTerm(r,pos-1,side);
936 if (first){
937 Asc_DStringAppend(dsPtr,"-",1);
938 PushRelation(pos,0,NOLHS);
939 switch(RelationTermType(term)){
940 case e_power:
941 case e_ipower:
942 case e_zero:
943 case e_int:
944 case e_real:
945 case e_var:
946 case e_func:
947 case e_uminus:
948 break;
949 default:
950 Asc_DStringAppend(dsPtr,"(",1);
951 break;
952 }
953 PushRelation(pos-1,1,NOLHS);
954 }
955 else{
956 switch(RelationTermType(term)){
957 case e_power:
958 case e_ipower:
959 case e_int:
960 case e_zero:
961 case e_real:
962 case e_var:
963 case e_func:
964 case e_uminus:
965 break;
966 default:
967 Asc_DStringAppend(dsPtr,")",1);
968 break;
969 }
970 }
971 break;
972 default:
973 Asc_Panic(2, "WriteSideDS", "Don't know this type of relation token");
974 break;
975 }
976 }
977 }
978
979 static
980 void WriteTokenRelation(FILE *f,
981 CONST struct relation *r,
982 CONST struct Instance *ref)
983 {
984 switch(RelationRelop(r)){
985 case e_equal:
986 case e_notequal:
987 case e_less:
988 case e_greater:
989 case e_lesseq:
990 case e_greatereq:
991 WriteSide(f,r,1,ref);
992 PUTC(' ',f);
993 WriteOp(f,RelationRelop(r));
994 PUTC(' ',f);
995 WriteSide(f,r,0,ref);
996 break;
997 case e_maximize:
998 case e_minimize:
999 WriteOp(f,RelationRelop(r));
1000 PUTC(' ',f);
1001 WriteSide(f,r,1,ref);
1002 break;
1003 default:
1004 FPRINTF(ASCERR,"Unexpected Relop in WriteTokenRelation\n");
1005 break;
1006 }
1007 }
1008
1009 static
1010 void WriteTokenRelationDS(Asc_DString *dsPtr,
1011 CONST struct relation *r,
1012 CONST struct Instance *ref,
1013 WRSNameFunc func, void *userdata,
1014 enum rel_lang_format lang)
1015 {
1016 switch(RelationRelop(r)){
1017 case e_equal:
1018 case e_notequal:
1019 case e_less:
1020 case e_greater:
1021 case e_lesseq:
1022 case e_greatereq:
1023 if (lang == relio_C) {
1024 Asc_DStringAppend(dsPtr,"( ",2);
1025 }
1026 WriteSideDS(dsPtr,r,1,ref,func,userdata,lang);
1027 switch (lang) {
1028 case relio_ascend:
1029 Asc_DStringAppend(dsPtr," ",1);
1030 WriteOpDS(dsPtr,RelationRelop(r),lang);
1031 Asc_DStringAppend(dsPtr," ",1);
1032 break;
1033 case relio_C:
1034 Asc_DStringAppend(dsPtr," ) - ( ",7);
1035 break;
1036 default:
1037 Asc_Panic(2, NULL, "Unknown lang in WriteRelationString.\n");
1038 exit(2); /* NOTREACHED , shuts up gcc */
1039 }
1040 WriteSideDS(dsPtr,r,0,ref,func,userdata,lang);
1041 if (lang == relio_C) {
1042 Asc_DStringAppend(dsPtr," )",2);
1043 }
1044 break;
1045 case e_maximize:
1046 case e_minimize:
1047 /* max/min are lhs-only expression, so no operator in C case. */
1048 switch (lang) {
1049 case relio_ascend:
1050 WriteOpDS(dsPtr,RelationRelop(r),lang);
1051 Asc_DStringAppend(dsPtr," ",1);
1052 WriteSideDS(dsPtr,r,1,ref,func,userdata,lang);
1053 break;
1054 case relio_C:
1055 Asc_DStringAppend(dsPtr,"( ",2);
1056 WriteSideDS(dsPtr,r,1,ref,func,userdata,lang);
1057 Asc_DStringAppend(dsPtr," )",2);
1058 break;
1059 default:
1060 Asc_Panic(2, NULL, "Unknown lang in WriteRelationString.\n");
1061 exit(2); /* NOTREACHED , shuts up gcc */
1062 }
1063 break;
1064 default:
1065 FPRINTF(ASCERR,"Unexpected Relop in WriteTokenRelationDS\n");
1066 Asc_DStringAppend(dsPtr,"BADRELOPR ",9);
1067 break;
1068 }
1069 }
1070
1071 static
1072 void Infix_WriteSide(FILE *f,
1073 CONST struct relation *r,
1074 struct relation_term *term,
1075 CONST struct Instance *ref)
1076 {
1077 enum Expr_enum t;
1078 struct Instance *cur_var;
1079 int parens;
1080
1081 switch(t = RelationTermType(term)) {
1082 case e_var:
1083 cur_var = RelationVariable(r,TermVarNumber(term));
1084 WriteInstanceName(f,cur_var,ref);
1085 break;
1086 case e_int:
1087 FPRINTF(f,"%ld",TermInteger(term));
1088 break;
1089 case e_zero:
1090 FPRINTF(f,"0");
1091 break;
1092 case e_real:
1093 FPRINTF(f,"%g",TermReal(term));
1094 break;
1095 case e_func:
1096 FPRINTF(f,"%s(",FuncName(TermFunc(term)));
1097 Infix_WriteSide(f,r,TermFuncLeft(term),ref);
1098 FPRINTF(f,")");
1099 break;
1100 case e_uminus:
1101 FPRINTF(f,"-(");
1102 Infix_WriteSide(f,r,TermUniLeft(term),ref);
1103 FPRINTF(f,")");
1104 break;
1105 case e_plus:
1106 case e_minus:
1107 case e_times:
1108 case e_divide:
1109 case e_power:
1110 case e_ipower:
1111 parens = NeedParen(RelationTermType(term),
1112 RelationTermType(TermBinLeft(term)),0);
1113 if (parens) PUTC('(',f);
1114 Infix_WriteSide(f,r,TermBinLeft(term),ref);
1115 if (parens) PUTC(')',f);
1116 PUTC(' ',f);
1117 WriteOp(f,t);
1118 PUTC(' ',f);
1119 parens = NeedParen(RelationTermType(term),
1120 RelationTermType(TermBinRight(term)),1);
1121 if (parens) PUTC('(',f);
1122 Infix_WriteSide(f,r,TermBinRight(term),ref);
1123 if (parens) PUTC('(',f);
1124 break;
1125 default:
1126 FPRINTF(f,"***");
1127 break;
1128 }
1129 }
1130
1131 void Infix_WriteRelation(FILE *f,
1132 CONST struct Instance *relinst,
1133 CONST struct Instance *ref)
1134 {
1135 CONST struct relation *r;
1136 enum Expr_enum type;
1137
1138 r = GetInstanceRelation(relinst,&type);
1139 if (type!=e_token) {
1140 FPRINTF(ASCERR,"Invalid relation type in Infix_WriteRelation\n");
1141 return;
1142 }
1143 switch(RelationRelop(r)){
1144 case e_equal:
1145 case e_notequal:
1146 case e_less:
1147 case e_greater:
1148 case e_lesseq:
1149 case e_greatereq:
1150 Infix_WriteSide(f,r,Infix_LhsSide(r),ref);
1151 PUTC(' ',f);
1152 WriteOp(f,RelationRelop(r));
1153 PUTC(' ',f);
1154 Infix_WriteSide(f,r,Infix_RhsSide(r),ref);
1155 break;
1156 case e_maximize:
1157 case e_minimize:
1158 WriteOp(f,RelationRelop(r));
1159 PUTC(' ',f);
1160 Infix_WriteSide(f,r,Infix_LhsSide(r),ref);
1161 break;
1162 default:
1163 FPRINTF(ASCERR,"Unexpected Relop in Infix_WriteRelation\n");
1164 }
1165 }
1166
1167
1168 /*
1169 * KAA.
1170 * Just a dumb little note about writing out variable lists --
1171 * We need to check for the penultimate variable so that we
1172 * can know if we must write : "var, " or simply "var)".
1173 * One of doing this without having an if within the main loop
1174 * is to run from 1 to len-1, and then writing the last variable.
1175 * By running from 1 to len, if the length of the list is 0, we
1176 * automatically skip the loop. But by running from 1 to len-1,
1177 * we skip the loop, but have to then check that len was in fact
1178 * greater than 0, as gl_fetch(list,0) is not a pretty sight. Overall
1179 * we save len-1 ifs!! yaaaa!
1180 *
1181 * BAA
1182 * yah, that's it, optimize code way way way off the critical path
1183 * instead of doing things right. idiot.
1184 */
1185 static
1186 void WriteGlassBoxRelation(FILE *f,
1187 CONST struct relation *r,
1188 CONST struct Instance *ref)
1189 {
1190 struct ExternalFunc *efunc;
1191 CONST char *name;
1192 struct Instance *var;
1193 CONST struct gl_list_t *list;
1194 unsigned long len,c;
1195
1196 efunc = GlassBoxExtFunc(r);
1197 name = ExternalFuncName(efunc);
1198 FPRINTF(f,"%s(",name);
1199 if (NULL != (list = RelationVarList(r))) {
1200 len = gl_length(list);
1201 for (c=1;c<len;c++) { /* the < is intentional */
1202 var = (struct Instance *)gl_fetch(list,c);
1203 WriteInstanceName(f,var,ref);
1204 FPRINTF(f,", ");
1205 }
1206 if (len) { /* check length */
1207 var = (struct Instance *)gl_fetch(list,len);
1208 WriteInstanceName(f,var,ref);
1209 FPRINTF(f," ; %d)",GlassBoxRelIndex(r));
1210 }
1211 }
1212 else{
1213 FPRINTF(f," )");
1214 }
1215 WriteOp(f,RelationRelop(r));
1216 }
1217
1218 static void WriteGlassBoxRelationDS(Asc_DString *dsPtr,
1219 CONST struct relation *r,
1220 CONST struct Instance *ref)
1221 {
1222 struct ExternalFunc *efunc;
1223 CONST char *name;
1224 struct Instance *var;
1225 CONST struct gl_list_t *list;
1226 unsigned long len,c;
1227
1228 efunc = GlassBoxExtFunc(r);
1229 name = ExternalFuncName(efunc);
1230 Asc_DStringAppend(dsPtr,name,-1);
1231 Asc_DStringAppend(dsPtr,"(",1);
1232 if (NULL != (list = RelationVarList(r))) {
1233 len = gl_length(list);
1234 for (c=1;c<len;c++) { /* the < is intentional */
1235 var = (struct Instance *)gl_fetch(list,c);
1236 WriteInstanceNameDS(dsPtr,var,ref);
1237 Asc_DStringAppend(dsPtr,", ",2);
1238 }
1239 if (len) { /* check length */
1240 var = (struct Instance *)gl_fetch(list,len);
1241 WriteInstanceNameDS(dsPtr,var,ref);
1242 sprintf(SB255," ; %d)",GlassBoxRelIndex(r));
1243 Asc_DStringAppend(dsPtr,SB255,-1);
1244 }
1245 }
1246 else{
1247 Asc_DStringAppend(dsPtr," )",2);
1248 }
1249 WriteOpDS(dsPtr,RelationRelop(r),relio_ascend);
1250 }
1251
1252 /**
1253 Output a blackbox relation to the specified file pointer
1254 */
1255 static
1256 void WriteBlackBoxRelation(FILE *f,
1257 CONST struct relation *r,
1258 CONST struct Instance *inst)
1259 {
1260 struct ExternalFunc *efunc;
1261 struct ExtCallNode *ext;
1262 struct gl_list_t *arglist;
1263 struct gl_list_t *branch;
1264 CONST struct Instance *arg;
1265 unsigned long len1,c1,len2,c2;
1266
1267 ext = BlackBoxExtCall(r);
1268 arglist = ExternalCallArgList(ext);
1269 len1 = gl_length(arglist);
1270 efunc = ExternalCallExtFunc(ext);
1271 FPRINTF(f,"%s(",ExternalFuncName(efunc)); /* function name */
1272
1273 if (len1) {
1274 FPRINTF(f,"\n\t");
1275 for (c1=1;c1<=len1;c1++) {
1276 branch = (struct gl_list_t *)gl_fetch(arglist,c1);
1277 if (branch) {
1278 len2 = gl_length(branch);
1279 for (c2=1;c2<=len2;c2++) {
1280 arg = (struct Instance *)gl_fetch(branch,c2);
1281 WriteInstanceName(f,arg,inst);
1282 if(c2<len2)FPRINTF(f,", ");
1283 }
1284 }
1285 if (c1<len1)
1286 FPRINTF(f,"\n);\n");
1287 }
1288 }
1289
1290 FPRINTF(f,");\n");
1291 }
1292
1293 static
1294 void WriteBlackBoxRelationDS(Asc_DString *dsPtr,
1295 CONST struct relation *r,
1296 CONST struct Instance *inst)
1297 {
1298 struct ExternalFunc *efunc;
1299 struct ExtCallNode *ext;
1300 struct gl_list_t *arglist;
1301 struct gl_list_t *branch;
1302 CONST struct Instance *arg;
1303 unsigned long len1,c1,len2,c2;
1304
1305 ext = BlackBoxExtCall(r);
1306 arglist = ExternalCallArgList(ext);
1307 len1 = gl_length(arglist);
1308 efunc = ExternalCallExtFunc(ext);
1309 sprintf(SB255," %s(",ExternalFuncName(efunc)); /* function name */
1310 Asc_DStringAppend(dsPtr,SB255,-1);
1311
1312 if (len1) {
1313 Asc_DStringAppend(dsPtr,"\n\t",2);
1314 for (c1=1;c1<=len1;c1++) {
1315 branch = (struct gl_list_t *)gl_fetch(arglist,c1);
1316 if (branch) {
1317 len2 = gl_length(branch);
1318 for (c2=1;c2<=len2;c2++) {
1319 arg = (struct Instance *)gl_fetch(branch,c2);
1320 WriteInstanceNameDS(dsPtr,arg,inst);
1321 if(c2<len2)Asc_DStringAppend(dsPtr,", ",2);
1322 }
1323 }
1324 if(c1<len1)
1325 Asc_DStringAppend(dsPtr,"\n\t, ",4);
1326 }
1327 Asc_DStringAppend(dsPtr,"\n",1);
1328 }
1329
1330 Asc_DStringAppend(dsPtr,");\n ",3);
1331 }
1332
1333
1334 void WriteRelation(FILE *f, CONST struct Instance *relinst,
1335 CONST struct Instance *ref)
1336 {
1337 CONST struct relation *reln;
1338 enum Expr_enum reltype;
1339
1340 reln = GetInstanceRelation(relinst,&reltype);
1341 if (!reln) {
1342 FPRINTF(f,"NULL relation\n");
1343 return;
1344 }
1345 switch (reltype) {
1346 case e_token:
1347 WriteTokenRelation(f,reln,ref);
1348 return;
1349 case e_blackbox:
1350 WriteBlackBoxRelation(f,reln,ref);
1351 return;
1352 case e_glassbox:
1353 WriteGlassBoxRelation(f,reln,ref);
1354 return;
1355 default:
1356 FPRINTF(ASCERR,"Unknown relation type in WriteRelation\n");
1357 return;
1358 }
1359 }
1360
1361 char *WriteRelationString(CONST struct Instance *relinst,
1362 CONST struct Instance *ref,
1363 WRSNameFunc func, void *userdata,
1364 enum rel_lang_format lang,
1365 int *lenptr)
1366 {
1367 CONST struct relation *reln;
1368 enum Expr_enum reltype;
1369 static Asc_DString ds;
1370 Asc_DString *dsPtr;
1371 char *result;
1372
1373 reln = GetInstanceRelation(relinst,&reltype);
1374 if (!reln) {
1375 result = ASC_NEW_ARRAY(char,15);
1376 if (result == NULL) return result;
1377 sprintf(result,"NULL relation\n");
1378 if (lenptr != NULL) {
1379 *lenptr = 14;
1380 }
1381 return result;
1382 }
1383
1384 dsPtr = &ds;
1385 Asc_DStringInit(dsPtr);
1386 switch (reltype) {
1387 case e_token:
1388 WriteTokenRelationDS(dsPtr,reln,ref,func,userdata,lang);
1389 break;
1390 case e_blackbox:
1391 WriteBlackBoxRelationDS(dsPtr,reln,ref);
1392 break;
1393 case e_glassbox:
1394 WriteGlassBoxRelationDS(dsPtr,reln,ref);
1395 break;
1396 default:
1397 FPRINTF(ASCERR,"Unknown relation type in WriteRelationString\n");
1398 if (lenptr != NULL) {
1399 *lenptr = -1;
1400 }
1401 return NULL;
1402 }
1403 if (lenptr != NULL) {
1404 *lenptr = Asc_DStringLength(dsPtr);
1405 }
1406 result = Asc_DStringResult(dsPtr);
1407 Asc_DStringFree(dsPtr);
1408 return result;
1409 }
1410
1411
1412 /*
1413 * some io to help in debugging relation manipulators.
1414 */
1415 static FILE *g_writfp = NULL;
1416 static void WriteIfRel(struct Instance *i)
1417 {
1418 struct Instance *p;
1419 char *string;
1420 struct RXNameData crd = {"x[",NULL,"]"};
1421 if (!i) {
1422 FPRINTF(ASCERR,"null child pointer in WriteIfRel\n");
1423 return;
1424 }
1425 if (InstanceKind(i)==REL_INST) {
1426 FPRINTF(g_writfp,"\n");
1427 WriteInstanceName(g_writfp,i,NULL);
1428 FPRINTF(g_writfp,"\n");
1429 p = InstanceParent(i,1);
1430 while (InstanceKind(p)!= MODEL_INST && InstanceKind(p) != SIM_INST) {
1431 p = InstanceParent(p,1);
1432 }
1433 FPRINTF(g_writfp,"INFIX\n");
1434 WriteRelation(g_writfp,i,p);
1435 FPRINTF(g_writfp,"\n");
1436 FFLUSH(g_writfp);
1437
1438 FPRINTF(g_writfp,"STRING-INFIX\n");
1439 string = WriteRelationString(i,p,NULL,NULL,relio_ascend,NULL);
1440 FPRINTF(g_writfp,"%s\n",(string==NULL)?"nullstring":string);
1441 if (string != NULL) {
1442 ascfree(string);
1443 }
1444 FFLUSH(g_writfp);
1445
1446 FPRINTF(g_writfp,"STRING-X-ASCEND\n");
1447 string = WriteRelationString(i,p,(WRSNameFunc)RelationVarXName,
1448 NULL,relio_ascend,NULL);
1449 FPRINTF(g_writfp,"%s\n",(string==NULL)?"nullstring":string);
1450 if (string != NULL) {
1451 ascfree(string);
1452 }
1453 FFLUSH(g_writfp);
1454
1455 FPRINTF(g_writfp,"STRING-C-pretty\n");
1456 string = WriteRelationString(i,p,(WRSNameFunc)RelationVarXName,
1457 (VOIDPTR)&crd,relio_C,NULL);
1458 print_long_string(g_writfp,string,60,8);
1459 FPRINTF(g_writfp,"STRING-C\n");
1460 FPRINTF(g_writfp,"%s\n",(string==NULL)?"nullstring":string);
1461 if (string != NULL) {
1462 ascfree(string);
1463 }
1464 FFLUSH(g_writfp);
1465
1466 FPRINTF(g_writfp,"POSTFIX\n");
1467 WriteRelationPostfix(g_writfp,i,p);
1468 FPRINTF(g_writfp,"\n");
1469 FFLUSH(g_writfp);
1470 }
1471 return;
1472 }
1473
1474 void WriteRelationsInTree(FILE *fp,struct Instance *i)
1475 {
1476 if (i==NULL || fp==NULL) return;
1477 g_writfp = fp;
1478 SlowVisitInstanceTree(i,WriteIfRel,0,0);
1479 }
1480
1481 void WriteRelationsInList(FILE *fp,struct gl_list_t *list)
1482 {
1483 if (list==NULL || fp==NULL) {
1484 return;
1485 }
1486 g_writfp = fp;
1487 gl_iterate(list,(void (*)(VOIDPTR))WriteIfRel);
1488 }
1489
1490
1491 /*
1492 *********************************************************************
1493 * Save Relation Code
1494 *
1495 * The below code is concerned with saving relations in a persistent
1496 * format. It writes out the code in a condensed format to allow
1497 * restoration to the original representation. A number of conversion
1498 * formats are provided. In particular, a token or opcode relation
1499 * may be saved as a glassbox relation, with the attendent loss of
1500 * information high level information.
1501 *
1502 * The grammar will follow later once it has stabilized.
1503 * In the mean time, the following keywords are used.
1504 * $KIND INTEGER - the reltype - e_token, e_opcode etc.
1505 * $RELOP INTEGER - the relational operator - e_maximize, e_equal etc.
1506 * $COUNT INTEGER - the number of variables.
1507 * $OPCODES INTEGER ':' (INTEGER)*
1508 * $VARIABLES ':' (INTEGER)* - global varindex
1509 * $CONSTANTS ':' (REAL)*
1510 *********************************************************************
1511 */
1512
1513 #undef LHS
1514 #undef RHS
1515 #define LHS 0
1516 #define RHS 1
1517 #define BREAKLINES 65
1518 static
1519 void SaveTokenRelnSide(FILE *fp,CONST struct relation *r,
1520 int side, struct gl_list_t *constants)
1521 {
1522 CONST struct relation_term *term;
1523 enum Expr_enum t;
1524 unsigned c,len;
1525 int count;
1526
1527 len = RelationLength(r,side);
1528 if (!len) return;
1529
1530 count = 16;
1531 FPRINTF(fp,"\t$OPCODES %d : ",side);
1532 for (c=1;c<=len;c++) {
1533 term = RelationTerm(r,c,side);
1534 t = RelationTermType(term);
1535 count += FPRINTF(fp," %d ",(int)t); /* the opcode is the enum */
1536 switch (t) {
1537 case e_var:
1538 count += FPRINTF(fp,"%lu",TermVarNumber(term));
1539 break;
1540 case e_func:
1541 count += FPRINTF(fp,"%d",(int)FuncId(TermFunc(term)));
1542 break;
1543 case e_int:
1544 case e_zero:
1545 case e_real:
1546 gl_append_ptr(constants,(VOIDPTR)term);
1547 count += FPRINTF(fp,"%lu",gl_length(constants));
1548 break;
1549 case e_uminus: /* DOUBLE CHECK -- KAA_DEBUG */
1550 case e_plus:
1551 case e_minus:
1552 case e_times:
1553 case e_divide:
1554 case e_power:
1555 case e_ipower:
1556 break;
1557 default:
1558 count += FPRINTF(fp,"%d",(int)e_nop);
1559 break;
1560 }
1561 if (count >= BREAKLINES) {
1562 PUTC('\n',fp); PUTC('\t',fp);
1563 count = 8;
1564 }
1565 }
1566 FPRINTF(fp,";\n"); /* terminate */
1567 }
1568
1569
1570 /*
1571 * We write out everybody as a floating point number. The
1572 * opcode will tell whether to coerce the double to a long
1573 * or vice verca.
1574 */
1575 static
1576 void SaveTokenConstants(FILE *fp, struct gl_list_t *constants)
1577 {
1578 CONST struct relation_term *term;
1579 unsigned long len,c;
1580
1581 len = gl_length(constants);
1582 if (!len) return;
1583
1584 FPRINTF(fp,"\t$CONSTANTS : ");
1585 for (c=1;c<=len;c++) {
1586 term = (CONST struct relation_term *)gl_fetch(constants,c);
1587 switch (RelationTermType(term)) {
1588 case e_zero:
1589 FPRINTF(fp,"%12.8e",0.0);
1590 break;
1591 case e_real:
1592 FPRINTF(fp,"%12.8e",TermReal(term));
1593 break;
1594 case e_int:
1595 FPRINTF(fp,"%12.8e",(double)TermInteger(term));
1596 break;
1597 default:
1598 Asc_Panic(2, NULL, "Illegal term in SaveTokenConstants\n");
1599 break;
1600 }
1601 PUTC(' ',fp);
1602 }
1603 FPRINTF(fp,";\n"); /* terminate */
1604 }
1605
1606 /*
1607 *********************************************************************
1608 * SaveRelationVariables
1609 *
1610 * This should be good for all types of relations, and the
1611 * conversions between those relations.
1612 *********************************************************************
1613 */
1614 void SaveRelationVariables(FILE *fp, CONST struct relation *r)
1615 {
1616 struct Instance *var;
1617 unsigned long len,c;
1618 int count;
1619 len = NumberVariables(r);
1620 if (!len) return;
1621
1622 count = 16;
1623 FPRINTF(fp,"\t$VARIABLES : ");
1624 for (c=1;c<=len;c++) {
1625 var = RelationVariable(r,c);
1626 count += FPRINTF(fp," %lu ",GetTmpNum(var));
1627 if (count >= BREAKLINES) {
1628 PUTC('\n',fp); PUTC('\t',fp);
1629 count = 8;
1630 }
1631 }
1632 FPRINTF(fp,";\n"); /* terminate */
1633 }
1634
1635 /*
1636 *********************************************************************
1637 * SaveTokenRelation
1638 *
1639 * Save a token relation in condensed opcode format.
1640 * Saving of dimensionality information is not done at the moment.
1641 *********************************************************************
1642 */
1643 void SaveTokenRelation(FILE *fp, CONST struct Instance *relinst)
1644 {
1645 CONST struct relation *reln;
1646 enum Expr_enum type;
1647 struct gl_list_t *constants = NULL;
1648
1649 reln = GetInstanceRelation(relinst,&type);
1650 if (type!=e_token) {
1651 FPRINTF(ASCERR,"Invalid relation type in SaveTokenRelation\n");
1652 return;
1653 }
1654 constants = gl_create(50L); /* overkill, but ... */
1655
1656 FPRINTF(fp,"$RELATION %lu {\n",GetTmpNum(relinst)); /* header */
1657 FPRINTF(fp,"\t$KIND %d, $RELOP %d, $COUNT %lu;\n",
1658 (int)type, (int)RelationRelop(reln), NumberVariables(reln));
1659 /*
1660 * Now write out the optional stuff.
1661 */
1662 SaveTokenRelnSide(fp,reln,LHS,constants);
1663 SaveTokenRelnSide(fp,reln,RHS,constants);
1664 SaveTokenConstants(fp,constants);
1665 SaveRelationVariables(fp,reln);
1666 FPRINTF(fp,"}\n\n"); /* the trailer */
1667
1668 gl_destroy(constants);
1669 }
1670
1671 /*
1672 *********************************************************************
1673 * SaveGlassBoxRelation
1674 *
1675 *********************************************************************
1676 */
1677 void SaveGlassBoxRelation(FILE *fp, CONST struct Instance *relinst)
1678 {
1679 CONST struct relation *reln;
1680 enum Expr_enum type;
1681 CONST char *tmp;
1682 int len;
1683
1684 reln = GetInstanceRelation(relinst,&type);
1685 len = GlassBoxNumberArgs(reln);
1686 if (len==0) return;
1687 if (NumberVariables(reln) != (unsigned long)len) {
1688 FPRINTF(ASCERR,"Corrupted arguements in glassbox relation\n");
1689 return;
1690 }
1691
1692 FPRINTF(fp,"$RELATION %lu {\n",GetTmpNum(relinst)); /* header */
1693 FPRINTF(fp,"\t$KIND %d, $RELOP %d, $COUNT %d;\n",
1694 (int)type, (int)RelationRelop(reln), len);
1695
1696 tmp = ExternalFuncName(GlassBoxExtFunc(reln));
1697 FPRINTF(fp,"\t$BASETYPE %s;\n",tmp); /* the funcname */
1698 FPRINTF(fp,"\t$INDEX %d\n",GlassBoxRelIndex(reln));
1699
1700 SaveRelationVariables(fp,reln);
1701 FPRINTF(fp,"}\n\n"); /* the trailer */
1702 }
1703
1704
1705 #ifdef THIS_IS_AN_UNUSED_FUNCTION
1706 /*
1707 * This function should be good enough to save token relations
1708 * and opcode relations to glassbox format. Blackbox relations
1709 * are not in order here.
1710 */
1711 static
1712 void Save__Reln2GlassBox(FILE *fp, CONST struct Instance *relinst,
1713 char *prefix, unsigned long index)
1714 {
1715 CONST struct relation *reln;
1716 enum Expr_enum type;
1717 unsigned long len;
1718
1719 reln = GetInstanceRelation(relinst,&type);
1720 assert(type!=e_blackbox);
1721 len = NumberVariables(reln);
1722 if (!len) return;
1723
1724 FPRINTF(fp,"$RELATION %lu {\n",GetTmpNum(relinst)); /* header */
1725 FPRINTF(fp,"\t$KIND %d, $RELOP %d, $COUNT %lu;\n",
1726 (int)type, (int)RelationRelop(reln), len);
1727 FPRINTF(fp,"\t$BASETYPE %s;\n",prefix); /* the funcname */
1728 FPRINTF(fp,"\t$INDEX %lu;\n",index);
1729
1730 SaveRelationVariables(fp,reln);
1731 FPRINTF(fp,"}\n\n"); /* the trailer */
1732 }
1733 #endif /* THIS_IS_AN_UNUSED_FUNCTION */
1734
1735
1736 /*
1737 *********************************************************************
1738 * SaveReln2GlassBox
1739 *
1740 * Save a relation and perform conversion to be able to restore it
1741 * as a glassbox.
1742 *********************************************************************
1743 */
1744 void SaveReln2GlassBox(FILE *fp, CONST struct Instance *relinst,
1745 char *prefix, unsigned long index_)
1746 {
1747 enum Expr_enum type;
1748
1749 type = GetInstanceRelationType(relinst);
1750 switch (type) {
1751 case e_token: /* token -> glassbox */
1752 case e_opcode: /* opcode -> glassbox */
1753 SaveReln2GlassBox(fp,relinst,prefix,index_);
1754 break;
1755 case e_glassbox:
1756 SaveGlassBoxRelation(fp,relinst); /* we will use the existing prefix */
1757 break;
1758 default:
1759 FPRINTF(ASCERR,"Relation type not supported in SaveGlassBox\n");
1760 break;
1761 }
1762 }
1763
1764 int ConversionIsValid(enum Expr_enum old, enum Expr_enum new)
1765 {
1766 if (new==old)
1767 return 1;
1768
1769 switch (old) {
1770 case e_token:
1771 if (new!=e_blackbox)
1772 return 1; /* we can handle all but blackboxes */
1773 return 0;
1774 case e_opcode: /* not fully supported yet */
1775 return 0;
1776 case e_glassbox:
1777 case e_blackbox:
1778 return 0;
1779 default:
1780 FPRINTF(ASCERR,"ConversionIsValid called with nonrelation type.\n");
1781 return 0;
1782 }
1783 }
1784
1785

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22