PIPS
genClib.c
Go to the documentation of this file.
1 /*
2 
3  $Id: genClib.c 1386 2018-10-24 09:18:26Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of NewGen.
8 
9  NewGen is free software: you can redistribute it and/or modify it under the
10  terms of the GNU General Public License as published by the Free Software
11  Foundation, either version 3 of the License, or any later version.
12 
13  NewGen is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16  License for more details.
17 
18  You should have received a copy of the GNU General Public License along with
19  NewGen. If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 /*
23  The file has all the generic functions to manipulate C objects
24  implemented by gen_chunks (see genC.c).
25 */
26 #ifdef HAVE_CONFIG_H
27  #include "config.h"
28 #endif
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdint.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <setjmp.h>
36 
37 #include "genC.h"
38 #undef gen_recurse
39 #undef gen_context_recurse
40 #include "newgen_include.h"
41 #include "newgen_hash.h"
42 #include "genread.h"
43 
44 /* starting the scanner.
45  */
46 extern void newgen_start_lexer(FILE*);
47 
48 #define GO (1)
49 
50 /* lex files
51  */
52 extern FILE *genspec_in, *genspec_out;
53 
54 /********************************************************** GLOBAL VARIABLES */
55 
56 /* pointer to tabulated domain hack
57  */
59 
61 static bool Read_spec_performed = false ;
62 
63 /* The debug flag can be changed by the user to check genClib code. */
64 /* If you set gen_debug dynamically with gdb, do not forget to set
65  * gen_debug_indent to a positive enough value to avoid problems
66  * when gen_trav_obj() moves upwards the point it was when gen_debug
67  * was set
68  */
69 int gen_debug = 0 ;
70 static int gen_debug_indent = 0 ;
71 
72 /* Default option in GEN_WRITE. */
73 
75 
76 /********************************************************************** MISC */
77 
78 /* GEN_TYPE returns the domain number for the object in argument
79  *
80  * FC 29/12/94
81  */
83 {
84  int dom;
85  message_assert("no domain for NULL object", obj!=(gen_chunk*)NULL);
86  message_assert("no domain for undefined object",
87  !gen_chunk_undefined_p(obj));
88  dom = obj->i; check_domain(dom);
89  return dom;
90 }
91 
92 /* GEN_DOMAIN_NAME returns the domain name, and may be used for debug
93  * purposes. It should be a valid domain name.
94  *
95  * FC 29/12/94
96  */
97 string gen_domain_name(int t)
98 {
99  check_domain(t);
100  return Domains[t].name;
101 }
102 
103 /* DOMAIN_INDEX returns the index in the Domain table for object OBJ.
104  */
106 {
107  message_assert("No NULL object", obj!=NULL);
108  message_assert("No undefined object", obj!=gen_chunk_undefined);
109  if ((obj->i)<0 || (obj->i)>=MAX_DOMAIN)
110  fatal("Inconsistent domain number %d (%p) found\n",
111  obj->i, obj);
112  return obj->i;
113 }
114 
115 /* FPRINTF_SPACES prints NUMBER spaces on the FD file descriptor.`
116  */
117 static void
118 fprintf_spaces( fd, number )
119 FILE *fd ;
120 int number ;
121 {
122  number = number<0 ? 0 : number;
123  number = number<40 ? number : 40; /* limited indentation */
124  for(; number ; number-- )
125  (void) fprintf( fd, " " ) ;
126 }
127 
128 #ifdef DBG_READ
129 /* WRITE_CHUNK prints on the FILE stream a succession of L gen_chunks
130  * (beginning at OBJ). This is used for debugging purposes.
131  */
132 void
133 write_gen_chunk( file, obj, l )
134  FILE *file ;
135  gen_chunk *obj ;
136  int l ;
137 {
138  int i ;
139 
140  (void) fprintf( file, "Chunk %x on %d:", obj, l ) ;
141 
142  for( i=0 ; i<l ; i++ )
143  (void) fprintf( file, "%d ", *(obj+i)) ;
144 
145  (void) fprintf( file, "\n" ) ;
146 }
147 #endif
148 
149 /**************************************************************** ALLOCATION */
150 
151 /* ARRAY_SIZE returns the number of elements in the array whose dimension
152  * list is DIM.
153  */
154 static int
156  struct intlist *dim ;
157 {
158  int sz = 1 ;
159 
160  for( ; dim != NULL ; dim = dim->cdr )
161  sz *= dim->val ;
162 
163  return( sz ) ;
164 }
165 
166 /* INIT_ARRAY returns a freshly allocated array initialized according to
167  * the information in its domain DP.
168  */
169 static gen_chunk * init_array(union domain * dp)
170 {
171  int sizarray = array_size( dp->ar.dimensions ) ;
172  /*NOSTRICT*/
173  gen_chunk *ar = (gen_chunk *)alloc( sizeof( gen_chunk )*sizarray ) ;
174 
175  for( ; sizarray ; sizarray-- )
176  ar[ sizarray-1 ].p = gen_chunk_undefined ;
177 
178  return ar;
179 }
180 
181 static int array_own_allocated_memory(union domain *dp)
182 {
183  return sizeof(gen_chunk)*array_size(dp->ar.dimensions);
184 }
185 
186 /** gen_alloc_component updates the gen_chunk CP from the arg list AP
187  according to the domain DP.
188 
189  It is now a macro to be able to update the va_list ap from
190  gen_alloc_constructed and respect the C norm. It should work both on x86
191  and x86_64...
192 
193 static void gen_alloc_component(union domain * dp,
194  gen_chunk * cp,
195  va_list ap,
196  int gen_check_p)
197 */
198 #define gen_alloc_component(dp, cp, ap, gen_check_p) \
199 { \
200  message_assert("gen_check_p parameter value ok", \
201  gen_check_p==0 || gen_check_p==1); \
202  \
203  switch( dp->ba.type ) { \
204  case ARRAY_DT : \
205  if( ((cp)->p = va_arg( ap, gen_chunk * )) == NULL ) \
206  (cp)->p = init_array( dp ) ; \
207  break ; \
208  case LIST_DT: \
209  (cp)->l = va_arg( ap, cons * ) ; \
210  break ; \
211  case SET_DT: \
212  (cp)->t = va_arg( ap, set ) ; \
213  break ; \
214  case BASIS_DT: \
215  if( IS_INLINABLE( dp->ba.constructand )) { \
216  switch( *dp->ba.constructand->name ) { \
217  case 'u': (cp)->u = va_arg( ap, unit ) ; break ; \
218  case 'b': (cp)->b = va_arg( ap, int )/*bool promoted to int when passed as a vararg*/ ; break ; \
219  case 'c': (cp)->c = va_arg( ap, int ) ; break ; \
220  case 'i': (cp)->i = va_arg( ap, int ) ; break ; \
221  case 'f': (cp)->f = va_arg( ap, double ) ; break ; \
222  case 's': (cp)->s = va_arg( ap, string ) ; break ; \
223  default: \
224  fatal( "gen_alloc: unknown inlinable %s\n", \
225  dp->ba.constructand->name ) ; \
226  } \
227  } \
228  else if( IS_EXTERNAL( dp->ba.constructand )) { \
229  (cp)->s = va_arg( ap, char * ) ; \
230  } \
231  else { \
232  (cp)->p = va_arg( ap, gen_chunk * ) ; \
233  \
234  if( gen_debug & GEN_DBG_CHECK || gen_check_p ) { \
235  (void) gen_check( (cp)->p, dp->ba.constructand-Domains ) ; \
236  } \
237  } \
238  break ; \
239  default: \
240  fatal("gen_alloc_component: unknown type %s\n", \
241  i2a(dp->ba.type)) ; \
242  } \
243 }
244 
245 /* GEN_ALLOC allocates SIZE bytes to implement an object whose TYPE is
246  the index in the Domains table. A fairly sophisticated initialization
247  process is run, namely arrays are filled with undefineds. */
248 
249 static void gen_alloc_constructed(va_list ap,
250  struct gen_binding * bp,
251  union domain * dp,
252  gen_chunk * cp,
253  int data,
254  int gen_check_p)
255 {
256  struct domainlist * dlp;
257 
258  message_assert("gen_check_p parameter value ok",
259  gen_check_p==0 || gen_check_p==1);
260 
261  switch( dp->co.op ) {
262  case AND_OP : {
263  gen_chunk *cpp ;
264 
265  for( dlp=dp->co.components, cpp=cp+data ;
266  dlp != NULL ;
267  dlp=dlp->cdr, cpp++ ) {
268  gen_alloc_component( dlp->domain, cpp, ap, gen_check_p ) ;
269  }
270  break ;
271  }
272  case OR_OP: {
273  int which ;
274 
275  (cp+data)->i = va_arg( ap, int ) ;
276  which = (cp+data)->i - dp->co.first ;
277 
278  for( dlp=dp->co.components; dlp!=NULL && which ;dlp=dlp->cdr ){
279  which-- ;
280  }
281  if( dlp == NULL ) {
282  user( "gen_alloc: unknown tag for type %s\n", bp->name ) ;
283  }
284  gen_alloc_component( dlp->domain, cp+data+1, ap, gen_check_p ) ;
285  break ;
286  }
287  case ARROW_OP: {
288  (cp+data)->h = hash_table_make( hash_chunk, 0 ) ;
289  break ;
290  }
291  default:
292  fatal( "gen_alloc: Unknown op %s\n", i2a( dp->co.op )) ;
293  }
294 }
295 
296 /* allocates something in newgen.
297  */
298 gen_chunk * gen_alloc(int size, int gen_check_p, int dom, ...)
299 {
300  va_list ap;
301  union domain * dp;
302  struct gen_binding * bp;
303  gen_chunk * cp;
304  int data;
305 
306  message_assert("gen_check_p parameter value ok",
307  gen_check_p==0 || gen_check_p==1);
308 
310 
311  va_start(ap, dom);
312 
313  cp = (gen_chunk *) alloc(size) ;
314  message_assert("allocated pointer", cp);
315 
316  // zero all bytes...
317  // I guess it must be an integral number of pointers, but just in case...
318  char * p = (char *) cp;
319  int i;
320  for (i=0; i<size; i++)
321  p[i] = '\0';
322 
323  // now initialize contents
324  cp->i = dom;
325 
326  bp = &Domains[dom];
327  data = 1 + IS_TABULATED( bp );
328 
329  switch( (dp = bp->domain)->ba.type ) {
330  case LIST_DT:
331  (cp+data)->l = va_arg( ap, cons *) ;
332  break ;
333  case SET_DT:
334  (cp+data)->t = va_arg( ap, set) ;
335  break ;
336  case ARRAY_DT:
337  if( ((cp+data)->p = va_arg( ap, gen_chunk *)) == NULL ) {
338  (cp+data)->p = init_array( dp ) ;
339  }
340  break ;
341  case CONSTRUCTED_DT:
342  gen_alloc_constructed( ap, bp, dp, cp, data, gen_check_p ) ;
343  break ;
344  default:
345  fatal( "gen_alloc: Unknown type %s\n", i2a( dp->ba.type )) ;
346  }
347 
348  if (IS_TABULATED(bp))
349  gen_enter_tabulated(dom, (cp+HASH_OFFSET)->s, cp, false);
350 
351  va_end( ap ) ;
352 
353  return cp;
354 }
355 
356 /********************************************************** NEWGEN RECURSION */
357 
358 /* The DRIVER structure is used to monitor the general function which
359  * traverses objects. NULL is called whenver an undefined pointer is found.
360  * <sort>_IN is called whenever an object of <sort> is entered. If the
361  * returned value is true, then recursive calls are made and, at the end,
362  * the <sort>_OUT function is called.
363  */
364 
365 struct driver {
366  void (*null)() ;
367  int (*leaf_in)() ;
368  void (*leaf_out)() ;
369  int (*simple_in)() ;
370  void (*array_leaf)() ;
371  void (*simple_out)() ;
372  int (*obj_in)() ;
373  void (*obj_out)() ;
374  // void * context;
375 } ;
376 
377 /* To be called on any object pointer.
378  */
379 
380 #define CHECK_NULL(obj,bp,dr) \
381  if((obj)==gen_chunk_undefined) {(*(dr)->null)(bp) ; return ;}
382 
383 static void gen_trav_obj() ;
384 static bool gen_trav_stop_recursion = false; /* set to true to stop... */
385 
386 /* GEN_TRAV_LEAF manages an OBJ value of type BP according to the current
387  driver DR. A leaf is an object (inlined or not). */
388 
389 static void
390 gen_trav_leaf(struct gen_binding * bp, gen_chunk * obj, struct driver * dr)
391 {
392  if (gen_trav_stop_recursion) return;
393 
394  CHECK_NULL(obj, bp, dr) ;
395 
397  {
398  fprintf_spaces( stderr, gen_debug_indent++ ) ;
399  (void) fprintf( stderr, "trav_leaf dealing with " ) ;
400 
401  if( IS_INLINABLE( bp ))
402  (void) fprintf( stderr, "inlined %s\n", bp->name ) ;
403  else if( IS_EXTERNAL( bp ))
404  (void) fprintf( stderr, "external %s\n", bp->name ) ;
405  else if( IS_TABULATED( bp ))
406  (void) fprintf( stderr, "tabulated %s\n", bp->name ) ;
407  else (void) fprintf( stderr, "constructed %s\n", bp->name ) ;
408  }
409 
410  if( (*dr->leaf_in)(obj, bp))
411  {
412  if (gen_trav_stop_recursion) return;
413  if( !IS_INLINABLE( bp ) && !IS_EXTERNAL( bp ))
414  {
415  if (gen_debug & GEN_DBG_CHECK)
416  (void) gen_check( obj->p, bp-Domains ) ;
417 
418  CHECK_NULL(obj->p, bp, dr) ;
419  gen_trav_obj( obj->p, dr ) ;
420  }
421  (*dr->leaf_out)(obj, bp) ;
422  }
423 
425 }
426 
427 /* GEN_TRAV_SIMPLE traverses a simple OBJ (which is a (CONS *) for a list
428  or points to the first element of an array) of type DP according to the
429  driver DR. */
430 static void
432  union domain * dp,
433  gen_chunk * obj,
434  struct driver * dr)
435 {
436  if (gen_trav_stop_recursion) return;
437 
438  CHECK_NULL(obj, (struct gen_binding *) NULL, dr);
439 
441  {
442  fprintf_spaces( stderr, gen_debug_indent++ ) ;
443  (void) fprintf( stderr, "trav_simple dealing with " ) ;
444  print_domain( stderr, dp ) ;
445  (void) fprintf( stderr, "\n" ) ;
446  }
447 
448  if( (*dr->simple_in)(obj, dp))
449  {
450  switch( dp->ba.type )
451  {
452  case BASIS_DT:
453  gen_trav_leaf( dp->ba.constructand, obj, dr ) ;
454  break ;
455  case LIST_DT:
456  {
457  cons *p ;
458  for (p = obj->l ; p != NULL ; p = p->cdr)
459  gen_trav_leaf( dp->li.element, &p->car, dr ) ;
460  break ;
461  }
462  case SET_DT:
463  SET_MAP(elt,
464  {
465  gen_trav_leaf(dp->se.element, (gen_chunk *)&elt, dr);
466  },
467  obj->t) ;
468  break ;
469  case ARRAY_DT:
470  {
471  int i, size = array_size(dp->ar.dimensions);
472  for (i=0 ; i<size; i++)
473  (*dr->array_leaf)(dp->ar.element, i, obj->p+i, dr);
474  break ;
475  }
476  default:
477  fatal("gen_trav_simple: Unknown type %s\n", i2a( dp->ba.type ));
478  }
479 
482  return;
483  }
484  (*dr->simple_out)( obj, dp ) ;
485  }
486 
488 }
489 
490 /* GEN_ARRAY_LEAF is the default recursive call to gen_trav_leaf.
491  */
492 
493 static void
495  struct gen_binding *bp,
496  int i,
497  gen_chunk *obj,
498  struct driver *dr)
499 {
500  if (gen_trav_stop_recursion) return;
501  message_assert("argument not used", i==i);
502  gen_trav_leaf( bp, obj, dr ) ;
503 }
504 
505 
506 /* GEN_TRAV_OBJ (the root function) traverses the object OBJ according to
507  the driver DR.
508  */
509 static void
511  gen_chunk *obj,
512  __attribute__((unused)) struct gen_binding *bp,
513  union domain *dp,
514  int data,
515  struct driver *dr)
516 {
517  struct domainlist *dlp;
518 
519  if (gen_trav_stop_recursion) return;
520  dlp = dp->co.components ;
521  switch(dp->co.op)
522  {
523  case AND_OP:
524  {
525  gen_chunk *cp ;
526  for(cp = obj+data ; dlp != NULL ; cp++, dlp = dlp->cdr)
527  {
528  gen_trav_simple(dlp->domain, cp, dr) ;
529  if (gen_trav_stop_recursion) return;
530  }
531  break ;
532  }
533  case OR_OP:
534  {
535  int which = (obj+data)->i - dp->co.first ;
536  for(; dlp!=NULL && which; which--,dlp=dlp->cdr)
537  ;
538  if(dlp == NULL)
539  fatal( "gen_trav_obj: Unknown tag %s\n", i2a( (obj+data)->i )) ;
540  gen_trav_simple(dlp->domain, obj+data+1, dr);
541  break ;
542  }
543  case ARROW_OP:
544  {
545  union domain
546  *dkeyp=dlp->domain,
547  *dvalp=dlp->cdr->domain;
548 
549  HASH_MAP(k, v,
550  {
551  // what if? persistent sg ->
552  // the source & target must be simple newgen objects, not sets/lists...
553  gen_trav_simple(dkeyp, (gen_chunk *) k, dr) ;
554  if (gen_trav_stop_recursion) return;
555  gen_trav_simple(dvalp, (gen_chunk *) v, dr) ;
556  if (gen_trav_stop_recursion) return;
557  },
558  (obj+data)->h ) ;
559  break ;
560  }
561  default:
562  fatal( "gen_trav_obj: Unknown op %s\n", i2a(dp->co.op)) ;
563  }
564 }
565 
566 /* "driver" driven recursion in newgen data structures.
567  * note that we do not know the expected type of the object...
568  */
569 static void
571  gen_chunk * obj,
572  struct driver * dr)
573 {
574  if (gen_trav_stop_recursion) return;
575 
576  if (obj == NULL)
577  fatal("unexpected NULL value encountered\n");
578 
579  // this detects undefined values:
580  CHECK_NULL(obj, (struct gen_binding *) NULL, dr);
581 
582  if ((*dr->obj_in)(obj, dr))
583  {
584  struct gen_binding *bp = &Domains[quick_domain_index(obj)] ;
585  union domain *dp = bp->domain ;
586  int data = 1+IS_TABULATED( bp ) ;
587 
588  if (gen_trav_stop_recursion) return;
589 
591  {
592  fprintf_spaces( stderr, gen_debug_indent++ ) ;
593  (void) fprintf( stderr, "trav_obj (%p) ", obj) ;
594  print_domain( stderr, dp ) ;
595  (void) fprintf( stderr, "\n" ) ;
596  }
597 
598  switch( dp->ba.type )
599  {
600  case LIST_DT:
601  case SET_DT:
602  case ARRAY_DT:
603  gen_trav_simple(dp, obj+data, dr);
604  break ;
605  case CONSTRUCTED_DT:
606  gen_trav_obj_constructed(obj, bp, dp, data, dr);
607  break ;
608  default:
609  fatal( "gen_trav_obj: Unknown type %s\n", i2a(dp->ba.type));
610  }
611 
612  if (gen_trav_stop_recursion) return;
613 
614  (*dr->obj_out)(obj, bp, dr);
615  }
617 }
618 
619 static int
621 {
622  message_assert("argument not used", obj==obj);
623  return(!IS_TABULATED(bp));
624 }
625 
626 /******************************************************************* SHARING */
627 
628 /* These functions computes an hash table of object pointers
629  * (to be used to manage sharing when dealing with objects).
630  */
631 
632 #define MAX_SHARED_OBJECTS 10000
633 
634 static char *first_seen = (char *)NULL ;
635 static char *seen_once = (char *)NULL ;
636 
637 #define FIRST_SEEN(s) ((s)>=first_seen && (s)<first_seen+MAX_SHARED_OBJECTS)
638 
639 /* The OBJ_TABLE maps objects to addresses within the arrays FIRST_SEEN
640  * and SEEN_ONCE. In the first case, if the address is FIRST_SEEN, then
641  * this is the first occurence of the object; if it has a non-zero
642  * offset i, then it is the i-th shared object seen so far. This offset
643  * is used in SHARED_OBJ to decide which number to print and update the
644  * OBJ_TABLE to associate the object to SEEN_ONCE+i so that latter
645  * references can be correctly generated.
646  */
647 
649 
650 /* returns the number of byte allocated for obj_table.
651  * for FI and debugging purposes...
652  * FC
653  */
655 {
657 }
658 
659 /* The running counter of shared objects number.
660  */
661 
662 static int shared_number = 0 ;
663 
664 /* SHARED_OBJ_IN introduces an object OBJ in the OBJ_TABLE. If it is
665  already in the table, don't recurse (at least, if you want to avoid an
666  infinite loop) and give it a number. Else recurse.
667  */
668 
669 static int
670 shared_obj_in(gen_chunk * obj, struct driver * dr)
671 {
672  void * seen = hash_get(obj_table, obj);
673  message_assert("argument not used", dr==dr);
674 
676  {
677  if(seen == first_seen)
678  {
679  shared_number++;
680  message_assert("shared table not full",
682 
684  }
685  return(!GO) ;
686  }
687 
688  hash_put(obj_table, obj, first_seen ) ;
689  return GO;
690 }
691 
692 static int
694 gen_chunk *obj ;
695 union domain *dp ;
696 {
697  switch( dp->ba.type ) {
698  case BASIS_DT:
699  return( !dp->ba.persistant ) ;
700  case LIST_DT: {
701  cons *p ;
702 
703  if( obj->l == list_undefined ) {
704  return( !GO) ;
705  }
706  for( p=obj->l ; p!=NIL ; p=p->cdr )
707  {
708  message_assert("no sharing of cons",
709  hash_get(obj_table, (char *)p) == HASH_UNDEFINED_VALUE);
710 
711  hash_put(obj_table, (char *)p, (char *)p);
712  }
713  return( !dp->li.persistant ) ;
714  }
715  case SET_DT:
716  return( !dp->se.persistant ) ;
717  case ARRAY_DT:
718  return( !dp->ar.persistant ) ;
719  default:
720  break;
721  }
722  fatal( "shared_simple_in: unknown type %s\n", i2a( dp->ba.type )) ;
723 
724  return(-1); /* just to avoid a gcc warning */
725 }
726 
727 /* SHARED_POINTERS creates (in OBJ_TABLE) the association between objects
728  and their numbers (!= 0 if sharing). Inlined values are NOT considered
729  to be shared (neither list and arrays), just objects (i.e. objects which
730  have a user name, a spec in Domains). KEEP says whether the previous
731  sharing table is preserved. */
732 
733 static void
735 gen_chunk *obj ;
736 bool keep ;
737 {
738  struct driver dr ;
739 
740  dr.null = dr.leaf_out = dr.simple_out = dr.obj_out = gen_null ;
741  dr.obj_in = shared_obj_in ;
745 
746  message_assert("obj_table not null", obj_table!=(hash_table)NULL);
747 
748  if(!keep) {
750  shared_number = 0 ;
751  }
752  /* else the obj_table is kept as it is.
753  */
754 
755  gen_trav_obj( obj, &dr ) ;
756 }
757 
758 /* SHARED_OBJ manages the OBJect modulo sharing (the OBJ_TABLE has to be
759  set first, see above). If the object isn't shared, don't do nothing.
760  else, if that's the first appearance, call FIRST and go on, else
761  call OTHERS. If the obj_table isn't defined, recurse. */
762 
763 static int
764 shared_obj( obj, first, others )
765 gen_chunk *obj ;
766 void (*first)() ;
767 void (*others)() ;
768 {
769  char *shared ;
770  int shared_number ;
771 
772  message_assert("Defined obj_table", obj_table!=(hash_table)NULL);
773 
774  shared = hash_get( obj_table, (char *)obj);
775 
776  if(shared==HASH_UNDEFINED_VALUE || shared == first_seen )
777  return(!GO) ;
778  else
779  if( FIRST_SEEN( shared ))
780  {
781  (*first)( shared_number = shared-first_seen ) ;
782  hash_update( obj_table, (char *)obj, seen_once+shared_number ) ;
783  return( !GO) ;
784  }
785  else
786  {
787  (*others)( shared - seen_once ) ;
788  return( GO) ;
789  }
790 }
791 
792 /***************************************************** RECURSION ENVIRONMENT */
793 
794 /* GEN_TRAV_ENVS are stacked to allow recursive calls to GEN_TRAV_OBJ
795  * (cf. GEN_RECURSE)
796  */
797 #define MAX_GEN_TRAV_ENV 100
798 
799 static int gen_trav_env_top = 0 ;
800 
801 struct gen_trav_env {
802  char *first_seen ;
803  char *seen_once ;
807 
808 static void push_gen_trav_env()
809 {
810  struct gen_trav_env *env ;
811 
812  message_assert("Too many recursive gen_trav",
814 
816  env->first_seen = first_seen ;
817  env->seen_once = seen_once ;
818  env->obj_table = obj_table ;
819  env->shared_number = shared_number ;
820 
821  first_seen = (char *)alloc( MAX_SHARED_OBJECTS ) ;
822  seen_once = (char *)alloc( MAX_SHARED_OBJECTS ) ;
824  shared_number = 0 ;
825 }
826 
827 static void pop_gen_trav_env()
828 {
829  struct gen_trav_env *env ;
830 
831  message_assert("Too many pops", gen_trav_env_top >= 0);
832 
836 
838  seen_once = env->seen_once ;
839  obj_table = env->obj_table ;
840  shared_number = env->shared_number ;
841 }
842 
843 /********************************************************************** FREE */
844 
845 /* These functions are used to implement the freeing of objects. A
846  tabulated constructor has to stop recursive freeing. */
847 
848 static __thread hash_table free_already_seen = (hash_table) NULL;
849 
850 static bool
852  gen_chunk *obj)
853 {
854  message_assert("hash_table defined", free_already_seen);
855 
856  if (hash_get(free_already_seen, (char *)obj)==(char*)true)
857  return true;
858  /* else seen for next time !
859  */
860  hash_put(free_already_seen, (char *)obj, (char *) true);
861  return false;
862 }
863 
864 /* A tabulated domain BP prohibits its OBJ to be recursively freed. */
865 
866 static int
867 free_leaf_in(gen_chunk * obj, struct gen_binding * bp)
868 {
869  message_assert("argument not used", obj==obj);
870  return !IS_TABULATED(bp)/* && !free_already_seen_p(obj) */; /* ??? */
871 }
872 
873 /* FREE_LEAF_OUT manages external types. */
874 
875 static void
876 free_leaf_out( obj, bp )
877 gen_chunk *obj ;
878 struct gen_binding *bp ;
879 {
880  if( IS_INLINABLE(bp )) {
881  /* is it a string with some allocated value? */
882  if( *bp->name == 's' && obj->s && !string_undefined_p(obj->s))
883  newgen_free(obj->s);
884  return ;
885  }
886  else
887  if( IS_EXTERNAL( bp )) {
888  if( bp->domain->ex.free == NULL ) {
889  user( "gen_free: uninitialized external type %s\n",
890  bp->name ) ;
891  return ;
892  }
893  (*(bp->domain->ex.free))( obj->s ) ;
894  }
895 }
896 
897 /* FREE_SIMPLE_OUT frees the spine of the list OBJ or the whole array
898  (according to the type DP). The components are (obviously ?) freed by the
899  recursive traversal functions (I said it once ... and for all). */
900 
901 static void free_simple_out(gen_chunk *obj, union domain *dp)
902 {
903  switch( dp->ba.type ) {
904  case LIST_DT:
905  gen_free_list( obj->l ) ;
906  break ;
907  case SET_DT:
908  set_free( obj->t ) ;
909  break ;
910  case ARRAY_DT:
911  /* ??? where is the size of the array? */
912  newgen_free( (char *) obj->p ) ;
913  break ;
914  default:
915  break;
916  }
917 }
918 
919 /* FREE_OBJ_OUT just frees the object OBJ. */
920 /* static gen_chunk freed_gen_chunk ; */
921 
922 static void free_obj_out(
923  gen_chunk * obj,
924  struct gen_binding * bp,
925  struct driver * dr)
926 {
927  union domain *dp ;
928 
929  message_assert("argument not used", dr==dr);
930 
931  if((dp=bp->domain)->ba.type == CONSTRUCTED_DT && dp->co.op == ARROW_OP) {
932  hash_table h = (obj+1 + IS_TABULATED( bp ))->h ;
933 
934  /* shouldn't this be done by hash_table_free ? */
935  HASH_MAP( k, v, {
936  newgen_free( (void *)k ) ;
937  newgen_free( (void *)v ) ;
938  }, h ) ;
939  hash_table_free( h ) ;
940  }
941 
942  obj->p = NEWGEN_FREED;
943  /* gen_free_area(obj->p, SIZE NOT DIRECTLY AVAILABLE); */
944  newgen_free((void *) obj) ;
945 }
946 
947 /* GEN_LOCAL_FREE frees the object OBJ with or without KEEPing the sharing. */
948 
949 static int
951 gen_chunk *obj ;
952 union domain *dp ;
953 {
954  switch( dp->ba.type ) {
955  case BASIS_DT:
956  return( !dp->ba.persistant && obj->i) ; /* ??? */
957  case LIST_DT:
958  return( !dp->li.persistant && obj->l && obj->l != list_undefined ) ;
959  case SET_DT:
960  return( !dp->se.persistant && obj->t && obj->t != set_undefined ) ;
961  case ARRAY_DT:
962  return( !dp->ar.persistant && obj->p && obj->p != array_undefined ) ;
963  default:
964  break;
965  }
966  fatal( "persistant_simple_in: unknown type %s\n", i2a( dp->ba.type )) ;
967 
968  return(-1); /* just to avoid a gcc warning */
969 }
970 
971 static int free_obj_in(gen_chunk * obj, struct driver * dr)
972 {
973  int notseen = !free_already_seen_p(obj);
974 
975  message_assert("argument not used", dr==dr);
976 
977  if (notseen)
978  {
979  struct gen_binding * bp = Domains+obj->i;
980  if (IS_TABULATED(bp))
981  {
983  }
984  }
985 
986  return notseen;
987 }
988 
989 /* version without shared_pointers.
990  * automatic re-entry allowed. FC.
991  */
992 void gen_free(gen_chunk *obj)
993 {
994  /* reentry or not: whether the already_seen table is initialized or not...
995  */
996  bool first_in_stack = (free_already_seen==(hash_table)NULL);
997  struct driver dr ;
998 
1000 
1001  dr.null = gen_null ;
1002  dr.leaf_out = free_leaf_out ;
1003  dr.leaf_in = free_leaf_in ;
1004  dr.obj_in = free_obj_in ;
1006  dr.array_leaf = gen_array_leaf ;
1008  dr.obj_out = free_obj_out ;
1009 
1010  if (first_in_stack)
1012 
1013  gen_trav_obj( obj, &dr ) ;
1014 
1015  if (first_in_stack)
1016  {
1018  free_already_seen = NULL;
1019  }
1020 }
1021 
1022 void
1024 {
1025  list p, nextp ;
1026  bool first_in_stack = (free_already_seen==(hash_table)NULL);
1027 
1028  if (first_in_stack)
1030 
1031  for (p = l; p ; p=nextp)
1032  {
1033  nextp = p->cdr;
1034  gen_free(CAR(p).p);
1035  newgen_free(p);
1036  }
1037 
1038  if (first_in_stack)
1039  {
1041  free_already_seen = NULL;
1042  }
1043 }
1044 
1045 /********************************************************************* COPY */
1046 
1047 /* These functions are used to implement the copying of objects. A
1048  tabulated constructor has to stop recursive duplication. */
1049 
1050 static hash_table copy_table = NULL;/* maps an object on its copy */
1051 
1052 static gen_chunk *
1054 {
1055  gen_chunk *p ;
1056 
1057  /* special cases... */
1058  if(!key || string_undefined_p((char*)key) ||
1059  key == (gen_chunk *)HASH_UNDEFINED_VALUE)
1060  return key;
1061 
1062  if ((p=(gen_chunk *)hash_get( copy_table, (char *)key ))==
1064  fatal( "[copy_hsearch] bad key: %p\n", key );
1065  }
1066  return(p);
1067 }
1068 
1069 static void
1071  hash_table t,
1072  char *k,
1073  char *v)
1074 {
1075  if( k != (char *) HASH_UNDEFINED_VALUE && k != (char *) NULL)
1076  hash_put(t, k, v) ;
1077 }
1078 
1079 
1080 /* COPY_OBJ_IN duplicates an object if it has not already been seen
1081  (this migth happen with shared objects). inlined sub-domains are copied
1082  by the call to memcpy. remaining sub-domains require further processing
1083 */
1084 
1085 static int
1086 copy_obj_in(gen_chunk * obj, __attribute__((unused)) struct driver * dr)
1087 {
1088  struct gen_binding *bp = &Domains[quick_domain_index( obj ) ] ;
1089 
1090  /* if (shared_obj( obj, gen_null, gen_null )) return 0;*/
1091 
1092  if (!hash_defined_p(copy_table, (char*) obj))
1093  {
1094  /* memory is allocated to duplicate the object referenced by obj
1095  */
1096  gen_chunk *new_obj;
1097  int size = gen_size(bp-Domains)*sizeof(gen_chunk);
1098  new_obj = (gen_chunk *)alloc(size);
1099 
1100  /* thus content is copied, thus no probleme with inlined and so
1101  * and newgen domain number.
1102  */
1103  (void) memcpy((char *) new_obj, (char *) obj, size);
1104 
1105  /* hash table copy_table is updated
1106  */
1107  copy_hput(copy_table, (char *)obj, (char *)new_obj);
1108  return true;
1109  }
1110 
1111  return false;
1112 }
1113 
1114 /* Just check for defined simple domains. */
1115 
1116 static int
1118  gen_chunk *obj,
1119  union domain *dp)
1120 {
1121  bool persistence = dp->ba.persistant;
1122 
1123  /* persistent arcs are put as copy of themself...
1124  */
1125  if (persistence)
1126  copy_hput(copy_table, (char *) obj->p, (char *) obj->p);
1127 
1128  switch(dp->ba.type) {
1129  case BASIS_DT:
1130  return(!persistence);
1131  case LIST_DT:
1132  return(!persistence && obj->l!=list_undefined);
1133  case SET_DT:
1134  return(!persistence && obj->t!=set_undefined);
1135  case ARRAY_DT:
1136  return(!persistence && obj->p!=array_undefined);
1137  default:
1138  break;
1139  }
1140  fatal("copy_simple_in: unknown type %s\n", i2a(dp->ba.type));
1141 
1142  return(-1); /* just to avoid a gcc warning */
1143 }
1144 
1145 /* COPY_LEAF_OUT manages external sub-domains. warning: the test
1146  IS_EXTERNAL cannot be applied on an inlined sub-domain */
1147 
1148 static void
1150 gen_chunk *obj ;
1151 struct gen_binding *bp ;
1152 {
1153  if (IS_INLINABLE(bp))
1154  {
1155  if (*bp->name=='s' && obj->s && !string_undefined_p(obj->s) &&
1156  !hash_defined_p(copy_table, obj->s))
1157  copy_hput(copy_table, obj->s, strdup(obj->s));
1158 
1159  return;
1160  }
1161 
1162  if (IS_EXTERNAL(bp)) {
1163  if (bp->domain->ex.copy == NULL) {
1164  user("gen_copy_tree: uninitialized external type %s\n",
1165  bp->name) ;
1166  return ;
1167  }
1168  copy_hput(copy_table, obj->s, (*(bp->domain->ex.copy))(obj->s)) ;
1169  }
1170 }
1171 
1172 /* GEN_COPY_LIST duplicates cons cells. if list elements are inlinable,
1173  the old cell CARs are copied into the new ones. if not, the new cells
1174  must contain the objects that copy_table provides for the old objects
1175  contained in old cells. the second argument is the domain pointer of old
1176  list */
1177 
1178 static list
1180  list old_l,
1181  union domain *dp)
1182 {
1183  list old_p, new_p = NIL, new_l, pc;
1184  bool inlinable, persistant, tabulated;
1185 
1188  persistant = dp->li.persistant;
1189  new_l = NIL;
1190 
1191  if (inlinable || persistant || tabulated)
1192  return gen_copy_seq(old_l);
1193 
1194  /* else the items must also be copied
1195  */
1196  for (old_p = old_l ; old_p != NIL ; old_p = old_p->cdr)
1197  {
1198  pc = (list)alloc(sizeof(struct cons)) ;
1199 
1200  pc->car.p = copy_hsearch(old_p->car.p) ;
1201  pc->cdr = NIL;
1202 
1203  /* pc is linked to the new list
1204  */
1205  if (new_l == NIL)
1206  new_l = pc;
1207  else
1208  new_p->cdr = pc;
1209  new_p = pc;
1210  }
1211 
1212  return new_l;
1213 }
1214 
1215 /* GEN_COPY_ARRAY duplicates an array. if array elements are inlinable,
1216  the old array is copied into the new one. if not, the new array must
1217  contain the objects that copy_table provides for the old objects
1218  contained in the old array. the second argument is the domain pointer of
1219  the old array */
1220 
1221 static gen_chunk *
1222 gen_copy_array(old_a, dp)
1223 gen_chunk *old_a;
1224 union domain *dp ;
1225 {
1226  int i, size, inlinable;
1227  gen_chunk *new_a;
1228 
1229  size = array_size(dp->ar.dimensions);
1231  new_a = (gen_chunk *) alloc( sizeof(gen_chunk)*size ) ;
1232 
1233  if (inlinable) {
1234  (void) memcpy((char *) new_a, (char *) old_a, size*sizeof(gen_chunk));
1235  }
1236  else {
1237  for (i = 0; i < size; i++) {
1238  new_a[i].p = copy_hsearch( old_a[i].p ) ;
1239  }
1240  }
1241  return(new_a);
1242 }
1243 
1244 /* GEN_COPY_SET duplicates a set. */
1245 
1246 static set
1247 gen_copy_set( old_s, dp )
1248 set old_s;
1249 union domain *dp ;
1250 {
1251  set new_s = set_make( dp->se.what ) ;
1252 
1253  if( IS_INLINABLE( dp->se.element )) {
1254  set_assign( new_s, old_s ) ;
1255  }
1256  else {
1257  SET_MAP( elt, {
1258  gen_chunk *new = copy_hsearch( (gen_chunk *)elt );
1259 
1260  set_add_element( new_s, new_s, (char *)new ) ;
1261  }, old_s ) ;
1262  }
1263  return( new_s );
1264 }
1265 
1266 /* COPY_SIMPLE_OUT copies the spine of the list OBJ or the whole array
1267  (according to the type DP). The components are copied by the recursive
1268  traversal functions */
1269 
1270 static void
1272 gen_chunk *obj ;
1273 union domain *dp ;
1274 {
1275  switch (dp->ba.type) {
1276  case LIST_DT:
1277  /* spine of the list is duplicated and hash table copy_table
1278  is updated */
1279  copy_hput(copy_table, (char *) (obj->l),
1280  (char *) gen_copy_list(obj->l, dp));
1281  break ;
1282  case SET_DT:
1283  copy_hput(copy_table, (char *) (obj->t),
1284  (char *) gen_copy_set(obj->t, dp));
1285  break ;
1286  case ARRAY_DT:
1287  /* array is duplicated and hash table copy_table is updated */
1288  copy_hput(copy_table, (char *)obj->p,
1289  (char *)gen_copy_array(obj->p, dp));
1290  break ;
1291  default:
1292  break;
1293  }
1294 }
1295 
1296 /* COPY_OBJ_OUT achieves to update the new object (copy of the old one)
1297  once all sub-domains have been recursively copied */
1298 
1299 #define COPYABLE_DOMAIN(d) \
1300 ( d->ba.type != BASIS_DT || \
1301  (!(IS_INLINABLE(d->ba.constructand) && (*d->ba.constructand->name!='s')) && \
1302  !IS_TABULATED( d->ba.constructand )))
1303 
1304 static void
1305 copy_obj_out_constructed( obj, bp, dp, data, new_obj, dr )
1306 gen_chunk * obj;
1307 struct gen_binding * bp;
1308 union domain * dp ;
1309 int data ;
1310 gen_chunk * new_obj ;
1311 struct driver * dr ;
1312 {
1313  struct domainlist *dlp = dp->co.components ;
1314 
1315  message_assert("arguments not used", bp==bp && dr==dr);
1316 
1317  switch( dp->co.op ) {
1318  case AND_OP: {
1319  gen_chunk *cp ;
1320 
1321  for( cp = obj+data ; dlp != NULL ; cp++, dlp = dlp->cdr ) {
1322  if(COPYABLE_DOMAIN( dlp->domain)) {
1323  (new_obj+(cp-obj))->p = copy_hsearch(cp->p);
1324  }
1325  }
1326  break ;
1327  }
1328  case OR_OP: {
1329  int which = (obj+data)->i - dp->co.first ;
1330 
1331  for( ; dlp!=NULL && which ; which--,dlp=dlp->cdr ) {
1332  ;
1333  }
1334  if( dlp == NULL ){
1335  fatal("[copy_obj_out] Unknown tag %s\n", i2a( (obj+data)->i )) ;
1336  }
1337  if( COPYABLE_DOMAIN( dlp->domain )) {
1338  (new_obj+data+1)->p = copy_hsearch((obj+data+1)->p);
1339  }
1340  break ;
1341  }
1342  case ARROW_OP: {
1343  bool cp_domain = (COPYABLE_DOMAIN( dlp->domain )) ;
1344  bool cp_codomain = (COPYABLE_DOMAIN( dlp->cdr->domain )) ;
1345 
1346  (new_obj+data)->h = hash_table_make(hash_table_type((obj+data)->h), 0);
1347 
1348  HASH_MAP( k, v, {
1349  k = (cp_domain ? (char *)copy_hsearch( (gen_chunk *)k ) : k) ;
1350  v = (cp_codomain ? (char *)copy_hsearch( (gen_chunk *)v ) : v) ;
1351  hash_put((new_obj+data)->h, k, v ) ;
1352  }, (obj+data)->h ) ;
1353  break ;
1354  }
1355  default:
1356  fatal( "[copy_obj_out] Unknown op %s\n", i2a( dp->co.op )) ;
1357  }
1358 }
1359 
1360 static void
1361 copy_obj_out(obj,bp,dr)
1362 gen_chunk *obj ;
1363 struct gen_binding *bp ;
1364 struct driver *dr ;
1365 {
1366  union domain *dp = bp->domain ;
1367  int data = 1+IS_TABULATED( bp ) ;
1368  gen_chunk *new_obj = copy_hsearch(obj) ;
1369 
1370  switch( dp->ba.type ) {
1371  case LIST_DT:
1372  case SET_DT:
1373  case ARRAY_DT:
1374  (new_obj+data)->p = copy_hsearch((obj+data)->p);
1375  break ;
1376  case CONSTRUCTED_DT:
1377  copy_obj_out_constructed( obj, bp, dp, data, new_obj, dr ) ;
1378  break ;
1379  default:
1380  fatal( "[copy_obj_out] Unknown type %s\n", i2a( dp->ba.type )) ;
1381  }
1382 }
1383 
1384 /* GEN_COPY_TREE makes a copy of the object OBJ */
1385 
1386 static gen_chunk *
1388  gen_chunk *obj,
1389  bool keep) /* whether to keep the copy tables... */
1390 {
1391  gen_chunk *copy;
1392  struct driver dr ;
1393  hash_table old_copy_table = hash_table_undefined;
1394 
1396 
1397  dr.null = gen_null ;
1398  dr.leaf_out = copy_leaf_out ;
1399  dr.leaf_in = tabulated_leaf_in ;
1400  dr.obj_in = copy_obj_in ;
1401  dr.simple_in = copy_simple_in ;
1402  dr.array_leaf = gen_array_leaf ;
1404  dr.obj_out = copy_obj_out;
1405 
1406  /* Save the old copy_table if required...
1407  */
1408  if (!keep)
1409  {
1410  old_copy_table = copy_table;
1412  }
1413 
1414  gen_trav_obj(obj, &dr) ;
1415  copy = copy_hsearch(obj) ;
1416 
1417  /* restore copy environment if needed
1418  */
1419  if (!keep)
1420  {
1422  copy_table = old_copy_table;
1423  }
1424 
1425  return copy;
1426 }
1427 
1428 gen_chunk *
1430  gen_chunk *obj)
1431 {
1432  if (gen_chunk_undefined_p(obj))
1433  return gen_chunk_undefined;
1434  else
1435  return gen_local_copy_tree(obj, false);
1436 }
1437 
1438 /* for re-entry only in gen_copy_tree...
1439  * ??? because externals are internals... FC.
1440  */
1441 gen_chunk *
1443  gen_chunk *obj)
1444 {
1445  return gen_local_copy_tree(obj, true);
1446 }
1447 
1448 
1449 /*********************************************************** FREE_TABULATED */
1450 
1451 /*
1452 static void free_this_tabulated(gen_chunk * obj)
1453 {
1454  gen_clear_tabulated_element(obj);
1455  gen_free(obj);
1456 }
1457 */
1458 
1459 /* free tabulated elements of this domain.
1460  */
1462 {
1464 
1465  /* since gen_free is reentrant and manages sharing globally
1466  * with the following table, we just call it for each object
1467  * and everything is fine. Well, I hope so. FC
1468  */
1469  message_assert("not initialized", !free_already_seen);
1471 
1473 
1475  free_already_seen = NULL;
1476 
1477  return domain;
1478 }
1479 
1480 /********************************************************************* WRITE */
1481 /* These functions implements the writing of objects.
1482  */
1483 
1484 /* USER_FILE is used by driver functions (sorry, no closure in C). */
1485 static FILE *user_file ;
1486 
1487 static void fputi(int i, FILE * f)
1488 {
1489  fprintf(f, "%d ", i);
1490 }
1491 
1492 static void fputci(char c, int i, FILE * f)
1493 {
1494  putc(c, f);
1495  fputi(i, f);
1496 }
1497 
1498 /* WRITE_DEFINE_SHARED_NODE defines the node whose number is N. */
1499 
1500 static void write_define_shared_node(int n)
1501 {
1502  fputci('[', n, user_file);
1503 }
1504 
1505 /* WRITE_SHARED_NODE references a shared node N. */
1506 
1507 static void write_shared_node(int n)
1508 {
1509  fputci('H', n, user_file);
1510 }
1511 
1512 static void write_null(struct gen_binding * bp)
1513 {
1514  message_assert("argument not used", bp==bp);
1515  putc('N', user_file);
1516 }
1517 
1518 /* WRITE_OBJ_IN writes the OBJect of type BP. We first prints its type
1519  (its index in the Domains table), its tag (for OR_OP types) and then
1520  ... let's do the recursion. */
1521 
1522 static int write_obj_in(gen_chunk *obj, struct driver *dr)
1523 {
1524  struct gen_binding *bp = &Domains[ quick_domain_index( obj ) ] ;
1525  union domain *dp = bp->domain ;
1526  int data = 1+IS_TABULATED( bp ) ;
1527  int type_number;
1528 
1529  message_assert("argument not used", dr==dr);
1530 
1532  return( !GO) ;
1533 
1534  type_number = gen_type_translation_actual_to_old(bp-Domains);
1535  fputci('T', type_number, user_file);
1536 
1537  /* tabulated number is skipped... */
1538 
1539  switch( dp->ba.type ) {
1540  case EXTERNAL_DT:
1541  fatal( "write_obj_in: Don't know how to write an EXTERNAL: %s\n",
1542  bp->name ) ;
1543  break ;
1544  case CONSTRUCTED_DT:
1545  if (dp->co.op == OR_OP)
1546  fputi((obj+data)->i, user_file); /* tag... */
1547  else if(dp->co.op == ARROW_OP) {
1548  putc('%', user_file) ;
1549  }
1550  break ;
1551  default:
1552  break;
1553  }
1554  return GO;
1555 }
1556 
1557 /* WRITE_OBJ_OUT is done when the OBJect (of type BP) has been printed. Just
1558  close the opening parenthese. */
1559 
1560 static void write_obj_out(gen_chunk * obj,
1561  struct gen_binding * bp,
1562  struct driver * dr)
1563 {
1564  union domain * dp = bp->domain ;
1565 
1566  message_assert("argument not used", dr==dr && obj==obj);
1567 
1568  switch (dp->ba.type) {
1569  case CONSTRUCTED_DT:
1570  if( dp->co.op == ARROW_OP ) {
1571  putc(')', user_file);
1572  }
1573  break ;
1574  default:
1575  break;
1576  }
1577  putc(')', user_file);
1578 }
1579 
1580 static void write_string(string init,
1581  string s,
1582  string end,
1583  string ifnull,
1584  string ifundefined)
1585 {
1586  if (!s)
1587  {
1588  if (ifnull)
1589  fputs(ifnull, user_file);
1590  else
1591  user("null string not allowed");
1592  return;
1593  }
1594  else if (string_undefined_p(s))
1595  {
1596  fputs(ifundefined, user_file);
1597  return;
1598  }
1599  /* else */
1600  fputs(init, user_file);
1601  for(; *s != '\0' ; s++)
1602  {
1603  if (*s=='"' || *s=='\\') putc('\\', user_file);
1604  putc(*s, user_file);
1605  }
1606  fputs(end, user_file);
1607 }
1608 
1609 /* WRITE_LEAF_IN prints the OBJect of type BP. If it is inlined, prints it
1610  according to the format, else recurse. */
1611 
1612 static int write_leaf_in(gen_chunk *obj, struct gen_binding *bp)
1613 {
1614  if(IS_TABULATED(bp))
1615  {
1616  if( obj->p == gen_chunk_undefined ) {
1618  {
1619  user("gen_write: writing undefined tabulated object\n", NULL);
1620  }
1621  else
1622  {
1623  (void) fputc('N', user_file);
1624  }
1625  }
1626  else {
1627  /* references are by name. The number may can be changed...
1628  */
1629  int type_number = gen_type_translation_actual_to_old(bp-Domains);
1630  fputci('R', type_number, user_file);
1631  write_string("\"", (obj->p+HASH_OFFSET)->s, "\" ", "_", "!") ;
1632  }
1633  return !GO;
1634  }
1635  else if( IS_INLINABLE( bp )) {
1636  /* hummm... */
1637  if (IS_UNIT_TYPE(bp-Domains))
1638  putc('U', user_file);
1639  else if (IS_BOOL_TYPE(bp-Domains))
1640  fputci('B', obj->b, user_file);
1641  else if (IS_INT_TYPE(bp-Domains))
1642  fputi(obj->i, user_file);
1643  else if (IS_FLOAT_TYPE(bp-Domains))
1644  (void) fprintf(user_file, "%f", obj->f) ;
1645  else if (IS_STRING_TYPE(bp-Domains))
1646  write_string( "\"", obj->s, "\"", "_", "!") ;
1647  else
1648  fatal( "write_leaf_in: Don't know how to print %s\n", bp->name ) ;
1649  }
1650  else if( IS_EXTERNAL( bp )) {
1651  int type_number;
1652  if( bp->domain->ex.write == NULL ) {
1653  user("gen_write: uninitialized external type %s (%d)\n",
1654  bp->name, bp-Domains);
1655  return !GO;
1656  }
1657  type_number = gen_type_translation_actual_to_old(bp-Domains);
1658  fputci('E', type_number, user_file);
1659  (*(bp->domain->ex.write))(user_file, obj->s);
1660  }
1661  return( GO) ;
1662 }
1663 
1664 /* WRITE_SIMPLE_IN is done before printing a simple OBJect of type DP. The
1665  sharing of basis objects will be done later. */
1666 
1667 static int
1669 gen_chunk *obj ;
1670 union domain *dp ;
1671 {
1672  switch( dp->ba.type ) {
1673  case LIST_DT:
1674  if( obj->l == list_undefined ) {
1675  putc('L', user_file);
1676  return !GO;
1677  }
1678  putc('(', user_file);
1679  break ;
1680  case SET_DT:
1681  if( obj->t == set_undefined ) {
1682  putc('S', user_file);
1683  return( !GO) ;
1684  }
1685  fputci('{', dp->se.what, user_file);
1686  break ;
1687  case ARRAY_DT:
1688  if( obj->p == array_undefined ) {
1689  putc('A', user_file);
1690  return !GO;
1691  }
1692  fputci('$', array_size(dp->ar.dimensions), user_file);
1693  break ;
1694  default:
1695  break;
1696  }
1697  return GO;
1698 }
1699 
1700 /* WRITE_ARRAY_LEAF only writes non-null elements, in a sparse way. */
1701 
1702 static void
1704  struct gen_binding *bp,
1705  int i,
1706  gen_chunk *obj,
1707  struct driver *dr)
1708 {
1709  if( IS_INLINABLE( bp ) || IS_EXTERNAL( bp )) {
1710  gen_trav_leaf( bp, obj, dr ) ;
1711  }
1712  else if (obj->p != gen_chunk_undefined)
1713  {
1714  fputi(i, user_file); /* write array index */
1715  gen_trav_leaf(bp, obj, dr); /* write array value at index */
1716  }
1717 }
1718 
1719 /* WRITE_LEAF_OUT prints the closing parenthesis of (non-basis) simple OBJect
1720  of type DP. */
1721 
1722 /*ARGSUSED*/
1723 static void
1725 {
1726  message_assert("argument not used", obj==obj);
1727 
1728  switch( dp->ba.type ) {
1729  case SET_DT:
1730  putc('}', user_file);
1731  break ;
1732  case LIST_DT:
1733  case ARRAY_DT:
1734  putc(')', user_file);
1735  break ;
1736  default:
1737  break;
1738  }
1739 }
1740 
1741 /* GEN_WRITE writes the OBJect on the stream FD. Sharing is managed (the
1742  number of which is printed before the object.)
1743  */
1744 void
1746  FILE * fd,
1747  gen_chunk * obj)
1748 {
1749  struct driver dr ;
1750 
1752 
1753  dr.null = write_null ;
1754  dr.leaf_out = gen_null ;
1755  dr.leaf_in = write_leaf_in ;
1756  dr.simple_in = write_simple_in ;
1759  dr.obj_in = write_obj_in ;
1760  dr.obj_out = write_obj_out ;
1761 
1762  user_file = fd ;
1763 
1765 
1766  shared_pointers(obj, false);
1767  fputi(shared_number, fd);
1768  gen_trav_obj( obj, &dr );
1769 
1770  pop_gen_trav_env() ;
1771 }
1772 
1773 /* GEN_WRITE_WITHOUT_SHARING writes the OBJect on the stream FD. Sharing
1774  is NOT managed.
1775 */
1776 void
1778 FILE *fd ;
1779 gen_chunk *obj ;
1780 {
1781  struct driver dr ;
1782 
1784 
1785  dr.null = write_null ;
1786  dr.leaf_out = gen_null ;
1787  dr.leaf_in = write_leaf_in ;
1788  dr.simple_in = write_simple_in ;
1789  dr.array_leaf = gen_array_leaf ;
1791  dr.obj_in = write_obj_in ;
1792  dr.obj_out = write_obj_out ;
1793 
1794  user_file = fd ;
1795 
1796  if (obj_table != (hash_table)NULL)
1797  {
1799  obj_table = (hash_table)NULL ;
1800  }
1801 
1802  fputs("0 ", fd);
1803  gen_trav_obj(obj, &dr);
1804 }
1805 
1806 /* WRITE_TABULATED_LEAF_IN prints the OBJect of type BP. If it is tabulated,
1807  then recurse.
1808  */
1809 static int write_tabulated_leaf_in(gen_chunk *obj, struct gen_binding *bp)
1810 {
1811  if (IS_TABULATED(bp))
1812  {
1813  int number ;
1814 
1815  if (obj->p == gen_chunk_undefined) {
1816  write_null(bp);
1817  return !GO;
1818  }
1819  number = (obj->p+1)->i;
1820 
1821  if (number==0) { /* boum! why? */
1822  fatal("write_tabulated_leaf_in: Zero index in domain %s\n", bp->name);
1823  }
1824 
1825  /* fprintf(stderr, "writing %d %s\n", number, (obj->p+HASH_OFFSET)->s);
1826  */
1827  if (number >= 0)
1828  {
1829  putc('D', user_file);
1830  /*
1831  int type_number = gen_type_translation_actual_to_old(bp-Domains);
1832  fputci('D', type_number, user_file);
1833  write_string("\"", (obj->p+HASH_OFFSET)->s, "\" ", "_", "!"); */
1834 
1835  /* once written the domain number sign is inverted,
1836  * to tag the object has been written, so that
1837  * its definition is not written twice on disk.
1838  * The second time a simple reference is written instead.
1839  * beurk. FC.
1840  */
1841  (obj->p+1)->i = - (obj->p+1)->i;
1842  return GO;
1843  }
1844  }
1845 
1846  return write_leaf_in(obj, bp);
1847 }
1848 
1849 static struct gen_binding * wtt_bp = NULL;
1850 static struct driver * wtt_dr = NULL;
1852 {
1853  gen_chunk g;
1854  g.p = o;
1855  gen_trav_leaf(wtt_bp, &g, wtt_dr);
1856 }
1857 
1858 static void change_sign(gen_chunk * o)
1859 {
1860  if ((o+1)->i < 0) (o+1)->i = -((o+1)->i);
1861 }
1862 
1863 /* GEN_WRITE_TABULATED writes the tabulated object TABLE on FD.
1864  Sharing is managed.
1865  */
1866 int gen_write_tabulated(FILE * fd, int domain)
1867 {
1868  struct gen_binding * bp = Domains+domain;
1869  struct driver dr ;
1870  int wdomain;
1871  gen_chunk * fake_obj;
1872 
1874 
1877 
1878  dr.null = write_null;
1879  dr.leaf_out = gen_null ;
1881  dr.simple_in = write_simple_in ;
1884  dr.obj_in = write_obj_in ;
1885  dr.obj_out = write_obj_out ;
1886  user_file = fd ;
1887 
1889  shared_pointers(fake_obj, false);
1890 
1891  /* headers: #shared, tag, domain number,
1892  */
1893  fputi(shared_number, fd);
1894  putc('*', fd);
1895  fputi(wdomain, fd);
1896 
1897  wtt_bp = bp, wtt_dr = &dr;
1899  wtt_bp = NULL, wtt_dr = NULL;
1900 
1901  putc(')', fd);
1902 
1903  pop_gen_trav_env();
1904 
1905  /* restore the index sign which was changed to tag as seen... */
1907 
1908  return domain;
1909 }
1910 
1911 #ifdef BSD
1912 static char * strdup(const char * s)
1913 {
1914  char * new = (char*) malloc(strlen(s)+1);
1915  strcpy(new, s);
1916  return new;
1917 }
1918 #endif
1919 
1920 /**************************************************** Type Translation Table */
1921 
1922 /* translation tables type...
1923  BUGS:
1924  - tabulated domains are not translated properly, I guess.
1925  - externals which appear several times as such, so are given
1926  several domain number, may lead to unexpected behaviors.
1927  */
1928 typedef struct
1929 {
1930  bool identity; /* whether the translation is nope... */
1931  int old_to_actual[MAX_DOMAIN]; /* forwards translation */
1932  int actual_to_old[MAX_DOMAIN]; /* backwards translation */
1933 }
1935 
1936 /* global translation table.
1937  */
1938 static gtt_p gtt_current_table = NULL;
1939 
1940 /* returns the allocated line read, whatever its length.
1941  * returns NULL on EOF. also some asserts. FC 09/97.
1942  */
1943 string gen_read_string(FILE * file, char upto)
1944 {
1945  int i=0, size = 20, c;
1946  char * buf = (char*) malloc(sizeof(char)*size), * res;
1947  message_assert("malloc ok", buf);
1948  while((c=getc(file)) && c!=EOF && c!=upto)
1949  {
1950  if (i==size-1) // larger for trailing '\0'
1951  {
1952  size+=20;
1953  buf = (char*) realloc((char*) buf, sizeof(char)*size);
1954  // we abort on failure...
1955  message_assert("realloc ok", buf);
1956  }
1957  buf[i++] = (char) c;
1958  }
1959  if (c==EOF && i==0) { res = NULL; free(buf); }
1960  else { buf[i++] = '\0'; res = strdup(buf); free(buf); }
1961 
1962  return res;
1963 }
1964 
1965 /* returns an allocated and initialized translation table... */
1966 static gtt_p gtt_make(void)
1967 {
1968  return (gtt_p) alloc(sizeof(gtt_t));
1969 }
1970 
1971 static void gtt_table_init(gtt_p table)
1972 {
1973  int i;
1974  table->identity = false;
1975  for (i=0; i<MAX_DOMAIN; i++)
1976  {
1977  table->old_to_actual[i] = -1;
1978  table->actual_to_old[i] = -1;
1979  }
1980 }
1981 
1982 static void gtt_table_identity(gtt_p table)
1983 {
1984  int i;
1985  table->identity = true;
1986  for (i=0; i<MAX_DOMAIN; i++)
1987  {
1988  table->old_to_actual[i] = i;
1989  table->actual_to_old[i] = i;
1990  }
1991 }
1992 
1993 /* == simplified lookup?
1994  * returns the index of domain name if found, looking up from i.
1995  * -1 if not found.
1996  */
1997 static int get_domain_number(string name, int i)
1998 {
1999  for (; i<MAX_DOMAIN; i++)
2000  {
2001  if (Domains[i].name && same_string_p(name, Domains[i].name))
2002  return i;
2003  }
2004  return -1;
2005 }
2006 
2007 static int first_available(int t[MAX_DOMAIN])
2008 {
2009  int i;
2010  for (i=0; i<MAX_DOMAIN; i++)
2011  if (t[i] == -1) return i;
2012  return -1;
2013 }
2014 
2015 /* read and setup a table from a file
2016  */
2017 static gtt_p gtt_read(string filename)
2018 {
2019  gtt_p table;
2020  FILE * file;
2021  bool same;
2022  int i;
2023 
2024  /* temporary data structure. */
2025  struct {
2026  string name;
2027  int number;
2028  string definition;
2029  } items[MAX_DOMAIN];
2030 
2031  /* set to 0 */
2032  for (i=0; i<MAX_DOMAIN; i++)
2033  {
2034  items[i].name = NULL;
2035  items[i].number = -1;
2036  items[i].definition = NULL;
2037  }
2038 
2039  table = gtt_make();
2040 
2041  /* READ FILE */
2042  file = fopen(filename, "r");
2043 
2044  if (!file)
2045  fatal("cannot open type translation file \"%s\"\n", file);
2046 
2047  /* read data */
2048  for (i=0;
2049  i<MAX_DOMAIN &&
2050  (items[i].name = gen_read_string(file, '\t')) &&
2051  fscanf(file, "%d", &items[i].number) &&
2052  (items[i].definition = gen_read_string(file, '\n'));
2053  i++);
2054 
2055  if (i==MAX_DOMAIN && !feof(file))
2056  fatal("file translation too long, extend MAX_DOMAIN");
2057 
2058  fclose(file);
2059 
2060  /* quick check for identity */
2061  for (i=0, same=true; i<MAX_DOMAIN && same; i++)
2062  {
2063  if (items[i].number!=-1 && items[i].name)
2064  same = same_string_p(Domains[i].name, items[i].name) &&
2065  (items[i].number==i);
2066  }
2067 
2068  /* identical stuff, ok! */
2069  if (same)
2070  {
2071  /* fprintf(stderr, "same table...\n"); */
2072  gtt_table_identity(table);
2073  return table;
2074  }
2075  /* else fprintf(stderr, "not same at %d: '%s':%d vs '%s':%d\n",
2076  i, items[i].name, items[i].number, Domains[i].name, i); */
2077 
2078  fprintf(stderr, "warning: newgen compatibility mode\n");
2079  gtt_table_init(table);
2080 
2081  /* ELSE build conversion table...
2082  * order is reversed so that dubbed externals are given the least number.
2083  */
2084  for (i=MAX_DOMAIN-1; i>=0; i--)
2085  {
2086  if (items[i].name && items[i].number!=-1)
2087  {
2088  int index = get_domain_number(items[i].name, 0);
2089  if (index!=-1)
2090  {
2091  table->old_to_actual[items[i].number] = index;
2092  table->actual_to_old[index] = items[i].number;
2093  }
2094  else
2095  {
2096  fprintf(stderr, "warning, domain \"%s\" (%d) not found\n",
2097  items[i].name, items[i].number);
2098  }
2099  }
2100  }
2101 
2102  /* maybe some domains where not found, give them a new number...
2103  * if these number are to be used, the table should be saved.
2104  */
2105  for (i=0; i<MAX_DOMAIN; i++)
2106  {
2107  if (Domains[i].name && table->actual_to_old[i] == -1)
2108  {
2109  int oindex = first_available(table->old_to_actual);
2110  if (oindex==-1)
2111  fatal("too many types to allow translations, extend MAX_DOMAIN...");
2112 
2113  table->old_to_actual[oindex] = i;
2114  table->actual_to_old[i] = oindex;
2115  }
2116  }
2117 
2118  /* debug */
2119  /*
2120  fprintf(stderr, "type translation table:\n");
2121  for (i=0; i<MAX_DOMAIN; i++)
2122  fprintf(stderr, "%s %d <- %d\n",
2123  Domains[i].name? Domains[i].name: "<null>",
2124  i, table->actual_to_old[i]);
2125  */
2126 
2127  return table;
2128 }
2129 
2130 /* writes what the previous reads...
2131  */
2132 static void gtt_write(string filename, gtt_p table)
2133 {
2134  int i;
2135  FILE * file = fopen(filename, "w");
2136  message_assert("open file", file);
2137 
2138  for (i=0; i<MAX_DOMAIN; i++)
2139  if (table->actual_to_old[i]!=-1 && Domains[i].name)
2140  fprintf(file, "%s\t%d\t*\n", Domains[i].name, table->actual_to_old[i]);
2141 
2142  fclose(file);
2143 }
2144 
2145 /* forwards conversion
2146  */
2148 {
2149  int nn;
2150  message_assert("valid old type number", n>=0 && n<MAX_DOMAIN);
2151  if (!gtt_current_table) return n;
2153  if (nn==-1) fatal("old type number %d not available", n);
2154  message_assert("valid new type number", nn>=0 && nn<MAX_DOMAIN);
2155  return nn;
2156 }
2157 
2158 /* backwards conversion
2159  */
2161 {
2162  int on;
2163  message_assert("valid new type number", n>=0 && n<MAX_DOMAIN);
2164  if (!gtt_current_table) return n;
2166  if (on==-1) fatal("new type number %d not available", n);
2167  message_assert("valid new type number", on>=0 && on<MAX_DOMAIN);
2168  return on;
2169 }
2170 
2172 {
2173  if (gtt_current_table)
2174  {
2176  gtt_current_table = NULL;
2177  }
2178 }
2179 
2181 {
2185 }
2186 
2187 /* set current type translation table according to file
2188  */
2189 void gen_type_translation_read(string filename)
2190 {
2192  gtt_current_table = gtt_read(filename);
2193 }
2194 
2195 void gen_type_translation_write(string filename)
2196 {
2197  message_assert("some type translation table to write", gtt_current_table);
2198  gtt_write(filename, gtt_current_table);
2199 }
2200 
2201 /********************************************* NEWGEN RUNTIME INITIALIZATION */
2202 
2203 /* GEN_READ_SPEC reads the specifications. This has to be used
2204  -- before -- any utilization of manipulation functions. */
2205 
2206 static void init_gen_quick_recurse_tables(void);
2207 
2208 extern void genspec_set_string_to_parse(char*);
2209 extern void genspec_reset_string_to_parse(void);
2210 #ifdef HAVE_LEXLIB
2211  /* not compatible with multiple lex calls ... */
2212  #define genspec_lex_destroy()
2213 #else
2214  extern void genspec_lex_destroy();
2215 #endif
2216 
2217 
2218 void gen_read_spec(char * spec, ...)
2219 {
2220  va_list ap;
2221  struct gen_binding * bp;
2222  extern int unlink();
2223 
2224  /* default initialization of newgen lexers files:
2225  */
2226  newgen_start_lexer(stdin);
2227  genspec_in = stdin;
2228  genspec_out = stdout;
2229 
2230  /* now let's read the spec strings...
2231  */
2232  va_start(ap, spec) ;
2233 
2234  init() ;
2235  Read_spec_mode = 1 ;
2236 
2237  while(spec)
2238  {
2240  genspec_parse() ;
2242 
2243  spec = va_arg( ap, char *);
2244  }
2246 
2247  compile() ;
2248 
2249  for (bp=Domains ; bp<&Domains[MAX_DOMAIN]; bp++)
2250  {
2251  if(bp->name && !IS_INLINABLE(bp) && !IS_EXTERNAL(bp) &&
2252  bp->domain->ba.type == IMPORT_DT) {
2253  user( "Cannot run with imported domains: %s\n", bp->name ) ;
2254  va_end(ap);
2255  return ;
2256  }
2257  }
2258 
2259  Read_spec_mode = 0 ;
2261 
2262  va_end(ap);
2263 
2264  /* quick recurse decision tables initializations
2265  */
2267 
2268  /* set identity type translation tables */
2270 }
2271 
2272 /* GEN_INIT_EXTERNAL defines entry points for free, read and write functions
2273  of external types */
2274 
2275 void
2277  void *(*read)(FILE*, int(*)(void)),
2278  void (*write)(FILE*, void*),
2279  void (*free)(void*),
2280  void *(*copy)(void*),
2281  int (*allocated_memory)(void*))
2282 {
2283  struct gen_binding *bp = &Domains[ which ] ;
2284  union domain *dp = bp->domain ;
2285 
2286  if( dp->ba.type != EXTERNAL_DT ) {
2287  user( "gen_init_external: %s isn't external\n", bp->name ) ;
2288  return ;
2289  }
2290  if( dp->ex.read != NULL ) {
2291  user( "gen_init_external: redefinition of %s skipped\n",
2292  bp->name ) ;
2293  return ;
2294  }
2295  dp->ex.read = read ;
2296  dp->ex.write = write ;
2297  dp->ex.free = free ;
2298  dp->ex.copy = copy ;
2300 }
2301 
2302 /********************************************************************** READ */
2303 
2304 /* GEN_MAKE_ARRAY allocates an initialized array of NUM gen_chunks. */
2305 
2306 gen_chunk *
2308  int num ;
2309 {
2310  int i ;
2311  /*NOSTRICT*/
2312  gen_chunk *ar = (gen_chunk *)alloc( sizeof( gen_chunk )) ;
2313 
2314  for( i=0 ; i<num ; i++ )
2315  ar[ i ].p = gen_chunk_undefined ;
2316 
2317  return( ar ) ;
2318 }
2319 
2320 /* GEN_READ reads any object from the FILE stream. Sharing is restored.
2321  */
2322 
2323 gen_chunk * gen_read(FILE * file)
2324 {
2326  newgen_start_lexer(file);
2327  genread_parse() ;
2328  return Read_chunk;
2329 }
2330 
2331 /* GEN_READ_TABULATED reads FILE to update the Gen_tabulated_ table. Creates
2332  if CREATE_P is true. */
2333 
2334 int gen_read_tabulated(FILE * file, int create_p)
2335 {
2336  extern int newgen_allow_forward_ref;
2337  int domain;
2338 
2339  message_assert("argument not used", create_p==create_p);
2340 
2341  newgen_start_lexer(file);
2342 
2343  newgen_allow_forward_ref = true;
2344  genread_parse();
2345  newgen_allow_forward_ref = false;
2346 
2347  domain = Read_chunk->i;
2348  newgen_free((char *) Read_chunk);
2349 
2350  return domain;
2351 }
2352 
2353 /* GEN_CHECK checks that the gen_chunk received OBJ is of the appropriate TYPE.
2354  */
2355 gen_chunk *
2357  gen_chunk *obj,
2358  int t)
2359 {
2360  extern int max_domain_index() ;
2361  int max_index ;
2362 
2363  if( obj == NULL ) {
2364  (void) user("gen_check: NULL pointer, expecting type %s\n",
2365  Domains[ t ].name);
2366  abort() ;
2367  }
2368  max_index = max_domain_index() ;
2369  message_assert("valid max domain index", max_index >= 0 ) ;
2370 
2371  if( obj != gen_chunk_undefined && t != obj->i ) {
2372  user("gen_check: Type clash (expecting %s, getting %s)\n",
2373  Domains[ t ].name,
2374  (obj->i >= 0 && obj->i<=max_index )? Domains[ obj->i ].name : "???") ;
2375  abort() ;
2376  }
2377  return obj;
2378 }
2379 
2380 /*************************************************************** CONSISTENCY */
2381 
2382 extern int error_seen ;
2383 
2384 /* used for consistence checking...
2385  */
2386 static FILE *black_hole = NULL ;
2387 static void open_black_hole()
2388 {
2389  if (black_hole == NULL)
2390  if ((black_hole=fopen("/dev/null", "r")) == NULL)
2391  fatal("Cannot open /dev/null !") ; /* not reached */
2392 }
2393 
2395 
2396 /* GEN_CONSISTENT_P dynamically checks the type correctness of OBJ.
2397  */
2399 {
2400  int old_gen_debug = gen_debug;
2402  open_black_hole();
2403 
2404  error_seen = 0 ;
2406 
2407  gen_write(black_hole, obj);
2408 
2409  gen_debug = old_gen_debug;
2411  return !error_seen;
2412 }
2413 
2414 /* for side effects only */
2416 {
2417  (void) gen_consistent_p(obj);
2418 }
2419 
2421 {
2424  return !cumulated_error_seen;
2425 }
2426 
2427 /* GEN_DEFINED_P checks that the OBJect is fully defined
2428 */
2429 static void defined_null(struct gen_binding * bp)
2430 {
2431  union domain *dp = bp->domain ;
2432  user( "", (char *)NULL ) ;
2433  (void) fprintf( stderr, "gen_defined_p: Undefined object of type < " );
2434  print_domain( stderr, dp ) ;
2435  (void) fprintf( stderr, "> found\n" ) ;
2436 }
2437 
2439 {
2440  struct driver dr ;
2441 
2443  open_black_hole();
2444 
2445  if (gen_chunk_undefined_p(obj))
2446  return false;
2447 
2448  error_seen = 0 ;
2449  dr.null = defined_null ;
2450  dr.leaf_out = gen_null ;
2451  dr.leaf_in = write_leaf_in ;
2452  dr.simple_in = write_simple_in ;
2453  dr.array_leaf = gen_array_leaf ;
2455  dr.obj_in = write_obj_in ;
2456  dr.obj_out = write_obj_out ;
2457  user_file = black_hole ;
2458 
2459  push_gen_trav_env() ;
2460 
2461  shared_pointers( obj, false ) ;
2462  gen_trav_obj( obj, &dr ) ;
2463 
2464  pop_gen_trav_env() ;
2465 
2466  return error_seen == 0;
2467 }
2468 
2469 /* GEN_SHARING_P checks whether OBJ1 uses objects (except tabulated) or
2470  CONS cells that appear in OBJ2. */
2471 
2473 static jmp_buf env ;
2474 
2475 static bool check_sharing(char * p, char * type)
2476 {
2477  if (hash_get(pointers, p) != HASH_UNDEFINED_VALUE) {
2478  user("Sharing of %s detected on %p", type, p ) ;
2479  longjmp( env, 1 ) ;
2480  /* NOTREACHED*/
2481  }
2482  return( false ) ;
2483 }
2484 
2485 static int sharing_obj_in(gen_chunk * obj, struct driver * dr)
2486 {
2487  message_assert("argument not used", dr==dr);
2488 
2489  if (shared_obj(obj, gen_null, gen_null))
2490  return !GO;
2491 
2493  return !GO;
2494 
2495  check_sharing((char *)obj, "CHUNK *");
2496  return GO;
2497 }
2498 
2499 static int sharing_simple_in(gen_chunk * obj, union domain * dp)
2500 {
2501  cons *p ;
2502 
2503  switch( dp->ba.type ) {
2504  case LIST_DT:
2505  if( obj->l == list_undefined ) {
2506  return( !GO) ;
2507  }
2508  for( p=obj->l ; p!=NIL ; p=p->cdr ) {
2509  check_sharing( (char *)p, "CONS *" ) ;
2510  }
2511  default:
2512  break;
2513  }
2514  return( persistant_simple_in( obj, dp )) ;
2515 }
2516 
2517 bool
2518 gen_sharing_p( obj1, obj2 )
2519 gen_chunk *obj1, *obj2 ;
2520 {
2521  struct driver dr ;
2522  bool found ;
2523 
2525 
2526  if( pointers == (hash_table)NULL )
2528  else
2530 
2531  dr.null = dr.leaf_out = dr.simple_out = dr.obj_out = gen_null ;
2532  dr.obj_in = sharing_obj_in ;
2534  dr.array_leaf = gen_array_leaf ;
2535  dr.leaf_in = tabulated_leaf_in ;
2536 
2537  push_gen_trav_env() ;
2538  shared_pointers(obj2, false );
2539 
2540  HASH_MAP( k, v, {
2541  hash_put( pointers, k, v ) ;
2542  }, obj_table ) ;
2543 
2544  shared_pointers( obj1, false ) ;
2545 
2546  if( (found=setjmp( env )) == 0 )
2547  gen_trav_obj( obj1, &dr ) ;
2548 
2549  pop_gen_trav_env() ;
2550 
2551  return(found) ;
2552 }
2553 
2554 /******************************************************************** SIZE */
2555 
2556 /* returns the number of bytes allocated for a given structure
2557  * may need additional fonctions for externals...
2558  * May be called recursively. If so, already_seen_objects table kept.
2559  */
2560 
2561 static int current_size;
2563 
2564 /* true if obj was already seen in this recursion, and put it at true
2565  */
2566 static bool
2568 gen_chunk * obj;
2569 {
2570  if (hash_get(already_seen_objects, (char *)obj)==(char*)true)
2571  return true;
2572  hash_put(already_seen_objects, (char *)obj, (char *) true);
2573  return false;
2574 }
2575 
2576 /* manages EXTERNALS and INLINABLES
2577  */
2578 static int
2580 gen_chunk *obj ;
2581 struct gen_binding *bp ;
2582 {
2583  if (IS_INLINABLE(bp))
2584  {
2585  if (*bp->name=='s' && obj->s && !string_undefined_p(obj->s) &&
2587  current_size += strlen(obj->s) + 1; /* under approximation! */
2588 
2589  return !GO;
2590  }
2591 
2593  return false;
2594 
2595  if (IS_EXTERNAL(bp))
2596  {
2597  if (bp->domain->ex.allocated_memory)
2598  current_size += (*(bp->domain->ex.allocated_memory))(obj->s);
2599  else
2600  user("[gen_allocated_memory] warning: "
2601  "external with no allocated memory function\n");
2602 
2603  return false;
2604  }
2605 
2606  return true;
2607 }
2608 
2609 /* manages newgen objects and strings...
2610  */
2611 static int
2613  gen_chunk *obj,
2614  struct driver *dr)
2615 {
2616  struct gen_binding *bp = &Domains[quick_domain_index(obj)];
2617 
2618  message_assert("argument not used", dr==dr);
2619 
2621  IS_TABULATED(bp) || IS_INLINABLE(bp))
2622  return !GO;
2623 
2624  /* gen size is quite slow. should precompute sizes...
2625  */
2626  current_size += sizeof(gen_chunk*)*gen_size(bp-Domains);
2627 
2628  return GO;
2629 }
2630 
2631 /* manages newgen simples (list, set, array)
2632  */
2633 static int
2635  gen_chunk *obj,
2636  union domain *dp)
2637 {
2638  if (dp->ba.persistant) return false;
2639 
2640  switch( dp->ba.type ) {
2641  case BASIS_DT:
2642  return( GO) ; /* !GO ??? */
2643  case LIST_DT:
2644  {
2645  list l = obj->l;
2646 
2647  if (l && !list_undefined_p(l))
2648  {
2650  return true;
2651  }
2652  else
2653  return false;
2654  }
2655  case SET_DT:
2656  {
2657  set s = obj->t;
2658 
2659  if (!set_undefined_p(s))
2660  {
2662  return true;
2663  }
2664  else
2665  return false;
2666  }
2667  case ARRAY_DT:
2668  {
2669  gen_chunk *p = obj->p;
2670 
2671  if (!array_undefined_p(p))
2672  {
2674  return true;
2675  }
2676  else
2677  return false;
2678  }
2679  default:
2680  break;
2681  }
2682 
2683  fatal("allocated_memory_simple_in: unknown type %s\n", i2a(dp->ba.type));
2684  return -1; /* just to avoid a gcc warning */
2685 }
2686 
2687 /* re-entry is automatic for this function.
2688  */
2689 int /* in bytes */
2691  gen_chunk *obj)
2692 {
2693  bool first_on_stack = (already_seen_objects==NULL);
2694  int result, saved_size;
2695  struct driver dr;
2696 
2697  /* save current status
2698  */
2699  saved_size = current_size;
2700  current_size = 0;
2701  if (first_on_stack)
2703 
2704  /* build driver for gen_trav...
2705  */
2706  dr.null = gen_null,
2708  dr.leaf_out = gen_null,
2711  dr.simple_out = gen_null,
2713  dr.obj_out = gen_null;
2714 
2715  /* recursion from obj
2716  */
2717  gen_trav_obj(obj, &dr);
2718 
2719  /* restores status and returns result
2720  */
2721  result = current_size;
2722  current_size = saved_size;
2723  if (first_on_stack)
2724  {
2726  already_seen_objects = NULL;
2727  }
2728 
2729  return result;
2730 }
2731 
2732 /*********************************************************** MULTI RECURSION */
2733 
2734 /** @defgroup gen_multi_recurse NewGen quick and intelligent recursion on objects (visitor pattern) */
2735 /** @{ */
2736 
2737 /** @defgroup gen_recurse_useful NewGen useful functions for recursion visitors
2738 
2739  They may be used by some recursion
2740  - when no rewrite is needed
2741  - when the filter is always yes
2742  - when it is false, to stop the recursion on some types
2743 */
2744 
2745 /** @{ */
2746 
2747 /** Ignore the argument.
2748 
2749  It is useful for example in a gen_recurse when we do not want to do
2750  anything in the rewrite part (bottom-up).
2751 */
2752 void gen_null(__attribute__((unused)) void * unused)
2753 {
2754  return;
2755 }
2756 
2757 /** idem with 2 args, to please overpeaky compiler checks */
2758 void gen_null2(__attribute__((unused)) void * u1, __attribute__((unused)) void * u2)
2759 {
2760  return;
2761 }
2762 
2763 /** idem with a void* return */
2764 void *gen_NULL(__attribute__((unused)) void * unused)
2765 {
2766  return NULL;
2767 }
2768 
2769 /** idem with 2 args, to please overpeaky compiler checks */
2770 void *gen_NULL2(__attribute__((unused)) void * u1, __attribute__((unused)) void * u2)
2771 {
2772  return NULL;
2773 }
2774 
2775 /** Return true and ignore the argument.
2776 
2777  Useful as a filter in a gen_recurse when we don't want to do anything
2778  in the filter part (top-down) but keeping visiting.
2779 */
2780 bool gen_true( __attribute__((unused)) gen_chunk * unused)
2781 {
2782  return true;
2783 }
2784 
2785 bool gen_true2( __attribute__((unused)) gen_chunk * u1, __attribute__((unused)) void * u2)
2786 {
2787  return true;
2788 }
2789 
2790 /** Return false and ignore the argument.
2791 
2792  Useful for example as a filter in a gen_multi_recurse() to stop
2793  recursing in a type/domain of object but do not prevent other domains
2794  precised in the gen_multi_recurse() to be investigated.
2795 */
2796 bool gen_false( __attribute__((unused)) gen_chunk * unused)
2797 {
2798  return false;
2799 }
2800 
2801 bool gen_false2( __attribute__((unused)) gen_chunk * u1, __attribute__((unused)) void * u2)
2802 {
2803  return false;
2804 }
2805 
2806 /** Just return the argument. */
2807 void * gen_identity(const void * x)
2808 {
2809  return (void *) x;
2810 }
2811 
2813 {
2814  return x.e;
2815 }
2816 
2817 /** Abort when called.
2818 
2819  Useful in a gen_recurse if we want to be sure a type of object is not
2820  here for example.
2821 */
2822 void gen_core( __attribute__((unused)) void * p)
2823 {
2824  abort();
2825 }
2826 
2827 void * gen_core_NULL( __attribute__((unused)) void * p)
2828 {
2829  abort();
2830  /* dead code */
2831  return NULL;
2832 }
2833 
2834 /** @} */
2835 /** @} */
2836 
2837 /* GLOBAL VARIABLES: to deal with decision tables
2838  *
2839  * number_of_domains:
2840  * the number of domains managed by newgen, max is MAX_DOMAIN.
2841  *
2842  * DirectDomainsTable:
2843  * DirectDomainsTable[domain_1, domain_2] is true if domain_2
2844  * may contains *directly* a domain_1 field.
2845  *
2846  * DecisionTables:
2847  * DecisionTables[domain] is the decision table to scan domain.
2848  * They are to be computed/set up after specifications' load.
2849  * A demand driven approach is implemented.
2850  *
2851  */
2852 
2853 #define decision_table_undefined ((char)25)
2856 
2857 static int
2859 
2860 static gen_tables
2863 
2865 {
2866  int i;
2867  fprintf(stderr, "[print_decision_table] %p\n", t);
2868  for (i=0; i<MAX_DOMAIN; i++)
2869  if (t[i]) fprintf(stderr, " go through %s\n", Domains[i].name);
2870 }
2871 
2872 /* demand driven computation of the decision table to scan domain.
2873  * this table is computed by a closure from the initial type matrix
2874  *
2875  * the algorithm is straightforward.
2876  * tabulated domains are skipped.
2877  * worst case complexity if O(n^2) for each requested domain.
2878  * the closure is shorten because already computed tables are used.
2879  */
2881 {
2882  GenDecisionTableType not_used;
2883  int i, j;
2884 
2885  if (gen_debug & GEN_DBG_RECURSE)
2886  fprintf(stderr,
2887  "[initialize_domain_DecisionTables] domain %s (%d)\n",
2888  Domains[domain].name, domain);
2889 
2890  for (i=0; i<number_of_domains; i++)
2891  not_used[i] = true;
2892 
2893  /* init with direct inclusions
2894  */
2895  for (i=0; i<number_of_domains; i++)
2897 
2898  not_used[domain]=false;
2899 
2900  /* now the closure is computed
2901  */
2902 
2903  while(1)
2904  {
2905  /* look for the next domain to include
2906  */
2907  for (i=0; i<number_of_domains; i++)
2908  if (DecisionTables[domain][i] & not_used[i])
2909  break;
2910 
2911  if (i>=number_of_domains) break; /* none */
2912 
2913  not_used[i] = false;
2914 
2915  /* cannot come from tabulated domains...
2916  * this should be discussed, or put as a parameter...
2917  */
2918  if (IS_TABULATED(&Domains[i])) continue;
2919 
2921  {
2922  /* shorten */
2923  if (gen_debug & GEN_DBG_RECURSE)
2924  fprintf(stderr,
2925  " - shortening with already computed %s (%d)\n",
2926  Domains[i].name, i);
2927 
2928  for (j=0; j<number_of_domains; j++)
2929  DecisionTables[domain][j] |= DecisionTables[i][j],
2930  not_used[j] &= !DecisionTables[i][j] /*? false : not_used[j] */;
2931  }
2932  else
2933  {
2934  if (gen_debug & GEN_DBG_RECURSE)
2935  fprintf(stderr,
2936  " - including %s (%d)\n",
2937  Domains[i].name, i);
2938 
2939  for (j=0; j<number_of_domains; j++)
2941  }
2942  }
2943 
2944  if (gen_debug & GEN_DBG_RECURSE)
2945  fprintf(stderr, " - computed table is\n"),
2947 }
2948 
2949 /* walks thru the domain to tag all types for target.
2950  */
2951 static void
2953 int target;
2954 union domain *dp;
2955 {
2956  if (dp==NULL) return; /* some domains are NULL */
2957 
2958  switch(dp->ba.type)
2959  {
2960  case EXTERNAL_DT:
2961  break; /* obvious: don't go inside externals! */
2962  case BASIS_DT:
2963  case LIST_DT:
2964  case ARRAY_DT:
2965  case SET_DT:
2966  if (gen_debug & GEN_DBG_RECURSE)
2967  fprintf(stderr,
2968  " - setting %s (%d) contains %s (%zd)\n",
2969  Domains[target].name, target,
2970  dp->se.element->name, dp->se.element-Domains);
2971  DirectDomainsTable[dp->se.element-Domains][target] = true;
2972  break;
2973  case CONSTRUCTED_DT:
2974  {
2975  struct domainlist *l=dp->co.components;
2976 
2977  for (; l!=NULL; l=l->cdr)
2978  initialize_domain_DirectDomainsTable(target, l->domain);
2979  }
2980  case IMPORT_DT:
2981  break; /* abort() ? true (safe) ? */
2982  case UNDEF_DT:
2983  break; /* nothing is done */
2984  default:
2985  fprintf(stderr, "newgen: unexpected domain type (%d)\n", dp->ba.type),
2986  abort();
2987  }
2988 }
2989 
2990 static void
2992 {
2993  int i,j;
2994 
2996 
2997  for (i=0; i<number_of_domains; i++)
2998  {
2999  struct gen_binding *bp = &Domains[i];
3000 
3001  if (gen_debug & GEN_DBG_RECURSE)
3002  fprintf(stderr,
3003  "[initialized_DirectDomainsTable] analysing %s\n",
3004  bp->name);
3005 
3006  if( bp->name == NULL || bp == Tabulated_bp ) continue ; /* ? */
3007 
3008  /* first put falses
3009  */
3010  for (j=0; j<number_of_domains; j++)
3011  DirectDomainsTable[j][i]=false;
3012 
3014  }
3015 
3016  if (gen_debug & GEN_DBG_RECURSE)
3017  for (i=0; i<number_of_domains; i++)
3018  fprintf(stderr, "[initialized_DirectDomainsTable] %s (%d)\n",
3019  Domains[i].name, i),
3021 
3022 }
3023 
3024 static void
3026 {
3027  int i;
3028 
3029  for(i=0; i<MAX_DOMAIN; i++)
3031 }
3032 
3033 /* called by gen_read_spec, should be called by a gen_init()
3034  */
3035 static void
3037 {
3038  int i;
3039 
3041 
3042  /* number_of_domains is first set
3043  */
3044  for (number_of_domains=-1, i=0; i<MAX_DOMAIN; i++)
3045  if (Domains[i].domain!=NULL && Domains[i].domain->ba.type != UNDEF_DT)
3046  number_of_domains = i;
3048 
3049  if (gen_debug & GEN_DBG_RECURSE)
3050  fprintf(stderr,
3051  "[init_gen_quick_recurse_tables] %d domains\n",
3053 
3056 }
3057 
3058 /* returns a decision table for the given domain.
3059  * demand driven definition of the table.
3060  */
3061 static GenDecisionTableType
3063 int domain;
3064 {
3066 
3069 
3070  return(&DecisionTables[domain]);
3071 }
3072 
3073 /*******************************************************************
3074  *
3075  * GENERALIZED VERSION: GEN MULTI RECURSE
3076  *
3077  * Fabien COELHO, Wed Sep 7 21:39:47 MET DST 1994
3078  *
3079  */
3080 
3081 typedef bool (*GenFilterType)();
3082 typedef void (*GenRewriteType)();
3083 
3086 
3087 /* the current data needed for a multi recursion are
3088  * stored in a multi recurse struct.
3089  *
3090  * - the seen hash_table stores the already encountered obj,
3091  * not to walk twice thru them. The previous implementation
3092  * used 2 recursions, one to mark the obj to visit, with an
3093  * associated number, and the other was the actual recursion.
3094  * This version is lazy, and just marks the encountered nodes,
3095  * thus allowing the full benefit of the decision table to avoid
3096  * walking thru the whole data structure.
3097  * - the visited domains are marked true in domains.
3098  * I could have checked that the filter is not NULL,
3099  * but it is clearer this way, I think, for the one who
3100  * will try to understand, if any:-)
3101  * - the decision table used is in decisions. It is computed
3102  * as the logical sum of the decision tables for the domains
3103  * to be walked thru
3104  * - filters and rewrites store the user decision functions
3105  * for each domain.
3106  * - context passed to filters and rewrites functions, as a 2nd arg.
3107  */
3109 {
3110  // what objects where already visited, with a record of their "ancestor"
3112  // hmmm... whether to ignore decision tables and always recurse
3113  // (just a quick and dirty "full" recurse implementation...)
3115  // domain to be visited
3117  // possibly intelligent decision tables, domains to recurse in
3119  // filter and rewrite functions for the visited domains
3122  // common context passed to everybody
3123  void * context;
3124  // keep track of the first ancestor of each object
3126  // previously visited object, if someone wants it...
3128  // current object, may be useful in a macro
3130 };
3131 
3132 /* the current multi recurse driver.
3133  * it is cleaner than the gen_recurse version since I added
3134  * the decisions table without modifying Pierre code, while here
3135  * I redefined a current status struct that stores everything needed.
3136  */
3137 static struct multi_recurse * current_mrc = (struct multi_recurse *) NULL;
3138 
3139 //**************************************************** MULTI RECURSE FUNCTIONS
3140 
3141 /* true if obj was already seen in this recursion.
3142  * also record ancestor on the fly.
3143  */
3145 {
3146  if (hash_defined_p(current_mrc->seen, obj))
3147  return true;
3148 
3150  return false;
3151 }
3152 
3153 static int
3155  __attribute__((unused)) struct driver * dr)
3156 {
3157  int dom = obj->i, go = !GO;
3158  check_domain(dom);
3159 
3160  // don't walk twice thru the same object:
3161  if (quick_multi_already_seen_p(obj))
3162  return !GO;
3163 
3164  // tabulated objects are not walked thru.
3165  // the decision could be managed by the table, or *after* the
3166  // filtering: the current status implied that you cannot enumerate
3167  // tabulated elements for instance.
3168  //
3169  // these features/bugs/limitations are compatible with gen_slow_recurse.
3170  //
3171  // FI told me that only persistant edges shouldn't be followed.
3172  // it may mean that tabulated elements are always persistent?
3173  if (!current_mrc->always_recurse &&
3175  return !GO;
3176 
3177  // set current object for call
3178  current_mrc->current = obj;
3179 
3180  // filter case, tell whether to apply rewrite
3181  // it should be different from recurring down...
3182  if ((*(current_mrc->domains))[dom])
3183  go = (*((*(current_mrc->filters))[dom]))(obj, current_mrc->context);
3184  else
3185  // else, here is the *maybe* intelligent decision to be made.
3186  go = current_mrc->always_recurse || (*(current_mrc->decisions))[dom];
3187 
3188  // else push current object before continuing the recursion downwards
3189  if (go) stack_push(obj, current_mrc->upwards);
3190 
3191  // we have just visited this one (downwards)
3192  current_mrc->previous = obj;
3193  current_mrc->current = NULL;
3194 
3195  return go;
3196 }
3197 
3198 static void
3200  __attribute__((unused)) struct gen_binding * bp,
3201  __attribute__((unused)) struct driver * dr)
3202 {
3203  int dom = obj->i;
3204  check_domain(dom);
3205 
3206  // pop before calling rewrite function, so that the current ancestor
3207  // should is the right one, not the current object
3208  gen_chunk * popped = stack_pop(current_mrc->upwards);
3209  message_assert("pop myself", popped==obj);
3210 
3211  // set current object before call
3212  current_mrc->current = obj;
3213 
3214  // now call the rewrite function
3215  if ((*(current_mrc->domains))[dom])
3216  (*((*(current_mrc->rewrites))[dom]))(obj, current_mrc->context);
3217 
3218  // we have just visited this one (upwards)
3219  current_mrc->previous = obj;
3220  current_mrc->current = NULL;
3221 }
3222 
3223 static int
3225 {
3226  int t;
3227  return
3229  (*(current_mrc->decisions))[dp->se.element-Domains] ||
3230  (*(current_mrc->domains))[dp->se.element-Domains]) &&
3231  (current_mrc->always_recurse || !dp->se.persistant) && // stay at level
3232  ((t=dp->ba.type)==BASIS_DT ? true :
3233  t==LIST_DT ? obj->l != list_undefined :
3234  t==SET_DT ? obj->t != set_undefined :
3235  t==ARRAY_DT ? obj->p != array_undefined :
3236  (fatal("persistant_simple_in: unknown type %s\n",
3237  i2a(dp->ba.type)), false));
3238 }
3239 
3240 
3241 /** @addtogroup gen_multi_recurse */
3242 
3243 /** @{ */
3244 
3245 /** Tells the recursion not to go in this object
3246 
3247  This may be interesting when the recursion modifies
3248  the visited data structure.
3249  if obj is NULL, the whole recursion is stopped !
3250 */
3251 void gen_recurse_stop(void * obj)
3252 {
3253  if (obj)
3254  hash_put(current_mrc->seen, obj, obj);
3255  else
3256  gen_trav_stop_recursion = true;
3257 }
3258 
3259 /** Multi recursion generic visitor function
3260 
3261  It is more intended for internal use, but may be useful instead of
3262  gen_context_multi_recurse() to give iteration parameters as a va_list.
3263 
3264  Refer to the documentation of gen_context_multi_recurse().
3265 
3266  Beware that the function is reentrant.
3267 */
3268 static void
3270  (void * o, // starting point
3271  void * context, // context passed to decision and rewrite functions
3272  bool gointabs, // whether to recurse within tabulated domains
3273  va_list pvar) // domain, decision (down) and rewrite (up) functions
3274 {
3275  gen_chunk * obj = (gen_chunk*) o;
3276  int i, domain;
3277  GenFilterTableType new_filter_table;
3278  GenRewriteTableType new_rewrite_table;
3279  GenDecisionTableType new_decision_table, new_domain_table, *p_table;
3280  struct multi_recurse *saved_mrc, new_mrc;
3281  struct driver dr;
3282 
3283  message_assert("tabulated domain recursion is not implemented", !gointabs);
3284 
3286 
3287  // the object must be a valid newgen object
3288  message_assert("not null and defined object to visit",
3289  obj!=(gen_chunk*)NULL && obj!=gen_chunk_undefined);
3290 
3291  // initialize the new tables
3292  for(i=0; i<MAX_DOMAIN; i++)
3293  {
3294  new_domain_table[i] = false;
3295  new_decision_table[i] = false;
3296  new_filter_table[i] = NULL;
3297  new_rewrite_table[i] = NULL;
3298  }
3299 
3300  // read the arguments
3301  while((domain=va_arg(pvar, int)) != 0)
3302  {
3303  message_assert("domain specified once", !new_domain_table[domain]);
3304 
3305  new_domain_table[domain] = true;
3306  new_filter_table[domain] = va_arg(pvar, GenFilterType);
3307  new_rewrite_table[domain] = va_arg(pvar, GenRewriteType);
3308 
3309  for(i=0, p_table=get_decision_table(domain); i<number_of_domains; i++)
3310  new_decision_table[i] |= (*p_table)[i];
3311  }
3312 
3313  // initialize multi recurse stuff
3314  new_mrc.seen = hash_table_make(hash_pointer, 0),
3315  new_mrc.always_recurse = gointabs, // quick and dirty...
3316  new_mrc.domains = &new_domain_table,
3317  new_mrc.decisions = &new_decision_table,
3318  new_mrc.filters = &new_filter_table,
3319  new_mrc.rewrites = &new_rewrite_table,
3320  new_mrc.context = context;
3321  new_mrc.upwards = stack_make(0, 20, 0);
3322  new_mrc.previous = NULL;
3323  new_mrc.current = NULL;
3324 
3325  // initialize recursion driver
3326  // (should contains a pointer to previous one to pass the context,
3327  // instead of relying on a global variable...)
3328  dr.null = gen_null,
3330  dr.leaf_out = gen_null,
3333  dr.simple_out = gen_null,
3336 
3337  // push the current context
3338  saved_mrc = current_mrc, current_mrc = &new_mrc;
3339 
3340  // recurse!
3341  gen_trav_stop_recursion = false;
3342  stack_push(NULL, new_mrc.upwards); // root is conventionaly set to NULL
3343  gen_trav_obj(obj, &dr);
3344  // if there was no interruption, the stack must be back to the root
3345  if (!gen_trav_stop_recursion) {
3346  message_assert("back to root", stack_size(current_mrc->upwards) == 1);
3347  void * popped = stack_pop(current_mrc->upwards);
3348  message_assert("back to root", popped == NULL);
3349  }
3350  gen_trav_stop_recursion = false;
3351 
3352  // cleanup, and restore the previous context
3353  hash_table_free(new_mrc.seen);
3354  stack_free(&new_mrc.upwards);
3355  current_mrc = saved_mrc;
3356 }
3357 
3358 /** Multi-recursion with context function visitor
3359 
3360  gen_context_multi_recurse(obj, context,
3361  [domain, filter, rewrite,]*
3362  NULL);
3363 
3364  recurse from object obj (in a top-down way), applies filter_i on
3365  encountered domain_i objects with the context, if true, recurses
3366  down from the domain_i object, and applies rewrite_i on exit from
3367  the object (in a bottom-up way).
3368 
3369  Newgen persistant fields are not visited.
3370 
3371  You can't visit domain number 0, but there are none...
3372 */
3373 void gen_context_multi_recurse(void * o, void * context, ...)
3374 {
3375  va_list pvar;
3376  va_start(pvar, context);
3378  va_end(pvar);
3379 }
3380 
3381 /** Full multi-recursion with context function visitor
3382 
3383  gen_full_recurse(obj, context,
3384  [domain, filter, rewrite,]*
3385  NULL);
3386 
3387  recurse from object obj (in a top-down way), applies filter_i on
3388  encountered domain_i objects with the context, if true, recurses
3389  down from the domain_i object, and applies rewrite_i on exit from
3390  the object (in a bottom-up way).
3391 
3392  Newgen persistant fields and their contents ARE VISITED.
3393 
3394  The current implementation does not try to be intelligent, thus
3395  will recurse anywhere until stopped by a decision or an object was
3396  already visited. Beware, if you do not take extra care, this mean
3397  visiting all entities and their contents when visiting from a
3398  statement in pips.
3399 
3400  You can't visit domain number 0, but there are none.
3401 */
3402 void gen_full_recurse(void * o, void * context, ...)
3403 {
3404  va_list pvar;
3405  va_start(pvar, context);
3407  va_end(pvar);
3408 }
3409 
3410 /** Multi recursion visitor function
3411 
3412  gen_context_multi_recurse(obj, context,
3413  [domain, filter, rewrite,]*
3414  NULL);
3415 
3416  recurse from object obj (in a top-down way),
3417  applies filter_i on encountered domain_i objects with the context,
3418  if true, recurses down from the domain_i object,
3419  and applies rewrite_i on exit from the object (in a bottom-up
3420  way).
3421 
3422  Newgen persistant fields are not visited.
3423 
3424  Bug : you can't visit domain number 0 if any... The good news is that
3425  there is no NewGen object of domain number 0, since it seems that to
3426  start at 7 for user domains...
3427 */
3428 void gen_multi_recurse(void * o, ...)
3429 {
3430  va_list pvar;
3431  va_start(pvar, o);
3432  gen_internal_context_multi_recurse(o, NULL, false, pvar);
3433  va_end(pvar);
3434 }
3435 
3436 /** Visit all the objects from a given types found in an object.
3437 
3438  @param obj the object to start visiting
3439 
3440  @param domain the type of objects we want to visit
3441 
3442  @param filter the filter method (function) to apply to an encountered
3443  object of the good type during the prefix (top-down) visit. If it
3444  returns true, the recursion is going on and the rewrite filter will be called
3445  during the bottom-up visit. If it returns false, the visit
3446  does not go further inside this object and the rewrite method will not be
3447  called during the bottom-up visit.
3448 
3449  @param rewrite is the method (function) to apply to an encountered
3450  object of the good type during the prefix (bottom-up) visit
3451  */
3453  void * obj, /**< starting point */
3454  int domain,
3455  bool (*filter)(void * encountered),
3456  void (*rewrite)(void * encountered_object))
3457 {
3458  gen_multi_recurse(obj, domain, filter, rewrite, NULL);
3459 }
3460 
3461 /** Visit all the objects from a given types found in an object with a context.
3462 
3463  @param obj the object to start visiting
3464 
3465  @param domain the type of objects we want to visit
3466 
3467  @param context is a pointer that is given to the filter and rewrite
3468  methods too. It is quite useful when one wants side effects on other
3469  objects without having to rely on (dirty) global variables.
3470 
3471  @param filter the filter method (function) to apply to an encountered
3472  object of the good type during the prefix (top-down) visit. Its second
3473  argument is the context passed texto from the global context
3474  parameter. If the method returns true, the recursion is going on. If
3475  it returns false, the visit does not go further inside this object and
3476  the rewrite method is not be called during the bottom-up visit.
3477 
3478  @param rewrite is the method (function) to apply to an encountered
3479  object of the good type during the prefix (bottom-up) visit. Its
3480  second argument is the context passed texto from the global context
3481  parameter
3482  */
3484  void * obj, /**< starting point */
3485  void * context,
3486  int domain,
3487  bool (*filter)(void * encountered_object, void * context),
3488  void (*rewrite)(void * encountered_object, void * context))
3489 {
3490  gen_context_multi_recurse(obj, context, domain, filter, rewrite, NULL);
3491 }
3492 
3493 
3494 
3495 /** @defgroup gen_recurse_heritage NewGen inheritance tracking during visiting object
3496 
3497  Methods to get parent information constructed during recursion.
3498 
3499  To have example of usage, have a look at the caller-graph in the
3500  Doxygen documentation of its functions, for example
3501  gen_get_recurse_ancestor(), that will point you to phases such as
3502  try_to_recover_for_loop_in_a_while().
3503 
3504  @{
3505 */
3506 
3507 /* Get the previously visited object.
3508 
3509  @return the previously visited object
3510 
3511  It may be a sibling, a parent, or an child.
3512  */
3514 {
3515  message_assert("in a recursion", current_mrc!=NULL);
3516  return current_mrc->previous;
3517 }
3518 
3519 /* Get the ancestor of the current object.
3520 
3521  @return the ancestor of the current object. If it fails to do it, it returns:
3522 
3523  - NULL if the current object is the root of the recursion (since it
3524  does not have any parent inside the reduction scope)
3525 */
3527 {
3528  message_assert("in a recursion", current_mrc!=NULL);
3529  return stack_head(current_mrc->upwards);
3530 }
3531 
3532 /* Get the first ancestor object encountered during the recursion for the
3533  given object.
3534 
3535  The heritage relation is built during the top-down phase (the
3536  filter-down phase), so if the objects are rewriten during the top-down
3537  rewriting phase (that should never happend, rewrite should be
3538  performed on the bottom-up pass, when the "rewrite" function is
3539  called), the heritage relation are not up-to-date for these objects.
3540 
3541  @p is the object we want the ancestor
3542  @return the object parent. If it fails, it returns:
3543  - NULL if the current object is the root of the recursion (so no parent)
3544  - HASH_UNDEFINED_VALUE if the current object does not have any ancestor.
3545 */
3546 gen_chunk * gen_get_recurse_ancestor(const void * object)
3547 {
3548  message_assert("in a recursion", current_mrc!=NULL);
3549  return (gen_chunk *) hash_get(current_mrc->seen, object);
3550 }
3551 
3552 /* return the first ancestor object found of the given type.
3553 
3554  @param type newgen domain of the ancestor looked for.
3555  @param object we want the ancestor of.
3556  @return NULL if the root is reached without finding the said type
3557 
3558  maybe it could move the search in the upper recursion if any...
3559  */
3560 gen_chunk * gen_get_ancestor(int type, const void * obj)
3561 {
3562  message_assert("in a recursion", current_mrc!=NULL);
3563  while (true)
3564  {
3565  gen_chunk * prev = hash_get(current_mrc->seen, obj);
3566  message_assert("some ancestor or NULL", prev!=HASH_UNDEFINED_VALUE);
3567  if (prev==NULL)
3568  return NULL;
3569  else if (prev->i == type)
3570  return prev;
3571  obj = prev;
3572  }
3573 }
3574 
3575 /* return the current visited object, or NULL if not in a recursion.
3576 
3577  Ok, we should have it, but its name may not be known in a macro,
3578  or deep in a called function...
3579 */
3581 {
3582  return current_mrc? current_mrc->current: NULL;
3583 }
3584 
3585 /* Return current object of that type... or NULL if none found
3586  */
3588 {
3590  return current? gen_get_ancestor(type, current): NULL;
3591 }
3592 
3593 /** @} */
3594 /** @} */
3595 
3596 
3597 /* That is all
3598  */
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
static hash_table seen
static function to store whether a module has been seen during the recursive generation of the daVinc...
Definition: graph.c:85
void const char const char const int
static int num
Definition: bourdoncle.c:137
char * alloc(int size)
ALLOC is an "iron-clad" version of malloc(3).
Definition: build.c:501
int max_domain_index()
Definition: build.c:181
void print_domain(FILE *out, union domain *dp)
PRINT_DOMAIN prints on the OUT stream a domain denoted by the DP pointer.
Definition: build.c:294
void compile(void)
COMPILE reconnects the Domains table (for not compiled types – note that an inlined type is already c...
Definition: build.c:422
int gen_size(int domain)
GEN_SIZE returns the size (in gen_chunks) of an object of type defined by the BP type.
Definition: genC.c:71
#define GEN_DBG_TRAV_OBJECT
Definition: genC.h:199
#define gen_chunk_undefined_p(c)
Definition: genC.h:75
union gen_chunk gen_chunk
A gen_chunk is used to store every object.
#define GEN_DBG_TRAV_LEAF
Definition: genC.h:197
#define GEN_DBG_TRAV_SIMPLE
Definition: genC.h:198
#define GEN_DBG_RECURSE
Definition: genC.h:201
#define gen_chunk_undefined
Definition: genC.h:74
#define GEN_DBG_CHECK
Definition: genC.h:200
static int shared_obj_in(gen_chunk *obj, struct driver *dr)
SHARED_OBJ_IN introduces an object OBJ in the OBJ_TABLE.
Definition: genClib.c:670
static void write_define_shared_node(int n)
WRITE_DEFINE_SHARED_NODE defines the node whose number is N.
Definition: genClib.c:1500
FILE * genspec_out
Definition: genClib.c:52
#define gen_alloc_component(dp, cp, ap, gen_check_p)
gen_alloc_component updates the gen_chunk CP from the arg list AP according to the domain DP.
Definition: genClib.c:198
void gen_free(gen_chunk *obj)
version without shared_pointers.
Definition: genClib.c:992
static int free_leaf_in(gen_chunk *obj, struct gen_binding *bp)
A tabulated domain BP prohibits its OBJ to be recursively freed.
Definition: genClib.c:867
static int allocated_memory_simple_in(gen_chunk *obj, union domain *dp)
manages newgen simples (list, set, array)
Definition: genClib.c:2634
static bool gen_trav_stop_recursion
Definition: genClib.c:384
static int quick_multi_recurse_obj_in(gen_chunk *obj, __attribute__((unused)) struct driver *dr)
Definition: genClib.c:3154
static gen_chunk * gen_copy_array(gen_chunk *old_a, dp)
GEN_COPY_ARRAY duplicates an array.
Definition: genClib.c:1222
gen_chunk * gen_alloc(int size, int gen_check_p, int dom,...)
allocates something in newgen.
Definition: genClib.c:298
static void gen_array_leaf(struct gen_binding *bp, int i, gen_chunk *obj, struct driver *dr)
GEN_ARRAY_LEAF is the default recursive call to gen_trav_leaf.
Definition: genClib.c:494
static int disallow_undefined_tabulated
Default option in GEN_WRITE.
Definition: genClib.c:74
static int copy_obj_in(gen_chunk *obj, __attribute__((unused)) struct driver *dr)
COPY_OBJ_IN duplicates an object if it has not already been seen (this migth happen with shared objec...
Definition: genClib.c:1086
static void write_obj_out(gen_chunk *obj, struct gen_binding *bp, struct driver *dr)
WRITE_OBJ_OUT is done when the OBJect (of type BP) has been printed.
Definition: genClib.c:1560
int gen_write_tabulated(FILE *fd, int domain)
GEN_WRITE_TABULATED writes the tabulated object TABLE on FD.
Definition: genClib.c:1866
string gen_domain_name(int t)
GEN_DOMAIN_NAME returns the domain name, and may be used for debug purposes.
Definition: genClib.c:97
static FILE * user_file
These functions implements the writing of objects.
Definition: genClib.c:1485
static gen_chunk * gen_local_copy_tree(gen_chunk *obj, bool keep)
GEN_COPY_TREE makes a copy of the object OBJ.
Definition: genClib.c:1387
static int write_obj_in(gen_chunk *obj, struct driver *dr)
WRITE_OBJ_IN writes the OBJect of type BP.
Definition: genClib.c:1522
static FILE * black_hole
used for consistence checking...
Definition: genClib.c:2386
int gen_type_translation_old_to_actual(int n)
forwards conversion
Definition: genClib.c:2147
void gen_full_free_list(list l)
Definition: genClib.c:1023
void gen_type_translation_reset(void)
Definition: genClib.c:2171
static gen_chunk * init_array(union domain *dp)
INIT_ARRAY returns a freshly allocated array initialized according to the information in its domain D...
Definition: genClib.c:169
void genspec_set_string_to_parse(char *)
Definition: genspec_lex.c:838
static int write_tabulated_leaf_in(gen_chunk *obj, struct gen_binding *bp)
WRITE_TABULATED_LEAF_IN prints the OBJect of type BP.
Definition: genClib.c:1809
bool(* GenFilterType)()
Definition: genClib.c:3081
int gen_read_tabulated(FILE *file, int create_p)
GEN_READ_TABULATED reads FILE to update the Gen_tabulated_ table.
Definition: genClib.c:2334
void gen_type_translation_write(string filename)
Definition: genClib.c:2195
int current_shared_obj_table_size(void)
returns the number of byte allocated for obj_table.
Definition: genClib.c:654
#define GO
Definition: genClib.c:48
static void copy_obj_out_constructed(gen_chunk *obj, struct gen_binding *bp, dp, data, new_obj, dr)
Definition: genClib.c:1305
FILE * genspec_in
lex files
#define FIRST_SEEN(s)
Definition: genClib.c:637
static struct multi_recurse * current_mrc
the current multi recurse driver.
Definition: genClib.c:3137
static int allocated_memory_obj_in(gen_chunk *obj, struct driver *dr)
manages newgen objects and strings...
Definition: genClib.c:2612
static void free_simple_out(gen_chunk *obj, union domain *dp)
FREE_SIMPLE_OUT frees the spine of the list OBJ or the whole array (according to the type DP).
Definition: genClib.c:901
void gen_write_without_sharing(fd, obj)
GEN_WRITE_WITHOUT_SHARING writes the OBJect on the stream FD.
Definition: genClib.c:1777
static void write_this_tabulated(gen_chunk *o)
Definition: genClib.c:1851
static gtt_p gtt_current_table
global translation table.
Definition: genClib.c:1938
static void init_gen_quick_recurse_tables(void)
GEN_READ_SPEC reads the specifications.
Definition: genClib.c:3036
int error_seen
Have we seen a user error somewhere ?
Definition: build.c:76
int gen_consistent_p(gen_chunk *obj)
GEN_CONSISTENT_P dynamically checks the type correctness of OBJ.
Definition: genClib.c:2398
bool gen_sharing_p(gen_chunk *obj1, gen_chunk *obj2)
Definition: genClib.c:2518
static int gen_debug_indent
Definition: genClib.c:70
static void free_obj_out(gen_chunk *obj, struct gen_binding *bp, struct driver *dr)
FREE_OBJ_OUT just frees the object OBJ.
Definition: genClib.c:922
static int free_obj_in(gen_chunk *obj, struct driver *dr)
Definition: genClib.c:971
static int tabulated_leaf_in(gen_chunk *obj, struct gen_binding *bp)
Definition: genClib.c:620
#define decision_table_undefined
GLOBAL VARIABLES: to deal with decision tables.
Definition: genClib.c:2853
static int array_own_allocated_memory(union domain *dp)
Definition: genClib.c:181
static char * first_seen
Definition: genClib.c:634
static void print_decision_table(GenDecisionTableType t)
Definition: genClib.c:2864
static void gen_trav_leaf(struct gen_binding *bp, gen_chunk *obj, struct driver *dr)
set to true to stop...
Definition: genClib.c:390
static hash_table obj_table
The OBJ_TABLE maps objects to addresses within the arrays FIRST_SEEN and SEEN_ONCE.
Definition: genClib.c:648
static void copy_obj_out(obj, bp, dr)
Definition: genClib.c:1361
static int write_simple_in(obj, dp)
WRITE_SIMPLE_IN is done before printing a simple OBJect of type DP.
Definition: genClib.c:1668
static struct driver * wtt_dr
Definition: genClib.c:1850
int newgen_domain_index(gen_chunk *obj)
DOMAIN_INDEX returns the index in the Domain table for object OBJ.
Definition: genClib.c:105
static hash_table copy_table
These functions are used to implement the copying of objects.
Definition: genClib.c:1050
GenDecisionTableType gen_tables[MAX_DOMAIN]
Definition: genClib.c:2855
static int quick_multi_recurse_simple_in(gen_chunk *obj, union domain *dp)
Definition: genClib.c:3224
#define MAX_SHARED_OBJECTS
These functions computes an hash table of object pointers (to be used to manage sharing when dealing ...
Definition: genClib.c:632
#define COPYABLE_DOMAIN(d)
COPY_OBJ_OUT achieves to update the new object (copy of the old one) once all sub-domains have been r...
Definition: genClib.c:1299
int gen_debug
The debug flag can be changed by the user to check genClib code.
Definition: genClib.c:69
void(* GenRewriteType)()
Definition: genClib.c:3082
static int get_domain_number(string name, int i)
== simplified lookup? returns the index of domain name if found, looking up from i.
Definition: genClib.c:1997
static char * seen_once
Definition: genClib.c:635
string gen_read_string(FILE *file, char upto)
returns the allocated line read, whatever its length.
Definition: genClib.c:1943
static void write_null(struct gen_binding *bp)
Definition: genClib.c:1512
static int first_available(int t[MAX_DOMAIN])
Definition: genClib.c:2007
static void write_shared_node(int n)
WRITE_SHARED_NODE references a shared node N.
Definition: genClib.c:1507
static int persistant_simple_in(obj, dp)
GEN_LOCAL_FREE frees the object OBJ with or without KEEPing the sharing.
Definition: genClib.c:950
int gen_defined_p(gen_chunk *obj)
Definition: genClib.c:2438
static void gtt_write(string filename, gtt_p table)
writes what the previous reads...
Definition: genClib.c:2132
static list gen_copy_list(list old_l, union domain *dp)
GEN_COPY_LIST duplicates cons cells.
Definition: genClib.c:1179
void newgen_start_lexer(FILE *)
starting the scanner.
Definition: genread_lex.c:822
gen_chunk * gen_copy_tree_with_sharing(gen_chunk *obj)
for re-entry only in gen_copy_tree...
Definition: genClib.c:1442
static int write_leaf_in(gen_chunk *obj, struct gen_binding *bp)
WRITE_LEAF_IN prints the OBJect of type BP.
Definition: genClib.c:1612
static void gtt_table_init(gtt_p table)
Definition: genClib.c:1971
static bool allocated_memory_already_seen_p(gen_chunk *obj)
true if obj was already seen in this recursion, and put it at true
Definition: genClib.c:2567
gen_chunk * gen_check(gen_chunk *obj, int t)
GEN_CHECK checks that the gen_chunk received OBJ is of the appropriate TYPE.
Definition: genClib.c:2356
int gen_free_tabulated(int domain)
free tabulated elements of this domain.
Definition: genClib.c:1461
static void void_gen_consistent_p(gen_chunk *obj)
for side effects only
Definition: genClib.c:2415
static gen_tables DecisionTables
Definition: genClib.c:2862
static void push_gen_trav_env()
Definition: genClib.c:808
gen_chunk * gen_make_array(num)
GEN_MAKE_ARRAY allocates an initialized array of NUM gen_chunks.
Definition: genClib.c:2307
#define CHECK_NULL(obj, bp, dr)
To be called on any object pointer.
Definition: genClib.c:380
static GenDecisionTableType * get_decision_table(int domain)
returns a decision table for the given domain.
Definition: genClib.c:3062
static void write_simple_out(gen_chunk *obj, union domain *dp)
WRITE_LEAF_OUT prints the closing parenthesis of (non-basis) simple OBJect of type DP.
Definition: genClib.c:1724
GenFilterType GenFilterTableType[MAX_DOMAIN]
Definition: genClib.c:3084
struct gen_binding * Tabulated_bp
pointer to tabulated domain hack
Definition: genClib.c:58
static void write_string(string init, string s, string end, string ifnull, string ifundefined)
Definition: genClib.c:1580
static bool Read_spec_performed
Definition: genClib.c:61
void gen_init_external(int which, void *(*read)(FILE *, int(*)(void)), void(*write)(FILE *, void *), void(*free)(void *), void *(*copy)(void *), int(*allocated_memory)(void *))
GEN_INIT_EXTERNAL defines entry points for free, read and write functions of external types.
Definition: genClib.c:2276
void genspec_reset_string_to_parse(void)
Definition: genspec_lex.c:839
static __thread hash_table free_already_seen
These functions are used to implement the freeing of objects.
Definition: genClib.c:848
int gen_type(gen_chunk *obj)
GEN_TYPE returns the domain number for the object in argument.
Definition: genClib.c:82
static struct gen_binding * wtt_bp
Definition: genClib.c:1849
static void write_array_leaf(struct gen_binding *bp, int i, gen_chunk *obj, struct driver *dr)
WRITE_ARRAY_LEAF only writes non-null elements, in a sparse way.
Definition: genClib.c:1703
gen_chunk * gen_read(FILE *file)
GEN_READ reads any object from the FILE stream.
Definition: genClib.c:2323
static void fputi(int i, FILE *f)
Definition: genClib.c:1487
static gen_tables DirectDomainsTable
Definition: genClib.c:2861
int gen_type_translation_actual_to_old(int n)
backwards conversion
Definition: genClib.c:2160
static void shared_pointers(obj, keep)
SHARED_POINTERS creates (in OBJ_TABLE) the association between objects and their numbers (!...
Definition: genClib.c:734
static gtt_p gtt_make(void)
returns an allocated and initialized translation table...
Definition: genClib.c:1966
static set gen_copy_set(set old_s, dp)
GEN_COPY_SET duplicates a set.
Definition: genClib.c:1247
static hash_table pointers
GEN_SHARING_P checks whether OBJ1 uses objects (except tabulated) or CONS cells that appear in OBJ2.
Definition: genClib.c:2472
static void fputci(char c, int i, FILE *f)
Definition: genClib.c:1492
static void change_sign(gen_chunk *o)
Definition: genClib.c:1858
static int copy_simple_in(gen_chunk *obj, union domain *dp)
Just check for defined simple domains.
Definition: genClib.c:1117
static int number_of_domains
Definition: genClib.c:2858
static int shared_obj(obj, void(*first)(), void(*others)())
SHARED_OBJ manages the OBJect modulo sharing (the OBJ_TABLE has to be set first, see above).
Definition: genClib.c:764
static void open_black_hole()
Definition: genClib.c:2387
static bool quick_multi_already_seen_p(gen_chunk *obj)
true if obj was already seen in this recursion.
Definition: genClib.c:3144
static void copy_hput(hash_table t, char *k, char *v)
Definition: genClib.c:1070
static int allocated_memory_leaf_in(obj, bp)
manages EXTERNALS and INLINABLES
Definition: genClib.c:2579
static void gen_alloc_constructed(va_list ap, struct gen_binding *bp, union domain *dp, gen_chunk *cp, int data, int gen_check_p)
GEN_ALLOC allocates SIZE bytes to implement an object whose TYPE is the index in the Domains table.
Definition: genClib.c:249
static void free_leaf_out(obj, bp)
FREE_LEAF_OUT manages external types.
Definition: genClib.c:876
char GenDecisionTableType[MAX_DOMAIN]
Definition: genClib.c:2854
static void initialize_DirectDomainsTable(void)
Definition: genClib.c:2991
static int shared_number
The running counter of shared objects number.
Definition: genClib.c:662
static void gen_trav_obj()
struct gtt_t * gtt_p
static int array_size(dim)
ARRAY_SIZE returns the number of elements in the array whose dimension list is DIM.
Definition: genClib.c:155
static hash_table already_seen_objects
Definition: genClib.c:2562
void gen_read_spec(char *spec,...)
Definition: genClib.c:2218
static void fprintf_spaces(fd, number)
FPRINTF_SPACES prints NUMBER spaces on the FD file descriptor.
Definition: genClib.c:118
static void initialize_domain_DecisionTables(int domain)
demand driven computation of the decision table to scan domain.
Definition: genClib.c:2880
static void copy_leaf_out(obj, bp)
COPY_LEAF_OUT manages external sub-domains.
Definition: genClib.c:1149
static void quick_multi_recurse_obj_out(gen_chunk *obj, __attribute__((unused)) struct gen_binding *bp, __attribute__((unused)) struct driver *dr)
Definition: genClib.c:3199
gen_chunk * gen_copy_tree(gen_chunk *obj)
Definition: genClib.c:1429
static bool cumulated_error_seen
Definition: genClib.c:2394
int gen_allocated_memory(gen_chunk *obj)
re-entry is automatic for this function.
Definition: genClib.c:2690
int gen_tabulated_consistent_p(int domain)
Definition: genClib.c:2420
static void gen_trav_simple(union domain *dp, gen_chunk *obj, struct driver *dr)
GEN_TRAV_SIMPLE traverses a simple OBJ (which is a (CONS *) for a list or points to the first element...
Definition: genClib.c:431
static void copy_simple_out(obj, dp)
COPY_SIMPLE_OUT copies the spine of the list OBJ or the whole array (according to the type DP).
Definition: genClib.c:1271
static int shared_simple_in(obj, dp)
Definition: genClib.c:693
void gen_type_translation_default(void)
Definition: genClib.c:2180
static gtt_p gtt_read(string filename)
read and setup a table from a file
Definition: genClib.c:2017
static bool free_already_seen_p(gen_chunk *obj)
Definition: genClib.c:851
static void initialize_domain_DirectDomainsTable(int target, union domain *dp)
walks thru the domain to tag all types for target.
Definition: genClib.c:2952
static bool check_sharing(char *p, char *type)
Definition: genClib.c:2475
GenRewriteType GenRewriteTableType[MAX_DOMAIN]
Definition: genClib.c:3085
static void gen_trav_obj_constructed(gen_chunk *obj, __attribute__((unused)) struct gen_binding *bp, union domain *dp, int data, struct driver *dr)
GEN_TRAV_OBJ (the root function) traverses the object OBJ according to the driver DR.
Definition: genClib.c:510
void genspec_lex_destroy()
static gen_chunk * copy_hsearch(gen_chunk *key)
maps an object on its copy
Definition: genClib.c:1053
#define MAX_GEN_TRAV_ENV
GEN_TRAV_ENVS are stacked to allow recursive calls to GEN_TRAV_OBJ (cf.
Definition: genClib.c:797
static int sharing_obj_in(gen_chunk *obj, struct driver *dr)
Definition: genClib.c:2485
void gen_write(FILE *fd, gen_chunk *obj)
GEN_WRITE writes the OBJect on the stream FD.
Definition: genClib.c:1745
void gen_type_translation_read(string filename)
set current type translation table according to file
Definition: genClib.c:2189
static void defined_null(struct gen_binding *bp)
GEN_DEFINED_P checks that the OBJect is fully defined.
Definition: genClib.c:2429
int Read_spec_mode
extern int Current_first ;
Definition: genClib.c:60
static void gtt_table_identity(gtt_p table)
Definition: genClib.c:1982
struct gen_trav_env gen_trav_envs[MAX_GEN_TRAV_ENV]
static void pop_gen_trav_env()
Definition: genClib.c:827
static jmp_buf env
Definition: genClib.c:2473
static int sharing_simple_in(gen_chunk *obj, union domain *dp)
Definition: genClib.c:2499
static int gen_trav_env_top
Definition: genClib.c:799
static int current_size
returns the number of bytes allocated for a given structure may need additional fonctions for externa...
Definition: genClib.c:2561
static void initialize_DecisionTables()
Definition: genClib.c:3025
int genread_parse(void)
void * malloc(YYSIZE_T)
int newgen_allow_forward_ref
The GEN_TABULATED_NAMES hash table maps ids to index in the table of the tabulated domains.
Definition: genread_yacc.c:151
void free(void *)
gen_chunk * Read_chunk
Where the root will be.
Definition: genread_yacc.c:134
int genspec_parse(void)
struct gen_binding Domains[MAX_DOMAIN]
in build.c
Definition: genspec_yacc.c:114
void gen_context_recurse(void *obj, void *context, int domain, bool(*filter)(void *encountered_object, void *context), void(*rewrite)(void *encountered_object, void *context))
Visit all the objects from a given types found in an object with a context.
Definition: genClib.c:3483
void gen_recurse_stop(void *obj)
Tells the recursion not to go in this object.
Definition: genClib.c:3251
void gen_recurse(void *obj, int domain, bool(*filter)(void *encountered), void(*rewrite)(void *encountered_object))
Visit all the objects from a given types found in an object.
Definition: genClib.c:3452
void gen_full_recurse(void *o, void *context,...)
Full multi-recursion with context function visitor.
Definition: genClib.c:3402
void gen_multi_recurse(void *o,...)
Multi recursion visitor function.
Definition: genClib.c:3428
static void gen_internal_context_multi_recurse(void *o, void *context, bool gointabs, va_list pvar)
Multi recursion generic visitor function.
Definition: genClib.c:3270
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
gen_chunk * gen_get_recurse_previous_visited_object(void)
Get the previously visited object.
Definition: genClib.c:3513
gen_chunk * gen_get_current_ancestor(int type)
Return current object of that type...
Definition: genClib.c:3587
gen_chunk * gen_get_current_object(void)
return the current visited object, or NULL if not in a recursion.
Definition: genClib.c:3580
gen_chunk * gen_get_ancestor(int type, const void *obj)
return the first ancestor object found of the given type.
Definition: genClib.c:3560
gen_chunk * gen_get_recurse_ancestor(const void *object)
Get the first ancestor object encountered during the recursion for the given object.
Definition: genClib.c:3546
gen_chunk * gen_get_recurse_current_ancestor(void)
Get the ancestor of the current object.
Definition: genClib.c:3526
void * gen_NULL(__attribute__((unused)) void *unused)
idem with a void* return
Definition: genClib.c:2764
void gen_null2(__attribute__((unused)) void *u1, __attribute__((unused)) void *u2)
idem with 2 args, to please overpeaky compiler checks
Definition: genClib.c:2758
void * gen_chunk_identity(gen_chunk x)
Definition: genClib.c:2812
void * gen_core_NULL(__attribute__((unused)) void *p)
Definition: genClib.c:2827
bool gen_false(__attribute__((unused)) gen_chunk *unused)
Return false and ignore the argument.
Definition: genClib.c:2796
void gen_core(__attribute__((unused)) void *p)
Abort when called.
Definition: genClib.c:2822
void * gen_NULL2(__attribute__((unused)) void *u1, __attribute__((unused)) void *u2)
idem with 2 args, to please overpeaky compiler checks
Definition: genClib.c:2770
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_false2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2801
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
void * gen_identity(const void *x)
Just return the argument.
Definition: genClib.c:2807
#define list_undefined_p(c)
Return if a list is undefined.
Definition: newgen_list.h:75
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
size_t list_own_allocated_memory(const list l)
Definition: list.c:158
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
char end
Definition: gtk_status.c:82
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
int hash_table_own_allocated_memory(hash_table htp)
Definition: hash.c:869
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
hash_key_type hash_table_type(hash_table htp)
returns the type of the hash_table.
Definition: hash.c:832
void hash_table_clear(hash_table htp)
Clears all entries of a hash table HTP.
Definition: hash.c:305
#define abort()
Definition: misc-local.h:53
#define message_assert(msg, ex)
Definition: newgen_assert.h:47
char * i2a(int)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
@ hash_chunk
Definition: newgen_hash.h:32
@ hash_pointer
Definition: newgen_hash.h:32
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56
#define hash_table_undefined
Value of an undefined hash_table.
Definition: newgen_hash.h:49
struct __hash_table * hash_table
Define hash_table structure which is hidden.
Definition: newgen_hash.h:43
#define IS_FLOAT_TYPE(n)
@ ARROW_OP
@ OR_OP
@ AND_OP
#define check_read_spec_performed()
#define IS_EXTERNAL(bp)
#define quick_domain_index(obj)
inlined version of domain_index.
gen_chunk * gen_tabulated_fake_object_hack(int)
WARNING: it is not reentrant...
Definition: tabulated.c:107
#define IS_INLINABLE(bp)
Different kinds of BINDING structure pointers.
#define IS_BOOL_TYPE(n)
#define NEWGEN_FREED
#define check_domain(dom)
@ EXTERNAL_DT
@ SET_DT
@ ARRAY_DT
@ LIST_DT
@ UNDEF_DT
@ BASIS_DT
@ IMPORT_DT
@ CONSTRUCTED_DT
#define HASH_OFFSET
For tabulated objects, the offset HASH_OFFSET of the hashed subdomain.
#define MAX_DOMAIN
MAX_DOMAIN is the maximum number of entries in the DOMAINS table.
#define IS_UNIT_TYPE(n)
void fatal(char *,...)
#define IS_STRING_TYPE(n)
void user(char *,...)
External routines.
#define IS_INT_TYPE(n)
gen_chunk * gen_enter_tabulated(int, char *, gen_chunk *, bool)
ENTER_TABULATED_DEF enters a new definition (previous refs are allowed if ALLOW_REF) in the INDEX tab...
Definition: tabulated.c:279
#define IS_TABULATED(bp)
#define same_string_p(s1, s2)
#define newgen_free(p)
void gen_mapc_tabulated(void(*)(gen_chunk *), int)
apply fp to domain...
Definition: tabulated.c:127
#define set_undefined
Definition: newgen_set.h:48
#define SET_MAP(element, code, the_set)
Definition: newgen_set.h:54
set set_assign(set, const set)
Assign a set with the content of another set.
Definition: set.c:129
int set_own_allocated_memory(const set)
Definition: set.c:423
void set_free(set)
Definition: set.c:332
#define set_undefined_p(s)
Definition: newgen_set.h:49
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
void * stack_head(const stack)
returns the item on top of stack s
Definition: stack.c:420
int stack_size(const stack)
observers
void stack_push(void *, stack)
stack use
Definition: stack.c:373
void stack_free(stack *)
type, bucket_size, policy
Definition: stack.c:292
stack stack_make(int, int, int)
allocation
Definition: stack.c:246
void * stack_pop(stack)
POPs one item from stack s.
Definition: stack.c:399
int bool
we cannot use an enum or stdbool because we need to be compatible with newgen, thus boolean need to h...
Definition: newgen_types.h:78
#define array_undefined_p(a)
Definition: newgen_types.h:104
#define true
Definition: newgen_types.h:81
#define string_undefined_p(s)
Definition: newgen_types.h:41
#define false
Definition: newgen_types.h:80
struct cons * list
Definition: newgen_types.h:106
#define array_undefined
ARRAY.
Definition: newgen_types.h:103
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
struct _newgen_struct_data_ * data
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
Pvecteur cp
pointeur sur l'egalite ou l'inegalite courante
Definition: sc_read.c:87
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
return(s1)
static char * x
Definition: split_file.c:159
static char buf[BSZ]
Definition: split_file.c:157
static size_t current
Definition: string.c:115
the stack head
Definition: stack.c:62
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
struct cons * cdr
The pointer to the next element.
Definition: newgen_list.h:43
gen_chunk car
The data payload of a list element.
Definition: newgen_list.h:42
Definition: delay.c:253
The DRIVER structure is used to monitor the general function which traverses objects.
Definition: genClib.c:365
void(* simple_out)()
Definition: genClib.c:371
void(* array_leaf)()
Definition: genClib.c:370
void(* null)()
Definition: genClib.c:366
void(* leaf_out)()
Definition: genClib.c:368
int(* simple_in)()
Definition: genClib.c:369
int(* leaf_in)()
Definition: genClib.c:367
void(* obj_out)()
Definition: genClib.c:373
int(* obj_in)()
Definition: genClib.c:372
union domain * domain
gen_tabulated_p tabulated
number of chunks to hold this data.
char * seen_once
Definition: genClib.c:803
int shared_number
Definition: genClib.c:805
char * first_seen
Definition: genClib.c:802
hash_table obj_table
Definition: genClib.c:804
translation tables type...
Definition: genClib.c:1929
bool identity
Definition: genClib.c:1930
int actual_to_old[MAX_DOMAIN]
forwards translation
Definition: genClib.c:1932
int old_to_actual[MAX_DOMAIN]
whether the translation is nope...
Definition: genClib.c:1931
INLINE[] gives, for each inlinable (i.e., unboxed) type, its NAME, its initial VALUE and its printing...
Definition: build.c:45
the current data needed for a multi recursion are stored in a multi recurse struct.
Definition: genClib.c:3109
gen_chunk * previous
Definition: genClib.c:3127
bool always_recurse
Definition: genClib.c:3114
GenFilterTableType * filters
Definition: genClib.c:3120
GenDecisionTableType * decisions
Definition: genClib.c:3118
GenDecisionTableType * domains
Definition: genClib.c:3116
GenRewriteTableType * rewrites
Definition: genClib.c:3121
gen_chunk * current
Definition: genClib.c:3129
void * context
Definition: genClib.c:3123
stack upwards
Definition: genClib.c:3125
hash_table seen
Definition: genClib.c:3111
void gen_clear_tabulated_element(gen_chunk *obj)
GEN_CLEAR_TABULATED_ELEMENT only clears the entry for object OBJ in the gen_tabulated_ and gen_tabula...
Definition: tabulated.c:251
@ keep
bj > b1 -> h1/hj = h1
Definition: union-local.h:61
A DOMAIN union describes the structure of a user type.
int(* allocated_memory)(void *)
struct gen_binding * element
enum domain_operator op
set_type what
struct domainlist * components
struct domain::@2 ex
int persistant
void *(* read)(FILE *, int(*)(void))
struct domain::@7 co
struct domain::@5 se
void *(* copy)(void *)
int type
EXTERNAL.
struct domain::@3 ba
struct intlist * dimensions
struct domain::@4 li
void(* free)(void *)
struct gen_binding * constructand
void(* write)(FILE *, void *)
struct domain::@6 ar
A gen_chunk is used to store every object.
Definition: genC.h:58
float f
Definition: genC.h:63
_int i
Definition: genC.h:62
struct cons * l
A pointer to a list element.
Definition: genC.h:66
set t
Definition: genC.h:67
bool b
Definition: genC.h:60
union gen_chunk * p
Definition: genC.h:69
string s
Definition: genC.h:64