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