1/******************************************************************************* 2* 3* McStas, neutron ray-tracing package 4* Copyright (C) 1997-2006, All rights reserved 5* Risoe National Laboratory, Roskilde, Denmark 6* Institut Laue Langevin, Grenoble, France 7* Copenhagen University, Copenhagen, Denmark 8* 9* Kernel: cogen.c 10* 11* %Identification 12* Written by: K.N. 13* Modifed for X-rays by E.K. 14* Date: Aug 20, 1997 15* Origin: Risoe 16* Release: McStas 1.6 17* Version: $Revision$ 18* 19* Code generation from instrument definition. 20* 21*******************************************************************************/ 22 23#include <stdarg.h> 24#include <string.h> 25#include <stdio.h> 26#include "mccode.h" 27 28 29/******************************************************************************* 30* Some general comments on code generation. 31* 32* Code is output in the form of strings using the following functions: 33* cout(); (one line at a time) 34* coutf(); (with printf-style formatting) 35* 36* The type of numbers used in the generated code is given by the macro MCNUM 37* (defined in mccode-r.h). 38* 39* All generated identifiers are prefixed with the string ID_PRE, to make name 40* clashes less likely to occur. Currently, for simplicity, we output modified 41* names directly, eg. 42* 43* cout("void " ID_PRE "init(void);"); 44* 45* But to make a later transition to a better name generation scheme possible, 46* it is important to use the ID_PRE macro everywhere identifiers are 47* generated. 48* 49* After the ID_PRE prefix a few letters occur in generated names to 50* distinguish different kinds of identifiers (instrument parameters, 51* component definition parameters, internal temporary variables and so on). 52* Care must be takes to choose these letters such that no name clashes will 53* occur with names generated by other parts of the code or generated from 54* user symbols. 55* 56* Finally, names generated from user symbols are generally chosen to match 57* the originals as closely as possible to make the generated code more 58* readable (for debugging purposes). 59* 60* The following is a list of the identifiers generated in the output. The 61* ID_PRE prefix is denoted by ##. The first column gives the identifier as it 62* appears in the generated code, the second explains the origin of the 63* identifier in the instrument definition source (if any). 64* 65* ##ip<PAR> From instrument parameter <PAR>. 66* ##init Function containing initialization code. 67* ##inputtable Table of instrument parameters. 68* ##NUMIPAR Macro giving the number of instrument parameters. 69* ##numipar Global variable with the value of ##NUMIPAR. 70* ##c<C>_<P> From definition or setting parameter <P> in component 71* instance <C>. 72* ##posa<COMP> Absolute position of coordinate system of <COMP>. 73* ##posr<COMP> Position of <COMP> relative to previous component. 74* ##rota<COMP> Absolute rotation. 75* ##rotr<COMP> Relative rotation. 76* ##tc1 Temporary variable used to compute transformations. 77* ##tc2 78* ##tr1 79* ##nx Neutron state (position, velocity, time, and spin). 80* ##ny or Xray state (position, wavevector, phase, polarisation, and weight). 81* ##nz 82* ##nvx nkx 83* ##nvy nky 84* ##nvz nkz 85* ##nt nphi 86* ##nsx nEx 87* ##nsy nEy 88* ##nsz nEz 89* ##np 90* ##compcurname 91* ##compcurtype 92* ##compcurindex 93* ##absorb label for ABSORB (goto) 94* ##Scattered Incremented each time a SCATTER is done 95* ##Restore Flag indicating that @MCCODE_PARTICLE@ should be restored 96* ##NCounter Incremented each time a @MCCODE_PARTICLE@ is entering the component 97* ##AbsorbProp single counter for removed events in PROP calls 98* ##comp_storein Positions of @MCCODE_PARTICLE@ entering each comp (loc. coords) 99* ##Group<GROUP> Flag true when in an active group 100* ##sig_message Message for the signal handler (debug/trace, sim status) 101* ##JumpCounter iteration counter for JUMP 102*******************************************************************************/ 103 104 105 106/******************************************************************************* 107* Generation of declarations. 108* 109* The following declarations are generated (## denotes the value ID_PRE): 110* 1. Header file #include - "mccode-r.h" for declarations for the 111* mcstas runtime. 112* 2. Declarations of global variables to hold the values of the instrument 113* parameters. For example, for an instrument parameter OMM, the 114* declaration "MCNUM ##ipOMM;" is generated. 115* 3. Declaration of a table ##inputtable containing the list of instrument 116* parameters. For each parameter, the name, a pointer to the 117* corresponding global variable, and the type (double, int, 118* string) is given. The macro ##NUMIPAR gives the number of 119* entries in the table and is also found as the value of the 120* variable ##numipar; in addition, the table is terminated by two 121* NULLs. This table is used to read the instrument parameters from 122* the user or from another program such as TASCOM. 123* 4. User declarations copied verbatim from the instrument definition file. 124* 5. Declarations for the component parameters. This uses #define for 125* definition parameters and global variables for setting parameters. 126* X. User declarations from component definitions. 127* X. Declarations of variables for coordinate system transformations. 128* X. Declaration of variables for @MCCODE_PARTICLE@ state. 129* X. Function prototypes. 130*******************************************************************************/ 131 132/* PROJECT=1 for McStas, 2 for McXtrace. Now using @MCCODE_PARTICLE@ McStas */ 133#ifndef MCCODE_PROJECT 134#define MCCODE_PROJECT @MCCODE_PROJECT@ 135#endif 136 137#ifndef MCCODE_LIBENV 138#define MCCODE_LIBENV @MCCODE_LIBENV@ 139#endif 140 141#ifndef MCCODE_PARTICLE 142#define MCCODE_PARTICLE @MCCODE_PARTICLE@ 143#endif 144 145#if MCCODE_PROJECT == 1 146#define NUM_STATE_PARS 11 147#elif MCCODE_PROJECT == 2 148#define NUM_STATE_PARS 12 149#endif 150 151/* Functions for outputting code. */ 152 153/* Handle for output file. */ 154static FILE *output_handle = NULL;/* Handle for output file. */ 155static int num_next_output_line = 1; /* Line number for next output line. */ 156static char *quoted_output_file_name = NULL; /* str_quote()'ed name 157 of output file. */ 158 159/* Convert instrument formal parameter type numbers to their enum name. */ 160char *instr_formal_type_names[] = 161 { "instr_type_double", "instr_type_int", "instr_type_string" }; 162 163char *instr_formal_type_names_real[] = 164 { "MCNUM", "int", "char*", "char"}; /* the last one is for static char allocation */ 165 166/******************************************************************************* 167* Output a line of code 168* Assumes that the output does not contain newlines. 169*******************************************************************************/ 170static void 171cout(char *s) 172{ 173 fprintf(output_handle, "%s\n", s); 174 num_next_output_line++; 175} 176 177/******************************************************************************* 178* Output a line of code using printf-style format string. 179* Assumes that the output does not contain newlines. 180*******************************************************************************/ 181static void 182coutf(char *format, ...) 183{ 184 va_list ap; 185 186 va_start(ap, format); 187 vfprintf(output_handle, format, ap); 188 va_end(ap); 189 fprintf(output_handle, "\n"); 190 num_next_output_line++; 191} 192 193/******************************************************************************* 194* Output #line directive to handle code coming from a different file. 195* The filename is assumed to be already properly quoted for special chars. 196*******************************************************************************/ 197static void 198code_set_source(char *filename, int linenum) 199{ 200 if(linenum > 0) 201 coutf("#line %d \"%s\"", linenum, filename); 202} 203 204/******************************************************************************* 205* Output #line directive to reset back to the generated output C file. 206*******************************************************************************/ 207static void 208code_reset_source(void) 209{ 210 /* Note: the number after #line refers to the line AFTER the directive. */ 211 coutf("#line %d \"%s\"", num_next_output_line + 1, quoted_output_file_name); 212} 213 214 215static void 216codeblock_out(struct code_block *code) 217{ 218 List_handle liter; /* For list iteration. */ 219 char *line; /* Single code line. */ 220 221 if(list_len(code->lines) <= 0) 222 return; 223 code_set_source(code->quoted_filename, code->linenum + 1); 224 liter = list_iterate(code->lines); 225 while(line = list_next(liter)) 226 { 227 fprintf(output_handle, "%s", line); 228 num_next_output_line++; 229 } 230 list_iterate_end(liter); 231 code_reset_source(); 232} 233 234static void 235codeblock_out_brace(struct code_block *code) 236{ 237 List_handle liter; /* For list iteration. */ 238 char *line; /* Single code line. */ 239 240 if(list_len(code->lines) <= 0) 241 return; 242 code_set_source(code->quoted_filename, code->linenum); 243 cout("{"); 244 liter = list_iterate(code->lines); 245 while(line = list_next(liter)) 246 { 247 fprintf(output_handle, "%s", line); 248 num_next_output_line++; 249 } 250 list_iterate_end(liter); 251 cout("}"); 252 code_reset_source(); 253} 254 255 256struct code_block * 257codeblock_new(void) 258{ 259 struct code_block *cb; 260 261 palloc(cb); 262 cb->filename = NULL; 263 cb->quoted_filename = NULL; 264 cb->linenum = -1; 265 cb->lines = list_create(); 266 return cb; 267} 268 269/******************************************************************************* 270* Read a file and output it to the generated simulation code. Uses a 271* fixed-size buffer, and will silently and arbitrarily break long lines. 272*******************************************************************************/ 273static void 274embed_file(char *name) 275{ 276 char buf[4096]; 277 FILE *f; 278 int last; 279 280 if (!symtab_lookup(lib_instances, name)) 281 { 282 /* First look in the system directory. */ 283 f = open_file_search_sys(name); 284 /* If not found, look in the full search path. */ 285 if(f == NULL) { 286 f = open_file_search(name); 287 /* If still not found, abort. */ 288 if(f == NULL) 289 fatal_error("Could not find file '%s'\n", name); 290 else if (verbose) printf("Embedding file %s (user path)\n", name); 291 } else if (verbose) printf("Embedding file %s (%s)\n", name, get_sys_dir()); 292 293 cout(""); 294 code_set_source(name, 1); 295 /* Now loop, reading lines and outputting them in the code. */ 296 while(!feof(f)) 297 { 298 if(fgets(buf, 4096, f) == NULL) 299 break; 300 last = strlen(buf) - 1; 301 if(last >= 0 && (buf[last] == '\n' || buf[last] == '\r')) 302 buf[last--] = '\0'; 303 if(last >= 0 && (buf[last] == '\n' || buf[last] == '\r')) 304 buf[last--] = '\0'; 305 cout(buf); 306 } 307 fclose(f); 308 coutf("/* End of file \"%s\". */", name); 309 cout(""); 310 code_reset_source(); 311 symtab_add(lib_instances, name, NULL); 312 } /* else file has already been embedded */ 313} /* embed_file */ 314 315 316/******************************************************************************* 317* The following two functions output #define directives around a given piece 318* of code to set up the right variable names (eg. the proper scope) for 319* instrument and component parameters. The functions are recursive on the 320* parameter lists. 321* 322* The functions first output an appropriate list of #define's, then call the 323* supplied function func with the argument data, and finally outputs a 324* matching list of #undef's. 325*******************************************************************************/ 326static void cogen_instrument_scope_rec(List_handle parlist, 327 void (*func)(void *), void *data) 328{ 329 struct instr_formal *par; 330 331 par = list_next(parlist); 332 if(par != NULL) 333 { 334 if (strlen(par->id)) coutf("#define %s %sip%s", par->id, ID_PRE, par->id); 335 cogen_instrument_scope_rec(parlist, func, data); 336 if (strlen(par->id)) coutf("#undef %s", par->id); 337 } 338 else 339 { 340 (*func)(data); 341 } 342} 343 344static void 345cogen_instrument_scope(struct instr_def *instr, 346 void (*func)(void *), void *data) 347{ 348 List_handle parlist; 349 350 coutf("#define %scompcurname %s", ID_PRE, instr->name); 351 coutf("#define %scompcurtype %s", ID_PRE, "INSTRUMENT"); 352 coutf("#define %scompcurindex %i", ID_PRE, 0); 353 coutf("#define %sposa%s coords_set(0,0,0)", ID_PRE, instr->name); 354 /* This simply starts up the recursion on parameters. */ 355 parlist = list_iterate(instr->formals); 356 cogen_instrument_scope_rec(parlist, func, data); 357 list_iterate_end(parlist); 358 coutf("#undef %sposa%s", ID_PRE, instr->name); 359 coutf("#undef %scompcurindex",ID_PRE); 360 coutf("#undef %scompcurtype", ID_PRE); 361 coutf("#undef %scompcurname", ID_PRE); 362} 363 364/* Create the bindings for the SETTING parameter scope. Since the types of 365* setting parameters are known, local declarations can be used, avoiding the 366* problems with #define macro definitions. 367* infunc=0: no definition of parameters 368* infunc=1: define local copies of setting/definition parameters 369* infunc=2: same as 1, but for TRACE adds the EXTEND block and handles JUMPs 370*/ 371static void 372cogen_comp_scope_setpar(struct comp_inst *comp, List_handle set, int infunc, 373 void (*func)(void *), void *data) 374{ 375 struct comp_iformal *formal; 376 377 /* Get the next setting parameter. */ 378 formal = list_next(set); 379 if(formal != NULL) 380 { 381 /* Create local parameter equal to global value. */ 382 if(infunc) 383 coutf("%s %s = %sc%s_%s;", instr_formal_type_names_real[formal->type], formal->id, ID_PRE, comp->name, formal->id); 384 else 385 coutf("#define %s %sc%s_%s", formal->id, ID_PRE, comp->name, formal->id); 386 cogen_comp_scope_setpar(comp, set, infunc, func, data); 387 388 if(!infunc) 389 coutf("#undef %s", formal->id); 390 } 391 else 392 { 393 /* adds conditional execution for the TRACE */ 394 if (infunc==2 && comp->when) { 395 coutf("/* '%s=%s()' component instance has conditional execution */",comp->name, comp->type); 396 coutf("if (%s)\n", exp_tostring(comp->when)); 397 } 398 (*func)(data); /* Now do the body. */ 399 if(infunc == 2 && list_len(comp->extend->lines) > 0) 400 { 401 coutf("/* '%s=%s()' component instance extend code */",comp->name, comp->type); 402 coutf(" SIG_MESSAGE(\"%s (Trace:Extend)\");", comp->name); /* signal handler message */ 403 if (comp->when) 404 coutf("if (%s) {\n", exp_tostring(comp->when)); 405 codeblock_out(comp->extend); 406 if (comp->when) 407 cout("}\n"); 408 } 409 if (infunc==2 && list_len(comp->jump) > 0) { 410 List_handle liter2; 411 liter2 = list_iterate(comp->jump); 412 struct jump_struct *this_jump; 413 while(this_jump = list_next(liter2)) { 414 char *exp=exp_tostring(this_jump->condition); 415 if (this_jump->iterate) 416 coutf("if (%sJumpCounter%s_%i < (%s)-1)" 417 "{ %sJumpCounter%s_%i++; goto %sJumpTrace_%s; }", 418 ID_PRE, comp->name, this_jump->index, exp, 419 ID_PRE, comp->name, this_jump->index, 420 ID_PRE, this_jump->target); 421 else 422 coutf("if (%s) goto %sJumpTrace_%s;", 423 exp, ID_PRE, this_jump->target); 424 } 425 list_iterate_end(liter2); 426 } 427 } 428} /* cogen_comp_scope_setpar */ 429 430/* Create the #define statements to set up the scope for DEFINITION and OUTPUT 431* parameters. 432*/ 433static void 434cogen_comp_scope_rec(struct comp_inst *comp, List_handle def, List set_list, 435 List_handle out, int infunc, 436 void (*func)(void *), void *data) 437{ 438 char *par; 439 struct comp_iformal *formal; 440 441 /* First get the next DEFINITION or OUTPUT parameter, if any. */ 442 if(def != NULL) 443 { 444 formal = list_next(def); 445 if(formal == NULL) 446 def = NULL; /* Now finished with definition parameters. */ 447 else 448 par = formal->id; 449 } 450 if(def == NULL) 451 par = list_next(out); 452 if(par != NULL) 453 { 454 /* Create #define / #undef pair for this parameter around rest of code. */ 455 coutf("#define %s %sc%s_%s", par, ID_PRE, comp->name, par); 456 cogen_comp_scope_rec(comp, def, set_list, out, infunc, func, data); 457 coutf("#undef %s", par); 458 } 459 else 460 { /* Now do the SETTING parameters. */ 461 List_handle set; 462 463 if(infunc && list_len(set_list) > 0) 464 coutf("{ /* Declarations of %s=%s() SETTING parameters. */", comp->name, comp->type); 465 set = list_iterate(set_list); 466 cogen_comp_scope_setpar(comp, set, infunc, func, data); 467 list_iterate_end(set); 468 if(infunc && list_len(set_list) > 0) 469 coutf("} /* End of %s=%s() SETTING parameter declarations. */", comp->name, comp->type); 470 } 471} /* cogen_comp_scope_rec */ 472 473static void 474cogen_comp_scope(struct comp_inst *comp, int infunc, 475 void (*func)(void *), void *data) 476{ 477 List_handle def, out; 478 479 coutf("#define %scompcurname %s", ID_PRE, comp->name); 480 coutf("#define %scompcurtype %s", ID_PRE, comp->type); 481 coutf("#define %scompcurindex %i", ID_PRE, comp->index); 482 def = list_iterate(comp->def->def_par); 483 out = list_iterate(comp->def->out_par); 484 cogen_comp_scope_rec(comp, def, comp->def->set_par, out, 485 infunc, func, data); 486 list_iterate_end(out); 487 list_iterate_end(def); 488 coutf("#undef %scompcurname", ID_PRE); 489 coutf("#undef %scompcurtype", ID_PRE); 490 coutf("#undef %scompcurindex", ID_PRE); 491} /* cogen_comp_scope */ 492 493 494/******************************************************************************* 495* Generate declarations from users declaration section in component definition. 496*******************************************************************************/ 497static void 498cogen_comp_decls_doit(void *arg) 499{ 500 struct comp_inst *comp = arg; 501 502 /* Output the user declaration code block. */ 503 if (list_len(comp->def->decl_code->lines) > 0) 504 codeblock_out(comp->def->decl_code); 505} 506 507static void 508cogen_comp_decls(struct comp_inst *comp) 509{ 510 cogen_comp_scope(comp, 0, cogen_comp_decls_doit, comp); 511} 512 513static void 514cogen_comp_shares(struct comp_inst *comp) 515{ 516 /* Output the 'share' declaration code block 517 (once for all same components)*/ 518 519 if (comp->def->comp_inst_number < 0) 520 { 521 coutf("/* Shared user declarations for all components '%s'. */", comp->def->name); 522 codeblock_out(comp->def->share_code); 523 comp->def->comp_inst_number *= -1; 524 } 525} 526 527 528/******************************************************************************* 529* Generate declaration part of code. 530*******************************************************************************/ 531 532static void 533cogen_decls(struct instr_def *instr) 534{ 535 List_handle liter; /* For list iteration. */ 536 struct comp_iformal *c_formal;/* Name of component formal input parameter */ 537 struct instr_formal *i_formal;/* Name of instrument formal parameter. */ 538 struct comp_inst *comp; /* Component instance. */ 539 int index = 0; /* index of comp instance */ 540 struct group_inst *group; /* group instances */ 541 542 if (verbose) fprintf(stderr, "Writing instrument and components DECLARE\n"); 543 544 /* 1. Function prototypes. */ 545 coutf("void %sinit(void);", ID_PRE); 546 coutf("void %sraytrace(void);", ID_PRE); 547 coutf("void %ssave(FILE *);", ID_PRE); 548 coutf("void %sfinally(void);", ID_PRE); 549 coutf("void %sdisplay(void);", ID_PRE); 550 cout(""); 551 552 /* 2. Component SHAREs. */ 553 liter = list_iterate(instr->complist); 554 while(comp = list_next(liter)) 555 { 556 if((list_len(comp->def->share_code->lines) > 0) && (comp->def->comp_inst_number < 0)) 557 { 558 cogen_comp_shares(comp); 559 cout(""); 560 } 561 } 562 list_iterate_end(liter); 563 564 /* 3. Global variables for instrument parameters. */ 565 cout("/* Instrument parameters. */"); 566 liter = list_iterate(instr->formals); 567 int numipar=0; 568 while(i_formal = list_next(liter)) 569 { 570 if (strlen(i_formal->id)) { 571 coutf("%s " ID_PRE "ip%s;", instr_formal_type_names_real[i_formal->type], i_formal->id); 572 numipar++; 573 } 574 } 575 list_iterate_end(liter); 576 cout(""); 577 578 /* 4. Table of instrument parameters. */ 579 coutf("#define %sNUMIPAR %d", ID_PRE, numipar); 580 coutf("int %snumipar = %d;", ID_PRE, numipar); 581 coutf("struct %sinputtable_struct %sinputtable[%sNUMIPAR+1] = {", 582 ID_PRE, ID_PRE, ID_PRE); 583 liter = list_iterate(instr->formals); 584 while(i_formal = list_next(liter)) 585 { 586 if (strlen(i_formal->id)) { 587 if (i_formal->isoptional && !strcmp(instr_formal_type_names[i_formal->type],"instr_type_string")) 588 coutf(" \"%s\", &%sip%s, %s, %s, ", i_formal->id, ID_PRE, 589 i_formal->id, instr_formal_type_names[i_formal->type], 590 exp_tostring(i_formal->default_value)); 591 else 592 coutf(" \"%s\", &%sip%s, %s, \"%s\", ", i_formal->id, ID_PRE, i_formal->id, 593 instr_formal_type_names[i_formal->type], 594 i_formal->isoptional ? exp_tostring(i_formal->default_value) : ""); 595 } 596 } 597 list_iterate_end(liter); 598 coutf(" NULL, NULL, instr_type_double, \"\""); 599 coutf("};"); /* 5. Declaration of component definition and setting parameters. */ 600 cout(""); 601 602 /* 5. User's declarations from the instrument definition file. */ 603 cout("/* User declarations from instrument definition. */"); 604 cogen_instrument_scope(instr, (void (*)(void *))codeblock_out, instr->decls); 605 cout(""); 606 607 /* 6. Table to store @MCCODE_PARTICLE@ states when entering each component */ 608 cout("/* @MCCODE_PARTICLE@ state table at each component input (local coords) */"); 609#if MCCODE_PROJECT == 1 /* neutron */ 610 cout("/* [x, y, z, vx, vy, vz, t, sx, sy, sz, p] */"); 611#elif MCCODE_PROJECT == 2 /* xray */ 612 cout("/* [x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p] */"); 613#endif 614 coutf("MCNUM %scomp_storein[%i*%i];", ID_PRE, NUM_STATE_PARS, list_len(instr->complist)+2); 615 616 /* 7. Table to store position (abs/rel) for each component */ 617 cout("/* Components position table (absolute and relative coords) */"); 618 coutf("Coords %scomp_posa[%i];", ID_PRE, list_len(instr->complist)+2); 619 coutf("Coords %scomp_posr[%i];", ID_PRE, list_len(instr->complist)+2); 620 cout("/* Counter for each comp to check for inactive ones */"); 621 coutf("MCNUM %sNCounter[%i];", ID_PRE, list_len(instr->complist)+2); 622 coutf("MCNUM %sPCounter[%i];", ID_PRE, list_len(instr->complist)+2); 623 coutf("MCNUM %sP2Counter[%i];", ID_PRE, list_len(instr->complist)+2); 624 coutf("#define %sNUMCOMP %d /* number of components */", ID_PRE, list_len(instr->complist)+1); 625 cout("/* Counter for PROP ABSORB */"); 626 coutf("MCNUM %sAbsorbProp[%i];", ID_PRE, list_len(instr->complist)+2); 627 628 /* 8. Declaration of SCATTER and RESTORE flags */ 629 cout("/* Flag true when previous component acted on the @MCCODE_PARTICLE@ (SCATTER) */"); 630 coutf("MCNUM %sScattered=0;", ID_PRE); 631 632 cout("/* Flag true when @MCCODE_PARTICLE@ should be restored (RESTORE) */"); 633 coutf("MCNUM %sRestore=0;", ID_PRE); 634 635 if (list_len(instr->grouplist) > 0) 636 { 637 cout("/* Component group definitions (flags), equals index of scattering comp */"); 638 liter = list_iterate(instr->grouplist); 639 while(group = list_next(liter)) 640 { 641 coutf("int %sGroup%s=0;", ID_PRE, group->name); 642 } 643 list_iterate_end(liter); 644 } 645 646 /* 9. Declaration of component definition/setting parameters */ 647 cout("/* Declarations of component definition and setting parameters. */"); 648 cout(""); 649 index = 0; 650 651 652 liter = list_iterate(instr->complist); 653 while(comp = list_next(liter)) 654 { 655 List_handle liter2; 656 657 index++; 658 comp->index = index; /* should match the one defined with bison */ 659 660 if(list_len(comp->def->def_par) > 0) 661 { /* (The if avoids a redundant comment.) */ 662 coutf("/* Definition parameters for component '%s' [%i]. */", comp->name, comp->index); 663 liter2 = list_iterate(comp->def->def_par); 664 while(c_formal = list_next(liter2)) 665 { 666 struct Symtab_entry *entry = symtab_lookup(comp->defpar, c_formal->id); 667 char *val = exp_tostring(entry->val); 668 if (c_formal->type != instr_type_string) 669 coutf("#define %sc%s_%s %s", ID_PRE, comp->name, c_formal->id, val); 670 else { 671 /* a string definition parameter should be converted into a setting parameter to avoid e.g. 672 * warning: format ‘%s’ expects type ‘char *’, but argument X has type ‘int’ */ 673 fprintf(stderr,"Warning: Component %s=%s(string %s) definition parameter\n" 674 " may be changed into a setting parameter to avoid\n" 675 " warnings at compile time.\n", 676 comp->name, comp->type, c_formal->id); 677 coutf("#define %sc%s_%s %s /* declared as a string. May produce warnings at compile */", ID_PRE, comp->name, c_formal->id, val); 678 } 679 str_free(val); 680 } 681 list_iterate_end(liter2); 682 } 683 if(list_len(comp->def->set_par) > 0) 684 { 685 coutf("/* Setting parameters for component '%s' [%i]. */", comp->name, comp->index); 686 liter2 = list_iterate(comp->def->set_par); 687 while(c_formal = list_next(liter2)) 688 { 689 if (c_formal->type != instr_type_string) 690 coutf("%s %sc%s_%s;", instr_formal_type_names_real[c_formal->type], ID_PRE, comp->name, c_formal->id); 691 else /* char type for component */ 692 coutf("%s %sc%s_%s[16384];", instr_formal_type_names_real[c_formal->type+1], ID_PRE, comp->name, c_formal->id); 693 } 694 list_iterate_end(liter2); 695 } 696 if(list_len(comp->def->def_par) > 0 || list_len(comp->def->set_par) > 0) 697 cout(""); 698 } 699 list_iterate_end(liter); 700 701 /* 10. User declarations from component definitions (for each instance). */ 702 cout("/* User component declarations. */"); 703 cout(""); 704 liter = list_iterate(instr->complist); 705 while(comp = list_next(liter)) 706 { 707 /* set target names for jumps and define iteration counters */ 708 if(list_len(comp->jump) > 0) { 709 struct jump_struct *this_jump; 710 int jump_index=0; 711 List_handle liter2; 712 liter2 = list_iterate(comp->jump); 713 while(this_jump = list_next(liter2)) { 714 List_handle liter3; 715 char *jump_target_type=NULL; 716 jump_index++; 717 struct comp_inst *comp3; 718 /* check name/type of target */ 719 liter3 = list_iterate(instr->complist); 720 while(comp3 = list_next(liter3)) { 721 if ((this_jump->target && !strcmp(this_jump->target, comp3->name)) 722 || (!this_jump->target && comp3->index == comp->index+this_jump->target_index) ) { 723 if (!this_jump->target) this_jump->target=comp3->name; 724 jump_target_type =comp3->type; 725 break; 726 } 727 } 728 list_iterate_end(liter3); 729 730 this_jump->index = jump_index; 731 if (!this_jump->target || !jump_target_type) { 732 fatal_error("JUMP %i (relative %i) from component %s " 733 "is not in the instrument.\n", 734 this_jump->index, this_jump->target_index, comp->name); 735 } 736 /* JUMP are valid only if MYSELF or between Arm's */ 737 if (!(!strcmp(this_jump->target, comp->name) || 738 (!strcmp(jump_target_type, "Arm")) )) 739 fatal_error("JUMPs can only apply on MYSELF or to Arm components.\n" 740 " Target %s is a %s (not an Arm).\n", 741 this_jump->target, jump_target_type); 742 /* create counter for iteration */ 743 if (this_jump->iterate) 744 coutf("long %sJumpCounter%s_%i;", 745 ID_PRE, comp->name, this_jump->index); 746 fprintf(stderr,"Info: Defining %s JUMP from %s to %s\n", 747 (this_jump->iterate ? "iterative" : "conditional"), 748 comp->name, this_jump->target); 749 } 750 list_iterate_end(liter2); 751 } 752 753 if((list_len(comp->def->decl_code->lines) > 0) || (comp->def->comp_inst_number < 0)) 754 { 755 coutf("/* User declarations for component '%s' [%i]. */", comp->name, comp->index); 756 cogen_comp_decls(comp); 757 cout(""); 758 } 759 } 760 list_iterate_end(liter); 761 762 /* 11. Declarations for the position and rotation transformations between 763 coordinate systems of components. */ 764 liter = list_iterate(instr->complist); 765 while(comp = list_next(liter)) 766 { 767 coutf("Coords %sposa%s, %sposr%s;", ID_PRE, comp->name, ID_PRE, comp->name); 768 coutf("Rotation %srota%s, %srotr%s;", ID_PRE, comp->name, ID_PRE, comp->name); 769 } 770 list_iterate_end(liter); 771 cout(""); 772 773 /* 12. @MCCODE_PARTICLE@ state. */ 774#if MCCODE_PROJECT == 1 /* neutron */ 775 coutf("MCNUM %snx, %sny, %snz, %snvx, %snvy, %snvz, %snt, " 776 "%snsx, %snsy, %snsz, %snp;", 777 ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, 778 ID_PRE, ID_PRE, ID_PRE, ID_PRE); 779#elif MCCODE_PROJECT == 2 /* xray */ 780 coutf("MCNUM %snx, %sny, %snz, %snkx, %snky, %snkz, %snphi, %snt, " 781 "%snEx, %snEy, %snEz, %snp;", 782 ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, 783 ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE); 784#endif 785 786 cout(""); 787 cout("/* end declare */"); 788 cout(""); 789 790} /* cogen_decls */ 791 792/******************************************************************************* 793* cogen_init: Generate the INIT section. 794*******************************************************************************/ 795static void 796cogen_init(struct instr_def *instr) 797{ 798 List_handle liter; 799 struct comp_inst *comp, *last; 800 char *d2r; 801 802 if (verbose) fprintf(stderr, "Writing instrument and components INITIALIZE\n"); 803 804 coutf("void %sinit(void) {", ID_PRE); 805 806 /* User initializations from instrument definition. */ 807 cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace, 808 instr->inits); 809 810 /* MOD: E. Farhi Sep 20th, 2001 moved transformation block so that */ 811 /* it can be used in following init block */ 812 813 /* Compute the necessary vectors and transformation matrices for coordinate 814 system changes between components. */ 815 cout(" /* Computation of coordinate transformations. */"); 816 cout(" {"); 817 coutf(" Coords %stc1, %stc2, %sLastComp;", ID_PRE, ID_PRE, ID_PRE); 818 coutf(" Rotation %str1;", ID_PRE); 819 coutf(" double %sAccumulatedILength = 0;", ID_PRE); 820 coutf(" /* Initialize \"last\" component origin as (0,0,0) */"); 821 coutf(" %sLastComp = coords_set(0,0,0);", ID_PRE); 822 cout(""); 823 /* Conversion factor degrees->radians for rotation angles. */ 824 d2r = "DEG2RAD"; 825 826 liter = list_iterate(instr->complist); 827 last = NULL; 828 coutf(" %sDEBUG_INSTR()", ID_PRE); 829 830 /* Initialization of component position, rotation 831 setting parameters and user initialization code. */ 832 cout(" /* Component initializations. */"); 833 liter = list_iterate(instr->complist); 834 while((comp = list_next(liter)) != NULL) 835 { 836 struct comp_inst *relcomp; /* Component relative to. */ 837 char *x, *y, *z; 838 839 List_handle setpar; /* component parameters */ 840 struct comp_iformal *par; 841 842 coutf(" /* Component %s. */", comp->name); 843 844 coutf(" /* Setting parameters for component %s. */", comp->name); 845 coutf(" SIG_MESSAGE(\"%s (Init:SetPar)\");", comp->name); /* signal handler message */ 846 /* Setting parameters of the component */ 847 setpar = list_iterate(comp->def->set_par); 848 while((par = list_next(setpar)) != NULL) 849 { 850 char *val; 851 struct Symtab_entry *entry; 852 853 entry = symtab_lookup(comp->setpar, par->id); 854 val = exp_tostring(entry->val); 855 code_set_source(instr->quoted_source, exp_getlineno(entry->val)); 856 if (par->type != instr_type_string) 857 { 858 coutf(" %sc%s_%s = %s;", ID_PRE, comp->name, par->id, val); 859 } 860 else 861 { 862 coutf(" if(%s) strncpy(%sc%s_%s, %s ? %s : \"\", 16384); else %sc%s_%s[0]='\\0';", 863 val, ID_PRE, comp->name, par->id, val, val, ID_PRE, comp->name, par->id); 864 } 865 str_free(val); 866 } 867 list_iterate_end(setpar); 868 if(list_len(comp->def->set_par) > 0) 869 code_reset_source(); 870 cout(""); 871 872 873 coutf(" SIG_MESSAGE(\"%s (Init:Place/Rotate)\");", comp->name); /* signal handler message */ 874 875 /* Absolute rotation. */ 876 x = exp_tostring(comp->pos->orientation.x); 877 y = exp_tostring(comp->pos->orientation.y); 878 z = exp_tostring(comp->pos->orientation.z); 879 relcomp = comp->pos->orientation_rel; 880 if(relcomp == NULL) 881 { /* Absolute orientation. */ 882 coutf(" rot_set_rotation(%srota%s,", ID_PRE, comp->name); 883 code_set_source(instr->quoted_source, 884 exp_getlineno(comp->pos->orientation.x)); 885 coutf(" (%s)*%s,", x, d2r); 886 code_set_source(instr->quoted_source, 887 exp_getlineno(comp->pos->orientation.y)); 888 coutf(" (%s)*%s,", y, d2r); 889 code_set_source(instr->quoted_source, 890 exp_getlineno(comp->pos->orientation.z)); 891 coutf(" (%s)*%s);", z, d2r); 892 code_reset_source(); 893 } 894 else 895 { 896 coutf(" rot_set_rotation(%str1,", ID_PRE); 897 code_set_source(instr->quoted_source, 898 exp_getlineno(comp->pos->orientation.x)); 899 coutf(" (%s)*%s,", x, d2r); 900 code_set_source(instr->quoted_source, 901 exp_getlineno(comp->pos->orientation.y)); 902 coutf(" (%s)*%s,", y, d2r); 903 code_set_source(instr->quoted_source, 904 exp_getlineno(comp->pos->orientation.z)); 905 coutf(" (%s)*%s);", z, d2r); 906 code_reset_source(); 907 coutf(" rot_mul(%str1, %srota%s, %srota%s);", 908 ID_PRE, ID_PRE, relcomp->name, ID_PRE, comp->name); 909 } 910 str_free(z); 911 str_free(y); 912 str_free(x); 913 914 /* Relative rotation. */ 915 if(last == NULL) 916 { /* First component. */ 917 coutf(" rot_copy(%srotr%s, %srota%s);", 918 ID_PRE, comp->name, ID_PRE, comp->name); 919 } 920 else 921 { 922 coutf(" rot_transpose(%srota%s, %str1);", ID_PRE, last->name, ID_PRE); 923 coutf(" rot_mul(%srota%s, %str1, %srotr%s);", 924 ID_PRE, comp->name, ID_PRE, ID_PRE, comp->name); 925 } 926 927 /* Absolute position. */ 928 x = exp_tostring(comp->pos->place.x); 929 y = exp_tostring(comp->pos->place.y); 930 z = exp_tostring(comp->pos->place.z); 931 relcomp = comp->pos->place_rel; 932 if(relcomp == NULL) 933 { 934 coutf(" %sposa%s = coords_set(", ID_PRE, comp->name); 935 code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.x)); 936 coutf(" %s,", x); 937 code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.y)); 938 coutf(" %s,", y); 939 code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.z)); 940 coutf(" %s);", z); 941 code_reset_source(); 942 } 943 else 944 { 945 coutf(" %stc1 = coords_set(", ID_PRE); 946 code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.x)); 947 coutf(" %s,", x); 948 code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.y)); 949 coutf(" %s,", y); 950 code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.z)); 951 coutf(" %s);", z); 952 code_reset_source(); 953 coutf(" rot_transpose(%srota%s, %str1);", 954 ID_PRE, relcomp->name, ID_PRE); 955 coutf(" %stc2 = rot_apply(%str1, %stc1);", 956 ID_PRE, ID_PRE, ID_PRE); 957 coutf(" %sposa%s = coords_add(%sposa%s, %stc2);", 958 ID_PRE, comp->name, ID_PRE, relcomp->name, ID_PRE); 959 } 960 961 str_free(z); 962 str_free(y); 963 str_free(x); 964 965 /* Relative position. */ 966 if(last == NULL) 967 coutf(" %stc1 = coords_neg(%sposa%s);", ID_PRE, ID_PRE, comp->name); 968 else 969 coutf(" %stc1 = coords_sub(%sposa%s, %sposa%s);", 970 ID_PRE, ID_PRE, last->name, ID_PRE, comp->name); 971 coutf(" %sposr%s = rot_apply(%srota%s, %stc1);", 972 ID_PRE, comp->name, ID_PRE, comp->name, ID_PRE); 973 974 coutf(" %sDEBUG_COMPONENT(\"%s\", %sposa%s, %srota%s)", 975 ID_PRE, comp->name, ID_PRE, comp->name, ID_PRE, comp->name); 976 977 coutf(" %scomp_posa[%i] = %sposa%s;", ID_PRE, comp->index, ID_PRE, comp->name); 978 coutf(" %scomp_posr[%i] = %sposr%s;", ID_PRE, comp->index, ID_PRE, comp->name); 979 coutf(" %sNCounter[%i] = %sPCounter[%i] = %sP2Counter[%i] = 0;", 980 ID_PRE, comp->index, ID_PRE, comp->index, ID_PRE, comp->index); 981 coutf(" %sAbsorbProp[%i]= 0;", ID_PRE, comp->index); 982 983 last = comp; 984 985 } /* end while instr->complist */ 986 list_iterate_end(liter); 987 988 /* Initialization of component and user initialization code. */ 989 cout(" /* Component initializations. */"); 990 liter = list_iterate(instr->complist); 991 while((comp = list_next(liter)) != NULL) 992 { 993 List_handle setpar; 994 struct comp_iformal *par; 995 996 coutf(" /* Initializations for component %s. */", comp->name); 997 coutf(" SIG_MESSAGE(\"%s (Init)\");", comp->name); /* signal handler message */ 998 999 /* Users initializations. */ 1000 if(list_len(comp->def->init_code->lines) > 0) 1001 cogen_comp_scope(comp, 0, (void (*)(void *))codeblock_out_brace, 1002 comp->def->init_code); 1003 cout(""); 1004 } 1005 list_iterate_end(liter); 1006 1007 /* Output graphics representation of components. */ 1008 coutf(" if(%sdotrace) %sdisplay();", ID_PRE, ID_PRE); 1009 coutf(" %sDEBUG_INSTR_END()", ID_PRE); 1010 cout(" }"); 1011 cout(""); 1012 1013 cout("} /* end init */"); 1014 cout(""); 1015} /* cogen_init */ 1016 1017/******************************************************************************* 1018* cogen_trace: Generate the TRACE section. 1019* Extended Grammar: uses goto and labels and installs tests 1020* WHEN: the trace section of comp is embraced in a: if (when) { ... } 1021* GROUP: defines a global Group_<name> flag which gets true when one of the 1022* comps SCATTER. Rest of GROUP is then skipped, using goto's. 1023* ABSORB @MCCODE_PARTICLE@ are sent to label absorbComp at the end of component 1024* and next comp in GROUP is tested. 1025* JUMP: sends @MCCODE_PARTICLE@ to the JumpTrace labels, either with condition 1026* or condition is (counter < iterations) 1027* SPLIT: loops from comp/group TRACE to END, incrementing mcrun_num 1028*******************************************************************************/ 1029static void 1030cogen_trace(struct instr_def *instr) 1031{ 1032 List_handle liter; 1033 struct comp_inst *comp; 1034 struct group_inst *group; 1035 int i; 1036 1037 if (verbose) fprintf(stderr, "Writing instrument and components TRACE\n"); 1038 1039 static char *statepars_all[NUM_STATE_PARS] = 1040 { /* these particle state parameter names are used for all calls */ 1041#if MCCODE_PROJECT == 1 /* neutron */ 1042 "x", "y", "z", "vx", "vy", "vz", 1043 "t", "sx", "sy", "sz", "p" 1044#elif MCCODE_PROJECT == 2 /* xray */ 1045 "x", "y", "z", "kx", "ky", "kz", 1046 "phi", "t", "Ex", "Ey","Ez", "p" 1047#endif 1048 }; 1049 static char *statepars_change[9] = 1050 { /* these particle state parameter names are used for coordinate change only */ 1051#if MCCODE_PROJECT == 1 /* neutron */ 1052 "x", "y", "z", "vx", "vy", "vz", "sx", "sy", "sz" 1053#elif MCCODE_PROJECT == 2 /* xray */ 1054 "x", "y", "z", "kx", "ky", "kz", "Ex", "Ey","Ez" 1055#endif 1056 }; 1057 1058 /* Output the function header. */ 1059 coutf("void %sraytrace(void) {", ID_PRE); 1060#if MCCODE_PROJECT == 1 /* neutron */ 1061 /* Neutronics-specific defines */ 1062 cout(" /* Neutronics-specific defines */"); 1063 cout("#ifdef NEUTRONICS"); 1064 coutf("extern double %snx, %sny, %snz, %snvx, %snvy, %snvz;", ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE); 1065 coutf("extern double %snt, %snsx, %snsy, %snsz, %snp;", ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE); 1066 cout("#endif"); 1067 cout(" /* End of Neutronics-specific defines */"); 1068#endif 1069 1070 /* Local @MCCODE_PARTICLE@ state. */ 1071 cout(" /* Copy @MCCODE_PARTICLE@ state to local variables. */"); 1072 for(i = 0; i < NUM_STATE_PARS; i++) 1073 coutf(" MCNUM %snl%s = %sn%s;", ID_PRE, statepars_all[i], ID_PRE, statepars_all[i]); 1074 cout(""); 1075 1076 /* Debugging (initial state). */ 1077 coutf(" %sDEBUG_ENTER()", ID_PRE); 1078 coutf(" %sDEBUG_STATE(" , ID_PRE); 1079 for(i = 0; i < NUM_STATE_PARS; i++) 1080 if (i < NUM_STATE_PARS-1) coutf(" %snl%s,", ID_PRE, statepars_all[i]); 1081 else coutf(" %snl%s)", ID_PRE, statepars_all[i]); 1082 1083 /* Set group flags */ 1084 if (list_len(instr->grouplist) > 0) 1085 { 1086 cout("/* Set Component group definitions (flags) */"); 1087 liter = list_iterate(instr->grouplist); 1088 while(group = list_next(liter)) 1089 { 1090 coutf(" %sGroup%s=0; /* equals index of scattering comp when in group */", ID_PRE, group->name); 1091 } 1092 list_iterate_end(liter); 1093 } 1094 /* default is the normal ABSORB to end of TRACE */ 1095 coutf("#define %sabsorb %sabsorbAll", ID_PRE, ID_PRE); 1096 1097 /* initiate iteration counters for each TRACE */ 1098 liter = list_iterate(instr->complist); 1099 while((comp = list_next(liter)) != NULL) 1100 { 1101 if(list_len(comp->jump) > 0) { 1102 struct jump_struct *this_jump; 1103 List_handle liter2; 1104 liter2 = list_iterate(comp->jump); 1105 while(this_jump = list_next(liter2)) { 1106 /* create counter for iteration */ 1107 if (this_jump->iterate) 1108 coutf(" %sJumpCounter%s_%i=0;", 1109 ID_PRE, comp->name, this_jump->index); 1110 } 1111 list_iterate_end(liter2); 1112 } 1113 /* if comp is in a split GROUP, install counter only for first comp of GROUP */ 1114 if (comp->group && comp->group->split) { 1115 if (!strcmp(comp->name, comp->group->first_comp)) 1116 comp->split = comp->group->split; 1117 else comp->split = NULL; 1118 } 1119 if (comp->split) { 1120 coutf(" /* SPLIT counter for component %s */", comp->name); 1121 coutf(" int %sSplit_%s=0;", ID_PRE, comp->name); 1122 fprintf(stderr,"Info: Defining SPLIT from %s=%s() to END in instrument %s\n", 1123 comp->name, comp->type, instr->name); 1124 } 1125 } 1126 list_iterate_end(liter); 1127 1128 /* Now the trace code for each component. Proper scope is set up for each 1129 component using #define/#undef. */ 1130 liter = list_iterate(instr->complist); 1131 while((comp = list_next(liter)) != NULL) 1132 { 1133 List_handle statepars_handle; 1134 1135 coutf(" /* TRACE Component %s [%i] */", comp->name, comp->index); 1136 1137 /* Change of coordinates to local frame, including spin. */ 1138 coutf(" %scoordschange(%sposr%s, %srotr%s,", ID_PRE, ID_PRE, comp->name, 1139 ID_PRE, comp->name); 1140 for(i = 0; i < 9; i++) 1141 if (i < 9-1) coutf(" &%snl%s,", ID_PRE, statepars_change[i]); 1142 else coutf(" &%snl%s);", ID_PRE, statepars_change[i]); 1143 1144 /* JUMP RELATIVE comp */ 1145 coutf(" /* define label inside component %s (without coords transformations) */", comp->name); 1146 coutf(" %sJumpTrace_%s:", ID_PRE, comp->name); 1147 1148 coutf(" SIG_MESSAGE(\"%s (Trace)\");", comp->name); /* signal handler message */ 1149 coutf(" %sDEBUG_COMP(\"%s\")", ID_PRE, comp->name); 1150 /* Debugging (entry into component). */ 1151 coutf(" %sDEBUG_STATE(", ID_PRE); 1152 for(i = 0; i < NUM_STATE_PARS; i++) 1153 if (i < NUM_STATE_PARS-1) coutf(" %snl%s,", ID_PRE, statepars_all[i]); 1154 else coutf(" %snl%s)", ID_PRE, statepars_all[i]); 1155 1156 for(i = 0; i < NUM_STATE_PARS; i++) 1157 coutf("#define %s %snl%s", statepars_all[i], ID_PRE, statepars_all[i]); 1158 1159 cout(""); 1160 coutf("#define %sabsorbComp %sabsorbComp%s", ID_PRE, ID_PRE, comp->name); 1161 1162 1163#if MCCODE_PROJECT == 1 /* neutron */ 1164 static char *store ="STORE_NEUTRON"; 1165 static char *restore="RESTORE_NEUTRON"; 1166#elif MCCODE_PROJECT == 2 /* xray */ 1167 static char *store ="STORE_XRAY"; 1168 static char *restore="RESTORE_XRAY"; 1169#endif 1170 1171 /* store @MCCODE_PARTICLE@ state in mccomp_storein */ 1172 if (!comp->split) { 1173 coutf(" %s(%i,", store, comp->index); /* STORE */ 1174 for(i = 0; i < NUM_STATE_PARS; i++) 1175 if (i < NUM_STATE_PARS-1) coutf(" %snl%s,", ID_PRE, statepars_all[i]); 1176 else coutf(" %snl%s);",ID_PRE, statepars_all[i]); 1177 } else { 1178 /* spliting: store first time, then restore @MCCODE_PARTICLE@ */ 1179 char *exp=exp_tostring(comp->split); /* number of splits */ 1180 coutf(" if (!%sSplit_%s) { /* STORE only the first time */", ID_PRE, comp->name); 1181 coutf(" if (floor(%s) > 1) p /= floor(%s); /* adapt weight for SPLITed @MCCODE_PARTICLE@ */", exp, exp); 1182 coutf(" %s(%i,", store, comp->index); /* STORE */ 1183 for(i = 0; i < NUM_STATE_PARS; i++) 1184 if (i < NUM_STATE_PARS-1) coutf(" %snl%s,", ID_PRE, statepars_all[i]); 1185 else coutf(" %snl%s);",ID_PRE, statepars_all[i]); 1186 coutf(" } else {"); 1187 coutf(" %s(%i,", restore, comp->index); /* RESTORE */ 1188 for(i = 0; i < NUM_STATE_PARS; i++) 1189 if (i < NUM_STATE_PARS-1) coutf(" %snl%s,", ID_PRE, statepars_all[i]); 1190 else coutf(" %snl%s);",ID_PRE, statepars_all[i]); 1191 cout (" }"); 1192 coutf(" %sSplit_%s++; /* SPLIT number */", ID_PRE, comp->name); 1193 str_free(exp); 1194 } /* SPLIT handling */ 1195 1196 coutf(" %sScattered=0;", ID_PRE); 1197 coutf(" %sRestore=0;", ID_PRE); 1198 coutf(" %sNCounter[%i]++;", ID_PRE, comp->index); 1199 coutf(" %sPCounter[%i] += p;", ID_PRE, comp->index); 1200 coutf(" %sP2Counter[%i] += p*p;", ID_PRE, comp->index); 1201 1202 if (comp->group) 1203 { 1204 coutf(" if (!%sGroup%s) { /* previous comps of GROUP have not SCATTERED yet */", ID_PRE, comp->group->name); 1205 coutf("#undef %sabsorb", ID_PRE); 1206 cout ("/* if ABSORBed in GROUP/comp, will go to end of component */"); 1207 coutf("#define %sabsorb %sabsorbComp%s", ID_PRE, ID_PRE, comp->name); 1208 1209 } /* GROUP */ 1210 1211 /* write component parameters and trace+extend code */ 1212 /* also handles jumps after extend */ 1213 cogen_comp_scope(comp, 2, (void (*)(void *))codeblock_out_brace, 1214 comp->def->trace_code); 1215 1216 if (comp->group) { 1217 coutf("#undef %sabsorb", ID_PRE); 1218 coutf("#define %sabsorb %sabsorbAll", ID_PRE, ID_PRE); 1219 coutf(" } /* end comp %s in GROUP %s */", comp->name, comp->group->name); 1220 coutf(" if (SCATTERED) {\n %sGroup%s=%i;\n } else {\n RESTORE=1;\n }", 1221 ID_PRE, comp->group->name, comp->index); 1222 } /* GROUP */ 1223 /* mcabsorbComp label for any component */ 1224 cout (" /* Label for restoring @MCCODE_PARTICLE@ */"); 1225 coutf(" %sabsorbComp%s:", ID_PRE, comp->name); 1226 coutf(" if (RESTORE) /* restore if needed */"); 1227 coutf(" { %s(%i,", restore, comp->index); /* RESTORE */ 1228 for(i = 0; i < NUM_STATE_PARS; i++) { 1229 if (i < NUM_STATE_PARS-1) coutf(" %snl%s,", ID_PRE, statepars_all[i]); 1230 else coutf(" %snl%s); }",ID_PRE, statepars_all[i]); 1231 } 1232 1233 /* GROUP - last element */ 1234 if (comp->group) { 1235 if (!strcmp(comp->name, comp->group->last_comp)) { 1236 /* last comp of GROUP: restore default ABSORB */ 1237 coutf("/* end of GROUP %s */", comp->group->name); 1238 coutf(" if (!%sGroup%s) ABSORB; /* absorb @MCCODE_PARTICLE@ non scattered in GROUP */", ID_PRE, comp->group->name); 1239 coutf(" %sGroup%s=0; /* reset group scattered flag */", ID_PRE, comp->group->name); 1240 } 1241 } 1242 1243 coutf("#undef %sabsorbComp", ID_PRE); 1244 for(i = NUM_STATE_PARS-1; i >= 0; i--) 1245 coutf("#undef %s", statepars_all[i]); 1246 1247 /* Debugging (exit from component). */ 1248 coutf(" %sDEBUG_STATE(", ID_PRE); 1249 for(i = 0; i < NUM_STATE_PARS; i++) 1250 if (i < NUM_STATE_PARS-1) coutf("%snl%s,", ID_PRE, statepars_all[i]); 1251 else coutf("%snl%s)", ID_PRE, statepars_all[i]); 1252 cout(""); 1253 } /* while comp */ 1254 list_iterate_end(liter); 1255 /* SPLITing: should loop components if required */ 1256 liter = list_iterate(instr->complist); 1257 char *reverse_SplitJumps = str_dup(""); 1258 char has_splits=0; 1259 while((comp = list_next(liter)) != NULL) 1260 { 1261 if (comp->split) { 1262 has_splits = 1; 1263 char *exp=exp_tostring(comp->split); /* number of splits */ 1264 char line[256]; 1265 char cat_line[1024]; strcpy(cat_line, ""); 1266 sprintf(line," if (%sSplit_%s && %sSplit_%s < (%s)) {\n", 1267 ID_PRE, comp->name, ID_PRE, comp->name, exp); 1268 strcat(cat_line, line); 1269 if (comp->group) { 1270 sprintf(line," %sGroup%s=0;\n", ID_PRE, comp->group->name); 1271 strcat(cat_line, line); 1272 } 1273 sprintf(line," goto %sJumpTrace_%s;\n }\n", ID_PRE, comp->name); 1274 strcat(cat_line, line); 1275 sprintf(line," else %sSplit_%s=0;\n", ID_PRE, comp->name); 1276 strcat(cat_line, line); 1277 char *tmp=str_cat(cat_line, reverse_SplitJumps, NULL); 1278 str_free(reverse_SplitJumps); reverse_SplitJumps = tmp; 1279 str_free(exp); 1280 } 1281 } /* while comp */ 1282 list_iterate_end(liter); 1283 1284 /* Absorbing @MCCODE_PARTICLE@ - goto this label to skip remaining components. End of TRACE */ 1285 coutf(" %sabsorbAll:", ID_PRE); 1286 1287 if (has_splits) coutf(" /* SPLIT loops in reverse order */\n%s", reverse_SplitJumps); 1288 1289 /* Debugging (final state). */ 1290 coutf(" %sDEBUG_LEAVE()", ID_PRE); 1291 coutf(" %sDEBUG_STATE(", ID_PRE); 1292 for(i = 0; i < NUM_STATE_PARS; i++) 1293 if (i < NUM_STATE_PARS-1) coutf("%snl%s,", ID_PRE, statepars_all[i]); 1294 else coutf("%snl%s)", ID_PRE, statepars_all[i]); 1295 1296 /* Copy back @MCCODE_PARTICLE@ state to global variables. */ 1297 /* ToDo: Currently, this will be in the local coordinate system of the last 1298 component - should be transformed back into the global system. */ 1299 cout(" /* Copy @MCCODE_PARTICLE@ state to global variables. */"); 1300 for(i = 0; i < NUM_STATE_PARS; i++) 1301 coutf(" %sn%s = %snl%s;", ID_PRE, statepars_all[i], ID_PRE, statepars_all[i]); 1302 cout(""); 1303 1304 /* Function end. */ 1305 cout("} /* end trace */"); 1306 cout(""); 1307} /* cogen_trace */ 1308/******************************************************************************* 1309* cogen_save: Generate the SAVE section. 1310*******************************************************************************/ 1311static void 1312cogen_save(struct instr_def *instr) 1313{ 1314 List_handle liter; /* For list iteration. */ 1315 struct comp_inst *comp; /* Component instance. */ 1316 1317 if (verbose) fprintf(stderr, "Writing instrument and components SAVE\n"); 1318 1319 /* User SAVE code from component definitions (for each instance). */ 1320 coutf("void %ssave(FILE *handle) {", ID_PRE); 1321 /* In case the save occurs during simulation (-USR2 not at end), we must close 1322 * current siminfo and re-open it, not to have redundant monitor entries 1323 * saved each time for each monitor. The sim_info is then incomplete, but 1324 * data is saved entirely. It is completed during the last siminfo_close 1325 * of mcraytrace 1326 */ 1327 coutf(" if (!handle) %ssiminfo_init(NULL);", ID_PRE); 1328 cout(" /* User component SAVE code. */"); 1329 cout(""); 1330 liter = list_iterate(instr->complist); 1331 while(comp = list_next(liter)) 1332 { 1333 if(list_len(comp->def->save_code->lines) > 0) 1334 { 1335 coutf(" /* User SAVE code for component '%s'. */", comp->name); 1336 coutf(" SIG_MESSAGE(\"%s (Save)\");", comp->name); /* signal handler message */ 1337 cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace, 1338 comp->def->save_code); 1339 cout(""); 1340 } 1341 } 1342 list_iterate_end(liter); 1343 1344 /* User's SAVE code from the instrument definition file. */ 1345 if(list_len(instr->saves->lines) > 0) 1346 { 1347 cout(" /* User SAVE code from instrument definition. */"); 1348 coutf(" SIG_MESSAGE(\"%s (Save)\");", instr->name); 1349 cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace, 1350 instr->saves); 1351 cout(""); 1352 } 1353 coutf(" if (!handle) %ssiminfo_close(); ", ID_PRE); 1354 cout("} /* end save */"); 1355} /* cogen_save */ 1356 1357/******************************************************************************* 1358* cogen_finally: Generate the FINALLY section. 1359*******************************************************************************/ 1360static void 1361cogen_finally(struct instr_def *instr) 1362{ 1363 List_handle liter; /* For list iteration. */ 1364 struct comp_inst *comp; /* Component instance. */ 1365 1366 if (verbose) fprintf(stderr, "Writing instrument and components FINALLY\n"); 1367 1368 /* User FINALLY code from component definitions (for each instance). */ 1369 coutf("void %sfinally(void) {", ID_PRE); 1370 cout(" /* User component FINALLY code. */"); 1371 /* first call SAVE code to save any remaining data */ 1372 coutf(" %ssiminfo_init(NULL);", ID_PRE); 1373 coutf(" %ssave(%ssiminfo_file); /* save data when simulation ends */", ID_PRE, ID_PRE); 1374 cout(""); 1375 liter = list_iterate(instr->complist); 1376 while(comp = list_next(liter)) 1377 { 1378 if(list_len(comp->def->finally_code->lines) > 0) 1379 { 1380 coutf(" /* User FINALLY code for component '%s'. */", comp->name); 1381 coutf(" SIG_MESSAGE(\"%s (Finally)\");", comp->name); /* signal handler message */ 1382 cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace, 1383 comp->def->finally_code); 1384 cout(""); 1385 } 1386 coutf(" if (!%sNCounter[%i]) " 1387 "fprintf(stderr, \"Warning: No @MCCODE_PARTICLE@ could reach Component[%i] %s\\n\");", 1388 ID_PRE, comp->index, comp->index, comp->name); 1389 if (comp->split) { 1390 char *exp=exp_tostring(comp->split); /* number of splits */ 1391 coutf(" if (%sNCounter[%i] < 1000*(%s)) fprintf(stderr, \n" 1392 "\"Warning: Number of events %%g reaching SPLIT position Component[%i] %s=%s()\\n\"\n" 1393 "\" is probably too low. Increase Ncount.\\n\", %sNCounter[%i]);\n", 1394 ID_PRE, comp->index, exp, comp->index, comp->name, comp->type, ID_PRE, comp->index); 1395 str_free(exp); 1396 } 1397 coutf(" if (%sAbsorbProp[%i]) " 1398 "fprintf(stderr, " 1399 "\"Warning: %%g events were removed in Component[%i] %s=%s()\\n\"\n" 1400 "\" (negative time, miss next components, rounding errors, Nan, Inf).\\n\"" 1401 ", %sAbsorbProp[%i]);" 1402 , ID_PRE, comp->index, comp->index, comp->name, comp->type, ID_PRE, comp->index); 1403 } 1404 list_iterate_end(liter); 1405 1406 /* User's FINALLY code from the instrument definition file. */ 1407 if(list_len(instr->finals->lines) > 0) 1408 { 1409 cout(" /* User FINALLY code from instrument definition. */"); 1410 coutf(" SIG_MESSAGE(\"%s (Finally)\");", instr->name); /* signal handler message */ 1411 cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace, 1412 instr->finals); 1413 cout(""); 1414 } 1415 coutf(" %ssiminfo_close(); ", ID_PRE); 1416 cout("} /* end finally */"); 1417} /* cogen_finally */ 1418 1419/******************************************************************************* 1420* cogen_mcdisplay: Generate the MCDISPLAY section. 1421*******************************************************************************/ 1422static void 1423cogen_mcdisplay(struct instr_def *instr) 1424{ 1425 List_handle liter; /* For list iteration. */ 1426 struct comp_inst *comp; /* Component instance. */ 1427 1428 if (verbose) fprintf(stderr, "Writing instrument and components MCDISPLAY\n"); 1429 1430 /* User FINALLY code from component definitions (for each instance). */ 1431 cout("#define magnify mcdis_magnify"); 1432 cout("#define line mcdis_line"); 1433 cout("#define dashed_line mcdis_dashed_line"); 1434 cout("#define multiline mcdis_multiline"); 1435 cout("#define rectangle mcdis_rectangle"); 1436 cout("#define box mcdis_box"); 1437 cout("#define circle mcdis_circle"); 1438 cout("#define cylinder mcdis_cylinder"); 1439 cout("#define sphere mcdis_sphere"); 1440 coutf("void %sdisplay(void) {", ID_PRE); 1441 cout(" printf(\"MCDISPLAY: start\\n\");"); 1442 cout(" /* Components MCDISPLAY code. */"); 1443 cout(""); 1444 1445 liter = list_iterate(instr->complist); 1446 while(comp = list_next(liter)) 1447 { 1448 if(list_len(comp->def->mcdisplay_code->lines) > 0) 1449 { 1450 char *quoted_name = str_quote(comp->name); 1451 coutf(" /* MCDISPLAY code for component '%s'. */", comp->name); 1452 coutf(" SIG_MESSAGE(\"%s (McDisplay)\");", comp->name); /* signal handler message */ 1453 coutf(" printf(\"MCDISPLAY: component %%s\\n\", \"%s\");", quoted_name); 1454 1455 cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace, 1456 comp->def->mcdisplay_code); 1457 cout(""); 1458 str_free(quoted_name); 1459 } 1460 } 1461 list_iterate_end(liter); 1462 1463 cout(" printf(\"MCDISPLAY: end\\n\");"); 1464 cout("} /* end display */"); 1465 cout("#undef magnify"); 1466 cout("#undef line"); 1467 cout("#undef dashed_line"); 1468 cout("#undef multiline"); 1469 cout("#undef rectangle"); 1470 cout("#undef box"); 1471 cout("#undef circle"); 1472 cout("#undef cylinder"); 1473 cout("#undef sphere"); 1474} /* cogen_mcdisplay */ 1475 1476 1477/******************************************************************************* 1478* Output code for the mcstas runtime system. Default is to copy the runtime 1479* code into the generated executable, to minimize problems with finding the 1480* right files during compilation and linking, but this may be changed using 1481* the --no-runtime compiler switch. 1482*******************************************************************************/ 1483static void 1484cogen_runtime(struct instr_def *instr) 1485{ 1486 char *sysdir_orig; 1487 char *sysdir_new; 1488 char pathsep[3]; 1489 int i,j=0; 1490 /* handles Windows '\' chararcters for embedding sys_dir into source code */ 1491 if (MC_PATHSEP_C != '\\') strcpy(pathsep, MC_PATHSEP_S); else strcpy(pathsep, "\\\\"); 1492 sysdir_orig = get_sys_dir(); 1493 sysdir_new = (char *)mem(2*strlen(sysdir_orig)); 1494 for (i=0; i < strlen(sysdir_orig); i++) 1495 { 1496 if (sysdir_orig[i] == '\\') 1497 { sysdir_new[j] = '\\'; j++; sysdir_new[j] = '\\'; } 1498 else sysdir_new[j] = sysdir_orig[i]; 1499 j++; 1500 } 1501 sysdir_new[j] = '\0'; 1502 if(instr->use_default_main) 1503 cout("#define MC_USE_DEFAULT_MAIN"); 1504 if(instr->enable_trace) 1505 cout("#define MC_TRACE_ENABLED"); 1506 if(instr->portable) 1507 cout("#define MC_PORTABLE"); 1508 if(instr->include_runtime) 1509 { 1510 cout("#define MC_EMBEDDED_RUNTIME"); /* Some stuff will be static. */ 1511 embed_file("mccode-r.h"); 1512#if MCCODE_PROJECT == 1 /* neutron */ 1513 embed_file("mcstas-r.h"); 1514#elif MCCODE_PROJECT == 2 /* xray */ 1515 embed_file("mcxtrace-r.h"); 1516#endif 1517 /* NeXus support, only active with -DUSE_NEXUS */ 1518 if (verbose) printf("Specify -DUSE_NEXUS -lNeXus in the CFLAGS (dependency) to enable NeXus support\n"); 1519 embed_file("mccode-r.c"); 1520#if MCCODE_PROJECT == 1 /* neutron */ 1521 embed_file("mcstas-r.c"); 1522#elif MCCODE_PROJECT == 2 /* xray */ 1523 embed_file("mcxtrace-r.c"); 1524#endif 1525 } 1526 else 1527 { 1528 coutf("#include \"%s%sshare%smccode-r.h\"", sysdir_new, pathsep, pathsep); 1529#if MCCODE_PROJECT == 1 /* neutron */ 1530 coutf("#include \"%s%sshare%smcstas-r.h\"", sysdir_new, pathsep, pathsep); 1531#elif MCCODE_PROJECT == 2 /* xray */ 1532 coutf("#include \"%s%sshare%smcxtrace-r.h\"", sysdir_new, pathsep, pathsep); 1533#endif 1534 1535 fprintf(stderr,"Dependency: '%s.o' (add it to CFLAGS)\n", "mccode-r"); 1536#if MCCODE_PROJECT == 1 /* neutron */ 1537 fprintf(stderr,"Dependency: '%s.o' (add it to CFLAGS)\n", "mcstas-r"); 1538#elif MCCODE_PROJECT == 2 /* xray */ 1539 fprintf(stderr,"Dependency: '%s.o' (add it to CFLAGS)\n", "mcxtrace-r"); 1540#endif 1541 fprintf(stderr,"Dependency: '%s.o' (add it to CFLAGS)\n", "mcstas-r"); 1542 fprintf(stderr,"Dependency: '-DUSE_NEXUS -lNeXus' (add it to CFLAGS) to enable NeXus support\n"); 1543 fprintf(stderr,"To build instrument %s, compile and link with these libraries (in %s%sshare)\n", instrument_definition->quoted_source, sysdir_new, pathsep); 1544 } 1545 1546 coutf("#ifdef MC_TRACE_ENABLED"); 1547 coutf("int %straceenabled = 1;", ID_PRE); 1548 coutf("#else"); 1549 coutf("int %straceenabled = 0;", ID_PRE); 1550 coutf("#endif"); 1551 coutf("#define MCSTAS \"%s%s\"", sysdir_new,pathsep); 1552 coutf("int %sdefaultmain = %d;", ID_PRE, instr->use_default_main); 1553 coutf("char %sinstrument_name[] = \"%s\";", ID_PRE, instr->name); 1554 coutf("char %sinstrument_source[] = \"%s\";", ID_PRE, instr->source); 1555 coutf("char *%sinstrument_exe=NULL; /* will be set to argv[0] in main */", ID_PRE); 1556 if(instr->use_default_main) 1557 cout("int main(int argc, char *argv[]){return mccode_main(argc, argv);}"); 1558} /* cogen_runtime */ 1559 1560 1561/******************************************************************************* 1562* Generate the output file (in C). 1563*******************************************************************************/ 1564void 1565cogen(char *output_name, struct instr_def *instr) 1566{ 1567 time_t t; 1568 char date[64]; 1569 1570 time(&t); 1571 strncpy(date, ctime(&t), 64); 1572 if (strlen(date)) date[strlen(date)-1] = '\0'; 1573 1574 /* Initialize output file. */ 1575 if(!output_name || !output_name[0] || !strcmp(output_name, "-")) 1576 { 1577 output_handle = fdopen(1, "w"); 1578 quoted_output_file_name = str_quote("<stdout>"); 1579 } 1580 else 1581 { 1582 output_handle = fopen(output_name, "w"); 1583 quoted_output_file_name = str_quote(output_name); 1584 } 1585 num_next_output_line = 1; 1586 if(output_handle == NULL) 1587 fatal_error("Error opening output file '%s'\n", output_name); 1588 1589 cout("/* Automatically generated file. Do not edit. "); 1590 cout(" * Format: ANSI C source code"); 1591#if MCCODE_PROJECT == 1 /* neutron */ 1592 cout(" * Creator: McStas <http://www.mcstas.org>"); 1593#elif MCCODE_PROJECT == 2 /* xray */ 1594 cout(" * Creator: McXtrace <http://www.mcxtrace.org>"); 1595#endif 1596 coutf(" * Instrument: %s (%s)", instr->source, instr->name); 1597 coutf(" * Date: %s", date); 1598 coutf(" * File: %s", output_name); 1599 coutf(" * Compile: cc -o %s.%s %s %s", 1600 instr->name, 1601#ifdef WIN32 1602 "exe", 1603#else 1604 "out", 1605#endif 1606 output_name, instr->dependency); 1607 coutf(" * CFLAGS=%s", instr->dependency); 1608 cout(" */\n"); 1609 cout(""); 1610 coutf("#define MCCODE_STRING \"%s\"", MCCODE_STRING); 1611 coutf("#define FLAVOR \"%s\"", FLAVOR); 1612 coutf("#define FLAVOR_UPPER \"%s\"", FLAVOR_UPPER); 1613 cogen_runtime(instr); 1614 cogen_decls(instr); 1615 cogen_init(instr); 1616 cogen_trace(instr); 1617 cogen_save(instr); 1618 cogen_finally(instr); 1619 cogen_mcdisplay(instr); 1620 coutf("/* end of generated C code %s */", output_name); 1621} /* cogen */ 1622