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