McStas 1.4 : instrument parameters as strings
Farhi
farhi at ill.fr
Tue Aug 29 14:51:30 CEST 2000
(sorry, I think previous message was incomplete)
Hello all mcneutron readers,
I've found a bug in the handling of string parameters for instruments.
Thus, I corrected that, and this requires to update the cogen.c and
lib/mcfrontlib.pl files before McStas 1.4 installation.
Then you will be able to use mcstas simlations with instrument string
parameters:
for instance if you define an instrument by
DEFINE INSTRUMENT D11(GuideSampleLength, string GuideType, Lambda)
you can run it with
mcrun d11 -f MyOutput -n 1e6 -N 32 GuideSampleLength=20 GuideType=Glass
Lambda=4.5,20
mcplot is ok with it.
Cheers.
EF.
--
Emmanuel FARHI, http://www.ill.fr/tas/people/Farhi.html \|/ ____ \|/
TAS-Group, Institut Laue-Langevin (ILL) Grenoble ~@-/ oO \-@~
Avenue J. Horowitz, BP 156, 38042 Grenoble Cedex 9,France /_( \__/ )_\
Work :Tel (33/0) 4 76 20 71 83. Fax (33/0) 4 76 48 39 06 \__U_/
La Grande Arche, Chateau d'Uriage, 38410 Saint Martin d'Uriage 04 76 59 73 94
-------------- next part --------------
/*******************************************************************************
* Code generation from instrument definition.
*
* Project: Monte Carlo Simulation of Triple Axis Spectrometers
* File name: cogen.c
*
* Author: K.N. Aug 20, 1997
*
* $Id: cogen.c,v 1.22 2000/07/27 09:05:30 kn Exp $
*
* Copyright (C) Risoe National Laboratory, 1997-1998, All rights reserved
*******************************************************************************/
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "mcstas.h"
/*******************************************************************************
* Some general comments on code generation.
*
* Code is output in the form of strings using the following functions:
* cout(); (one line at a time)
* coutf(); (with printf-style formatting)
*
* The type of numbers used in the generated code is given by the macro MCNUM
* (defined in mcstas-r.h).
*
* All generated identifiers are prefixed with the string ID_PRE, to make name
* clashes less likely to occur. Currently, for simplicity, we output modified
* names directly, eg.
*
* cout("void " ID_PRE "init(void);");
*
* But to make a later transition to a better name generation scheme possible,
* it is important to use the ID_PRE macro everywhere identifiers are
* generated.
*
* After the ID_PRE prefix a few letters occur in generated names to
* distinguish different kinds of identifiers (instrument parameters,
* component definition parameters, internal temporary variables and so on).
* Care must be takes to choose these letters such that no name clashes will
* occur with names generated by other parts of the code or generated from
* user symbols.
*
* Finally, names generated from user symbols are generally chosen to match
* the originals as closely as possible to make the generated code more
* readable (for debugging purposes).
*
* The following is a list of the identifiers generated in the output. The
* ID_PRE prefix is denoted by ##. The first column gives the identifier as it
* appears in the generated code, the second explains the origin of the
* identifier in the instrument definition source (if any).
*
* ##ip<PAR> From instrument parameter <PAR>.
* ##init Function containing initialization code.
* ##inputtable Table of instrument parameters.
* ##NUMIPAR Macro giving the number of instrument parameters.
* ##numipar Global variable with the value of ##NUMIPAR.
* ##c<C>_<P> From definition or setting parameter <P> in component
* instance <C>.
* ##posa<COMP> Absolute position of coordinate system of <COMP>.
* ##posr<COMP> Position of <COMP> relative to previous component.
* ##rota<COMP> Absolute rotation.
* ##rotr<COMP> Relative rotation.
* ##tc1 Temporary variable used to compute transformations.
* ##tc2
* ##tr1
* ##tr2
* ##nx Neutron state (position, velocity, time, and spin).
* ##ny
* ##nz
* ##nvx
* ##nvy
* ##nvz
* ##nt
* ##nsx
* ##nsy
* ##nsz
* ##np
* ##absorb
*******************************************************************************/
/*******************************************************************************
* Generation of declarations.
*
* The following declarations are generated (## denotes the value ID_PRE):
* 1. Header file #include - "mcstas-r.h" for declarations for the
* mcstas runtime.
* 2. Declarations of global variables to hold the values of the instrument
* parameters. For example, for an instrument parameter OMM, the
* declaration "MCNUM ##ipOMM;" is generated.
* 3. Declaration of a table ##inputtable containing the list of instrument
* parameters. For each parameter, the name, a pointer to the
* corresponding global variable, and the type (double, int,
* string) is given. The macro ##NUMIPAR gives the number of
* entries in the table and is also found as the value of the
* variable ##numipar; in addition, the table is terminated by two
* NULLs. This table is used to read the instrument parameters from
* the user or from another program such as TASCOM.
* 4. User declarations copied verbatim from the instrument definition file.
* 5. Declarations for the component parameters. This uses #define for
* definition parameters and global variables for setting parameters.
* X. User declarations from component definitions.
* X. Declarations of variables for coordinate system transformations.
* X. Declaration of variables for neutron state.
* X. Function prototypes.
*******************************************************************************/
/* Functions for outputting code. */
/* Handle for output file. */
static FILE *output_handle = NULL;/* Handle for output file. */
static int num_next_output_line = 1; /* Line number for next output line. */
static char *quoted_output_file_name = NULL; /* str_quote()'ed name
of output file. */
/* Convert instrument formal parameter type numbers to their enum name. */
char *instr_formal_type_names[] =
{ "instr_type_double", "instr_type_int", "instr_type_string" };
char *instr_formal_type_names_real[] =
{ "MCNUM", "int", "char*" };
/*******************************************************************************
* Output a line of code
* Assumes that the output does not contain newlines.
*******************************************************************************/
static void
cout(char *s)
{
fprintf(output_handle, "%s\n", s);
num_next_output_line++;
}
/*******************************************************************************
* Output a line of code using printf-style format string.
* Assumes that the output does not contain newlines.
*******************************************************************************/
static void
coutf(char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(output_handle, format, ap);
va_end(ap);
fprintf(output_handle, "\n");
num_next_output_line++;
}
/*******************************************************************************
* Output #line directive to handle code coming from a different file.
* The filename is assumed to be already properly quoted for special chars.
*******************************************************************************/
static void
code_set_source(char *filename, int linenum)
{
if(linenum > 0)
coutf("#line %d \"%s\"", linenum, filename);
}
/*******************************************************************************
* Output #line directive to reset back to the generated output C file.
*******************************************************************************/
static void
code_reset_source(void)
{
/* Note: the number after #line refers to the line AFTER the directive. */
coutf("#line %d \"%s\"", num_next_output_line + 1, quoted_output_file_name);
}
static void
codeblock_out(struct code_block *code)
{
List_handle liter; /* For list iteration. */
char *line; /* Single code line. */
if(list_len(code->lines) <= 0)
return;
code_set_source(code->quoted_filename, code->linenum + 1);
liter = list_iterate(code->lines);
while(line = list_next(liter))
{
fprintf(output_handle, "%s", line);
num_next_output_line++;
}
list_iterate_end(liter);
code_reset_source();
}
static void
codeblock_out_brace(struct code_block *code)
{
List_handle liter; /* For list iteration. */
char *line; /* Single code line. */
if(list_len(code->lines) <= 0)
return;
code_set_source(code->quoted_filename, code->linenum);
cout("{");
liter = list_iterate(code->lines);
while(line = list_next(liter))
{
fprintf(output_handle, "%s", line);
num_next_output_line++;
}
list_iterate_end(liter);
cout("}");
code_reset_source();
}
struct code_block *
codeblock_new(void)
{
struct code_block *cb;
palloc(cb);
cb->filename = NULL;
cb->quoted_filename = NULL;
cb->linenum = -1;
cb->lines = list_create();
return cb;
}
/*******************************************************************************
* Read a file and output it to the generated simulation code. Uses a
* fixed-size buffer, and will silently and arbitrarily break long lines.
*******************************************************************************/
static void
embed_file(char *name)
{
char buf[4096];
FILE *f;
int last;
/* First look in the system directory. */
f = open_file_search_sys(name);
/* If not found, look in the full search path. */
if(f == NULL)
f = open_file_search(name);
/* If still not found, abort. */
if(f == NULL)
fatal_error("Could not find file '%s'\n", name);
cout("");
code_set_source(name, 1);
/* Now loop, reading lines and outputting them in the code. */
while(!feof(f))
{
if(fgets(buf, 4096, f) == NULL)
break;
last = strlen(buf) - 1;
if(last >= 0 && (buf[last] == '\n' || buf[last] == '\r'))
buf[last--] = '\0';
if(last >= 0 && (buf[last] == '\n' || buf[last] == '\r'))
buf[last--] = '\0';
cout(buf);
}
fclose(f);
coutf("/* End of file \"%s\". */", name);
cout("");
code_reset_source();
}
/*******************************************************************************
* The following two functions output #define directives around a given piece
* of code to set up the right variable names (eg. the proper scope) for
* instrument and component parameters. The functions are recursive on the
* parameter lists.
*
* The functions first output an appropriate list of #define's, then call the
* supplied function func with the argument data, and finally outputs a
* matching list of #undef's.
*******************************************************************************/
static void cogen_instrument_scope_rec(List_handle parlist,
void (*func)(void *), void *data)
{
struct instr_formal *par;
par = list_next(parlist);
if(par != NULL)
{
coutf("#define %s %sip%s", par->id, ID_PRE, par->id);
cogen_instrument_scope_rec(parlist, func, data);
coutf("#undef %s", par->id);
}
else
{
(*func)(data);
}
}
static void
cogen_instrument_scope(struct instr_def *instr,
void (*func)(void *), void *data)
{
List_handle parlist;
/* This simply starts up the recursion. */
parlist = list_iterate(instr->formals);
cogen_instrument_scope_rec(parlist, func, data);
list_iterate_end(parlist);
}
/* Create the bindings for the SETTING parameter scope. Since the types of
* setting parameters are known, local declarations can be used, avoiding the
* problems with #define macro definitions.
*/
static void
cogen_comp_scope_setpar(char *compname, List_handle set, int infunc,
void (*func)(void *), void *data)
{
char *par;
struct comp_iformal *formal;
/* Get the next setting parameter. */
formal = list_next(set);
if(formal != NULL)
{
/* Create local parameter equal to global value. */
if(infunc)
coutf(" MCNUM %s = %sc%s_%s;", formal->id, ID_PRE, compname, formal->id);
else
coutf("#define %s %sc%s_%s", formal->id, ID_PRE, compname, formal->id);
cogen_comp_scope_setpar(compname, set, infunc, func, data);
if(!infunc)
coutf("#undef %s", formal->id);
}
else
{
(*func)(data); /* Now do the body. */
}
}
/* Create the #define statements to set up the scope for DEFINITION and OUTPUT
* parameters.
*/
static void
cogen_comp_scope_rec(char *compname, List_handle def, List set_list,
List_handle out, int infunc,
void (*func)(void *), void *data)
{
char *par;
struct comp_iformal *formal;
/* First get the next DEFINITION or OUTPUT parameter, if any. */
if(def != NULL)
{
formal = list_next(def);
if(formal == NULL)
def = NULL; /* Now finished with definition parameters. */
else
par = formal->id;
}
if(def == NULL)
par = list_next(out);
if(par != NULL)
{
/* Create #define / #undef pair for this parameter around rest of code. */
coutf("#define %s %sc%s_%s", par, ID_PRE, compname, par);
cogen_comp_scope_rec(compname, def, set_list, out, infunc, func, data);
coutf("#undef %s", par);
}
else
{ /* Now do the SETTING parameters. */
List_handle set;
if(infunc && list_len(set_list) > 0)
coutf("{ /* Declarations of SETTING parameters. */");
set = list_iterate(set_list);
cogen_comp_scope_setpar(compname, set, infunc, func, data);
list_iterate_end(set);
if(infunc && list_len(set_list) > 0)
coutf("} /* End of SETTING parameter declarations. */");
}
}
static void
cogen_comp_scope(struct comp_inst *comp, int infunc,
void (*func)(void *), void *data)
{
List_handle def, out;
coutf("#define %scompcurname \"%s\"", ID_PRE, comp->name);
def = list_iterate(comp->def->def_par);
out = list_iterate(comp->def->out_par);
cogen_comp_scope_rec(comp->name, def, comp->def->set_par, out,
infunc, func, data);
list_iterate_end(out);
list_iterate_end(def);
coutf("#undef %scompcurname", ID_PRE, comp->name);
}
/*******************************************************************************
* Generate declarations from users declaration section in component definition.
*******************************************************************************/
static void
cogen_comp_decls_doit(void *arg)
{
struct comp_inst *comp = arg;
/* Output the user declaration code block. */
codeblock_out(comp->def->decl_code);
}
static void
cogen_comp_decls(struct comp_inst *comp)
{
cogen_comp_scope(comp, 0, cogen_comp_decls_doit, comp);
}
/*******************************************************************************
* Generate declaration part of code.
*******************************************************************************/
static void
cogen_decls(struct instr_def *instr)
{
List_handle liter; /* For list iteration. */
struct comp_iformal *c_formal;/* Name of component formal input parameter */
struct instr_formal *i_formal;/* Name of instrument formal parameter. */
struct comp_inst *comp; /* Component instance. */
/* 1. Function prototypes. */
coutf("void %sinit(void);", ID_PRE);
coutf("void %sraytrace(void);", ID_PRE);
coutf("void %sfinally(void);", ID_PRE);
coutf("void %sdisplay(void);", ID_PRE);
cout("");
/* 2. Global variables for instrument parameters. */
cout("/* Instrument parameters. */");
liter = list_iterate(instr->formals);
while(i_formal = list_next(liter))
{
coutf("%s " ID_PRE "ip%s;", instr_formal_type_names_real[i_formal->type], i_formal->id);
}
list_iterate_end(liter);
cout("");
/* 3. Table of instrument parameters. */
coutf("#define %sNUMIPAR %d", ID_PRE, list_len(instr->formals));
coutf("int %snumipar = %d;", ID_PRE, list_len(instr->formals));
coutf("struct %sinputtable_struct %sinputtable[%sNUMIPAR+1] = {",
ID_PRE, ID_PRE, ID_PRE);
liter = list_iterate(instr->formals);
while(i_formal = list_next(liter))
{
coutf(" \"%s\", &%sip%s, %s,", i_formal->id, ID_PRE, i_formal->id,
instr_formal_type_names[i_formal->type]);
}
list_iterate_end(liter);
coutf(" NULL, NULL, instr_type_double");
coutf("};");
cout("");
/* User's declarations from the instrument definition file. */
cout("/* User declarations from instrument definition. */");
cogen_instrument_scope(instr, (void (*)(void *))codeblock_out, instr->decls);
cout("");
/* Declaration of component definition and setting parameters. */
cout("/* Declarations of component definition and setting parameters. */");
cout("");
liter = list_iterate(instr->complist);
while(comp = list_next(liter))
{
List_handle liter2;
if(list_len(comp->def->def_par) > 0)
{ /* (The if avoids a redundant comment.) */
coutf("/* Definition parameters for component '%s'. */", comp->name);
liter2 = list_iterate(comp->def->def_par);
while(c_formal = list_next(liter2))
{
struct Symtab_entry *entry = symtab_lookup(comp->defpar, c_formal->id);
char *val = exp_tostring(entry->val);
coutf("#define %sc%s_%s %s", ID_PRE, comp->name, c_formal->id, val);
str_free(val);
}
list_iterate_end(liter2);
}
if(list_len(comp->def->set_par) > 0)
{
coutf("/* Setting parameters for component '%s'. */", comp->name);
liter2 = list_iterate(comp->def->set_par);
while(c_formal = list_next(liter2))
{
coutf("MCNUM %sc%s_%s;", ID_PRE, comp->name, c_formal->id);
}
list_iterate_end(liter2);
}
if(list_len(comp->def->def_par) > 0 || list_len(comp->def->set_par) > 0)
cout("");
}
list_iterate_end(liter);
/* User declarations from component definitions (for each instance). */
cout("/* User component declarations. */");
cout("");
liter = list_iterate(instr->complist);
while(comp = list_next(liter))
{
if(list_len(comp->def->decl_code->lines) > 0)
{
coutf("/* User declarations for component '%s'. */", comp->name);
cogen_comp_decls(comp);
cout("");
}
}
list_iterate_end(liter);
/* Declarations for the position and rotation transformations between
coordinate systems of components. */
liter = list_iterate(instr->complist);
while(comp = list_next(liter))
{
coutf("Coords %sposa%s, %sposr%s;", ID_PRE, comp->name, ID_PRE, comp->name);
coutf("Rotation %srota%s, %srotr%s;", ID_PRE, comp->name, ID_PRE, comp->name);
}
list_iterate_end(liter);
cout("");
/* Neutron state. */
coutf("MCNUM %snx, %sny, %snz, %snvx, %snvy, %snvz, %snt, "
"%snsx, %snsy, %snsz, %snp;",
ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
ID_PRE, ID_PRE, ID_PRE, ID_PRE);
cout("");
}
/*******************************************************************************
* Code generation for any NXDICT or NXDICTFILE declarations.
*******************************************************************************/
static void
cogen_nxdict(struct instr_def *instr)
{
List_handle liter;
struct NXDentry *entry;
coutf("#ifdef HAVE_NXDICT");
coutf("static NXDdict %snxd_handle;", ID_PRE);
coutf("static NXhandle %snxd_file;", ID_PRE);
coutf("");
coutf("void %snxdict_init(void) {", ID_PRE);
/* Code to read any specified fictionary file. */
if(instr->nxdinfo->nxdfile)
{
char *quoted_name = str_quote(instr->nxdinfo->nxdfile);
coutf(" %snxd_handle = NXDinitfromfile(\"%s\");", ID_PRE, quoted_name);
str_free(quoted_name);
}
else
{
coutf(" %snxd_handle = NXDinitfromfile(NULL);", ID_PRE);
}
coutf(" if(%snxd_handle == NULL) {", ID_PRE);
coutf(" printf(stderr, \"Error: could not read NeXus dictionary file.\\n\");");
coutf(" exit(1);");
coutf(" }", ID_PRE);
/* Code for additional embedded dictionary entries. */
liter = list_iterate(instr->nxdinfo->nxdentries);
while((entry = list_next(liter)) != NULL)
{
char *spec = exp_tostring(entry->spec);
coutf(" NXDadd(%snxd_handle, \"%s_%s\",", ID_PRE,
entry->compname, entry->param);
code_set_source(instr->quoted_source, exp_getlineno(entry->spec));
coutf(" %s);", spec);
code_reset_source();
str_free(spec);
}
list_iterate_end(liter);
coutf("}");
coutf("");
coutf("void %snxdict_cleanup(void) {", ID_PRE);
coutf(" NXDclose(%snxd_handle, NULL);", ID_PRE);
coutf("}");
coutf("");
coutf("void %snxdict_nxout(void) {", ID_PRE);
/* ToDo: automatically generate suitable calls to NXDputalias() here. */
coutf("}");
coutf("#else /* HAVE_NXDICT */");
coutf("void %snxdict_init(void) { }", ID_PRE);
coutf("void %snxdict_cleanup(void) { }", ID_PRE);
coutf("void %snxdict_nxout(void) { }", ID_PRE);
coutf("#endif /* HAVE_NXDICT */", ID_PRE);
coutf("");
}
/*******************************************************************************
* Generate the ##init() function.
*******************************************************************************/
static void
cogen_init(struct instr_def *instr)
{
List_handle liter;
struct comp_inst *comp, *last;
char *d2r;
coutf("void %sinit(void) {", ID_PRE);
/* User initializations from instrument definition. */
cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace,
instr->inits);
/* Initialization of component setting parameters and user initialization
code. */
cout(" /* Component initializations. */");
liter = list_iterate(instr->complist);
while((comp = list_next(liter)) != NULL)
{
List_handle setpar;
struct comp_iformal *par;
coutf(" /* Initializations for component %s. */", comp->name);
/* Initialization of the component setting parameters. */
setpar = list_iterate(comp->def->set_par);
while((par = list_next(setpar)) != NULL)
{
char *val;
struct Symtab_entry *entry;
entry = symtab_lookup(comp->setpar, par->id);
val = exp_tostring(entry->val);
code_set_source(instr->quoted_source, exp_getlineno(entry->val));
coutf(" %sc%s_%s = %s;", ID_PRE, comp->name, par->id, val);
str_free(val);
}
list_iterate_end(setpar);
if(list_len(comp->def->set_par) > 0)
code_reset_source();
cout("");
/* Users initializations. */
if(list_len(comp->def->init_code->lines) > 0)
cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
comp->def->init_code);
cout("");
}
list_iterate_end(liter);
/* Compute the necessary vectors and transformation matrices for coordinate
system changes between components. */
cout(" /* Computation of coordinate transformations. */");
cout(" {");
coutf(" Coords %stc1, %stc2;", ID_PRE, ID_PRE);
coutf(" Rotation %str1, %str2;", ID_PRE, ID_PRE);
cout("");
/* Conversion factor degrees->radians for rotation angles. */
d2r = "DEG2RAD";
liter = list_iterate(instr->complist);
last = NULL;
coutf(" %sDEBUG_INSTR()", ID_PRE);
while((comp = list_next(liter)) != NULL)
{
struct comp_inst *relcomp; /* Component relative to. */
char *x, *y, *z;
coutf(" /* Component %s. */", comp->name);
/* Absolute rotation. */
x = exp_tostring(comp->pos->orientation.x);
y = exp_tostring(comp->pos->orientation.y);
z = exp_tostring(comp->pos->orientation.z);
relcomp = comp->pos->orientation_rel;
if(relcomp == NULL)
{ /* Absolute orientation. */
coutf(" rot_set_rotation(%srota%s,", ID_PRE, comp->name);
code_set_source(instr->quoted_source,
exp_getlineno(comp->pos->orientation.x));
coutf(" (%s)*%s,", x, d2r);
code_set_source(instr->quoted_source,
exp_getlineno(comp->pos->orientation.y));
coutf(" (%s)*%s,", y, d2r);
code_set_source(instr->quoted_source,
exp_getlineno(comp->pos->orientation.z));
coutf(" (%s)*%s);", z, d2r);
code_reset_source();
}
else
{
coutf(" rot_set_rotation(%str1,", ID_PRE);
code_set_source(instr->quoted_source,
exp_getlineno(comp->pos->orientation.x));
coutf(" (%s)*%s,", x, d2r);
code_set_source(instr->quoted_source,
exp_getlineno(comp->pos->orientation.y));
coutf(" (%s)*%s,", y, d2r);
code_set_source(instr->quoted_source,
exp_getlineno(comp->pos->orientation.z));
coutf(" (%s)*%s);", z, d2r);
code_reset_source();
coutf(" rot_mul(%str1, %srota%s, %srota%s);",
ID_PRE, ID_PRE, relcomp->name, ID_PRE, comp->name);
}
str_free(z);
str_free(y);
str_free(x);
/* Relative rotation. */
if(last == NULL)
{ /* First component. */
coutf(" rot_copy(%srotr%s, %srota%s);",
ID_PRE, comp->name, ID_PRE, comp->name);
}
else
{
coutf(" rot_transpose(%srota%s, %str1);", ID_PRE, last->name, ID_PRE);
coutf(" rot_mul(%srota%s, %str1, %srotr%s);",
ID_PRE, comp->name, ID_PRE, ID_PRE, comp->name);
}
/* Absolute position. */
x = exp_tostring(comp->pos->place.x);
y = exp_tostring(comp->pos->place.y);
z = exp_tostring(comp->pos->place.z);
relcomp = comp->pos->place_rel;
if(relcomp == NULL)
{
coutf(" %sposa%s = coords_set(", ID_PRE, comp->name);
code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.x));
coutf(" %s,", x);
code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.y));
coutf(" %s,", y);
code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.z));
coutf(" %s);", z);
code_reset_source();
}
else
{
coutf(" %stc1 = coords_set(", ID_PRE);
code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.x));
coutf(" %s,", x);
code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.y));
coutf(" %s,", y);
code_set_source(instr->quoted_source, exp_getlineno(comp->pos->place.z));
coutf(" %s);", z);
code_reset_source();
coutf(" rot_transpose(%srota%s, %str1);",
ID_PRE, relcomp->name, ID_PRE);
coutf(" %stc2 = rot_apply(%str1, %stc1);",
ID_PRE, ID_PRE, ID_PRE);
coutf(" %sposa%s = coords_add(%sposa%s, %stc2);",
ID_PRE, comp->name, ID_PRE, relcomp->name, ID_PRE);
}
str_free(z);
str_free(y);
str_free(x);
/* Relative position. */
if(last == NULL)
coutf(" %stc1 = coords_neg(%sposa%s);", ID_PRE, ID_PRE, comp->name);
else
coutf(" %stc1 = coords_sub(%sposa%s, %sposa%s);",
ID_PRE, ID_PRE, last->name, ID_PRE, comp->name);
coutf(" %sposr%s = rot_apply(%srota%s, %stc1);",
ID_PRE, comp->name, ID_PRE, comp->name, ID_PRE);
coutf(" %sDEBUG_COMPONENT(\"%s\", %sposa%s, %srota%s)",
ID_PRE, comp->name, ID_PRE, comp->name, ID_PRE, comp->name);
last = comp;
}
list_iterate_end(liter);
/* Output graphics representation of components. */
coutf(" if(mcdotrace) mcdisplay();");
coutf(" %sDEBUG_INSTR_END()", ID_PRE);
cout(" }");
cout("");
cout("}");
cout("");
}
static void
cogen_trace(struct instr_def *instr)
{
List_handle liter;
struct comp_inst *comp;
/* Output the function header. */
coutf("void %sraytrace(void) {", ID_PRE);
/* Local neutron state. */
cout(" /* Copy neutron state to local variables. */");
coutf(" MCNUM %snlx = %snx;", ID_PRE, ID_PRE);
coutf(" MCNUM %snly = %sny;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlz = %snz;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlvx = %snvx;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlvy = %snvy;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlvz = %snvz;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlt = %snt;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlsx = %snsx;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlsy = %snsy;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlsz = %snsz;", ID_PRE, ID_PRE);
coutf(" MCNUM %snlp = %snp;", ID_PRE, ID_PRE);
cout("");
/* Debugging (initial state). */
coutf(" %sDEBUG_ENTER()", ID_PRE);
coutf(" %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
"%snlt,%snlsx,%snlsy, %snlp)",
ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
ID_PRE, ID_PRE, ID_PRE, ID_PRE);
/* Now the trace code for each component. Proper scope is set up for each
component using #define/#undef. */
liter = list_iterate(instr->complist);
while((comp = list_next(liter)) != NULL)
{
char *statepars[10];
static char *statepars_names[10] =
{
"nlx", "nly", "nlz", "nlvx", "nlvy", "nlvz",
"nlt", "nlsx", "nlsy", "nlp"
};
int i;
List_handle statepars_handle;
coutf(" /* Component %s. */", comp->name);
coutf(" %sDEBUG_COMP(\"%s\")", ID_PRE, comp->name);
/* Change of coordinates. */
coutf(" %scoordschange(%sposr%s, %srotr%s,", ID_PRE, ID_PRE, comp->name,
ID_PRE, comp->name);
coutf(" &%snlx, &%snly, &%snlz,", ID_PRE, ID_PRE, ID_PRE);
coutf(" &%snlvx, &%snlvy, &%snlvz,", ID_PRE, ID_PRE, ID_PRE);
coutf(" &%snlt, &%snlsx, &%snlsy);", ID_PRE, ID_PRE, ID_PRE);
if(instr->polarised)
coutf(" %scoordschange_polarisation("
"%srotr%s, &%snlsx, &%snlsy, &%snlsz);",
ID_PRE, ID_PRE, comp->name, ID_PRE, ID_PRE, ID_PRE);
/* Debugging (entry into component). */
coutf(" %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
"%snlt,%snlsx,%snlsy, %snlp)",
ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
ID_PRE, ID_PRE, ID_PRE, ID_PRE);
/* Trace code. */
for(i = 0; i < 10; i++)
statepars[i] = NULL;
statepars_handle = list_iterate(comp->def->state_par);
for(i = 0; i < 10; i++)
{
statepars[i] = list_next(statepars_handle);
if(statepars[i] == NULL)
break;
}
list_iterate_end(statepars_handle);
for(i = 0; i < 10; i++)
{
if(statepars[i] != NULL)
coutf("#define %s %s%s", statepars[i], ID_PRE, statepars_names[i]);
else
break;
}
if(comp->def->polarisation_par)
{
coutf("#define %s %s%s", comp->def->polarisation_par[0], ID_PRE, "nlsx");
coutf("#define %s %s%s", comp->def->polarisation_par[1], ID_PRE, "nlsy");
coutf("#define %s %s%s", comp->def->polarisation_par[2], ID_PRE, "nlsz");
}
cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
comp->def->trace_code);
if(comp->def->polarisation_par)
{
coutf("#undef %s", comp->def->polarisation_par[2]);
coutf("#undef %s", comp->def->polarisation_par[1]);
coutf("#undef %s", comp->def->polarisation_par[0]);
}
for(i = 9; i >= 0; i--)
{
if(statepars[i] != NULL)
coutf("#undef %s", statepars[i]);
}
/* Debugging (exit from component). */
coutf(" %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
"%snlt,%snlsx,%snlsy, %snlp)",
ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
ID_PRE, ID_PRE, ID_PRE, ID_PRE);
cout("");
}
list_iterate_end(liter);
/* Absorbing neutrons - goto this label to skip remaining components. */
coutf(" %sabsorb:", ID_PRE);
/* Debugging (final state). */
coutf(" %sDEBUG_LEAVE()", ID_PRE);
coutf(" %sDEBUG_STATE(%snlx, %snly, %snlz, %snlvx, %snlvy, %snlvz,"
"%snlt,%snlsx,%snlsy, %snlp)",
ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE, ID_PRE,
ID_PRE, ID_PRE, ID_PRE, ID_PRE);
/* Copy back neutron state to global variables. */
/* ToDo: Currently, this will be in the local coordinate system of the last
component - should be transformed back into the global system. */
cout(" /* Copy neutron state to global variables. */");
coutf(" %snx = %snlx;", ID_PRE, ID_PRE);
coutf(" %sny = %snly;", ID_PRE, ID_PRE);
coutf(" %snz = %snlz;", ID_PRE, ID_PRE);
coutf(" %snvx = %snlvx;", ID_PRE, ID_PRE);
coutf(" %snvy = %snlvy;", ID_PRE, ID_PRE);
coutf(" %snvz = %snlvz;", ID_PRE, ID_PRE);
coutf(" %snt = %snlt;", ID_PRE, ID_PRE);
coutf(" %snsx = %snlsx;", ID_PRE, ID_PRE);
coutf(" %snsy = %snlsy;", ID_PRE, ID_PRE);
coutf(" %snsz = %snlsz;", ID_PRE, ID_PRE);
coutf(" %snp = %snlp;", ID_PRE, ID_PRE);
/* Function end. */
cout("}");
cout("");
}
static void
cogen_finally(struct instr_def *instr)
{
List_handle liter; /* For list iteration. */
struct comp_inst *comp; /* Component instance. */
/* User FINALLY code from component definitions (for each instance). */
coutf("void %sfinally(void) {", ID_PRE);
cout(" /* User component FINALLY code. */");
cout("");
liter = list_iterate(instr->complist);
while(comp = list_next(liter))
{
if(list_len(comp->def->finally_code->lines) > 0)
{
coutf(" /* User FINALLY code for component '%s'. */", comp->name);
cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
comp->def->finally_code);
cout("");
}
}
list_iterate_end(liter);
/* User's FINALLY code from the instrument definition file. */
if(list_len(instr->finals->lines) > 0)
{
cout(" /* User FINALLY code from instrument definition. */");
cogen_instrument_scope(instr, (void (*)(void *))codeblock_out_brace,
instr->finals);
cout("");
}
cout("}");
}
static void
cogen_mcdisplay(struct instr_def *instr)
{
List_handle liter; /* For list iteration. */
struct comp_inst *comp; /* Component instance. */
/* User FINALLY code from component definitions (for each instance). */
cout("#define magnify mcdis_magnify");
cout("#define line mcdis_line");
cout("#define multiline mcdis_multiline");
cout("#define circle mcdis_circle");
coutf("void %sdisplay(void) {", ID_PRE);
cout(" printf(\"MCDISPLAY: start\\n\");");
cout(" /* Component MCDISPLAY code. */");
cout("");
liter = list_iterate(instr->complist);
while(comp = list_next(liter))
{
if(list_len(comp->def->mcdisplay_code->lines) > 0)
{
char *quoted_name = str_quote(comp->name);
coutf(" /* MCDISPLAY code for component '%s'. */", comp->name);
coutf(" printf(\"MCDISPLAY: component %%s\\n\", \"%s\");", quoted_name);
cogen_comp_scope(comp, 1, (void (*)(void *))codeblock_out_brace,
comp->def->mcdisplay_code);
cout("");
str_free(quoted_name);
}
}
list_iterate_end(liter);
cout(" printf(\"MCDISPLAY: end\\n\");");
cout("}");
cout("#undef magnify");
cout("#undef line");
cout("#undef multiline");
cout("#undef circle");
}
/*******************************************************************************
* Output code for the mcstas runtime system. Default is to copy the runtime
* code into the generated executable, to minimize problems with finding the
* right files during compilation and linking, but this may be changed using
* the --no-runtime compiler switch.
*******************************************************************************/
static void
cogen_runtime(struct instr_def *instr)
{
if(instr->use_default_main)
cout("#define MC_USE_DEFAULT_MAIN");
if(instr->enable_trace)
cout("#define MC_TRACE_ENABLED");
if(instr->portable)
cout("#define MC_PORTABLE");
if(instr->include_runtime)
{
cout("#define MC_EMBEDDED_RUNTIME"); /* Some stuff will be static. */
embed_file("mcstas-r.h");
embed_file("mcstas-r.c");
}
else
{
cout("#include \"mcstas-r.h\"");
}
coutf("#ifdef MC_TRACE_ENABLED");
coutf("int %straceenabled = 1;", ID_PRE);
coutf("#else");
coutf("int %straceenabled = 0;", ID_PRE);
coutf("#endif");
coutf("int %sdefaultmain = %d;", ID_PRE, instr->use_default_main);
coutf("char %sinstrument_name[] = \"%s\";", ID_PRE, instr->name);
coutf("char %sinstrument_source[] = \"%s\";", ID_PRE, instr->source);
if(instr->use_default_main)
cout("int main(int argc, char *argv[]){return mcstas_main(argc, argv);}");
}
/*******************************************************************************
* Generate the output file (in C).
*******************************************************************************/
void
cogen(char *output_name, struct instr_def *instr)
{
/* Initialize output file. */
if(!output_name || !output_name[0] || !strcmp(output_name, "-"))
{
output_handle = fdopen(1, "w");
quoted_output_file_name = str_quote("<stdout>");
}
else
{
output_handle = fopen(output_name, "w");
quoted_output_file_name = str_quote(output_name);
}
num_next_output_line = 1;
if(output_handle == NULL)
fatal_error("Error opening output file '%s'\n", output_name);
cout("/* Automatically generated file. Do not edit. */");
cout("");
cogen_runtime(instr);
cogen_decls(instr);
cogen_init(instr);
if(instr->nxdinfo->any)
cogen_nxdict(instr); /* Only if NXDICT/NXDICTFILE actually used */
cogen_trace(instr);
cogen_finally(instr);
cogen_mcdisplay(instr);
}
-------------- next part --------------
v 1.4.1.ef Aug 23, 2000
cogen.c : l127: add instr_formal_type_names_real
lib/mcfrontlib.pl: l113: add case Param = string without quotes
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mcfrontlib.pl
Type: application/x-perl
Size: 8330 bytes
Desc: not available
URL: <http://mailman2.mcstas.org/pipermail/mcstas-users/attachments/20000829/3f426e39/attachment.pl>
More information about the mcstas-users
mailing list