NEURON
modl.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 
3 /*
4  * int main(int argc, char *argv[]) --- returns 0 if translation is
5  * successful. Diag will exit with 1 if error.
6  *
7  * ---The overall strategy of the translation consists of three phases.
8  *
9  * 1) read in the whole file as a sequence of tokens, parsing as we go. Most of
10  * the trivial C translation such as appending ';' to statements is performed
11  * in this phase as is the creation of the symbol table. Item lists maintain
12  * the proper token order. Ater a whole block is read in, nontrivial
13  * manipulation may be performed on the entire block.
14  *
15  * 2) Some blocks and statements can be manipulated only after the entire file
16  * has been read in. The solve statement is an example since it can be
17  * analysed only after we know what is the type of the associated block. The
18  * kinetic block is another example whose translation depends on the SOLVE
19  * method and so cannot be processed until the whole input file has been
20  * read.
21  *
22  * 3) Output the lists.
23  *
24  * void openfiles(int argc, char *argv[]) parse the argument list, and open
25  * files. Print usage message and exit if no argument
26  *
27  */
28 
29 /*
30  * In order to interface this process with merge, a second argument is
31  * allowed which gives the complete input filename. The first argument
32  * still gives the prefix of the .c and .var files.
33  */
34 
35 /* the first arg may also be a file.mod (containing the .mod suffix)*/
36 
37 #include <getopt.h>
38 
39 #if MAC
40 #include <sioux.h>
41 #endif
42 #if HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45 #include "modl.h"
46 FILE *fin, /* input file descriptor for filename.mod */
47  /* or file2 from the second argument */
48  *fparout, /* output file descriptor for filename.var */
49  *fcout; /* output file descriptor for filename.c */
50 #if SIMSYS
51 FILE *fctlout, /* filename.ctl */
52  *fnumout; /* filename.num */
53 #endif
54 
55 
56 char* modprefix;
57 
58 char* finname;
59 
60 #if LINT
61 char* clint;
62 int ilint;
63 Item* qlint;
64 #endif
65 
66 int nmodl_text = 1;
68 
69 extern int yyparse();
70 extern int mkdir_p(const char*);
71 
72 #if NMODL && VECTORIZE
73 extern int vectorize;
74 extern int numlist;
75 extern char* nmodl_version_;
76 extern int usederivstatearray;
77 #endif
78 
79 /*SUPPRESS 763*/
80 static char pgm_name[] = "nmodl";
81 extern char* RCS_version;
82 extern char* RCS_date;
83 
84 static struct option long_options[] = {{"version", no_argument, 0, 'v'},
85  {"help", no_argument, 0, 'h'},
86  {"outdir", required_argument, 0, 'o'},
87  {0, 0, 0, 0}};
88 
89 static void show_options(char** argv) {
90  fprintf(stderr, "Source to source compiler from NMODL to C\n");
91  fprintf(stderr, "Usage: %s [options] Inputfile\n", argv[0]);
92  fprintf(stderr, "Options:\n");
93  fprintf(stderr,
94  "\t-o | --outdir <OUTPUT_DIRECTORY> directory where output files will be written\n");
95  fprintf(stderr, "\t-h | --help print this message\n");
96  fprintf(stderr, "\t-v | --version print version number\n");
97 }
98 
99 static void openfiles(char* given_filename, char* output_dir);
100 
101 int main(int argc, char** argv) {
102  int option = -1;
103  int option_index = 0;
104  char* output_dir = NULL;
105 
106  if (argc < 2) {
108  exit(1);
109  }
110 
111  while ((option = getopt_long(argc, argv, ":vho:", long_options, &option_index)) != -1) {
112  switch (option) {
113  case 'v':
114  printf("%s\n", nmodl_version_);
115  exit(0);
116 
117  case 'o':
118  output_dir = strdup(optarg);
119  break;
120 
121  case 'h':
123  exit(0);
124 
125  case ':':
126  fprintf(stderr, "%s: option '-%c' requires an argument\n", argv[0], optopt);
127  exit(-1);
128 
129  case '?':
130  default:
131  fprintf(stderr, "%s: invalid option `-%c' \n", argv[0], optopt);
132  exit(-1);
133  }
134  }
135  if ((argc - optind) > 1) {
136  fprintf(stderr,
137  "%s: Warning several input files specified on command line but only one will be "
138  "processed\n",
139  argv[0]);
140  }
141 
142  filetxtlist = newlist();
143 
144 #if MAC
145  SIOUXSettings.asktosaveonclose = false;
146 #if !SIMSYS
147  Fprintf(stderr, "%s %s %s\n", pgm_name, RCS_version, RCS_date);
148 #endif
149 #endif
150 
151  init(); /* keywords into symbol table, initialize
152  * lists, etc. */
153 
154  finname = argv[optind];
155 
156  openfiles(finname, output_dir); /* .mrg else .mod, .var, .c */
157 #if NMODL || HMODL
158 #else
159 #if !SIMSYS
160  Fprintf(stderr, "Translating %s into %s.c and %s.var\n", finname, modprefix, modprefix);
161 #endif
162 #endif
163  IGNORE(yyparse());
164  /*
165  * At this point all blocks are fully processed except the kinetic
166  * block and the solve statements. Even in these cases the
167  * processing doesn't involve syntax since the information is
168  * held in intermediate lists of specific structure.
169  *
170  */
171 
172  /*
173  * go through the list of solve statements and construct the model()
174  * code
175  */
176  solvhandler();
177  netrec_discon();
178  /*
179  * NAME's can be used in many cases before they were declared and
180  * no checking up to this point has been done to make sure that
181  * names have been used in only one way.
182  *
183  */
184  consistency();
185 #if 0 && !_CRAY && NMODL && VECTORIZE
186 /* allowing Kinetic models to be vectorized on cray. So nonzero numlist is
187 no longer adequate for saying we can not */
188  if (numlist) {
189  vectorize = 0;
190  }
191 #endif
192  chk_thread_safe();
194  parout(); /* print .var file.
195  * Also #defines which used to be in defs.h
196  * are printed into .c file at beginning.
197  */
198  c_out(); /* print .c file */
199 #if HMODL || NMODL
200 #else
201  IGNORE(fclose(fparout));
202 #endif
203 #if SIMSYS
204  IGNORE(fclose(fctlout));
205  IGNORE(fclose(fnumout));
206 #endif
207 
208 #if !defined NMODL_TEXT
209 #define NMODL_TEXT 1
210 #endif
211 #if NMODL && NMODL_TEXT
212 #if 0
213 /* test: temp.txt should be identical to text of input file except for INCLUDE */
214 {
215  FILE* f = fopen("temp.txt", "w");
216  assert(f);
217  Item* q;
218  ITERATE(q, filetxtlist) {
219  char* s = STR(q);
220  fprintf(f, "%s", s);
221  }
222  fclose(f);
223 }
224 #endif
225  if (nmodl_text) {
226  Item* q;
227  char* pf = NULL;
228 #if HAVE_REALPATH && !defined(NRN_AVOID_ABSOLUTE_PATHS)
229  pf = realpath(finname, NULL);
230 #endif
231  fprintf(fcout,
232  "\n#if NMODL_TEXT\nstatic const char* nmodl_filename = \"%s\";\nstatic const char* "
233  "nmodl_file_text = \n",
234  pf ? pf : finname);
235  if (pf) {
236  free(pf);
237  }
238  ITERATE(q, filetxtlist) {
239  char* s = STR(q);
240  char* cp;
241  fprintf(fcout, " \"");
242  /* Escape double quote, backslash, and end each line with \n */
243  for (cp = s; *cp; ++cp) {
244  if (*cp == '"' || *cp == '\\') {
245  fprintf(fcout, "\\");
246  }
247  if (*cp == '\n') {
248  fprintf(fcout, "\\n\"");
249  }
250  fputc(*cp, fcout);
251  }
252  }
253  fprintf(fcout, " ;\n#endif\n");
254  }
255 #endif
256 
257  IGNORE(fclose(fcout));
258 
259 #if NMODL && VECTORIZE
260  if (vectorize) {
261  Fprintf(stderr, "Thread Safe\n");
262  }
263  if (usederivstatearray) {
264  fprintf(stderr,
265  "Derivatives of STATE array variables are not translated correctly and compile "
266  "time errors will be generated.\n");
267  fprintf(stderr, "The %s.c file may be manually edited to fix these errors.\n", modprefix);
268  }
269 #endif
270 
271 #if LINT
272  { /* for lex */
273  extern int yytchar, yylineno;
274  extern FILE* yyin;
275  IGNORE(yyin);
276  IGNORE(yytchar);
277  IGNORE(yylineno);
278  IGNORE(yyinput());
279  yyunput(ilint);
280  yyoutput(ilint);
281  }
282 #endif
283 #if MAC
284  printf("Done\n");
285  SIOUXSettings.autocloseonquit = true;
286 #endif
287  free(modprefix); /* allocated in openfiles below */
288  return 0;
289 }
290 
291 static void openfiles(char* given_filename, char* output_dir) {
292  char s[NRN_BUFSIZE];
293 
294  char output_filename[NRN_BUFSIZE];
295  char input_filename[NRN_BUFSIZE];
296  modprefix = strdup(given_filename); // we want to keep original string to open input file
297  // find last '.' after last '/' that delimit file name from extension
298  // we are not bothering to deal with filenames that begin with a . but do
299  // want to deal with paths like ../foo/hh
300  char* first_ext_char = strrchr(modprefix, '.');
301  if (strrchr(modprefix, '/') > first_ext_char) {
302  first_ext_char = NULL;
303  }
304 
305  Sprintf(input_filename, "%s", given_filename);
306 
307  if (first_ext_char)
308  *first_ext_char = '\0'; // effectively cut the extension from prefix if it exist in
309  // given_filename
310  if ((fin = fopen(input_filename, "r")) == (FILE*) 0) { // first try to open given_filename
311  Sprintf(input_filename, "%s.mod", given_filename); // if it dont work try to add ".mod"
312  // extension and retry
313  Sprintf(finname, "%s.mod", given_filename); // finname is still a global variable, so we
314  // need to update it
315  if ((fin = fopen(input_filename, "r")) == (FILE*) 0) {
316  diag("Can't open input file: ", input_filename);
317  }
318  }
319  if (output_dir) {
320  if (mkdir_p(output_dir) != 0) {
321  fprintf(stderr, "Can't create output directory %s\n", output_dir);
322  exit(1);
323  }
324  char* basename = strrchr(modprefix, '/');
325  if (basename) {
326  Sprintf(output_filename, "%s%s.c", output_dir, basename);
327  } else {
328  Sprintf(output_filename, "%s/%s.c", output_dir, modprefix);
329  }
330  } else {
331  Sprintf(output_filename, "%s.c", modprefix);
332  }
333 
334  if ((fcout = fopen(output_filename, "w")) == (FILE*) 0) {
335  diag("Can't create C file: ", output_filename);
336  }
337  Fprintf(stderr, "Translating %s into %s\n", input_filename, output_filename);
338 
339 #if HMODL || NMODL
340 #else
341  Sprintf(s, "%s.var", modprefix);
342  if ((fparout = fopen(s, "w")) == (FILE*) 0) {
343  diag("Can't create variable file: ", s);
344  }
345 #endif
346 #if SIMSYS
347  Sprintf(s, "%s.ctl", modprefix);
348  if ((fctlout = fopen(s, "w")) == (FILE*) 0) {
349  diag("Can't create variable file: ", s);
350  }
351  Sprintf(s, "%s.num", modprefix);
352  if ((fnumout = fopen(s, "w")) == (FILE*) 0) {
353  diag("Can't create C file: ", s);
354  }
355 #endif
356 }
357 
358 static std::string str_replace(std::string str,
359  const std::string& search_str,
360  const std::string& replace_str) {
361  if (search_str.empty()) {
362  return str;
363  }
364 
365  size_t pos;
366  while ((pos = str.find(search_str)) != std::string::npos) {
367  str.replace(pos, search_str.size(), replace_str);
368  }
369 
370  return str;
371 }
372 
373 // Post-adjustments for VERBATIM blocks (i.e make them compatible with CPP).
374 void verbatim_adjust(char* q) {
375  // template is a reserved CPP keyword
376  const std::string repl = str_replace(q, "u.template", "u.ctemplate");
377  Fprintf(fcout, "%s", repl.c_str());
378 }
void c_out()
Definition: cout.cpp:252
int numlist
Definition: deriv.cpp:16
#define diag(s)
Definition: fmenu.cpp:192
List * filetxtlist
Definition: modl.cpp:67
void verbatim_adjust(char *q)
Definition: modl.cpp:374
char * finname
Definition: modl.cpp:58
char * modprefix
Definition: modl.cpp:56
FILE * fin
Definition: modl.cpp:46
int nmodl_text
Definition: modl.cpp:66
#define assert(ex)
Definition: hocassrt.h:32
static int argc
Definition: inithoc.cpp:53
static char ** argv
Definition: inithoc.cpp:54
#define STR(q)
Definition: model.h:87
#define ITERATE(itm, lst)
Definition: model.h:25
#define IGNORE(arg)
Definition: model.h:247
#define Sprintf
Definition: model.h:233
#define NRN_BUFSIZE
Definition: model.h:13
#define Fprintf
Definition: model.h:234
static void show_options(char **argv)
Definition: modl.cpp:89
FILE * fcout
Definition: modl.cpp:49
int main(int argc, char **argv)
Definition: modl.cpp:101
static char pgm_name[]
Definition: modl.cpp:80
char * RCS_version
Definition: version.cpp:4
int mkdir_p(const char *)
Definition: io.cpp:457
char * RCS_date
Definition: version.cpp:5
static std::string str_replace(std::string str, const std::string &search_str, const std::string &replace_str)
Definition: modl.cpp:358
static void openfiles(char *given_filename, char *output_dir)
Definition: modl.cpp:291
FILE * fparout
Definition: modl.cpp:48
static struct option long_options[]
Definition: modl.cpp:84
int yyparse()
NMODL parser global flags / functions.
void consistency()
Definition: consist.cpp:22
void init()
Definition: init.cpp:291
List * newlist()
Definition: list.cpp:47
#define printf
Definition: mwprefix.h:26
#define fprintf
Definition: mwprefix.h:30
void netrec_discon()
int vectorize
void chk_thread_safe()
Definition: nocpout.cpp:2951
void chk_global_state()
Definition: nocpout.cpp:2965
void parout()
Definition: nocpout.cpp:227
void solvhandler()
Definition: solve.cpp:133
char * nmodl_version_
Definition: nocpout.cpp:11
size_t q
FILE * fopen()
#define NULL
Definition: sptree.h:16
Definition: model.h:15