PIPS
build.c
Go to the documentation of this file.
1 /*
2 
3  $Id: build.c 1372 2017-02-03 09:09:13Z 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 /*
24 
25  This file manages the building of the "data dictionary" (i.e. the Domains
26  table) and the generation of the specification file.
27 
28 */
29 #ifdef HAVE_CONFIG_H
30  #include "config.h"
31 #endif
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 
37 #include "genC.h"
38 #include "newgen_include.h"
39 
40 
41 /* INLINE[] gives, for each inlinable (i.e., unboxed) type, its NAME,
42  its initial VALUE and its printing FORMAT (for each language which can
43  be a target. */
44 
45 struct inlinable {
46  string name;
47  string C_value;
48  string C_format;
49  string Lisp_value;
50  string Lisp_format;
51 };
52 
53 static char *keywords[] = {
54  "external",
55  "import",
56  "tabulated",
57  "from",
58  "persistant",
59  NULL
60 } ;
61 
63 
64 /* Warning: this table knows about the actual values used for AND_OP
65  and OR_OP. */
66 
67 static char *Op_names[] = {
68  "-- shouldn't appear --",
69  "x",
70  "+",
71  "->"
72  } ;
73 
74 /* Have we seen a user error somewhere ? */
75 
77 
78 /* FATAL generates a fatal error by printing (according to FORMAT)
79  the given MSG. If there already is a user error, let's suppose that's
80  her fault ! */
81 
82 __attribute__((__noreturn__)) void
83 fatal(char * fmt, ...)
84 {
85  va_list args;
86  va_start(args, fmt);
87  fprintf( stderr, "\nNewgen Fatal Error -- " ) ;
88  vfprintf( stderr, fmt, args) ;
89  va_end(args);
90 
91  abort() ;
92 }
93 
94 /* USER generates a user error (i.e., non fatal) by printing the given MSG
95  according to the FMT.
96  */
97 __attribute__((__noreturn__)) void
98 user(char * fmt, ...)
99 {
100  va_list args;
101  va_start(args, fmt);
102 
103  fprintf( stderr, "\nNewgen User Error -- " ) ;
104  vfprintf( stderr, fmt, args ) ;
105  fflush(stderr);
106 
107  va_end(args);
108  error_seen++ ;
109 
110  // it seems that the parser may go on in a loop on some syntax errors...
111  // probably some issue in "genspec_lex.c"
112  abort();
113 }
114 
115 /* CHECK_NOT_KEYWORD checks if S isn't a reserved word. */
116 
117 void check_not_keyword(char *s)
118 {
119  char **sp ;
120 
121  for( sp = keywords ; *sp != NULL ; sp++ ) {
122  if( strcmp( s, *sp ) == 0 ) {
123  user( "Trying to use the reserved word %s\n", s ) ;
124  }
125  }
126 }
127 
128 /* INIT initializes global data structures. */
129 
130 void init(void)
131 {
132  struct gen_binding *bp ;
133  struct inlinable *ip ;
134 
135  /* FC: formats are directly inlined in genClib...
136  */
137  struct inlinable Inline[] = {
138  {UNIT_TYPE_NAME, "U", "U", ":unit", "U"},
139  {"bool", "1", "B%d", "newgen:gen-true", "~S"},
140  {"char", "#\\a", "#\\%c", "#\\space", "~C"},
141  {"int", "0", "%d", "0", "~D"},
142  {"float", "0.0", "%f", "0.0", "~F"},
143  {"string", "\"\"", "\"%s\"", "\"\"", "~S"},
144  {NULL, "-- HELP --", "-- HELP --", "-- HELP --", "-- HELP --"},
145  } ;
146 
147  for( bp = Domains ; bp < &Domains[ MAX_DOMAIN ] ; bp++ ) {
148  bp->name = NULL ;
149  bp->compiled = 0 ;
150  bp->size = 0 ;
151  bp->tabulated = NULL;
152  bp->domain = NULL ;
153  bp->inlined = NULL ;
154  }
155 
156  for( ip = Inline, bp = Domains ; ip->name != NULL ; ip++, bp++ ) {
157  bp->name = ip->name ;
158  bp->compiled = 1 ;
159  bp->inlined = ip ;
160  }
161 
162  /* Tabulated_bp hack is statically allocated here. */
163  {
164  static union domain d ;
165  bp->name = "Name for tabulated domain" ;
166  bp->domain = &d ;
167  d.ba.type = ARRAY_DT ;
168  d.ar.constructor = "Constructor for tabulated domain" ;
169  d.ar.element = (struct gen_binding *) NULL ;
170  d.ar.dimensions = (struct intlist *) NULL;
171  Tabulated_bp = bp ;
172  }
173 
174  Current_op = UNDEF_OP ;
175  Current_start = -1 ;
176  error_seen = 0 ;
177 }
178 
179 static int max_domain = -1 ;
180 
182 {
183  return max_domain;
184 }
185 
186 /* LOOKUP checks whether a given NAME is in the Domains table. If not, the
187  ACTION says whether this is an error or it should be introduced. If this
188  is for a new gen_binding, look in the current allocation range, else from
189  beginning */
190 
191 struct gen_binding * lookup(char * name, int action)
192 {
193  struct gen_binding *bp ;
194 
195  //bp = (action == NEW_BINDING) ? Tabulated_bp+Current_start+1 : Domains ;
196  bp = Domains + ((action == NEW_BINDING) ? Current_start : 0);
197 
198  for( ; bp < &Domains[ MAX_DOMAIN ] ; bp++ ) {
199  if( bp->name == NULL ) {
200  if( action == NEW_BINDING )
201  break ;
202  }
203  else if( strcmp( bp->name, name ) == 0 ) break ;
204  }
205  switch( action ) {
206  case NEW_BINDING:
207  if( bp == &Domains[ MAX_DOMAIN ] )
208  fatal( "lookup: Domains overflow on %s -- new\n", name ) ;
209 
210  break;
211  case OLD_BINDING:
212  if( bp == &Domains[ MAX_DOMAIN ] )
213  user( "Unknown domain <%s>\n", name ) ;
214 
215  break ;
216  default:
217  fatal( "lookup: Unknown type %s\n", i2a( action )) ;
218  }
219  if( max_domain < bp-Domains ) {
220  max_domain = bp-Domains ;
221  }
222  return( bp ) ;
223 }
224 
225 /* NEW_BINDING introduces a new pair (NAME, VAL) in the Domains table.
226  Redeclaration is allowed if this is to overwrite a previous IMPORT
227  definition. Note that we could (should ?) check that this new gen_binding
228  isn't a new (and incompatible) IMPORT definition. */
229 
230 struct gen_binding * new_binding(char * name, union domain * val)
231 {
232  struct gen_binding * bp;
233 
234  if( Read_spec_mode && val->ba.type == IMPORT_DT ) {
235  bp = lookup(name, OLD_BINDING);
236  }
237  else {
238  bp = lookup(name, NEW_BINDING);
239  }
240  if( bp->domain == NULL ) {
241 #ifdef DBG_BINDING
242  (void)fprintf(stderr, "Introducing %s at index %d\n",
243  name, bp-Domains ) ;
244 #endif
245  bp->domain = val ;
246  bp->name = name ;
247  }
248  else
249  {
250  if( val->ba.type == IMPORT_DT ||
251  (Read_spec_mode && val->ba.type == EXTERNAL_DT )) {
252  }
253  else
254  user( "Redeclaration skipped: <%s>\n", name ) ;
255  free(val);
256  }
257 
258  return( bp ) ;
259 }
260 
261 /* PRINT_DOMAINLIST prints, in the OUT stream, the List of domains, bound
262  together by an OPerator. */
263 
264 void
266  FILE *out ;
267  struct domainlist *l ;
268  int op ;
269 {
270  if( l == NULL )
271  fatal( "print_domainlist: null", "" ) ;
272 
273  for( ; l->cdr != NULL ; l = l->cdr ) {
274  print_domain( out, l->domain ) ;
275  (void)fprintf( out, " %s ", Op_names[ op ] ) ;
276  }
277  print_domain( out, l->domain ) ;
278 }
279 
280 void
282 FILE *out ;
283 union domain *dp ;
284 {
285  if( dp->ba.persistant ) {
286  (void)fprintf( out, "persistant " ) ;
287  }
288 }
289 
290 /* PRINT_DOMAIN prints on the OUT stream a domain denoted by the DP pointer.
291  This is done before the compilation so (STRUCT BINDING *) members are
292  still strings. */
293 
294 void print_domain(FILE * out, union domain * dp)
295 {
296  if (!dp) {
297  fprintf(out, " NULL union domain");
298  return;
299  }
300 
301  switch( dp->ba.type ) {
302  case EXTERNAL_DT:
303  break ;
304  case IMPORT_DT:
305  (void)fprintf( out, " from \"%s\"", dp->im.filename ) ;
306  break ;
307  case BASIS_DT:
308  (void)print_persistant( out, dp ) ;
309 #ifdef DBG_DOMAINS
310  (void)fprintf( out, "%s:%s (%d)",
311  dp->ba.constructor, dp->ba.constructand->name,
312  dp->ba.constructand-Domains ) ;
313 #else
314  (void)fprintf(out, "%s:%s",
315  dp->ba.constructor, dp->ba.constructand->name );
316 #endif
317  break ;
318  case LIST_DT:
319  print_persistant( out, dp ) ;
320  (void)fprintf(out, "%s:%s*",
321  dp->li.constructor, dp->li.element->name ) ;
322  break ;
323  case SET_DT:
324  print_persistant( out, dp ) ;
325  (void)fprintf(out, "%s:%s{}",
326  dp->se.constructor, dp->se.element->name ) ;
327  break ;
328  case ARRAY_DT: {
329  struct intlist *ilp ;
330 
331  print_persistant( out, dp ) ;
332  (void)fprintf(out, "%s:%s",
333  dp->ar.constructor, dp->ar.element->name ) ;
334 
335  for( ilp = dp->ar.dimensions ; ilp != NULL ; ilp = ilp->cdr )
336  (void)fprintf( out, "[%d]", ilp->val ) ;
337 
338  break ;
339  }
340  case CONSTRUCTED_DT:
341  print_domainlist( out, dp->co.components, dp->co.op ) ;
342  break ;
343  default:
344  fatal( "print_domain: switch on %s\n", i2a( dp->ba.type )) ;
345  }
346 }
347 
348 /* PRINT_DOMAINS prints on the OUT stream the Domains table. Inlined domains
349  aren't printed. */
350 
351 void
353 {
354  struct gen_binding *bp ;
355 
356  for( bp = Domains ; bp < &Domains[ MAX_DOMAIN ] ; bp++ ) {
357  if( bp->name == NULL || bp == Tabulated_bp ) continue ;
358 
359  if( !IS_INLINABLE( bp )) {
360 
361  /* if( (dp=bp->domain)->ba.type==CONSTRUCTED_DT && dp->co.op==OR_OP)
362  (void)fprintf( out, "--NEWGEN-FIRST %d\n", dp->co.first ) ; */
363 
364  (void)fprintf( out,
365  (IS_EXTERNAL( bp ) ? "external %s" :
366  IS_IMPORT( bp ) ? "import %s" :
367  IS_TABULATED( bp ) ? "tabulated %s = " :
368  "%s = "),
369  bp->name ) ;
370  print_domain( out, bp->domain ) ;
371  (void)fprintf( out, ";\n" ) ;
372  }
373  }
374 }
375 
376 /* RECONNECT replaces the (STRUCT BINDING *) members of the DP domain
377  which are, on entry, strings by their effective values, i.e. pointers
378  in the Domains table which have the corresponding names.
379 
380  FIRST members for OR_OP (checked with OP) domains are updated. */
381 
382 static int current_first ;
383 
384 void reconnect(int op, union domain * dp)
385 {
386  struct domainlist *dlp ;
387 
388  if( op == OR_OP ) current_first++ ;
389 
390  switch( dp->ba.type ) {
391  case EXTERNAL_DT:
392  case IMPORT_DT:
393  return ;
394  case BASIS_DT:
395  dp->ba.constructand = lookup( (char *)dp->ba.constructand, OLD_BINDING ) ;
396  break;
397  case LIST_DT:
398  dp->li.element = lookup( (char *)dp->li.element, OLD_BINDING ) ;
399  break ;
400  case SET_DT:
401  dp->se.element = lookup( (char *)dp->se.element, OLD_BINDING ) ;
402  break ;
403  case ARRAY_DT:
404  dp->ar.element = lookup( (char *)dp->ar.element, OLD_BINDING ) ;
405  break ;
406  case CONSTRUCTED_DT:
407  if( dp->co.op == OR_OP && !Read_spec_mode )
408  dp->co.first = current_first ;
409 
410  for( dlp = dp->co.components ; dlp != NULL ; dlp = dlp->cdr ) {
411  reconnect( dp->co.op, dlp->domain ) ;
412  }
413  return ;
414  default:
415  fatal( "reconnect: switch on %s\n", i2a( dp->ba.type )) ;
416  }
417 }
418 
419 /* COMPILE reconnects the Domains table (for not compiled types -- note that
420  an inlined type is already compiled). */
421 
422 void compile(void)
423 {
424  int i;
425  current_first = 0;
426 
427  for(i=0; i<MAX_DOMAIN; i++)
428  {
429  struct gen_binding * bp = &Domains[i];
430 
431  if( bp->name == NULL || bp->compiled || bp == Tabulated_bp )
432  continue ;
433 
434  reconnect( -1, bp->domain ) ;
435  bp->compiled = (bp->domain->ba.type != EXTERNAL_DT ) ;
436 
437  if( IS_TABULATED( bp )) {
438  union domain *dp = NULL;
439 
440  if( !(bp->domain->ba.type == CONSTRUCTED_DT &&
441  (dp=bp->domain->co.components->domain)->ba.type == BASIS_DT &&
442  strcmp( dp->ba.constructand->name, "string" ) == 0)) {
443  user( "compile: tabulated first %s domain isn't string\n",
444  dp->ba.constructand->name ) ;
445  }
446  }
447 
448  /* set size of domain. */
449  if (bp->domain->ba.type == BASIS_DT ||
450  bp->domain->ba.type == ARRAY_DT ||
451  bp->domain->ba.type == SET_DT ||
452  bp->domain->ba.type == LIST_DT ||
453  bp->domain->ba.type == CONSTRUCTED_DT)
454  bp->size = gen_size(i);
455  }
456 
457 #ifdef DBG_COMPILE
458  print_domains( stderr ) ;
459 #endif
460 }
461 
462 /* GEN_WRITE_SPEC prints the Domains table in the given FILENAME. */
463 
465 {
466  extern int fclose();
467  FILE *id ;
468 
469  if( (id = fopen( filename, "w" )) == NULL ) {
470  user( "Cannot open spec file %s in write mode\n", filename ) ;
471  return ;
472  }
473  print_domains( id ) ;
474 
475  if( fclose( id ))
476  user( "Cannot close spec file %s\n", filename ) ;
477 }
478 
479 /* BUILD (in fact, the "main" function) parses the specifications and generates
480  the manipulation functions. */
481 
482 /*ARGSUSED*/
483 int build(int argc, char * argv[])
484 {
485  init();
486  genspec_parse();
487  compile();
488 
489  if (error_seen == 0) {
490  if (argc<3)
491  user("not enough arguments provided, need 3, got %d!", argc);
492  gencode(argv[1]);
493  gen_write_spec(argv[2]);
494  return 0;
495  }
496  return 1;
497 }
498 
499 /* ALLOC is an "iron-clad" version of malloc(3). */
500 
501 char * alloc(int size)
502 {
503  char * p;
504 
505  if( (p=malloc( (unsigned)size )) == NULL && size != 0)
506  fatal( "alloc: No more memory for %s bytes\n", i2a( size )) ;
507 
508  return p;
509 }
static FILE * out
Definition: alias_check.c:128
void reconnect(int op, union domain *dp)
Definition: build.c:384
static char * keywords[]
Definition: build.c:53
void init(void)
INIT initializes global data structures.
Definition: build.c:130
int error_seen
Have we seen a user error somewhere ?
Definition: build.c:76
char * alloc(int size)
ALLOC is an "iron-clad" version of malloc(3).
Definition: build.c:501
static char * Op_names[]
Warning: this table knows about the actual values used for AND_OP and OR_OP.
Definition: build.c:67
static int current_first
RECONNECT replaces the (STRUCT BINDING *) members of the DP domain which are, on entry,...
Definition: build.c:382
int max_domain_index()
Definition: build.c:181
struct gen_binding * new_binding(char *name, union domain *val)
NEW_BINDING introduces a new pair (NAME, VAL) in the Domains table.
Definition: build.c:230
__attribute__((__noreturn__))
FATAL generates a fatal error by printing (according to FORMAT) the given MSG.
Definition: build.c:82
int Current_op
Used to check, while parsing specs, that a constructed domain use only one operator type.
Definition: build.c:62
void print_domains(FILE *out)
PRINT_DOMAINS prints on the OUT stream the Domains table.
Definition: build.c:352
void check_not_keyword(char *s)
CHECK_NOT_KEYWORD checks if S isn't a reserved word.
Definition: build.c:117
void gen_write_spec(char *filename)
GEN_WRITE_SPEC prints the Domains table in the given FILENAME.
Definition: build.c:464
struct gen_binding * lookup(char *name, int action)
LOOKUP checks whether a given NAME is in the Domains table.
Definition: build.c:191
void print_domainlist(out, l, op)
PRINT_DOMAINLIST prints, in the OUT stream, the List of domains, bound together by an OPerator.
Definition: build.c:265
int Current_start
Definition: build.c:62
static int max_domain
Definition: build.c:179
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 build(int argc, char *argv[])
BUILD (in fact, the "main" function) parses the specifications and generates the manipulation functio...
Definition: build.c:483
void print_persistant(out, dp)
Definition: build.c:281
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
void gencode(string file)
generate the code necessary to manipulate every internal non-inlinable type in the Domains table.
Definition: genC.c:928
struct gen_binding * Tabulated_bp
pointer to tabulated domain hack
Definition: genClib.c:58
int Read_spec_mode
extern int Current_first ;
Definition: genClib.c:60
void * malloc(YYSIZE_T)
void free(void *)
int genspec_parse(void)
struct gen_binding Domains[MAX_DOMAIN]
in build.c
Definition: genspec_yacc.c:114
#define abort()
Definition: misc-local.h:53
char * i2a(int)
I2A (Integer TO Ascii) yields a string for a given Integer.
Definition: string.c:121
#define OLD_BINDING
@ OR_OP
@ UNDEF_OP
#define IS_EXTERNAL(bp)
#define IS_INLINABLE(bp)
Different kinds of BINDING structure pointers.
@ EXTERNAL_DT
@ SET_DT
@ ARRAY_DT
@ LIST_DT
@ BASIS_DT
@ IMPORT_DT
@ CONSTRUCTED_DT
#define MAX_DOMAIN
MAX_DOMAIN is the maximum number of entries in the DOMAINS table.
void fatal(char *,...)
#define IS_IMPORT(bp)
void user(char *,...)
External routines.
#define IS_TABULATED(bp)
#define UNIT_TYPE_NAME
The UNIT_TYPE_NAME is the used to type expressions which only perform side-effects.
#define NEW_BINDING
Action parameter to the LOOKUP() function in the symbol table.
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
return(s1)
union domain * domain
struct inlinable * inlined
gen_tabulated_p tabulated
number of chunks to hold this data.
INLINE[] gives, for each inlinable (i.e., unboxed) type, its NAME, its initial VALUE and its printing...
Definition: build.c:45
string Lisp_value
Definition: build.c:49
string C_format
Definition: build.c:48
string Lisp_format
Definition: build.c:50
string C_value
Definition: build.c:47
string name
Definition: build.c:46
A DOMAIN union describes the structure of a user type.
char * constructor
struct gen_binding * element
enum domain_operator op
struct domainlist * components
int persistant
struct domain::@7 co
struct domain::@5 se
int type
EXTERNAL.
struct domain::@3 ba
struct domain::@8 im
struct intlist * dimensions
struct domain::@4 li
struct gen_binding * constructand
char * filename
struct domain::@6 ar