root/branches/mcstas-1.x/instrument.y

Revision 2886, 54.9 KB (checked in by farhi, 2 years ago)

grammar: redundant instrument parameters will use last definition for %include to work.

Line 
1/*******************************************************************************
2*
3* McStas, neutron ray-tracing package
4*         Copyright (C) 1997-2007, All rights reserved
5*         Risoe National Laboratory, Roskilde, Denmark
6*         Institut Laue Langevin, Grenoble, France
7*
8* Kernel: instrument.y
9*
10* %Identification
11* Written by: K.N.
12* Date: Jul  1, 1997
13* Origin: Risoe
14* Release: McStas X.Y.Z
15* Version: $Revision: 1.79 $
16*
17* Bison parser for instrument definition files.
18*
19* $Id: instrument.y,v 1.79 2007-09-03 16:10:26 farhi Exp $
20*
21*******************************************************************************/
22
23
24%{
25#include <math.h>
26#include <string.h>
27#include <stdio.h>
28
29#include "mcstas.h"
30
31#define YYERROR_VERBOSE 1
32#define YYDEBUG 1
33
34%}
35
36/* Need a pure parser to allow for recursive calls when autoloading component
37   definitions. */
38%pure_parser
39
40/*******************************************************************************
41* Type definition for semantic values.
42*******************************************************************************/
43
44%union {
45  char *number;
46  char *string;
47  struct code_block *ccode; /* User-supplied C code block */
48  CExp exp;     /* Expression datatype (for arguments) */
49  int linenum;      /* Starting line number for code block */
50  Coords_exp coords;    /* Coordinates for location or rotation */
51  List formals;     /* List of formal parameters */
52  List iformals;    /* List of formal instrument parameters */
53  List comp_iformals;   /* List of formal comp. input parameters */
54  struct instr_formal *iformal; /* Single formal instrument parameter */
55  struct comp_iformal *cformal; /* Single formal component input parameter */
56  Symtab actuals;   /* Values for formal parameters */
57  char **polform;   /* Polarisation state formal parameter */
58  struct {List def, set, out, state;
59    char **polarisation;} parms;  /* Parameter lists */
60  struct instr_def *instrument; /* Instrument definition */
61  struct comp_inst *instance; /* Component instance */
62  struct comp_place place;  /* Component place */
63  struct comp_orientation ori;  /* Component orientation */
64  struct NXinfo *nxinfo;  /* Info for NeXus interface */
65  struct group_inst *groupinst;
66  struct jump_struct *jump;
67  List   jumps;
68  struct jump_condition jumpcondition;
69  struct jump_name      jumpname;
70}
71
72%token TOK_RESTRICTED TOK_GENERAL
73
74%token TOK_ABSOLUTE   "ABSOLUTE"
75%token TOK_AT         "AT"
76%token TOK_COMPONENT  "COMPONENT"
77%token TOK_DECLARE    "DECLARE"
78%token TOK_DEFINE     "DEFINE"
79%token TOK_DEFINITION "DEFINITION"
80%token TOK_END        "END"
81%token TOK_FINALLY    "FINALLY"
82%token TOK_EXTERN     "EXTERN"  /* optional */
83%token TOK_INITIALIZE "INITIALIZE"
84%token TOK_INSTRUMENT "INSTRUMENT"
85%token TOK_MCDISPLAY  "MCDISPLAY"
86%token TOK_OUTPUT     "OUTPUT"
87%token TOK_PARAMETERS "PARAMETERS"
88%token TOK_POLARISATION "POLARISATION"
89%token TOK_RELATIVE   "RELATIVE"
90%token TOK_ROTATED    "ROTATED"
91%token TOK_PREVIOUS   "PREVIOUS"
92%token TOK_SETTING    "SETTING"
93%token TOK_STATE      "STATE"
94%token TOK_TRACE      "TRACE"
95%token TOK_SHARE      "SHARE"
96%token TOK_EXTEND     "EXTEND"
97%token TOK_GROUP      "GROUP"   /* extended McStas grammar */
98%token TOK_SAVE       "SAVE"
99%token TOK_NEXUS      "NEXUS"   /* optional */
100%token TOK_JUMP       "JUMP"    /* extended McStas grammar */
101%token TOK_WHEN       "WHEN"    /* extended McStas grammar */
102%token TOK_NEXT       "NEXT"    /* extended McStas grammar */
103%token TOK_ITERATE    "ITERATE" /* extended McStas grammar */
104%token TOK_MYSELF     "MYSELF"  /* extended McStas grammar */
105%token TOK_COPY       "COPY"    /* extended McStas grammar */
106%token TOK_SPLIT      "SPLIT"    /* extended McStas grammar */
107
108/*******************************************************************************
109* Declarations of terminals and nonterminals.
110*******************************************************************************/
111
112%token <string> TOK_ID    /* Note: returns new str_dup()'ed copy each time. */
113%token <string> TOK_STRING
114%token <number> TOK_NUMBER
115%token <string> TOK_CTOK
116%token <linenum> TOK_CODE_START
117%token TOK_CODE_END
118%token <string> TOK_CODE_LINE
119%token TOK_INVALID
120
121%type <instance> component compref reference instref
122%type <groupinst> groupdef groupref
123%type <ccode>   code codeblock share declare initialize trace extend save finally mcdisplay
124%type <coords>  coords
125%type <exp>     exp topexp topatexp genexp genatexp when split
126%type <actuals> actuallist actuals actuals1
127%type <comp_iformals> comp_iformallist comp_iformals comp_iformals1
128%type <cformal> comp_iformal
129%type <formals> formallist formals formals1 def_par set_par out_par state_par
130%type <iformals> instrpar_list instr_formals instr_formals1
131%type <iformal> instr_formal
132%type <polform> polarisation_par
133%type <parms>   parameters
134%type <place>   place
135%type <ori>     orientation
136%type <nxinfo>  nexus
137%type <string>  instname
138%type <number>  hdfversion
139%type <jump>    jump
140%type <jumps>   jumps jumps1
141%type <jumpname> jumpname
142%type <jumpcondition> jumpcondition
143%type <linenum> notshare
144%%
145
146main:     TOK_GENERAL compdefs instrument
147    | TOK_RESTRICTED compdef
148;
149
150/* COMPONENT grammar ************************************************************* */
151
152compdefs:   /* empty */
153    | compdefs compdef
154;
155
156compdef:    "DEFINE" "COMPONENT" TOK_ID parameters share declare initialize trace save finally mcdisplay "END"
157      {
158        struct comp_def *c;
159        palloc(c);
160        c->name = $3;
161        c->source = str_quote(instr_current_filename);
162        c->def_par = $4.def;
163        c->set_par = $4.set;
164        c->out_par = $4.out;
165        c->state_par = $4.state;
166        c->polarisation_par = $4.polarisation;
167        c->share_code = $5;
168        c->decl_code = $6;
169        c->init_code = $7;
170        c->trace_code = $8;
171        c->save_code = $9;
172        c->finally_code = $10;
173        c->mcdisplay_code = $11;
174        c->comp_inst_number = 0;
175
176        /* Check definition and setting params for uniqueness */
177        check_comp_formals(c->def_par, c->set_par, c->name);
178        /* Put component definition in table. */
179        symtab_add(read_components, c->name, c);
180        /* checks */
181        if (!list_len(c->state_par)) print_error("No particule state parameters defined in component "
182          "%s at line %s:%d.\n", $3, instr_current_filename, instr_current_line);
183        if (verbose) fprintf(stderr, "Embedding component %s from file %s\n", c->name, c->source);
184      }
185    | "DEFINE" "COMPONENT" TOK_ID "COPY" TOK_ID parameters share declare initialize trace save finally mcdisplay "END"
186      {
187        /* create a copy of a comp, and initiate it with given blocks */
188        /* all redefined blocks override */
189        struct comp_def *def;
190        def = read_component($5);
191        struct comp_def *c;
192        palloc(c);
193        c->name = $3;
194        c->source = str_quote(instr_current_filename);
195        /* only catenate if defined as non empty  */
196        c->def_par   = list_create(); list_cat(c->def_par, def->def_par);
197        if (list_len($6.def)) list_cat(c->def_par,$6.def);
198
199        c->set_par   = list_create(); list_cat(c->set_par, def->set_par);
200        if (list_len($6.set)) list_cat(c->set_par,$6.set);
201
202        c->out_par   = list_create(); list_cat(c->out_par, def->out_par);
203        if (list_len($6.out)) list_cat(c->out_par,$6.out);
204
205        c->state_par = (list_len($6.state) ? $6.state : def->state_par);
206        c->polarisation_par = ($6.polarisation ? $6.polarisation : def->polarisation_par);
207
208        c->share_code = ($7->linenum ?  $7  : def->share_code);
209        c->decl_code  = ($8->linenum ?  $8  : def->decl_code);
210        c->init_code  = ($9->linenum ?  $9  : def->init_code);
211        c->trace_code = ($10->linenum ? $10 : def->trace_code);
212        c->save_code  = ($11->linenum ? $11 : def->save_code);
213        c->finally_code = ($12->linenum ? $12 : def->finally_code);
214        c->mcdisplay_code = ($13->linenum ? $13 : def->mcdisplay_code);
215        c->comp_inst_number = 0;
216
217        /* Check definition and setting params for uniqueness */
218        check_comp_formals(c->def_par, c->set_par, c->name);
219        /* Put component definition in table. */
220        symtab_add(read_components, c->name, c);
221        /* checks */
222        if (!list_len(c->state_par)) print_error("No particule state parameters defined in (copied) component "
223          "%s at line %s:%d.\n", $3, instr_current_filename, instr_current_line);
224        if (verbose) fprintf(stderr, "Embedding component %s from file %s\n", c->name, c->source);
225
226      }
227;
228
229parameters:   def_par set_par out_par state_par polarisation_par
230      {
231        $$.def = $1;
232        $$.set = $2;
233        $$.out = $3;
234        $$.state = $4;
235        $$.polarisation = $5;
236      }
237;
238
239
240def_par:    /* empty */
241      {
242        $$ = list_create();
243      }
244    | "DEFINITION" "PARAMETERS" comp_iformallist
245      {
246        $$ = $3;
247      }
248;
249
250set_par:    /* empty */
251      {
252        $$ = list_create();
253      }
254    | "SETTING" "PARAMETERS" comp_iformallist
255      {
256        $$ = $3;
257      }
258;
259
260out_par:    /* empty */
261      {
262        $$ = list_create();
263      }
264    | "OUTPUT" "PARAMETERS" formallist
265      {
266        $$ = $3;
267      }
268;
269
270state_par:    /* empty */
271      {
272        $$ = list_create();
273      }
274    | "STATE" "PARAMETERS" formallist
275      {
276        $$ = $3;
277      }
278;
279
280polarisation_par: /* empty */
281      {
282        $$ = NULL;
283      }
284    | "POLARISATION" "PARAMETERS" '(' TOK_ID ',' TOK_ID ',' TOK_ID ')'
285      {
286        char **polform;
287        nalloc(polform, 3);
288        polform[0] = $4;
289        polform[1] = $6;
290        polform[2] = $8;
291        $$ = polform;
292      }
293;
294
295comp_iformallist: '(' comp_iformals ')'
296      {
297        $$ = $2;
298      }
299;
300
301comp_iformals:    /* empty */
302      {
303        $$ = list_create();
304      }
305    | comp_iformals1
306      {
307        $$ = $1;
308      }
309;
310
311comp_iformals1:   comp_iformal
312      {
313        $$ = list_create();
314        list_add($$, $1);
315      }
316    | comp_iformals1 ',' comp_iformal
317      {
318        list_add($1, $3);
319        $$ = $1;
320      }
321;
322
323comp_iformal:  TOK_ID TOK_ID
324      {
325        struct comp_iformal *formal;
326        palloc(formal);
327        if(!strcmp($1, "double")) {
328          formal->type = instr_type_double;
329        } else if(!strcmp($1, "int")) {
330          formal->type = instr_type_int;
331        } else if(!strcmp($1, "string")) {
332          formal->type = instr_type_string;
333        } else {
334          print_error("Illegal type %s for component "
335          "parameter %s at line %s:%d.\n", $1, $2, instr_current_filename, instr_current_line);
336          formal->type = instr_type_double;
337        }
338        formal->id = $2;
339        $$ = formal;
340      }
341    | TOK_ID '*' TOK_ID
342      {
343        struct comp_iformal *formal;
344        palloc(formal);
345        if(!strcmp($1, "char")) {
346          formal->type = instr_type_string;
347        } else {
348          print_error("Illegal type %s* for component "
349          "parameter %s at line $s:%d.\n", $1, $3, instr_current_filename, instr_current_line);
350          formal->type = instr_type_double;
351        }
352        formal->id = $3;
353        $$ = formal;
354      }
355    | TOK_ID
356      {
357        struct comp_iformal *formal;
358        palloc(formal);
359        formal->id = str_dup($1);
360        formal->isoptional = 0; /* No default value */
361        formal->type = instr_type_double;
362        $$ = formal;
363      }
364    | TOK_ID '=' exp
365      {
366        struct comp_iformal *formal;
367        palloc(formal);
368        formal->id = $1;
369        formal->isoptional = 1; /* Default value available */
370        formal->default_value = $3;
371        formal->type = instr_type_double;
372        $$ = formal;
373      }
374    | TOK_ID TOK_ID '=' exp
375      {
376        struct comp_iformal *formal;
377        palloc(formal);
378        if(!strcmp($1, "double")) {
379          formal->type = instr_type_double;
380        } else if(!strcmp($1, "int")) {
381          formal->type = instr_type_int;
382        } else if(!strcmp($1, "string")) {
383          formal->type = instr_type_string;
384        } else {
385          print_error("Illegal type %s for component "
386          "parameter %s at line %s:%d.\n", $1, $2, instr_current_filename, instr_current_line);
387          formal->type = instr_type_double;
388        }
389        formal->id = $2;
390        formal->isoptional = 1; /* Default value available */
391        formal->default_value = $4;
392        $$ = formal;
393      }
394    | TOK_ID '*' TOK_ID '=' exp
395      {
396        struct comp_iformal *formal;
397        palloc(formal);
398        formal->id = $3;
399        formal->isoptional = 1; /* Default value available */
400        formal->default_value = $5;
401        if(!strcmp($1, "char")) {
402          formal->type = instr_type_string;
403        } else {
404          print_error("Illegal type %s* for component "
405          "parameter %s at line %s:%d.\n", $1, $3, instr_current_filename, instr_current_line);
406          formal->type = instr_type_double;
407        }
408        $$ = formal;
409      }
410;
411
412/* INSTRUMENT grammar ************************************************************* */
413
414/* read instrument definition and catenate if this not the first instance */
415instrument:   "DEFINE" "INSTRUMENT" TOK_ID instrpar_list
416      { if (!instrument_definition->formals) instrument_definition->formals = $4;
417        else { if (list_len($4)) list_cat(instrument_definition->formals,$4); }
418        if (!instrument_definition->name)    instrument_definition->name = $3;
419        else {
420          if (verbose) fprintf(stderr, "Catenate instrument %s to master instrument %s\n", $3, instrument_definition->name);
421          instrument_definition->has_included_instr++;
422        }
423      }
424      declare initialize nexus instr_trace save finally "END"
425      {
426        if (!instrument_definition->decls) instrument_definition->decls = $6;
427        else list_cat(instrument_definition->decls->lines, $6->lines);
428        if (!instrument_definition->inits) instrument_definition->inits = $7;
429        else list_cat(instrument_definition->inits->lines, $7->lines);
430        if (!instrument_definition->nxinfo) instrument_definition->nxinfo = $8;
431        if (!instrument_definition->saves) instrument_definition->saves = $10;
432        else list_cat(instrument_definition->saves->lines, $10->lines);
433        if (!instrument_definition->finals) instrument_definition->finals = $11;
434        else list_cat(instrument_definition->finals->lines, $11->lines);
435        instrument_definition->compmap = comp_instances;
436        instrument_definition->groupmap = group_instances;
437        instrument_definition->complist = comp_instances_list;
438        instrument_definition->grouplist = group_instances_list;
439
440        /* Check instrument parameters for uniqueness */
441        check_instrument_formals(instrument_definition->formals,
442               instrument_definition->name);
443        if (verbose) fprintf(stderr, "Creating instrument %s (with %i component instances)\n", $3, comp_current_index);
444      }
445;
446
447/* The instrument parameters may be either double (for numeric input),
448   int (for integer-only), or char * (for strings). */
449instrpar_list:    '(' instr_formals ')'
450      {
451        $$ = $2;
452      }
453;
454
455instr_formals:    /* empty */
456      {
457        $$ = list_create();
458      }
459    | instr_formals1
460      {
461        $$ = $1;
462      }
463;
464
465instr_formals1:   instr_formal
466      {
467        $$ = list_create();
468        list_add($$, $1);
469      }
470    | instr_formals1 ',' instr_formal
471      {
472        list_add($1, $3);
473        $$ = $1;
474      }
475;
476
477instr_formal:   TOK_ID TOK_ID
478      {
479        struct instr_formal *formal;
480        palloc(formal);
481        if(!strcmp($1, "double")) {
482          formal->type = instr_type_double;
483        } else if(!strcmp($1, "int")) {
484          formal->type = instr_type_int;
485        } else if(!strcmp($1, "string")) {
486          formal->type = instr_type_string;
487        } else {
488          print_error("Illegal type %s for instrument "
489          "parameter %s at line %s:%d.\n", $1, $2, instr_current_filename, instr_current_line);
490          formal->type = instr_type_double;
491        }
492        formal->id = $2;
493        $$ = formal;
494      }
495    | TOK_ID '*' TOK_ID
496      {
497        struct instr_formal *formal;
498        palloc(formal);
499        if(!strcmp($1, "char")) {
500          formal->type = instr_type_string;
501        } else {
502          print_error("Illegal type $s* for instrument "
503          "parameter %s at line %s:%d.\n", $1, $3, instr_current_filename, instr_current_line);
504          formal->type = instr_type_double;
505        }
506        formal->id = $3;
507        $$ = formal;
508      }
509    | TOK_ID  /* Default type is "double" */
510      {
511        struct instr_formal *formal;
512        palloc(formal);
513        formal->type = instr_type_double;
514        formal->id = $1;
515        formal->isoptional = 0; /* No default value */
516        $$ = formal;
517      }
518    | TOK_ID '=' exp
519      {
520        struct instr_formal *formal;
521        palloc(formal);
522        formal->id = $1;
523        formal->isoptional = 1; /* Default value available */
524        formal->default_value = $3;
525        formal->type = instr_type_double;
526        $$ = formal;
527      }
528    | TOK_ID TOK_ID '=' exp
529      {
530        struct instr_formal *formal;
531        palloc(formal);
532        if(!strcmp($1, "double")) {
533          formal->type = instr_type_double;
534        } else if(!strcmp($1, "int")) {
535          formal->type = instr_type_int;
536        } else if(!strcmp($1, "string")) {
537          formal->type = instr_type_string;
538        } else {
539          print_error("Illegal type %s for instrument "
540          "parameter %s at line %s:%d.\n", $1, $2, instr_current_filename, instr_current_line);
541          formal->type = instr_type_double;
542        }
543        formal->id = $2;
544        formal->isoptional = 1; /* Default value available */
545        formal->default_value = $4;
546        $$ = formal;
547      }
548    | TOK_ID '*' TOK_ID '=' exp
549      {
550        struct instr_formal *formal;
551        palloc(formal);
552        formal->id = $3;
553        formal->isoptional = 1; /* Default value available */
554        formal->default_value = $5;
555        if(!strcmp($1, "char")) {
556          formal->type = instr_type_string;
557        } else {
558          print_error("Illegal type %s* for instrument "
559          "parameter %s at line %s:%d.\n", $1, $3, instr_current_filename, instr_current_line);
560          formal->type = instr_type_double;
561        }
562        $$ = formal;
563      }
564;
565
566/* NeXus output support */
567nexus:      /* empty: default NeXus support */
568      {
569        struct NXinfo *nxinfo;
570        palloc(nxinfo);
571        nxinfo->any = 0;
572        nxinfo->hdfversion    = NULL;
573        $$ = nxinfo;
574      }
575    | nexus "NEXUS" hdfversion
576      { /* specify NeXus version */
577        struct NXinfo *nxinfo = $1;
578        nxinfo->hdfversion    = $3;
579        nxinfo->any = 1;
580        $$ = nxinfo;
581      }
582;
583hdfversion: /* empty: default HDF version */
584      {
585        $$ = "5 zip";
586      }
587    | hdfversion TOK_STRING
588      {
589        $$ = $1;
590      }
591;
592
593
594declare:    /* empty */
595      {
596        $$ = codeblock_new();
597      }
598    | "DECLARE" codeblock
599      {
600        $$ = $2;
601      }
602    | "DECLARE" "COPY" TOK_ID
603      {
604        struct comp_def *def;
605        def = read_component($3);
606        $$ = def->decl_code;
607      }
608    | "DECLARE" "COPY" TOK_ID "EXTEND" codeblock
609      {
610        struct comp_def   *def;
611        struct code_block *cb;
612        cb = codeblock_new();
613        def = read_component($3);
614        cb->filename        = def->decl_code->filename;
615        cb->quoted_filename = def->decl_code->quoted_filename;
616        cb->linenum         = def->decl_code->linenum;
617        list_cat(cb->lines, def->decl_code->lines);
618        list_cat(cb->lines, $5->lines);
619        $$ = cb;
620      }
621;
622
623initialize:   /* empty */
624      {
625        $$ = codeblock_new();
626      }
627    | "INITIALIZE" "COPY" TOK_ID
628      {
629        struct comp_def *def;
630        def = read_component($3);
631        $$ = def->init_code;
632      }
633    | "INITIALIZE" "COPY" TOK_ID "EXTEND" codeblock
634      {
635        struct comp_def   *def;
636        struct code_block *cb;
637        cb = codeblock_new();
638        def = read_component($3);
639        cb->filename        = def->init_code->filename;
640        cb->quoted_filename = def->init_code->quoted_filename;
641        cb->linenum         = def->init_code->linenum;
642        list_cat(cb->lines, def->init_code->lines);
643        list_cat(cb->lines, $5->lines);
644        $$ = cb;
645      }
646    | "INITIALIZE" codeblock
647      {
648        $$ = $2;
649      }
650;
651
652/* SHARE component block included once. Toggle comp_inst_number sign from neg to pos in cogen.c */
653share:    /* empty */
654      {
655        $$ = codeblock_new();
656      }
657    | "SHARE" codeblock
658      {
659        $$ = $2;
660      }
661    | "SHARE" "COPY" TOK_ID
662      {
663        struct comp_def *def;
664        def = read_component($3);
665        $$ = def->share_code;
666      }
667    | "SHARE" "COPY" TOK_ID "EXTEND" codeblock
668      {
669        struct comp_def *def;
670        struct code_block *cb;
671        cb = codeblock_new();
672        def = read_component($3);
673        cb->filename        = def->share_code->filename;
674        cb->quoted_filename = def->share_code->quoted_filename;
675        cb->linenum         = def->share_code->linenum;
676        list_cat(cb->lines, def->share_code->lines);
677        list_cat(cb->lines, $5->lines);
678        $$ = cb;
679      }
680
681;
682
683
684trace: /* empty */
685      {
686        $$ = codeblock_new();
687      }
688    | "TRACE" codeblock
689      {
690        $$ = $2;
691      }
692    | "TRACE" "COPY" TOK_ID
693      {
694        struct comp_def *def;
695        def = read_component($3);
696        $$ = def->trace_code;
697      }
698    | "TRACE" "COPY" TOK_ID "EXTEND" codeblock
699      {
700        struct comp_def *def;
701        struct code_block *cb;
702        cb = codeblock_new();
703        def = read_component($3);
704        cb->filename        = def->trace_code->filename;
705        cb->quoted_filename = def->trace_code->quoted_filename;
706        cb->linenum         = def->trace_code->linenum;
707        list_cat(cb->lines, def->trace_code->lines);
708        list_cat(cb->lines, $5->lines);
709        $$ = cb;
710      }
711;
712
713save:   /* empty */
714      {
715        $$ = codeblock_new();
716      }
717    | "SAVE" codeblock
718      {
719        $$ = $2;
720      }
721    | "SAVE" "COPY" TOK_ID
722      {
723        struct comp_def *def;
724        def = read_component($3);
725        $$ = def->save_code;
726      }
727    | "SAVE" "COPY" TOK_ID "EXTEND" codeblock
728      {
729        struct comp_def *def;
730        struct code_block *cb;
731        cb = codeblock_new();
732        def = read_component($3);
733        cb->filename        = def->save_code->filename;
734        cb->quoted_filename = def->save_code->quoted_filename;
735        cb->linenum         = def->save_code->linenum;
736        list_cat(cb->lines, def->save_code->lines);
737        list_cat(cb->lines, $5->lines);
738        $$ = cb;
739      }
740;
741
742finally:    /* empty */
743      {
744        $$ = codeblock_new();
745      }
746    | "FINALLY" codeblock
747      {
748        $$ = $2;
749      }
750    | "FINALLY" "COPY" TOK_ID
751      {
752        struct comp_def *def;
753        def = read_component($3);
754        $$ = def->finally_code;
755      }
756    | "FINALLY" "COPY" TOK_ID "EXTEND" codeblock
757      {
758        struct comp_def *def;
759        struct code_block *cb;
760        cb = codeblock_new();
761        def = read_component($3);
762        cb->filename        = def->finally_code->filename;
763        cb->quoted_filename = def->finally_code->quoted_filename;
764        cb->linenum         = def->finally_code->linenum;
765        list_cat(cb->lines, def->finally_code->lines);
766        list_cat(cb->lines, $5->lines);
767        $$ = cb;
768      }
769;
770
771mcdisplay:    /* empty */
772      {
773        $$ = codeblock_new();
774      }
775    | "MCDISPLAY" codeblock
776      {
777        $$ = $2;
778      }
779    | "MCDISPLAY" "COPY" TOK_ID
780      {
781        struct comp_def *def;
782        def = read_component($3);
783        $$ = def->mcdisplay_code;
784      }
785    | "MCDISPLAY" "COPY" TOK_ID "EXTEND" codeblock
786      {
787        struct comp_def *def;
788        struct code_block *cb;
789        cb = codeblock_new();
790        def = read_component($3);
791        cb->filename        = def->mcdisplay_code->filename;
792        cb->quoted_filename = def->mcdisplay_code->quoted_filename;
793        cb->linenum         = def->mcdisplay_code->linenum;
794        list_cat(cb->lines, def->mcdisplay_code->lines);
795        list_cat(cb->lines, $5->lines);
796        $$ = cb;
797      }
798;
799
800instr_trace:    "TRACE" complist
801;
802complist:   /* empty */
803      {
804        if (!comp_instances)      comp_instances      = symtab_create();
805        if (!comp_instances_list) comp_instances_list = list_create();
806        if (!group_instances)     group_instances     = symtab_create();
807        if (!group_instances_list)group_instances_list= list_create();
808      }
809    | complist component
810      {
811        if (!$2->removable) { /* must not be an INSTRUMENT COMPONENT after %include instr */
812          /* Check that the component instance name has not
813                        been used before. */
814          if(symtab_lookup(comp_instances, $2->name))
815          {
816            print_error("Multiple use of component instance name "
817            "'%s' at line %s:%d.\n", $2->name, instr_current_filename, instr_current_line);
818            /* Since this is an error condition, we do not
819              worry about freeing the memory allocated for
820              the component instance. */
821          }
822          else
823          {
824            symtab_add(comp_instances, $2->name, $2);
825            list_add(comp_instances_list, $2);
826            if($2->def)
827            {
828              /* Check if the component handles polarisation. */
829              if($2->def->polarisation_par)
830              {
831                instrument_definition->polarised = 1;
832              }
833            }
834            if (verbose) fprintf(stderr, "Component[%i]: %s = %s().\n", comp_current_index, $2->name, $2->type);
835          }
836        } /* if shared */
837        else
838        {
839          if (verbose) fprintf(stderr, "Component[%i]: %s = %s() SKIPPED (INSTRUMENT COMPONENT, removable when included)\n", comp_current_index, $2->name, $2->type);
840        }
841      }
842    | complist instrument
843    {
844      /* included instrument */
845    }
846;
847
848instname: "COPY" '(' TOK_ID ')'
849      {
850        char str_index[10];
851        sprintf(str_index, "_%i", comp_current_index+1);
852        $$ = str_cat($3, str_index, NULL);
853      }
854    | TOK_ID
855      {
856        $$ = $1;
857      }
858;
859
860instref: "COPY" '(' compref ')' actuallist /* make a copy of a previous instance, with def+set */
861      {
862        struct comp_inst *comp_src;
863        struct comp_inst *comp;
864        comp_src = $3;
865        palloc(comp);
866        comp->type   = comp_src->type;
867        comp->def    = comp_src->def;
868        comp->extend = comp_src->extend;
869        comp->group  = comp_src->group;
870        comp->jump   = comp_src->jump;
871        comp->when   = comp_src->when;
872        /* now catenate src and actual parameters */
873        comp->actuals= symtab_create();
874        symtab_cat(comp->actuals, $5);
875        symtab_cat(comp->actuals, comp_src->actuals);
876        comp_formals_actuals(comp, comp->actuals);
877        $$ = comp;
878      }
879    | "COPY" '(' compref ')'
880      {
881        struct comp_inst *comp_src;
882        struct comp_inst *comp;
883        comp_src = $3;
884        palloc(comp);
885        comp->type   = comp_src->type;
886        comp->defpar = comp_src->defpar;
887        comp->setpar = comp_src->setpar;
888        comp->def    = comp_src->def;
889        comp->extend = comp_src->extend;
890        comp->group  = comp_src->group;
891        comp->jump   = comp_src->jump;
892        comp->when   = comp_src->when;
893        comp->actuals= comp_src->actuals;
894        $$ = comp;
895      }
896    | TOK_ID actuallist /* define new instance with def+set parameters */
897      {
898        struct comp_def *def;
899        struct comp_inst *comp;
900        def = read_component($1);
901        if (def != NULL) def->comp_inst_number--;
902        palloc(comp);
903        comp->type         = $1;
904        comp->def          = def;
905        comp->extend = codeblock_new();
906        comp->group  = NULL;
907        comp->jump   = list_create();
908        comp->when   = NULL;
909        comp->actuals= $2;
910        if(def != NULL)
911        {
912          /* Check actual parameters against definition and
913                         setting parameters. */
914          comp_formals_actuals(comp, comp->actuals);
915        }
916        $$ = comp;
917      }
918;
919
920notshare:    /* empty */
921      {
922        $$ = 0;
923      }
924    | "INSTRUMENT"
925      {
926        $$ = instrument_definition->has_included_instr; /* ignore comp if included from other instrument */
927      }
928;
929
930/* INSTRUMENT TRACE grammar ******************************************************* */
931
932component: notshare split "COMPONENT" instname '=' instref when place orientation groupref extend jumps
933      {
934        struct comp_inst *comp;
935
936        comp = $6;
937        if (comp->def != NULL) comp->def->comp_inst_number--;
938
939        comp->name  = $4;
940        comp->split = $2;
941        comp->removable = $1;
942
943        if ($7) comp->when  = $7;
944
945        palloc(comp->pos);
946        comp->pos->place           = $8.place;
947        comp->pos->place_rel       = $8.place_rel;
948        comp->pos->orientation     = $9.orientation;
949        comp->pos->orientation_rel =
950            $9.isdefault ? $8.place_rel : $9.orientation_rel;
951
952        if ($10) {
953          comp->group = $10;    /* component is part of an exclusive group */
954          /* store first and last comp of group. Check if a SPLIT is inside */
955          if (!comp->group->first_comp) comp->group->first_comp =comp->name;
956          comp->group->last_comp=comp->name;
957          if (comp->split && !comp->group->split) comp->group->split = comp->split;
958        }
959        if ($11->linenum)   comp->extend= $11;  /* EXTEND block*/
960        if (list_len($12))  comp->jump  = $12;
961        comp->index = ++comp_current_index;     /* index of comp instance */
962
963        debugn((DEBUG_HIGH, "Component[%i]: %s = %s().\n", comp_current_index, $4, $6->type));
964        /* this comp will be 'previous' for the next, except if removed at include */
965        if (!comp->removable) previous_comp = comp;
966        $$ = comp;
967
968      }
969;
970
971split:    /* empty */
972      {
973        $$ = NULL;
974      }
975    | "SPLIT"
976      {
977        $$ = exp_number("10");
978      }
979    | "SPLIT" exp
980      {
981        $$ = $2;
982      }
983;
984
985formallist:   '(' formals ')'
986      {
987        $$ = $2;
988      }
989;
990
991
992formals:    /* empty */
993      {
994        $$ = list_create();
995      }
996    | formals1
997      {
998        $$ = $1;
999      }
1000;
1001
1002formals1:   TOK_ID
1003      {
1004        $$ = list_create();
1005        list_add($$, $1);
1006      }
1007    | formals1 ',' TOK_ID
1008      {
1009        list_add($1, $3);
1010        $$ = $1;
1011      }
1012;
1013
1014actuallist:   '(' actuals ')'
1015      {
1016        $$ = $2;
1017      }
1018;
1019
1020actuals:    /* empty */
1021      {
1022        $$ = symtab_create();
1023      }
1024    | actuals1
1025      {
1026        $$ = $1;
1027      }
1028;
1029
1030actuals1:   TOK_ID '=' exp
1031      {
1032        $$ = symtab_create();
1033        symtab_add($$, $1, $3);
1034        str_free($1);
1035      }
1036    | actuals1 ',' TOK_ID '=' exp
1037      {
1038        symtab_add($1, $3, $5);
1039        str_free($3);
1040        $$ = $1;
1041      }
1042;
1043
1044when: /* empty */
1045    {
1046      $$ = NULL;
1047    }
1048  | "WHEN" exp
1049    {
1050      $$ = $2;
1051    }
1052;
1053
1054place:      "AT" coords reference
1055      {
1056        $$.place = $2;
1057        $$.place_rel = $3;
1058      }
1059;
1060
1061orientation:    /* empty */
1062      {
1063        $$.orientation = coords_exp_origo(); /* Default to (0,0,0). */
1064        $$.isdefault = 1; /* No ROTATED modifier was present */
1065      }
1066    | "ROTATED" coords reference
1067      {
1068        $$.orientation = $2;
1069        $$.orientation_rel = $3;
1070        $$.isdefault = 0;
1071      }
1072;
1073
1074
1075reference:    "ABSOLUTE"
1076      {
1077        $$ = NULL;
1078      }
1079    | "RELATIVE" "ABSOLUTE"
1080      {
1081        $$ = NULL; /* tolerate this reference error */
1082      }
1083    | "RELATIVE" compref
1084      {
1085        $$ = $2;
1086      }
1087;
1088
1089/* component is part of an exclusive group */
1090groupref:  /* empty */
1091      {
1092        $$ = NULL;
1093      }
1094    | "GROUP" groupdef
1095      {
1096        $$ = $2;
1097      }
1098;
1099
1100groupdef:   TOK_ID
1101      {
1102        struct group_inst *group;
1103        struct Symtab_entry *ent;
1104
1105        ent = symtab_lookup(group_instances, $1);
1106        if(ent == NULL)
1107        {
1108          palloc(group);    /* create new group instance */
1109          group->name       = $1;
1110          group->index      = 0;
1111          group->first_comp = NULL;
1112          group->last_comp  = NULL;
1113          group->split      = NULL;
1114          symtab_add(group_instances, $1, group);
1115          list_add(group_instances_list, group);
1116        }
1117        else
1118          group = ent->val;
1119        $$ = group;
1120      }
1121;
1122
1123compref: "PREVIOUS"
1124      {
1125        if (previous_comp) {
1126          $$ = previous_comp;
1127        } else {
1128          print_warn(NULL, "Found invalid PREVIOUS reference at line %s:%d. Using ABSOLUTE.\n", instr_current_filename, instr_current_line);
1129          $$ = NULL;
1130        }
1131      }
1132    | "PREVIOUS" '(' TOK_NUMBER ')'
1133      {
1134        /* get the $3 previous item in comp_instances */
1135        struct Symtab_entry *entry;
1136        int index;
1137        index = atoi($3);
1138        entry = symtab_previous(comp_instances, index);
1139        if (!index || !entry) { /* invalid index reference */
1140          print_warn(NULL, "Found invalid PREVIOUS(%i) reference at line %s:%d. Using ABSOLUTE.\n", index, instr_current_filename, instr_current_line);
1141          $$ = NULL;
1142        } else {
1143          $$ = entry->val;
1144        }
1145      }
1146    | TOK_ID
1147      {
1148        struct comp_inst *comp;
1149        struct Symtab_entry *ent;
1150
1151        ent = symtab_lookup(comp_instances, $1);
1152        comp = NULL;
1153        if(ent == NULL)
1154          print_error("Reference to undefined component %s at line %s:%d.\n",
1155          $1, instr_current_filename, instr_current_line);
1156        else
1157          comp = ent->val;
1158        str_free($1);
1159        $$ = comp;
1160      }
1161;
1162
1163coords:     '(' exp ',' exp ',' exp ')'
1164      {
1165        $$.x = $2;
1166        $$.y = $4;
1167        $$.z = $6;
1168      }
1169;
1170
1171/* EXTEND block executed after component instance */
1172extend:   /* empty */
1173      {
1174        $$ = codeblock_new();
1175      }
1176    | "EXTEND" codeblock
1177      {
1178        $$ = $2;
1179      }
1180;
1181
1182jumps: /* empty */
1183    {
1184      $$ = list_create();
1185    }
1186  | jumps1
1187    {
1188      $$ = $1;
1189    }
1190;
1191
1192jumps1: jump
1193    {
1194      $$ = list_create();
1195      list_add($$, $1);
1196    }
1197  | jumps1 jump
1198    {
1199      list_add($1, $2);
1200      $$ = $1;
1201    }
1202;
1203
1204jump: "JUMP" jumpname jumpcondition
1205    {
1206      struct jump_struct *jump;
1207      palloc(jump);
1208      jump->target      =$2.name;
1209      jump->target_index=$2.index;
1210      jump->condition  = $3.condition;
1211      jump->iterate    = $3.iterate;
1212      $$=jump;
1213    }
1214;
1215
1216jumpcondition: "WHEN" exp
1217    {
1218      $$.condition = $2;
1219      $$.iterate   = 0;
1220    }
1221  | "ITERATE" exp
1222    {
1223      $$.condition = $2;
1224      $$.iterate   = 1;
1225    }
1226;
1227
1228jumpname: "PREVIOUS"
1229    {
1230      $$.name  = NULL;
1231      $$.index = -1;
1232    }
1233  | "PREVIOUS" '(' TOK_NUMBER ')'
1234    {
1235      $$.name  = NULL;
1236      $$.index = -atoi($3);
1237    }
1238  | "MYSELF"
1239    {
1240      $$.name  = NULL;
1241      $$.index = 0;
1242    }
1243  | "NEXT"
1244    {
1245      $$.name  = NULL;
1246      $$.index = +1;
1247    }
1248  | "NEXT" '(' TOK_NUMBER ')'
1249    {
1250      $$.name  = NULL;
1251      $$.index = +atoi($3);    }
1252  | TOK_ID
1253    {
1254      $$.name  = str_dup($1);
1255      $$.index = 0;
1256    }
1257;
1258
1259/* C expressions used to give component actual parameters.
1260   Top-level comma (',') operator NOT allowed. */
1261exp:      { $<linenum>$ = instr_current_line; } topexp
1262      {
1263        CExp e = $2;
1264        exp_setlineno(e, $<linenum>1 );
1265        $$ = e;
1266      }
1267    | "EXTERN" { $<linenum>$ = instr_current_line; } TOK_ID
1268      {
1269        CExp e;
1270        /* Note: "EXTERN" is now obsolete and redundant. */
1271        e = exp_extern_id($3);
1272        exp_setlineno(e, $<linenum>2 );
1273        str_free($3);
1274        $$ = e;
1275      }
1276;
1277
1278topexp:     topatexp
1279      {
1280        $$ = $1;
1281      }
1282    | topexp topatexp
1283      {
1284        $$ = exp_compound(2, $1, $2);
1285        exp_free($2);
1286        exp_free($1);
1287      }
1288;
1289
1290/* An atomic top-level C expression: either a parenthesized expression, or a
1291   single token that is NOT comma (','). */
1292topatexp:   TOK_ID
1293      {
1294        List_handle liter=NULL;
1295        struct instr_formal *formal;
1296        /* Check if this is an instrument parameter or not. */
1297        /* ToDo: This will be inefficient if the number of
1298                       instrument parameters is really huge. */
1299        /* check if instrument parameters have been defined */
1300        if (instrument_definition->formals)
1301          liter = list_iterate(instrument_definition->formals);
1302        if (liter)
1303        while(formal = list_next(liter))
1304        {
1305          if($1 && formal->id && strcmp($1, "NULL") && !strcmp($1, formal->id))
1306          {
1307            /* It was an instrument parameter */
1308            $$ = exp_id($1);
1309            goto found;
1310          }
1311        }
1312        if (liter) list_iterate_end(liter);
1313        /* It was an external id. */
1314        $$ = exp_extern_id($1);
1315      found:
1316        str_free($1);
1317      }
1318    | TOK_NUMBER
1319      {
1320        $$ = exp_number($1);
1321        str_free($1);
1322      }
1323    | TOK_STRING
1324      {
1325        $$ = exp_string($1);
1326        str_free($1);
1327      }
1328    | TOK_CTOK
1329      {
1330        $$ = exp_ctoken($1);
1331        str_free($1);
1332      }
1333    | '='
1334      {
1335        $$ = exp_ctoken("=");
1336      }
1337    | '*'
1338      {
1339        $$ = exp_ctoken("*");
1340      }
1341    | '(' genexp ')'
1342      {
1343        CExp p1 = exp_ctoken("(");
1344        CExp p2 = exp_ctoken(")");
1345        $$ = exp_compound(3, p1, $2, p2);
1346        exp_free(p2);
1347        exp_free(p1);
1348        exp_free($2);
1349      }
1350    | '(' ')'
1351      {
1352        CExp p1 = exp_ctoken("(");
1353        CExp p2 = exp_ctoken(")");
1354        $$ = exp_compound(2, p1, p2);
1355        exp_free(p2);
1356        exp_free(p1);
1357      }
1358    | '[' genexp ']'
1359      {
1360        CExp p1 = exp_ctoken("[");
1361        CExp p2 = exp_ctoken("]");
1362        $$ = exp_compound(3, p1, $2, p2);
1363        exp_free(p2);
1364        exp_free(p1);
1365        exp_free($2);
1366      }
1367    | '[' ']'
1368      {
1369        CExp p1 = exp_ctoken("[");
1370        CExp p2 = exp_ctoken("]");
1371        $$ = exp_compound(2, p1, p2);
1372        exp_free(p2);
1373        exp_free(p1);
1374      }
1375    | '{' genexp '}'
1376      {
1377        CExp p1 = exp_ctoken("{");
1378        CExp p2 = exp_ctoken("}");
1379        $$ = exp_compound(3, p1, $2, p2);
1380        exp_free(p2);
1381        exp_free(p1);
1382        exp_free($2);
1383      }
1384    | '{' '}'
1385      {
1386        CExp p1 = exp_ctoken("{");
1387        CExp p2 = exp_ctoken("}");
1388        $$ = exp_compound(2, p1, p2);
1389        exp_free(p2);
1390        exp_free(p1);
1391      }
1392;
1393
1394/* Any C expression, including a top-level comma (',') operator. */
1395genexp:     genatexp
1396      {
1397        $$ = $1;
1398      }
1399    | genexp genatexp
1400      {
1401        $$ = exp_compound(2, $1, $2);
1402        exp_free($2);
1403        exp_free($1);
1404      }
1405;
1406
1407genatexp:   topatexp
1408      {
1409        $$ = $1;
1410      }
1411    | ','
1412      {
1413        $$ = exp_ctoken(",");
1414      }
1415;
1416
1417codeblock:    TOK_CODE_START code TOK_CODE_END
1418      {
1419        $2->filename = instr_current_filename;
1420        $2->quoted_filename = str_quote(instr_current_filename);
1421        $2->linenum = $1;
1422        $$ = $2;
1423      }
1424;
1425
1426code:     /* empty */
1427      {
1428        $$ = codeblock_new();
1429      }
1430
1431    | code TOK_CODE_LINE
1432      {
1433        list_add($1->lines, $2);
1434        $$ = $1;
1435      }
1436;
1437
1438%%
1439
1440static Pool parser_pool = NULL; /* Pool of parser allocations. */
1441
1442static int mc_yyparse(void)
1443{
1444  int ret;
1445  Pool oldpool;
1446
1447  oldpool = parser_pool;
1448  parser_pool = pool_create();
1449  ret = yyparse();
1450  pool_free(parser_pool);
1451  parser_pool = oldpool;
1452  return ret;
1453}
1454
1455/* Name of the file currently being parsed. */
1456char *instr_current_filename = NULL;
1457/* Number of the line currently being parsed. */
1458int instr_current_line = 0;
1459/* current instance index */
1460long comp_current_index=0;
1461
1462/* Result from parsing instrument definition. */
1463struct instr_def *instrument_definition;
1464
1465/* Map from names to component instances. */
1466Symtab comp_instances;
1467
1468/* Will store component instance for PREVIOUS reference */
1469struct comp_inst *previous_comp=NULL;
1470
1471/* Map from names to component group instances. */
1472Symtab group_instances;
1473
1474/* Map from names to embedded libraries */
1475Symtab lib_instances;
1476
1477/* List of components, in the order they where declared in the instrument
1478   definition. */
1479List comp_instances_list;
1480
1481/* List of component groups, in the order they where declared in the instrument
1482   definition. */
1483List group_instances_list;
1484
1485/* Filename for outputting generated simulation program ('-' means stdin). */
1486static char *output_filename;
1487
1488/* Verbose parsing/code generation */
1489char verbose;
1490
1491/* Map of already-read components. */
1492Symtab read_components = NULL;
1493
1494/* Print a summary of the command usage and exit with error. */
1495static void
1496print_usage(void)
1497{
1498  fprintf(stderr, "Usage:\n"
1499    "  mcstas [-o file] [-I dir1 ...] [-t] [-p] [-v] "
1500    "[--no-main] [--no-runtime] [--verbose] file\n");
1501  fprintf(stderr, "      -o FILE --output-file=FILE Place C output in file FILE.\n");
1502  fprintf(stderr, "      -I DIR  --search-dir=DIR   Append DIR to the component search list. \n");
1503  fprintf(stderr, "      -t      --trace            Enable 'trace' mode for instrument display.\n");
1504  fprintf(stderr, "      -v      --version          Prints McStas version.\n");
1505  fprintf(stderr, "      --no-main                  Do not create main(), for external embedding.\n");
1506  fprintf(stderr, "      --no-runtime               Do not embed run-time libraries.\n");
1507  fprintf(stderr, "      --verbose                  Display compilation process steps.\n");
1508  fprintf(stderr, "  The file will be processed and translated into a C code program.\n");
1509  fprintf(stderr, "  The default component search list is usually defined by the 'MCSTAS'\n");
1510  fprintf(stderr, "  environment variable. Use 'mcrun' to both run mcstas and the C compiler.\n");
1511  fprintf(stderr, "  Use 'mcgui' to run the McStas GUI.\n");
1512  fprintf(stderr, "  If run-time libraries are not embedded, you will have to pre-compile\n");
1513  fprintf(stderr, "  them (.c -> .o) before assembling the program.\n");
1514  fprintf(stderr, "SEE ALSO: mcrun, mcplot, mcdisplay, mcresplot, mcstas2vitess, mcgui, mcformat, mcdoc\n");
1515  fprintf(stderr, "DOC:      Please visit " PACKAGE_BUGREPORT "\n");
1516  exit(1);
1517}
1518
1519/* Print McStas version and copyright. */
1520static void
1521print_version(void)
1522{ /* MOD: E. Farhi Sep 20th, 2001 version number */
1523  printf("McStas version " MCSTAS_VERSION "\n"
1524    "Copyright (C) Risoe National Laboratory, 1997-2007\n"
1525    "Additions (C) Institut Laue Langevin, 2003-2007\n"
1526    "All rights reserved\n");
1527  exit(0);
1528}
1529
1530/* Construct default filename for simulation output from instrument file
1531   name. Strip any leading directory path and trailing .instr, and add .c to
1532   the end. */
1533static char *
1534make_output_filename(char *name)
1535{
1536  char *p;
1537  int l;
1538
1539  /* Find basename */
1540  p = strrchr(name, '/');
1541  if(p == NULL)
1542    p = name;     /* No initial path. */
1543  else
1544    p++;      /* Point past last '/' character. */
1545
1546  /* Check for trailing .instr suffix. */
1547  l = strlen(p);
1548  if(l > 6 && !strcmp(&p[l - 6], ".instr"))
1549  {
1550    char *tmp = str_dup(p);
1551    tmp[l - 6] = '\0';
1552    p = str_cat(tmp, ".c", NULL);
1553    str_free(tmp);
1554  }
1555  else
1556    p = str_cat(p, ".c", NULL);
1557  return p;
1558}
1559
1560
1561static void
1562set_output_filename(char *name)
1563{
1564  output_filename = str_dup(name);
1565}
1566
1567/* Parse command line options. */
1568static void
1569parse_command_line(int argc, char *argv[])
1570{
1571  int i;
1572
1573  output_filename = NULL;
1574  verbose = 0;
1575  instr_current_filename = NULL;
1576  instrument_definition->use_default_main = 1;
1577  instrument_definition->include_runtime = 1;
1578  instrument_definition->enable_trace = 0;
1579  instrument_definition->portable = 0;
1580  instrument_definition->polarised = 0;
1581  for(i = 1; i < argc; i++)
1582  {
1583    if(!strcmp("-o", argv[i]) && (i + 1) < argc)
1584      set_output_filename(argv[++i]);
1585    else if(!strncmp("-o", argv[i], 2))
1586      set_output_filename(&argv[i][2]);
1587    else if(!strcmp("--output-file", argv[i]) && (i + 1) < argc)
1588      set_output_filename(argv[++i]);
1589    else if(!strncmp("--output-file=", argv[i], 14))
1590      set_output_filename(&argv[i][14]);
1591    else if(!strcmp("-I", argv[i]) && (i + 1) < argc)
1592      add_search_dir(argv[++i]);
1593    else if(!strncmp("-I", argv[i], 2))
1594      add_search_dir(&argv[i][2]);
1595    else if(!strcmp("--search-dir", argv[i]) && (i + 1) < argc)
1596      add_search_dir(argv[++i]);
1597    else if(!strncmp("--search-dir=", argv[i], 13))
1598      add_search_dir(&argv[i][13]);
1599    else if(!strcmp("-t", argv[i]))
1600      instrument_definition->enable_trace = 1;
1601    else if(!strcmp("--trace", argv[i]))
1602      instrument_definition->enable_trace = 1;
1603    else if(!strcmp("-p", argv[i]))
1604      instrument_definition->portable = 1;
1605    else if(!strcmp("--portable", argv[i]))
1606      instrument_definition->portable = 1;
1607    else if(!strcmp("-v", argv[i]))
1608      print_version();
1609    else if(!strcmp("--version", argv[i]))
1610      print_version();
1611    else if(!strcmp("--verbose", argv[i]))
1612      verbose = 1;
1613    else if(!strcmp("--no-main", argv[i]))
1614      instrument_definition->use_default_main = 0;
1615    else if(!strcmp("--no-runtime", argv[i]))
1616      instrument_definition->include_runtime = 0;
1617    else if(argv[i][0] != '-')
1618    {
1619      if(instr_current_filename != NULL)
1620        print_usage();    /* Multiple instruments given. */
1621      instr_current_filename = str_dup(argv[i]);
1622    }
1623    else
1624      print_usage();
1625  }
1626
1627  /* Instrument filename must be given. */
1628  if(instr_current_filename == NULL)
1629    print_usage();
1630  /* If no '-o' option was given for INSTR.instr, default to INSTR.c  */
1631  if(output_filename == NULL)
1632    output_filename = make_output_filename(instr_current_filename);
1633}
1634
1635
1636int
1637main(int argc, char *argv[])
1638{
1639  FILE *file;
1640  int err;
1641
1642#ifdef MAC
1643  argc = ccommand(&argv);
1644#endif
1645
1646  yydebug = 0;      /* If 1, then bison gives verbose parser debug info. */
1647
1648  palloc(instrument_definition); /* Allocate instrument def. structure. */
1649  /* init root instrument to NULL */
1650  instrument_definition->formals   = NULL;
1651  instrument_definition->name      = NULL;
1652  instrument_definition->decls     = NULL;
1653  instrument_definition->inits     = NULL;
1654  instrument_definition->nxinfo    = NULL;
1655  instrument_definition->saves     = NULL;
1656  instrument_definition->finals    = NULL;
1657  instrument_definition->compmap   = NULL;
1658  instrument_definition->groupmap  = NULL;
1659  instrument_definition->complist  = NULL;
1660  instrument_definition->grouplist = NULL;
1661  instrument_definition->has_included_instr=0;
1662  comp_instances      = NULL;
1663  comp_instances_list = NULL;
1664  group_instances     = NULL;
1665  group_instances_list= NULL;
1666  parse_command_line(argc, argv);
1667  if(!strcmp(instr_current_filename, "-"))
1668  {
1669    instrument_definition->source = str_dup("<stdin>");
1670    file = fdopen(0, "r");  /* Lone '-' designates stdin. */
1671  }
1672  else
1673  {
1674    instrument_definition->source = str_dup(instr_current_filename);
1675    file = fopen(instr_current_filename, "r");
1676  }
1677  if(file == NULL)
1678    fatal_error("Instrument definition file `%s' not found\n",
1679    instr_current_filename);
1680  instrument_definition->quoted_source =
1681    str_quote(instrument_definition->source);
1682  if (verbose) fprintf(stderr, "Analyzing file      %s\n", instrument_definition->quoted_source);
1683  instr_current_line = 1;
1684  lex_new_file(file);
1685  read_components = symtab_create(); /* Create table of components. */
1686  lib_instances   = symtab_create(); /* Create table of libraries. */
1687  err = mc_yyparse();
1688  fclose(file);
1689  if(err != 0 || error_encountered != 0)
1690  {
1691    print_error("Errors encountered during parse.\n");
1692    exit(1);
1693  }
1694  else
1695  {
1696    if (verbose) fprintf(stderr, "Starting to create C code %s\n", output_filename);
1697    cogen(output_filename, instrument_definition);
1698    if (verbose) fprintf(stderr, "Generated C code    %s\n", output_filename);
1699    exit(0);
1700  }
1701}
1702
1703
1704int
1705yyerror(char *s)
1706{
1707  print_error("%s at line %d.\n", s, instr_current_line);
1708  return 0;
1709}
1710
1711
1712/*******************************************************************************
1713* Check that all formal parameters of a component definition are unique.
1714*******************************************************************************/
1715void
1716check_comp_formals(List deflist, List setlist, char *compname)
1717{
1718  Symtab formals;
1719  struct comp_iformal *formal;
1720  struct Symtab_entry *entry;
1721  List_handle liter;
1722
1723  /* We check the uniqueness by adding all the formals to a symbol table with
1724     a dummy pointer value. Any formal parameter that already appears in the
1725     symbol table is an error. */
1726  formals = symtab_create();
1727  liter = list_iterate(deflist);
1728  while(formal = list_next(liter))
1729  {
1730    entry = symtab_lookup(formals, formal->id);
1731    if(entry != NULL)
1732      print_error("Definition parameter name %s is used multiple times "
1733      "in component %s\n", formal->id, compname);
1734    else
1735      symtab_add(formals, formal->id, NULL);
1736  }
1737  list_iterate_end(liter);
1738  liter = list_iterate(setlist);
1739  while(formal = list_next(liter))
1740  {
1741    entry = symtab_lookup(formals, formal->id);
1742    if(entry != NULL)
1743      print_error("Setting parameter name %s is used multiple times "
1744      "in component %s\n", formal->id, compname);
1745    else
1746      symtab_add(formals, formal->id, NULL);
1747  }
1748  list_iterate_end(liter);
1749  symtab_free(formals, NULL);
1750}
1751
1752
1753/*******************************************************************************
1754* Check that all formal parameters of an instrument definition are unique.
1755*******************************************************************************/
1756void
1757check_instrument_formals(List formallist, char *instrname)
1758{
1759  struct instr_formal *formal;
1760  List_handle liter;
1761
1762  /* We check the uniqueness. Any formal parameter that already appears in the
1763     formal list is reported. */
1764  liter = list_iterate(formallist);
1765  while(formal = list_next(liter))
1766  if (strcmp(formal->id,"")) {
1767      /* find first definition of parameter */
1768      List_handle liter2;
1769      struct instr_formal *formal2;
1770     
1771      liter2 = list_iterate(formallist);
1772      while(formal2 = list_next(liter2)) {
1773        if (formal != formal2 && strlen(formal2->id) && !strcmp(formal->id, formal2->id)) {
1774                strcpy(formal2->id, "");  /* unactivate recurrent previous definition */
1775                if (verbose) print_warn(NULL, "Instrument parameter name %s is used multiple times "
1776            "in instrument %s. Using last definition %s\n", formal->id, instrname,
1777                formal->isoptional ? exp_tostring(formal->default_value) : "");
1778          break;
1779        }
1780      }
1781  }
1782  list_iterate_end(liter);
1783}
1784
1785/*******************************************************************************
1786* Check the actual parameters to a component against the formal parameters.
1787*******************************************************************************/
1788void
1789comp_formals_actuals(struct comp_inst *comp, Symtab actuals)
1790{
1791  List_handle liter;
1792  struct comp_iformal *formal;
1793  struct Symtab_entry *entry;
1794  Symtab defpar, setpar;
1795  Symtab_handle siter;
1796
1797  /* We need to check
1798     1. That all actual parameters correspond to formal parameters.
1799     2. That all formal parameters are assigned actual parameters. */
1800
1801  /* First check the formal parameters one by one. */
1802  defpar = symtab_create();
1803  setpar = symtab_create();
1804  liter = list_iterate(comp->def->def_par);
1805  while(formal = list_next(liter))
1806  {
1807    entry = symtab_lookup(actuals, formal->id);
1808    if(entry == NULL)
1809    {
1810      if(formal->isoptional)
1811      {
1812        /* Use default value for unassigned optional parameter */
1813        symtab_add(defpar, formal->id, formal->default_value);
1814      } else {
1815        print_error("Unassigned DEFINITION parameter %s for component %s at line %s:%d.\n",
1816              formal->id, comp->type,
1817              instr_current_filename, instr_current_line);
1818        symtab_add(defpar, formal->id, exp_number("0.0"));
1819      }
1820    } else {
1821      symtab_add(defpar, formal->id, entry->val);
1822      /* Ensure that the actual DEFINITION parameters are all values
1823         (identifiers, constant numbers, and constant strings). This is
1824         necessary to avoid duplication of computations or side effects in the
1825         expressions for the actual parameters, since DEFINITION parameters
1826         are assigned using #define's. */
1827      if(!exp_isvalue(entry->val))
1828      {
1829  print_warn(NULL, "Using DEFINITION parameter of component %s (potential syntax error) at line %s:%d\n"
1830    "  %s=%s\n",
1831    comp->type, instr_current_filename, instr_current_line,
1832    formal->id, exp_tostring(entry->val));
1833      }
1834    }
1835  }
1836  list_iterate_end(liter);
1837  liter = list_iterate(comp->def->set_par);
1838  while(formal = list_next(liter))
1839  {
1840    entry = symtab_lookup(actuals, formal->id);
1841    if(entry == NULL)
1842    {
1843      if(formal->isoptional)
1844      {
1845        /* Use default value for unassigned optional parameter */
1846        symtab_add(setpar, formal->id, formal->default_value);
1847      } else {
1848        print_error("Unassigned SETTING parameter %s for component %s at line %s:%d.\n",
1849              formal->id, comp->type,
1850              instr_current_filename, instr_current_line);
1851        symtab_add(setpar, formal->id, exp_number("0.0"));
1852      }
1853    } else {
1854      symtab_add(setpar, formal->id, entry->val);
1855    }
1856  }
1857  list_iterate_end(liter);
1858
1859  /* Now check the actual parameters one by one. */
1860  siter = symtab_iterate(actuals);
1861  while(entry = symtab_next(siter))
1862  {
1863    if(symtab_lookup(defpar, entry->name) == NULL &&
1864       symtab_lookup(setpar, entry->name) == NULL)
1865    {
1866      Symtab_handle siter2;
1867      struct Symtab_entry *entry2;
1868
1869      fprintf(stderr, "Unmatched actual parameter %s for component %s at line %s:%d.\n",
1870        entry->name, comp->type,
1871        instr_current_filename, instr_current_line);
1872      siter2 = symtab_iterate(defpar);
1873      fprintf(stderr,"  Definition parameters: ");
1874      while(entry2 = symtab_next(siter2))
1875        fprintf(stderr, "%s ", entry2->name);
1876      symtab_iterate_end(siter2);
1877      siter2 = symtab_iterate(setpar);
1878      fprintf(stderr,"\n  Setting parameters: ");
1879      while(entry2 = symtab_next(siter2))
1880        fprintf(stderr, "%s ", entry2->name);
1881      symtab_iterate_end(siter2);
1882      print_error("\n");
1883    }
1884  }
1885  symtab_iterate_end(siter);
1886  comp->defpar = defpar;
1887  comp->setpar = setpar;
1888}
1889
1890
1891/*******************************************************************************
1892* This is the main entry point for reading a component. When a component
1893* definition is needed, this function is called with the name of the
1894* component. A map of previously read components is maintained. If a
1895* component definition (struct comp)def) is found, it is returned. Otherwise
1896* an attempt is made to read the component definition from a file with the
1897* same name as the component with added file extension ".com".
1898* If for some reasons the component cannot be read, NULL is returned; else a
1899* pointer to a struct comp_def is returned. Since components definitions can
1900* be used multiple times, the returned structure is shared and should not be
1901* modified.
1902*******************************************************************************/
1903struct comp_def *
1904read_component(char *name)
1905{
1906  struct Symtab_entry *entry;
1907
1908  /* Look for an existing definition for the component. */
1909  entry = symtab_lookup(read_components, name);
1910  if(entry != NULL)
1911  {
1912    return entry->val;    /* Return it if found. */
1913  }
1914  else
1915  {
1916    FILE *file;
1917    int err;
1918
1919    /* Attempt to read definition from file components/<name>.com. */
1920    file = open_component_search(name);
1921    if(file == NULL)
1922    {
1923      print_error(
1924        "Cannot find file containing definition of component `%s'.\n", name);
1925      return NULL;
1926    }
1927    push_autoload(file);
1928    /* Note: the str_dup copy of the file name is stored in codeblocks, and
1929       must not be freed. */
1930    instr_current_filename = component_pathname;
1931    instr_current_line = 1;
1932    err = mc_yyparse();   /* Read definition from file. */
1933    if(err != 0)
1934      fatal_error("Errors encountered during autoload of component %s.\n",
1935        name);
1936    fclose(file);
1937    /* Now check if the file contained the required component definition. */
1938    entry = symtab_lookup(read_components, name);
1939    if(entry != NULL)
1940    {
1941      return entry->val;
1942    }
1943    else
1944    {
1945      print_error("Definition of component %s not found.\n", name);
1946      return NULL;
1947    }
1948  }
1949}
Note: See TracBrowser for help on using the browser.