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