NEURON
nocpout.cpp
Go to the documentation of this file.
1 #include <../../nmodlconf.h>
2 /* /local/src/master/nrn/src/nmodl/nocpout.c,v 4.1 1997/08/30 20:45:28 hines Exp */
3 
4 /*
5 nrnversion is a string that is passed via the _mechanism structure
6 as the first arg. It will be interpreted within neuron to determine if
7 that version is compatible with this version.
8 For now try to use something of the form d.d
9 If this is changed then also change nrnoc/init.c
10 */
11 char* nmodl_version_ = "7.7.0";
12 
13 /* Point processes are now interfaced to nrnoc via objectvars.
14 Thus, p-array variables and functions accessible to hoc do not have
15 suffixes, and there is a constructor, destructor.
16 Also hoc interface functions always have a void* _vptr arg which is
17 always cast to (Point_process*) and the _p and _ppvar pointers set.
18 This makes the old setdata and create obsolete.
19 */
20 /* The strategy is to use as much of parout and hparout method as possible.
21 The bulk of the variables is in a p-array. The variables that don't belong
22 in this p-array are indicated by a flag with sym->subtype & NRNNOTP.
23 All other variables have values in that single array but not all those values
24 are available from HOC.
25 
26 Variables accessible to NEURON are variables that appear within
27 GLOBAL, SECTION, and RANGE statements.
28 SECTION variables are not currently implemented.
29 
30 Variables that do not appear in the p-array are:
31  1)externally declared variables such as celsius, t.
32  2)parameters and assigned not declared in the NEURON{RANGE list}
33  that are global with respect to sections.
34  3) variables static to this model, ie. v
35  4) read only variables like "diam"
36 States always are in the p-array.
37 
38 USEION variables in the p-array have connections to other places and
39 depending on the context may get their value from somewhere else, or
40 add their value to somewhere else, or place their value somewhere else.
41 The cases are:
42  NONSPECIFIC and USEION WRITE i... value added to proper ion current
43  and total current.
44  USEION READ entry value assigned to local copy.
45  USEION WRITE e.. ..o ..i exit value of local copy assigned to pointer..
46  It is an error for an ionic current or ionic variable
47  to be a STATE. Use another variable as the state, make the
48  ionic variable an ASSIGNED and just assign it at the
49  proper place.
50  Alternatively, if they are STATE's then they should not be READ
51  since their value comes from the p-array itself.
52 
53 POINTER variables are like USEION variables. Unfortunately, it is up to
54 the hoc user to make sure they point to the proper place with a connect
55 statement. At this time we only check for a null pointer. The pointers
56 are kept in the ppvar array.
57 
58 each model creates a setdata_suffix(x) (or setdata_suffix(i)) function
59 which sets up _p and _ppvar for use by functions in the model called
60 directly by hoc.
61 */
62 
63 /* FUNCTIONS are made external so they are callable from other models */
64 #define GLOBFUNCT 1
65 
66 #include "modl.h"
67 #include "parse1.hpp"
68 #include <stdlib.h>
69 #include <unistd.h>
70 #define GETWD(buf) getcwd(buf, NRN_BUFSIZE)
71 
72 #if VECTORIZE
73 int vectorize = 1;
74 /*
75 the idea is to put all variables into a vector of vectors so there
76 there is no static data. Every function has an implicit argument, underbar ix
77 which tells which set of data _p[ix][...] to use. There are going to have
78 to be limits on the kinds of scopmath functions called since many of them
79 need static data. We can have special versions of the most useful of these.
80 ie sparse.c.
81 Above is obsolete in detail , underbar ix is no longer used.
82 When vectorize = 1 then we believe the code is thread safe and most functions
83 pass around _p, _ppvar, _thread. When vectorize is 0 then we are definitely
84 not thread safe and _p and _ppvar are static.
85 */
86 
87 #endif
88 #define NRNEXTRN 01 /* t, dt, celsius, etc. */
89 #define NRNCURIN 02 /* input value used */
90 #define NRNCUROUT 04 /* added to output value */
91 #define NRNRANGE 010
92 #define NRNPRANGEIN 020
93 #define NRNPRANGEOUT 040
94 #define NRNGLOBAL 0100 /* same for all sections, defined here */
95 #define NRNSTATIC 0200 /* v */
96 #define NRNNOTP 0400 /* doesn't belong in p array */
97 #define NRNIONFLAG 01000 /* temporary flag to allow READ and WRITE
98  without declaring twice */
99 #define NRNSECTION 02000
100 #define NRNPOINTER 04000
101 #define IONCONC 010000
102 #define NRNBBCOREPOINTER 020000
103 
104 #define IONEREV 0 /* Parameter */
105 #define IONIN 1
106 #define IONOUT 2
107 #define IONCUR 3 /* assigned */
108 #define IONDCUR 4
109 
110 extern int assert_threadsafe;
111 extern int brkpnt_exists;
112 static char* brkpnt_str_;
113 extern Symbol *indepsym;
114 extern Symbol *scop_indep;
115 extern List *indeplist;
116 extern Symbol *stepsym;
117 extern char *reprime();
118 extern List *symlist[];
119 extern List* ldifuslist;
120 extern char* finname;
121 extern int check_tables_threads(List*);
130 extern int protect_;
131 extern int protect_include_;
132 extern List *set_ion_variables(int), *get_ion_variables(int);
133 extern int netrec_need_v;
134 
135  int decode_limits(Symbol* sym, double* pg1, double* pg2);
136  int decode_tolerance(Symbol* sym, double* pg1);
137 
138 
139 /* NEURON block information */
144 static List *rangeparm;
145 static List *rangedep;
146 static List *rangestate;
148 static List* uip; /* void _update_ion_pointer(Datum* _ppvar){...} text */
149 static char suffix[256];
150 static char *rsuffix; /* point process range and functions don't have suffix*/
151 static char *mechname;
152 int point_process; /* 1 if a point process model */
153 int artificial_cell; /* 1 if also explicitly declared an ARTIFICIAL_CELL */
154 static int diamdec = 0; /*1 if diam is declared*/
155 static int areadec = 0;
156 static int use_bbcorepointer = 0;
157 
158  void defs_h(Symbol*);
159  int iontype(char* s1, char* s2);
160 void nrndeclare();
161 void del_range(List*);
162 void declare_p();
163  int iondef(int*);
164  void ion_promote(Item*);
165 static int ppvar_cnt;
167 static void ppvar_semantics(int, const char*);
168 static int for_netcons_; /* number of FOR_NETCONS statements */
171 static int ba_index_; /* BEFORE AFTER blocks. See bablk */
172 static List* ba_list_;
173 
174 #if CVODE
175 List* state_discon_list_;
177 static int cvode_emit, cvode_ieq_index;
178 static int cond_index;
179 static int tqitem_index;
180 static int watch_index;
181 static int cvode_index;
182 static List* ion_synonym;
183 extern int singlechan_;
184 int debugging_;
185 int net_receive_;
186 int net_send_seen_;
187 int net_event_seen_;
188 int watch_seen_; /* number of WATCH statements + 1*/
189 extern List* watch_alloc;
190 static Item* net_send_delivered_; /* location for if flag is 1 then clear the
191  tqitem_ to allow an error message for net_move */
192 #endif
193 
194 #define SYMITER(arg) ITERATE(q, syminorder){ \
195  s = SYM(q); if (s->type == arg)
196 
197 #define SYMLISTITER for (i = 'A'; i <= 'z'; i++)\
198  ITERATE(q, symlist[i])
199 
200 #define IFTYPE(arg) if ((s->subtype & arg)\
201  && ( (s->usage & EXPLICIT_DECL) != automatic) )
202 
203 /* varcount holds the index into the .var file and is saved in s->used
204  parraycount holds the index into the p array and is saved in s->varnum
205  pvarcount indexes pointers to variables such as ena
206 */
207 static int varcount, parraycount;
208 
209 void nrninit() {
210  extern int using_default_indep;
211  currents = newlist();
212  rangeparm = newlist();
213  rangedep = newlist();
214  rangestate = newlist();
215  useion = newlist();
216  nrnpointers = newlist();
217  using_default_indep = 0;
218  indepinstall(install("t", NAME), "0", "1", "100", (Item*)0, "ms", 0);
219  using_default_indep = 1;
220  debugging_ = 1;
221  thread_cleanup_list = newlist();
222  thread_mem_init_list = newlist();
223 }
224 
225 void parout() {
226  int i, j, ioncount, pointercount, gind, emit_check_table_thread;
227  Item *q, *q1;
228  Symbol *s, *sion;
229  double d1, d2;
230  extern char *modprefix;
231  char *modbase;
232 
233  defs_list = newlist(); /* relates hoc names to c-variables */
234  if (brkpnt_exists) {
235  brkpnt_str_ = "nrn_cur, nrn_jacob, nrn_state";
236  }else{
237  brkpnt_str_ = "0, 0, 0";
238 #if 1 || defined(__MINGW32__)
239  /* x86_64-w64-mingw32-gcc passed 0 without zeroing the high 32 bits */
240  /* also cygwin64 gcc 4.8.1, so cast to void* universally */
241  brkpnt_str_ = "(void*)0, (void*)0, (void*)0";
242 #endif
243  }
244 
245  for (modbase = modprefix + strlen(modprefix); modbase != modprefix;
246  modbase--) {
247  if (*modbase == '\\' || *modbase == '/') {
248  modbase++;
249  break;
250  }
251  }
252  if (!mechname) {
253  sprintf(suffix,"_%s", modbase);
254  mechname = modbase;
255  } else if (strcmp(mechname, "nothing") == 0) {
256  vectorize = 0;
257  suffix[0] = '\0';
258  mechname = modbase;
259  nmodl_text = 0;
260  }else{
261  sprintf(suffix, "_%s", mechname);
262  }
263  if (artificial_cell && vectorize && (thread_data_index || toplocal_)) {
264 fprintf(stderr, "Notice: ARTIFICIAL_CELL models that would require thread specific data are not thread safe.\n");
265  vectorize = 0;
266  }
267  if (point_process) {
268  rsuffix = "";
269  }else{
270  rsuffix = suffix;
271  }
272 
273  Lappendstr(defs_list, "\
274 \n#if METHOD3\nextern int _method3;\n#endif\n\
275 \n#if !NRNGPU\
276 \n#undef exp\
277 \n#define exp hoc_Exp\nextern double hoc_Exp(double);\
278 \n#endif\n\
279 ");
280  if (protect_include_) {
281  Lappendstr(defs_list, "\n#include \"nmodlmutex.h\"");
282  }
283 
284 #if 1
285  /* for easier profiling, give distinct names to otherwise reused static names */
286  sprintf(buf, "\n\
287 #define nrn_init _nrn_init_%s\n\
288 #define _nrn_initial _nrn_initial_%s\n\
289 #define nrn_cur _nrn_cur_%s\n\
290 #define _nrn_current _nrn_current_%s\n\
291 #define nrn_jacob _nrn_jacob_%s\n\
292 #define nrn_state _nrn_state_%s\n\
293 #define _net_receive _net_receive_%s\
295  Lappendstr(defs_list, buf);
296  SYMLISTITER {
297  Symbol* s = SYM(q);
298  /* note that with GLOBFUNCT, FUNCT will be redefined anyway */
299  if (s->type == NAME && s->subtype & (PROCED | DERF | KINF)) {
300  sprintf(buf, "\n#define %s %s_%s", s->name, s->name, suffix);
301  Lappendstr(defs_list, buf);
302  }
303  }
304  Lappendstr(defs_list, "\n");
305 #endif /* distinct names for easier profiling */
306 
307  if (vectorize) {
308  Lappendstr(defs_list, "\n\
309 #define _threadargscomma_ _p, _ppvar, _thread, _nt,\n\
310 #define _threadargsprotocomma_ double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt,\n\
311 #define _threadargs_ _p, _ppvar, _thread, _nt\n\
312 #define _threadargsproto_ double* _p, Datum* _ppvar, Datum* _thread, NrnThread* _nt\n\
313 ");
314  }else{
315  Lappendstr(defs_list, "\n\
316 #define _threadargscomma_ /**/\n\
317 #define _threadargsprotocomma_ /**/\n\
318 #define _threadargs_ /**/\n\
319 #define _threadargsproto_ /**/\n\
320 ");
321  }
322  Lappendstr(defs_list, "\
323  /*SUPPRESS 761*/\n\
324  /*SUPPRESS 762*/\n\
325  /*SUPPRESS 763*/\n\
326  /*SUPPRESS 765*/\n\
327  ");
328  Lappendstr(defs_list, "extern double *getarg();\n");
329 #if VECTORIZE
330  if (vectorize) {
331  Sprintf(buf, "/* Thread safe. No static _p or _ppvar. */\n");
332  }else
333 #endif
334  {
335  Sprintf(buf, "static double *_p; static Datum *_ppvar;\n");
336  }
337  Lappendstr(defs_list, buf);
338 
339  nrndeclare();
340  varcount = parraycount = 0;
341  declare_p();
342  ioncount = iondef(&pointercount); /* first is _nd_area if point process */
343  Lappendstr(defs_list, "\n#if MAC\n#if !defined(v)\n#define v _mlhv\n#endif\n#if !defined(h)\n#define h _mlhh\n#endif\n#endif\n");
344  Lappendstr(defs_list, "\n#if defined(__cplusplus)\nextern \"C\" {\n#endif\n");
345  Lappendstr(defs_list, "static int hoc_nrnpointerindex = ");
346  if (pointercount) {
347  q = nrnpointers->next;
348  Sprintf(buf, "%d;\n", SYM(q)->used);
349  }else{
350  Sprintf(buf, "-1;\n");
351  }
352  Lappendstr(defs_list, buf);
353  /*above modified to also count and define pointers*/
354 
355  if (vectorize) {
356  Lappendstr(defs_list, "static Datum* _extcall_thread;\n static Prop* _extcall_prop;\n");
357  }
358 #if 0
359  Lappendstr(defs_list, "/* static variables special to NEURON */\n");
360  SYMLISTITER {
361  if (SYM(q)->nrntype & NRNSTATIC) {
362  Sprintf(buf, "static double %s;\n", SYM(q)->name);
363  Lappendstr(defs_list, buf);
364  }
365  }
366 #endif
367  Lappendstr(defs_list, "/* external NEURON variables */\n");
368  SYMLISTITER {
369  s = SYM(q);
370  if (s->nrntype & NRNEXTRN) {
371  if (strcmp(s->name, "dt") == 0) { continue; }
372  if (strcmp(s->name, "t") == 0) { continue; }
373  if (s->subtype & ARRAY) {
374  Sprintf(buf, "extern double* %s;\n", s->name);
375  }else{
376  Sprintf(buf, "extern double %s;\n", s->name);
377  }
378  Lappendstr(defs_list, buf);
379  }
380  }
381 
382  Lappendstr(defs_list, "/* declaration of user functions */\n");
383  SYMLISTITER {
384  s = SYM(q);
385  if (s->subtype & (FUNCT | PROCED) && s->name[0] != '_') {
386  if (point_process) {
387  Sprintf(buf, "static double _hoc_%s(void*);\n", s->name);
388  }else{
389  Sprintf(buf, "static void _hoc_%s(void);\n", s->name);
390  }
391  Lappendstr(defs_list, buf);
392  }
393  }
394 
395  Lappendstr(defs_list, "static int _mechtype;\n\
396 extern void _nrn_cacheloop_reg(int, int);\n\
397 extern void hoc_register_prop_size(int, int, int);\n\
398 extern void hoc_register_limits(int, HocParmLimits*);\n\
399 extern void hoc_register_units(int, HocParmUnits*);\n\
400 extern void nrn_promote(Prop*, int, int);\n\
401 extern Memb_func* memb_func;\n\
402 " );
403 
404  if (nmodl_text) {
405  Lappendstr(defs_list, "\n"
406 "#define NMODL_TEXT 1\n"
407 "#if NMODL_TEXT\n"
408 "static const char* nmodl_file_text;\n"
409 "static const char* nmodl_filename;\n"
410 "extern void hoc_reg_nmodl_text(int, const char*);\n"
411 "extern void hoc_reg_nmodl_filename(int, const char*);\n"
412 "#endif\n\n"
413  );
414  }
415 
416  /**** create special point process functions */
417  if (point_process) {
418  Lappendstr(defs_list, "extern Prop* nrn_point_prop_;\n");
419  Lappendstr(defs_list, "static int _pointtype;\n");
420  Lappendstr(defs_list, "static void* _hoc_create_pnt(Object* _ho) { void* create_point_process(int, Object*);\n");
421  Lappendstr(defs_list, "return create_point_process(_pointtype, _ho);\n}\n");
422  Lappendstr(defs_list, "static void _hoc_destroy_pnt(void*);\n");
423  Lappendstr(defs_list, "static double _hoc_loc_pnt(void* _vptr) {double loc_point_process(int, void*);\n");
424  Lappendstr(defs_list, "return loc_point_process(_pointtype, _vptr);\n}\n");
425  Lappendstr(defs_list, "static double _hoc_has_loc(void* _vptr) {double has_loc_point(void*);\n");
426  Lappendstr(defs_list, "return has_loc_point(_vptr);\n}\n");
427  Lappendstr(defs_list, "static double _hoc_get_loc_pnt(void* _vptr) {\n");
428  Lappendstr(defs_list, "double get_loc_point_process(void*); return (get_loc_point_process(_vptr));\n}\n");
429  }
430  /* function to set up _p and _ppvar */
431  Lappendstr(defs_list, "extern void _nrn_setdata_reg(int, void(*)(Prop*));\n");
432  Lappendstr(defs_list, "static void _setdata(Prop* _prop) {\n");
433 #if VECTORIZE
434  if (vectorize) {
435  Lappendstr(defs_list, "_extcall_prop = _prop;\n");
436  }else
437 #endif
438  {
439  Lappendstr(defs_list, "_p = _prop->param; _ppvar = _prop->dparam;\n");
440  }
441  Lappendstr(defs_list, "}\n");
442 
443  if (point_process) {
444  Lappendstr(defs_list, "static void _hoc_setdata(void* _vptr) { Prop* _prop;\n");
445  Lappendstr(defs_list, "_prop = ((Point_process*)_vptr)->_prop;\n");
446  }else{
447  Lappendstr(defs_list, "static void _hoc_setdata() {\n Prop *_prop, *hoc_getdata_range(int);\n");
448  Sprintf(buf, "_prop = hoc_getdata_range(_mechtype);\n");
449  Lappendstr(defs_list, buf);
450  }
451  Lappendstr(defs_list, " _setdata(_prop);\n");
452  if (point_process) {
453  Lappendstr(defs_list, "}\n");
454  }else{
455  Lappendstr(defs_list, "hoc_retpushx(1.);\n}\n");
456  }
457 
458  /* functions */
459  Lappendstr(defs_list, "/* connect user functions to hoc names */\n");
460  Lappendstr(defs_list, "static VoidFunc hoc_intfunc[] = {\n");
461  if (point_process) {
462  Lappendstr(defs_list, "0,0\n};\n");
463  Lappendstr(defs_list, "static Member_func _member_func[] = {\n");
464  Sprintf(buf, "\"loc\", _hoc_loc_pnt,\n");
465  Lappendstr(defs_list, buf);
466  Sprintf(buf, "\"has_loc\", _hoc_has_loc,\n");
467  Lappendstr(defs_list, buf);
468  Sprintf(buf, "\"get_loc\", _hoc_get_loc_pnt,\n");
469  Lappendstr(defs_list, buf);
470  }else{
471  Sprintf(buf, "\"setdata_%s\", _hoc_setdata,\n", mechname);
472  Lappendstr(defs_list, buf);
473  }
474  SYMLISTITER {
475  s = SYM(q);
476  if ((s->subtype & (FUNCT | PROCED)) && s->name[0] != '_') {
477 Sprintf(buf, "\"%s%s\", _hoc_%s,\n", s->name, rsuffix, s->name);
478  Lappendstr(defs_list, buf);
479  }
480  }
481  Lappendstr(defs_list, "0, 0\n};\n");
482 
483 #if GLOBFUNCT
484  /* FUNCTION's are now global so callable from other models */
485  /* change name to namesuffix. This propagates everywhere except
486  to hoc_name*/
487  /* but don't do it if suffix is empty */
488  if (suffix[0]) SYMLISTITER {
489  s = SYM(q);
490  if ((s->subtype & FUNCT)) {
491  Sprintf(buf, "#define %s %s%s\n", s->name, s->name, suffix);
492  q1 = Lappendstr(defs_list, buf);
493  q1->itemtype = VERBATIM;
494  }
495  }
496  SYMLISTITER {
497  int j;
498  s = SYM(q);
499  if ((s->subtype & FUNCT)) {
500  Sprintf(buf, "extern double %s(", s->name);
501  Lappendstr(defs_list, buf);
502  if (vectorize && !s->no_threadargs) {
503  if (s->varnum) {
504  Lappendstr(defs_list, "_threadargsprotocomma_");
505  }else{
506  Lappendstr(defs_list, "_threadargsproto_");
507  }
508  }
509  for (j=0; j < s->varnum; ++j) {
510  Lappendstr(defs_list, "double");
511  if (j+1 < s->varnum) {
512  Lappendstr(defs_list, ",");
513  }
514  }
515  Lappendstr(defs_list, ");\n");
516  }
517  }
518 #endif
519 
520  emit_check_table_thread = 0;
521  if (vectorize && check_tables_threads(defs_list)) {
522  emit_check_table_thread = 1;
523  }
524 
525  /* per thread top LOCAL */
526  /* except those that are marked assigned_to_ == 2 stay static double */
527  if (vectorize && toplocal_) {
528  int cnt;
529  cnt = 0;
530  ITERATE(q, toplocal_) {
531  if (SYM(q)->assigned_to_ != 2) {
532  if (SYM(q)->subtype & ARRAY) {
533  cnt += SYM(q)->araydim;
534  }else{
535  ++cnt;
536  }
537  }
538  }
539  sprintf(buf, " _thread[%d]._pval = (double*)ecalloc(%d, sizeof(double));\n", thread_data_index, cnt);
540  lappendstr(thread_mem_init_list, buf);
541  sprintf(buf, " free((void*)(_thread[%d]._pval));\n", thread_data_index);
542  lappendstr(thread_cleanup_list, buf);
543  cnt = 0;
544  ITERATE(q, toplocal_) {
545  if (SYM(q)->assigned_to_ != 2) {
546  if (SYM(q)->subtype & ARRAY) {
547 sprintf(buf, "#define %s (_thread[%d]._pval + %d)\n", SYM(q)->name, thread_data_index, cnt);
548  cnt += SYM(q)->araydim;
549  }else{
550 sprintf(buf, "#define %s _thread[%d]._pval[%d]\n", SYM(q)->name, thread_data_index, cnt);
551  ++cnt;
552  }
553  }else{ /* stay file static */
554  if (SYM(q)->subtype & ARRAY) {
555 sprintf(buf, "static double %s[%d];\n", SYM(q)->name, SYM(q)->araydim);
556  }else{
557 sprintf(buf, "static double %s;\n", SYM(q)->name);
558  }
559  }
560  lappendstr(defs_list, buf);
561  }
563  }
564  /* per thread global data */
565  gind = 0;
566  if (vectorize) SYMLISTITER {
567  s = SYM(q);
568  if (s->nrntype & (NRNGLOBAL) && s->assigned_to_ == 1) {
569  if (s->subtype & ARRAY) {
570  gind += s->araydim;
571  }else{
572  ++gind;
573  }
574  }
575  }
576  /* double scalars declared internally */
577  Lappendstr(defs_list, "/* declare global and static user variables */\n");
578  if (gind) {
579  sprintf(buf, "static int _thread1data_inuse = 0;\nstatic double _thread1data[%d];\n#define _gth %d\n", gind, thread_data_index);
580  Lappendstr(defs_list, buf);
581  sprintf(buf, " if (_thread1data_inuse) {_thread[_gth]._pval = (double*)ecalloc(%d, sizeof(double));\n }else{\n _thread[_gth]._pval = _thread1data; _thread1data_inuse = 1;\n }\n", gind);
582  lappendstr(thread_mem_init_list, buf);
583  lappendstr(thread_cleanup_list, " if (_thread[_gth]._pval == _thread1data) {\n _thread1data_inuse = 0;\n }else{\n free((void*)_thread[_gth]._pval);\n }\n");
585  }
586  gind = 0;
587  SYMLISTITER { /* globals are now global with respect to C as well as hoc */
588  s = SYM(q);
589  if (s->nrntype & (NRNGLOBAL)) {
590  if (vectorize && s->assigned_to_ == 1) {
591  if (s->subtype & ARRAY) {
592  sprintf(buf, "#define %s%s (_thread1data + %d)\n\
593 #define %s (_thread[_gth]._pval + %d)\n",
594 s->name, suffix, gind, s->name, gind);
595  }else{
596  sprintf(buf, "#define %s%s _thread1data[%d]\n\
597 #define %s _thread[_gth]._pval[%d]\n",
598 s->name, suffix, gind, s->name, gind);
599  }
600  q1 = Lappendstr(defs_list, buf);
601  q1->itemtype = VERBATIM;
602  if (s->subtype & ARRAY) {
603  gind += s->araydim;
604  }else{
605  ++gind;
606  }
607  continue;
608  }
609  if (suffix[0]) {
610  Sprintf(buf, "#define %s %s%s\n", s->name, s->name, suffix);
611  q1 = Lappendstr(defs_list, buf);
612  q1->itemtype = VERBATIM;
613  }
614  decode_ustr(s, &d1, &d2, buf);
615  if (s->subtype & ARRAY) {
616  Sprintf(buf, "double %s[%d];\n", s->name, s->araydim);
617  }else{
618  Sprintf(buf, "double %s = %g;\n", s->name, d1);
619  }
620  Lappendstr(defs_list, buf);
621  }
622  }
623 
624  Lappendstr(defs_list, "/* some parameters have upper and lower limits */\n");
625  Lappendstr(defs_list, "static HocParmLimits _hoc_parm_limits[] = {\n");
626  SYMLISTITER {
627  s = SYM(q);
628  if (s->subtype & PARM) {
629  double d1=0., d2=0.;
630  if (decode_limits(s, &d1, &d2)) {
631  if (s->nrntype & NRNGLOBAL || !point_process) {
632 Sprintf(buf, "\"%s%s\", %g, %g,\n", s->name, suffix, d1, d2);
633  }else{
634 Sprintf(buf, "\"%s\", %g, %g,\n", s->name, d1, d2);
635  }
636  Lappendstr(defs_list, buf);
637  }
638  }
639  }
640  Lappendstr(defs_list, "0,0,0\n};\n");
641 
642  units_reg();
643 
644  SYMLISTITER {
645  s = SYM(q);
646  if (s->nrntype & (NRNSTATIC)) {
647 #if VECTORIZE && 0
648  if (vectorize) {
649 diag("No statics allowed for thread safe models:", s->name);
650  }
651 #endif
652  decode_ustr(s, &d1, &d2, buf);
653  if (s->subtype & ARRAY) {
654  Sprintf(buf, "static double %s[%d];\n", s->name, s->araydim);
655  }else{
656  Sprintf(buf, "static double %s = %g;\n", s->name, d1);
657  }
658  Lappendstr(defs_list, buf);
659  }
660  }
661  Lappendstr(defs_list, "/* connect global user variables to hoc */\n");
662  Lappendstr(defs_list, "static DoubScal hoc_scdoub[] = {\n");
663  ITERATE(q, syminorder) {
664  s = SYM(q);
665  if (s->nrntype & NRNGLOBAL && !(s->subtype & ARRAY)) {
666  Sprintf(buf, "\"%s%s\", &%s%s,\n", s->name, suffix, s->name, suffix);
667  Lappendstr(defs_list, buf);
668  }
669  }
670  Lappendstr(defs_list, "0,0\n};\n");
671 
672  /* double vectors */
673  Lappendstr(defs_list, "static DoubVec hoc_vdoub[] = {\n");
674  ITERATE(q, syminorder) {
675  s = SYM(q);
676  if (s->nrntype & NRNGLOBAL && (s->subtype & ARRAY)) {
677  Sprintf(buf, "\"%s%s\", %s%s, %d,\n", s->name, suffix, s->name, suffix, s->araydim);
678  Lappendstr(defs_list, buf);
679  }
680  }
681  Lappendstr(defs_list, "0,0,0\n};\n");
682  Lappendstr(defs_list, "static double _sav_indep;\n");
683  if (ba_index_ > 0) {
684  Lappendstr(defs_list, "static void _ba1(Node*_nd, double* _pp, Datum* _ppd, Datum* _thread, NrnThread* _nt)");
685  for (i=2; i <= ba_index_; ++i) {
686  sprintf(buf, ", _ba%d(Node*_nd, double* _pp, Datum* _ppd, Datum* _thread, NrnThread* _nt)", i);
687  Lappendstr(defs_list, buf);
688  }
689  Lappendstr(defs_list, ";\n");
690  }
691 
692  /******** what normally goes into cabvars.h structures */
693 
694  /*declaration of the range variables names to HOC */
695  Lappendstr(defs_list, "static void nrn_alloc(Prop*);\nstatic void nrn_init(NrnThread*, _Memb_list*, int);\nstatic void nrn_state(NrnThread*, _Memb_list*, int);\n\
696 ");
697  if (brkpnt_exists) {
698  Lappendstr(defs_list, "static void nrn_cur(NrnThread*, _Memb_list*, int);\nstatic void nrn_jacob(NrnThread*, _Memb_list*, int);\n");
699  }
700  /* count the number of pointers needed */
701  ppvar_cnt = ioncount + diamdec + pointercount + areadec;
702 #if CVODE
703  if (net_send_seen_) {
704  tqitem_index = ppvar_cnt;
705  ppvar_semantics(ppvar_cnt, "netsend");
706  ppvar_cnt++;
707  }
708  if (watch_seen_) {
709  watch_index = ppvar_cnt;
710  for (i=0; i < watch_seen_ ; ++i) {
711  ppvar_semantics(i+ppvar_cnt, "watch");
712  }
713  ppvar_cnt += watch_seen_;
714  sprintf(buf, "\n#define _watch_array _ppvar + %d", watch_index);
715  Lappendstr(defs_list, buf);
716  Lappendstr(defs_list, "\n");
717  Lappendstr(defs_list, "static void _watch_alloc(Datum*);\n");
718  Lappendstr(defs_list, "extern void hoc_reg_watch_allocate(int, void(*)(Datum*));");
719  Lappendstr(watch_alloc, "}\n\n");
720  movelist(watch_alloc->next, watch_alloc->prev, procfunc);
721  }
722  if (for_netcons_) {
723  sprintf(buf, "\n#define _fnc_index %d\n", ppvar_cnt);
724  Lappendstr(defs_list, buf);
725  ppvar_semantics(ppvar_cnt, "fornetcon");
726  ppvar_cnt += 1;
727  }
728  if (point_process) {
729  Lappendstr(defs_list, "static void _hoc_destroy_pnt(void* _vptr) {\n");
730  if (watch_seen_ || for_netcons_) {
731  Lappendstr(defs_list, " Prop* _prop = ((Point_process*)_vptr)->_prop;\n");
732  }
733  if (watch_seen_) {
734 sprintf(buf, " if (_prop) { _nrn_free_watch(_prop->dparam, %d, %d);}\n", watch_index, watch_seen_);
735  Lappendstr(defs_list, buf);
736  }
737  if (for_netcons_) {
738 sprintf(buf, " if (_prop) { _nrn_free_fornetcon(&(_prop->dparam[_fnc_index]._pvoid));}\n");
739  Lappendstr(defs_list, buf);
740  }
741  Lappendstr(defs_list, " destroy_point_process(_vptr);\n}\n");
742  }
743  if (cvode_emit) {
744  cvode_ieq_index = ppvar_cnt;
745  ppvar_semantics(ppvar_cnt, "cvodeieq");
746  ppvar_cnt++;
747  }
749 #endif
751  if (! point_process) {
752  diag("DESTRUCTOR only permitted for POINT_PROCESS", (char*)0);
753  }
754  Lappendstr(defs_list, "static void _destructor(Prop*);\n");
755  }
756 
758  Lappendstr(defs_list, "static void _constructor(Prop*);\n");
759  }
760 
761  Lappendstr(defs_list,
762 "/* connect range variables in _p that hoc is supposed to know about */\n");
763  Lappendstr(defs_list, "\
764 static const char *_mechanism[] = {\n\
765 ");
766  Sprintf(buf, "\"%s\",\n\"%s\",\n", nmodl_version_, mechname);
767  Lappendstr(defs_list, buf);
768  ITERATE(q, rangeparm) {
769  s = SYM(q);
770  if (s->subtype & ARRAY) {
771  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
772  }else{
773  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
774  }
775  Lappendstr(defs_list, buf);
776  }
777  Lappendstr(defs_list, "0,\n");
778  ITERATE(q, rangedep) {
779  s = SYM(q);
780  if (s->subtype & ARRAY) {
781  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
782  }else{
783  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
784  }
785  Lappendstr(defs_list, buf);
786  }
787  Lappendstr(defs_list, "0,\n");
788  ITERATE(q, rangestate) {
789  s = SYM(q);
790  if (s->subtype & ARRAY) {
791  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
792  }else{
793  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
794  }
795  Lappendstr(defs_list, buf);
796  }
797  Lappendstr(defs_list, "0,\n");
798 
799  /* pointer variable names */
800  ITERATE(q, nrnpointers) {
801  s = SYM(q);
802  if (s->subtype & ARRAY) {
803  Sprintf(buf, "\"%s%s[%d]\",\n", s->name, rsuffix, s->araydim);
804  }else{
805  Sprintf(buf, "\"%s%s\",\n", s->name, rsuffix);
806  }
807  Lappendstr(defs_list, buf);
808  }
809 
810  Lappendstr(defs_list, "0};\n");
811 
812  /*********Creation of the allocation function*/
813 
814  if (diamdec) {
815  Lappendstr(defs_list, "static Symbol* _morphology_sym;\n");
816  }
817  if (areadec) {
818  Lappendstr(defs_list, "extern Node* nrn_alloc_node_;\n");
819  }
820  ITERATE(q, useion) {
821  sion = SYM(q);
822  Sprintf(buf, "static Symbol* _%s_sym;\n",sion->name);
823  Lappendstr(defs_list, buf);
824  if (ldifuslist) {
825  sprintf(buf, "static int _type_i%s;\n", sion->name);
826  lappendstr(defs_list, buf);
827  }
828  q=q->next->next->next;
829  }
830 
831  Lappendstr(defs_list, "\n\
832 extern Prop* need_memb(Symbol*);\n\n\
833 static void nrn_alloc(Prop* _prop) {\n\
834  Prop *prop_ion;\n\
835  double *_p; Datum *_ppvar;\n\
836 ");
837  if (point_process) {
838  Lappendstr(defs_list, " if (nrn_point_prop_) {\n\
839  _prop->_alloc_seq = nrn_point_prop_->_alloc_seq;\n\
840  _p = nrn_point_prop_->param;\n\
841  _ppvar = nrn_point_prop_->dparam;\n }else{\n");
842  }
843 Sprintf(buf, " _p = nrn_prop_data_alloc(_mechtype, %d, _prop);\n", parraycount);
844  Lappendstr(defs_list, buf);
845  Lappendstr(defs_list, " /*initialize range parameters*/\n");
846  ITERATE(q, rangeparm) {
847  s = SYM(q);
848  if (s->subtype & ARRAY) {
849  continue;
850  }
851  decode_ustr(s, &d1, &d2, buf);
852  Sprintf(buf, " %s = %g;\n", s->name, d1);
853  Lappendstr(defs_list, buf);
854  }
855  if (point_process) {
856  Lappendstr(defs_list, " }\n");
857  }
858  Lappendstr(defs_list, "\t_prop->param = _p;\n");
859  Sprintf(buf, "\t_prop->param_size = %d;\n", parraycount);
860  Lappendstr(defs_list, buf);
861  if (ppvar_cnt) {
862  if (point_process) {
863  Lappendstr(defs_list, " if (!nrn_point_prop_) {\n");
864  }
865 Sprintf(buf, " _ppvar = nrn_prop_datum_alloc(_mechtype, %d, _prop);\n", ppvar_cnt);
866  Lappendstr(defs_list, buf);
867  if (point_process) {
868  Lappendstr(defs_list, " }\n");
869  }
870  Lappendstr(defs_list, "\t_prop->dparam = _ppvar;\n");
871  Lappendstr(defs_list, "\t/*connect ionic variables to this model*/\n");
872  }
873  if (diamdec) {
874  Sprintf(buf, "prop_ion = need_memb(_morphology_sym);\n");
875  Lappendstr(defs_list, buf);
876  Sprintf(buf,
877  "\t_ppvar[%d]._pval = &prop_ion->param[0]; /* diam */\n",
878  ioncount + pointercount),
879  Lappendstr(defs_list, buf);
880  ppvar_semantics(ioncount + pointercount, "diam");
881  }
882  if (areadec) {
883  Sprintf(buf,
884  "\t_ppvar[%d]._pval = &nrn_alloc_node_->_area; /* diam */\n",
885  ioncount + pointercount + diamdec),
886  Lappendstr(defs_list, buf);
887  ppvar_semantics(ioncount + pointercount + diamdec, "area");
888  }
889 
890  if (point_process) {
891  ioncount = 2;
892  }else{
893  ioncount = 0;
894  }
895  ITERATE(q, useion) {
896  int dcurdef = 0;
897  int need_style = 0;
898  sion = SYM(q);
899  Sprintf(buf, "prop_ion = need_memb(_%s_sym);\n", sion->name);
900  Lappendstr(defs_list, buf);
901  if (ldifuslist) {
902  sprintf(buf, " _type_i%s = prop_ion->_type;\n", sion->name);
903  lappendstr(defs_list, buf);
904  }
905  ion_promote(q);
906  q=q->next;
907  ITERATE(q1, LST(q)) {
908  SYM(q1)->nrntype |= NRNIONFLAG;
909  Sprintf(buf,
910  "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* %s */\n",
911  ioncount++, iontype(SYM(q1)->name, sion->name),
912  SYM(q1)->name);
913  Lappendstr(defs_list, buf);
914  }
915  q=q->next;
916  ITERATE(q1, LST(q)) {
917  int itype = iontype(SYM(q1)->name, sion->name);
918 
919  if (SYM(q1)->nrntype & NRNIONFLAG) {
920  SYM(q1)->nrntype &= ~NRNIONFLAG;
921  }else{
922  Sprintf(buf,
923  "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* %s */\n",
924  ioncount++, itype, SYM(q1)->name);
925  Lappendstr(defs_list, buf);
926  }
927  if (itype == IONCUR) {
928  dcurdef = 1;
929  Sprintf(buf,
930 "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* _ion_di%sdv */\n",
931  ioncount++, IONDCUR, sion->name);
932  Lappendstr(defs_list, buf);
933  }
934  if (itype == IONIN || itype == IONOUT) {
935  need_style = 1;
936  }
937  }
938  if (need_style) {
939  Sprintf(buf,
940 "\t_ppvar[%d]._pvoid = (void*)(&(prop_ion->dparam[0]._i)); /* iontype for %s */\n",
941  ioncount++, sion->name);
942  Lappendstr(defs_list, buf);
943  }
944  q=q->next;
945  if (!dcurdef && ldifuslist) {
946  Sprintf(buf,
947 "\t_ppvar[%d]._pval = &prop_ion->param[%d]; /* _ion_di%sdv */\n",
948  ioncount++, IONDCUR, sion->name);
949  Lappendstr(defs_list, buf);
950  }
951  }
952 
954  Lappendstr(defs_list, "if (!nrn_point_prop_) {_constructor(_prop);}\n");
955  if (vectorize) {
956  Lappendstr(procfunc, "\n\
957 static void _constructor(Prop* _prop) {\n\
958  double* _p; Datum* _ppvar; Datum* _thread;\n\
959  _thread = (Datum*)0;\n\
960  _p = _prop->param; _ppvar = _prop->dparam;\n\
961 {\n\
962 ");
963  }else{
964  Lappendstr(procfunc, "\n\
965 static void _constructor(Prop* _prop) {\n\
966  _p = _prop->param; _ppvar = _prop->dparam;\n\
967 {\n\
968 ");
969  }
971  Lappendstr(procfunc, "\n}\n}\n");
972  }
973  Lappendstr(defs_list, "\n}\n");
974 
975  Lappendstr(defs_list, "static void _initlists();\n");
976 #if CVODE
977  if (cvode_emit) {
978  Lappendstr(defs_list, " /* some states have an absolute tolerance */\n");
979  Lappendstr(defs_list, "static Symbol** _atollist;\n");
980  Lappendstr(defs_list, "static HocStateTolerance _hoc_state_tol[] = {\n");
981  ITERATE(q, rangestate) {
982  double d1;
983  s = SYM(q);
984  if (decode_tolerance(s, &d1)) {
985  if (!point_process) {
986 Sprintf(buf, "\"%s%s\", %g,\n", s->name, suffix, d1);
987  }else{
988 Sprintf(buf, "\"%s\", %g,\n", s->name, d1);
989  }
990  Lappendstr(defs_list, buf);
991  }
992  }
993  Lappendstr(defs_list, "0,0\n};\n");
994  }
995  if (singlechan_) {
996  sprintf(buf, "static _singlechan_declare%d();\n", singlechan_);
997  Lappendstr(defs_list, buf);
998  }
999 #endif
1000 
1001 #if VECTORIZE
1002  if (net_send_seen_) {
1003  if (!net_receive_) {
1004  diag("can't use net_send if there is no NET_RECEIVE block", (char*)0);
1005  }
1006  sprintf(buf, "\n#define _tqitem &(_ppvar[%d]._pvoid)\n", tqitem_index);
1007  Lappendstr(defs_list, buf);
1008  if (net_send_delivered_) {
1009  insertstr(net_send_delivered_, " if (_lflag == 1. ) {*(_tqitem) = 0;}\n");
1010  }
1011  }
1012  if (net_receive_) {
1013  Lappendstr(defs_list, "static void _net_receive(Point_process*, double*, double);\n");
1014  if (for_netcons_) {
1015  Lappendstr(defs_list, "extern int _nrn_netcon_args(void*, double***);\n");
1016  }
1017  if (net_init_q1_) {
1018  Lappendstr(defs_list, "static void _net_init(Point_process*, double*, double);\n");
1019  }
1020  }
1021  if (vectorize && thread_mem_init_list->next != thread_mem_init_list) {
1022  Lappendstr(defs_list, "static void _thread_mem_init(Datum*);\n");
1023  }
1024  if (vectorize && thread_cleanup_list->next != thread_cleanup_list) {
1025  Lappendstr(defs_list, "static void _thread_cleanup(Datum*);\n");
1026  }
1027  if (uip) {
1028  lappendstr(defs_list, "static void _update_ion_pointer(Datum*);\n");
1029  }
1030  if (use_bbcorepointer) {
1031  lappendstr(defs_list, "static void bbcore_write(double*, int*, int*, int*, _threadargsproto_);\n");
1032  lappendstr(defs_list, "extern void hoc_reg_bbcore_write(int, void(*)(double*, int*, int*, int*, _threadargsproto_));\n");
1033  lappendstr(defs_list, "static void bbcore_read(double*, int*, int*, int*, _threadargsproto_);\n");
1034  lappendstr(defs_list, "extern void hoc_reg_bbcore_read(int, void(*)(double*, int*, int*, int*, _threadargsproto_));\n");
1035  }
1036  Lappendstr(defs_list, "\
1037 extern Symbol* hoc_lookup(const char*);\n\
1038 extern void _nrn_thread_reg(int, int, void(*)(Datum*));\n\
1039 extern void _nrn_thread_table_reg(int, void(*)(double*, Datum*, Datum*, NrnThread*, int));\n\
1040 extern void hoc_register_tolerance(int, HocStateTolerance*, Symbol***);\n\
1041 extern void _cvode_abstol( Symbol**, double*, int);\n\n\
1042 ");
1043  Sprintf(buf, "void _%s_reg() {\n\
1044  int _vectorized = %d;\n", modbase, vectorize);
1045  Lappendstr(defs_list, buf);
1046  q = lappendstr(defs_list, "");
1047  Lappendstr(defs_list, "_initlists();\n");
1048 #else
1049  Sprintf(buf, "void _%s_reg() {\n _initlists();\n", modbase);
1050  Lappendstr(defs_list, buf);
1051 #endif
1052 
1053  if (suffix[0]) { /* not "nothing" */
1054 
1055  ITERATE(q, useion) {
1056  Sprintf(buf, "\tion_reg(\"%s\", %s);\n", SYM(q)->name,
1057  STR(q->next->next->next));
1058  Lappendstr(defs_list, buf);
1059  q = q->next->next->next;
1060  }
1061  if (diamdec) {
1062  Lappendstr(defs_list, "\t_morphology_sym = hoc_lookup(\"morphology\");\n");
1063  }
1064  ITERATE(q, useion) {
1065  Sprintf(buf, "\t_%s_sym = hoc_lookup(\"%s_ion\");\n",
1066  SYM(q)->name, SYM(q)->name);
1067  Lappendstr(defs_list, buf);
1068  q = q->next->next->next;
1069  }
1070 #if VECTORIZE
1071  if (point_process) {
1072  sprintf(buf, "\
1073  _pointtype = point_register_mech(_mechanism,\n\
1074  nrn_alloc,%s, nrn_init,\n\
1075  hoc_nrnpointerindex, %d,\n\
1076  _hoc_create_pnt, _hoc_destroy_pnt, _member_func);\n",
1078  Lappendstr(defs_list, buf);
1080  Lappendstr(defs_list, " register_destructor(_destructor);\n");
1081  }
1082  }else{
1083  sprintf(buf, "\
1084  register_mech(_mechanism, nrn_alloc,%s, nrn_init, hoc_nrnpointerindex, %d);\n", brkpnt_str_, vectorize ? 1 + thread_data_index : 0);
1085  Lappendstr(defs_list, buf);
1086  }
1087  if (vectorize && thread_data_index) {
1088  sprintf(buf, " _extcall_thread = (Datum*)ecalloc(%d, sizeof(Datum));\n", thread_data_index);
1089  Lappendstr(defs_list, buf);
1090  if (thread_mem_init_list->next != thread_mem_init_list) {
1091  Lappendstr(defs_list, " _thread_mem_init(_extcall_thread);\n");
1092  if (gind) {Lappendstr(defs_list, " _thread1data_inuse = 0;\n");}
1093  }
1094  }
1095 #endif
1096  Lappendstr(defs_list, "_mechtype = nrn_get_mechtype(_mechanism[1]);\n");
1097  lappendstr(defs_list, " _nrn_setdata_reg(_mechtype, _setdata);\n");
1098  if (vectorize && thread_mem_init_list->next != thread_mem_init_list) {
1099  lappendstr(defs_list, " _nrn_thread_reg(_mechtype, 1, _thread_mem_init);\n");
1100  }
1101  if (vectorize && thread_cleanup_list->next != thread_cleanup_list) {
1102  lappendstr(defs_list, " _nrn_thread_reg(_mechtype, 0, _thread_cleanup);\n");
1103  }
1104  if (uip) {
1105  lappendstr(defs_list, " _nrn_thread_reg(_mechtype, 2, _update_ion_pointer);\n");
1106  }
1107  if (emit_check_table_thread) {
1108  lappendstr(defs_list, " _nrn_thread_table_reg(_mechtype, _check_table_thread);\n");
1109  }
1110  if (use_bbcorepointer) {
1111  lappendstr(defs_list, " hoc_reg_bbcore_write(_mechtype, bbcore_write);\n");
1112  lappendstr(defs_list, " hoc_reg_bbcore_read(_mechtype, bbcore_read);\n");
1113  }
1114  if (nmodl_text) {
1115  lappendstr(defs_list, "#if NMODL_TEXT\n hoc_reg_nmodl_text(_mechtype, nmodl_file_text);\n hoc_reg_nmodl_filename(_mechtype, nmodl_filename);\n#endif\n");
1116  }
1117  sprintf(buf, " hoc_register_prop_size(_mechtype, %d, %d);\n", parraycount, ppvar_cnt);
1118  Lappendstr(defs_list, buf);
1119  if (watch_seen_) {
1120  Lappendstr(defs_list, " hoc_reg_watch_allocate(_mechtype, _watch_alloc);\n");
1121  }
1122  if (ppvar_semantics_) ITERATE(q, ppvar_semantics_) {
1123  sprintf(buf, " hoc_register_dparam_semantics(_mechtype, %d, \"%s\");\n",
1124  (int)q->itemtype, q->element.str);
1125  Lappendstr(defs_list, buf);
1126  }
1127  /* Models that write concentration need their INITIAL blocks called
1128  before those that read the concentration or reversal potential. */
1129  i = 0;
1130  ITERATE(q, useion) {
1131  ITERATE(q1, LST(q->next->next)) {
1132  int type;
1133  type = iontype(SYM(q1)->name, SYM(q)->name);
1134  if (type == IONIN || type == IONOUT) {
1135  i += 1;
1136  }
1137  }
1138  q = q->next->next->next;
1139  }
1140  if (i) {
1141  Lappendstr(defs_list, "\tnrn_writes_conc(_mechtype, 0);\n");
1142  }
1143 
1144 #if CVODE
1145  if (cvode_emit) {
1146  Lappendstr(defs_list, "\
1147  hoc_register_cvode(_mechtype, _ode_count, _ode_map, _ode_spec, _ode_matsol);\n");
1148  Lappendstr(defs_list, "\
1149  hoc_register_tolerance(_mechtype, _hoc_state_tol, &_atollist);\n");
1150  if (ion_synonym) {
1151 Lappendstr(defs_list, " hoc_register_synonym(_mechtype, _ode_synonym);\n");
1152  }
1153  }else if (cvode_not_allowed) {
1154  Lappendstr(defs_list, "\
1155  hoc_register_cvode(_mechtype, _ode_count, 0, 0, 0);\n");
1156  }
1157  if (singlechan_) {
1158  sprintf(buf, "hoc_reg_singlechan(_mechtype, _singlechan_declare%d);\n", singlechan_);
1159  Lappendstr(defs_list, buf);
1160  }
1161 #endif
1162  if (artificial_cell) {
1163  if (brkpnt_exists || !net_receive_
1164  || nrnpointers->next != nrnpointers
1165  || useion->next != useion
1166  ) {
1167  printf(
1168 "Notice: ARTIFICIAL_CELL is a synonym for POINT_PROCESS which hints that it\n\
1169 only affects and is affected by discrete events. As such it is not\n\
1170 located in a section and is not associated with an integrator\n"
1171 );
1172  }
1173  sprintf(buf, "add_nrn_artcell(_mechtype, %d);\n", tqitem_index);
1174  Lappendstr(defs_list, buf);
1175  }
1176  if (net_event_seen_) {
1177  Lappendstr(defs_list, "add_nrn_has_net_event(_mechtype);\n");
1178  }
1179  if (net_receive_) {
1180  Lappendstr(defs_list, "pnt_receive[_mechtype] = _net_receive;\n");
1181  if (net_init_q1_) {
1182  Lappendstr(defs_list, "pnt_receive_init[_mechtype] = _net_init;\n");
1183  }
1184  sprintf(buf, "pnt_receive_size[_mechtype] = %d;\n", net_receive_);
1185  Lappendstr(defs_list, buf);
1186  }
1187  if (for_netcons_) {
1188  sprintf(buf, "add_nrn_fornetcons(_mechtype, _fnc_index);\n");
1189  Lappendstr(defs_list, buf);
1190  }
1191  q = ba_list_;
1192  for (i = 1; i <= ba_index_; ++i) {
1193  List* lst;
1194  q = q->next;
1195  if (electrode_current) {
1196  insertstr(ITM(q), " \
1197 #if EXTRACELLULAR\n\
1198 if (_nd->_extnode) {\n\
1199  v = NODEV(_nd) +_nd->_extnode->_v[0];\n\
1200 }else\n\
1201 #endif\n\
1202 {\n\
1203  v = NODEV(_nd);\n\
1204 }\n");
1205  }else{
1206  insertstr(ITM(q), " v = NODEV(_nd);\n");
1207  }
1208  lst = get_ion_variables(0);
1209  if (lst->next != lst->prev) {
1210  move(lst->next, lst->prev, ITM(q));
1211  freelist((List**)lst);
1212  }
1213  q = q->next;
1214  lst = set_ion_variables(0);
1215  if (lst->next != lst->prev) {
1216  move(lst->next, lst->prev, ITM(q));
1217  freelist((List**)lst);
1218  }
1219  q = q->next;
1220  sprintf(buf, "\thoc_reg_ba(_mechtype, _ba%d, %s);\n", i, STR(q));
1221  Lappendstr(defs_list, buf);
1222  }
1223  if (ldifuslist) {
1224  Lappendstr(defs_list, "\thoc_register_ldifus1(_difusfunc);\n");
1225  Linsertstr(defs_list, "static void _difusfunc(ldifusfunc2_t, NrnThread*);\n");
1226  }
1227  } /* end of not "nothing" */
1228  Lappendstr(defs_list, "\
1229  hoc_register_var(hoc_scdoub, hoc_vdoub, hoc_intfunc);\n");
1230  {
1231  char buf1[NRN_BUFSIZE];
1232  char* pf{};
1233 #if HAVE_REALPATH && !defined(NRN_AVOID_ABSOLUTE_PATHS)
1234  pf = realpath(finname, NULL);
1235 #endif
1236  sprintf(buf1, "\tivoc_help(\"help ?1 %s %s\\n\");\n", mechname, pf ? pf : finname);
1237  if(pf) { free(pf); }
1238  Lappendstr(defs_list, buf1);
1239  }
1240  if (suffix[0]) {
1241  Lappendstr(defs_list, "hoc_register_limits(_mechtype, _hoc_parm_limits);\n");
1242  Lappendstr(defs_list, "hoc_register_units(_mechtype, _hoc_parm_units);\n");
1243  }
1244  Lappendstr(defs_list, "}\n"); /* end of _reg */
1245  if (vectorize && thread_mem_init_list->next != thread_mem_init_list) {
1246  Lappendstr(procfunc, "\nstatic void _thread_mem_init(Datum* _thread) {\n");
1247  move(thread_mem_init_list->next, thread_mem_init_list->prev, procfunc);
1248  Lappendstr(procfunc, "}\n");
1249  }
1250  if (vectorize && thread_cleanup_list->next != thread_cleanup_list) {
1251  Lappendstr(procfunc, "\nstatic void _thread_cleanup(Datum* _thread) {\n");
1252  move(thread_cleanup_list->next, thread_cleanup_list->prev, procfunc);
1253  Lappendstr(procfunc, "}\n");
1254  }
1255  if (uip) {
1256  move(uip->next, uip->prev, procfunc);
1257  }
1259  if (vectorize) {
1260  Lappendstr(procfunc, "\n\
1261 static void _destructor(Prop* _prop) {\n\
1262  double* _p; Datum* _ppvar; Datum* _thread;\n\
1263  _thread = (Datum*)0;\n\
1264  _p = _prop->param; _ppvar = _prop->dparam;\n\
1265 {\n\
1266 ");
1267  }else{
1268  Lappendstr(procfunc, "\n\
1269 static void _destructor(Prop* _prop) {\n\
1270  _p = _prop->param; _ppvar = _prop->dparam;\n\
1271 {\n\
1272 ");
1273  }
1275  Lappendstr(procfunc, "\n}\n}\n");
1276  }
1277  if (ldifuslist) {
1278  ldifusreg();
1279  }
1280  SYMLISTITER {
1281  s = SYM(q);
1282  if ((s->subtype & PARM)) {
1283  warn_ignore(s);
1284  }
1285  }
1286 }
1287 
1289  int b;
1290  double d1, d2;
1291  b = 0;
1292  if (s->nrntype & (NRNEXTRN | NRNPRANGEIN | NRNPRANGEOUT)) b = 1;
1293  if (strcmp(s->name, "v") == 0) b = 1;
1294 
1295  decode_ustr(s, &d1, &d2, buf);
1296  if (d1 == 0.0) b = 0;
1297  if (b) {
1298  printf("Warning: Default %g of PARAMETER %s will be ignored and set by NEURON.\n", d1, s->name);
1299  }
1300 }
1301 
1302 void ldifusreg() {
1303  Item* q, *qdexp, *qb1, *qvexp, *qb2, *q1;
1304  char* cfindex, *dfdcur;
1305  Symbol* s, *d;
1306  int n;
1307 
1308  /* ldifuslist format: series of symbol qdexp qb1 svexp qb2
1309  indexforflux dflux/dconc */
1310  n = 0;
1311  ITERATE(q, ldifuslist) {
1312  s = SYM(q); q = q->next;
1313  qdexp = ITM(q); q = q->next;
1314  qb1 = ITM(q); q = q->next;
1315  qvexp = ITM(q); q = q->next;
1316  qb2 = ITM(q); q = q->next;
1317  cfindex = STR(q); q = q->next;
1318  dfdcur = STR(q);
1319  ++n;
1320 sprintf(buf, "static void* _difspace%d;\nextern double nrn_nernst_coef();\n\
1321 static double _difcoef%d(int _i, double* _p, Datum* _ppvar, double* _pdvol, double* _pdfcdc, Datum* _thread, NrnThread* _nt) {\n \
1322  *_pdvol = ", n, n);
1324  for (q1 = qvexp; q1 != qb2; q1 = q1->next) {
1325  lappenditem(procfunc, q1);
1326  }
1327  if (dfdcur[0]) {
1328  sprintf(buf, ";\n\
1329  if (_i == %s) {\n *_pdfcdc = %s;\n }else{ *_pdfcdc=0.;}\n", cfindex, dfdcur);
1330  }else{
1331  sprintf(buf, "; *_pdfcdc=0.;\n");
1332  }
1334  lappendstr(procfunc, " return");
1335  for (q1 = qdexp; q1 != qb1; q1 = q1->next) {
1336  lappenditem(procfunc, q1);
1337  }
1338  lappendstr(procfunc, ";\n}\n");
1339  }
1340  lappendstr(procfunc, "static void _difusfunc(ldifusfunc2_t _f, NrnThread* _nt) {int _i;\n");
1341  n = 0;
1342  ITERATE(q, ldifuslist) {
1343  s = SYM(q); q = q->next;
1344  qdexp = ITM(q); q = q->next;
1345  qb1 = ITM(q); q = q->next;
1346  qvexp = ITM(q); q = q->next;
1347  qb2 = ITM(q); q = q->next;
1348  cfindex = STR(q); q = q->next;
1349  dfdcur = STR(q);
1350  ++n;
1351 
1352  if (s->subtype & ARRAY) {
1353 #if MAC
1354 sprintf(buf, " for (_i=0; _i < %d; ++_i) mac_difusfunc(_f, _mechtype, _difcoef%d, &_difspace%d, _i, ", s->araydim, n, n);
1355 #else
1356 sprintf(buf, " for (_i=0; _i < %d; ++_i) (*_f)(_mechtype, _difcoef%d, &_difspace%d, _i, ", s->araydim, n, n);
1357 #endif
1358  }else{
1359 #if MAC
1360 sprintf(buf, " mac_difusfunc(_f,_mechtype, _difcoef%d, &_difspace%d, 0, ", n, n);
1361 #else
1362 sprintf(buf, " (*_f)(_mechtype, _difcoef%d, &_difspace%d, 0, ", n, n);
1363 #endif
1364  }
1366 
1367  sprintf(buf, "D%s", s->name);
1368  d = lookup(buf);
1369  assert(d);
1370  if (s->nrntype & IONCONC) {
1371  sprintf(buf, "%d, %d",
1372  - (s->ioncount_ + 1), d->varnum);
1373  }else{
1374  sprintf(buf, "%d, %d", s->varnum, d->varnum);
1375  }
1377  lappendstr(procfunc, ", _nt);\n");
1378  }
1379  lappendstr(procfunc, "}\n");
1380 }
1381 
1382 int decode_limits(Symbol* sym, double* pg1, double* pg2)
1383 {
1384  int i;
1385  double d1;
1386  if (sym->subtype & PARM) {
1387  char* cp;
1388  int n;
1389  assert(sym->u.str);
1390  for (n=0, cp = sym->u.str; *cp; ++cp) {
1391  if (*cp == '\n') {
1392  ++n;
1393  if (n == 3) {
1394  ++cp;
1395  break;
1396  }
1397  }
1398  }
1399  i = sscanf(cp, "%lf %lf\n", pg1, pg2);
1400  if (i == 2) {
1401  return 1;
1402  }
1403  }
1404  return 0;
1405 }
1406 
1407 int decode_tolerance(Symbol* sym, double* pg1)
1408 {
1409  int i;
1410  double d1;
1411  if (sym->subtype & STAT) {
1412  char* cp;
1413  int n;
1414  for (n=0, cp = sym->u.str; *cp; ++cp) {
1415  if (*cp == '\n') {
1416  ++n;
1417  if (n == 3) {
1418  ++cp;
1419  break;
1420  }
1421  }
1422  }
1423  i = sscanf(cp, "%lf\n", pg1);
1424  if (i == 1) {
1425  return 1;
1426  }
1427  }
1428  return 0;
1429 }
1430 
1431 void decode_ustr(Symbol* sym, double* pg1, double* pg2, char* s) /* decode sym->u.str */
1432 {
1433  int i, n;
1434  char *cp, *cp1;
1435 
1436  switch (sym->subtype & (INDEP | DEP | STAT | PARM)) {
1437 
1438  case INDEP: /* but doesnt get all info */
1439  case DEP:
1440  case STAT:
1441  assert(sym && sym->u.str);
1442  if (sym->subtype & ARRAY) { /* see parsact.c */
1443  i = sscanf(sym->u.str, "[%*d]\n%lf%*c%lf", pg1, pg2);
1444  }else{
1445  i = sscanf(sym->u.str, "%lf%*c%lf", pg1, pg2);
1446  }
1447  assert(i == 2);
1448  for (n=0, cp = sym->u.str; n < 2;) {
1449  if (*cp++ == '\n') {
1450  n++;
1451  }
1452  }
1453  for (cp1 = s; *cp != '\n';) {
1454  *cp1++ = *cp++;
1455  }
1456  *cp1 = '\0';
1457  break;
1458 
1459  case PARM:
1460  assert(sym && sym->u.str);
1461  if (sym->subtype & ARRAY) { /* see parsact.c */
1462  i = sscanf(sym->u.str, "[%*d]\n%lf\n%s", pg1, s);
1463  }else{
1464  i = sscanf(sym->u.str, "%lf\n%s", pg1, s);
1465  }
1466  if (i == 1) {
1467  s[0] = '\0';
1468  i = 2;
1469  }
1470  assert(i == 2);
1471  break;
1472  default:
1473  diag(sym->name, " does not have a proper declaration");
1474  }
1475  if (s[0] == '0') {s[0] = '\0';}
1476 }
1477 
1478 void units_reg() {
1479  Symbol* s;
1480  Item* q;
1481  double d1, d2;
1482  char u[NRN_BUFSIZE];
1483 
1484  Lappendstr(defs_list, "static HocParmUnits _hoc_parm_units[] = {\n");
1485  ITERATE (q, syminorder) {
1486  s = SYM(q);
1487  if (s->nrntype & NRNGLOBAL) {
1488  decode_ustr(s, &d1, &d2, u);
1489  if (u[0]) {
1490  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, suffix, u);
1491  lappendstr(defs_list, buf);
1492  }
1493  }
1494  }
1495  ITERATE (q, rangeparm) {
1496  s = SYM(q);
1497  decode_ustr(s, &d1, &d2, u);
1498  if (u[0]) {
1499  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1500  lappendstr(defs_list, buf);
1501  }
1502  }
1503  ITERATE (q, rangestate) {
1504  s = SYM(q);
1505  decode_ustr(s, &d1, &d2, u);
1506  if (u[0]) {
1507  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1508  lappendstr(defs_list, buf);
1509  }
1510  }
1511  ITERATE (q, rangedep) {
1512  s = SYM(q);
1513  decode_ustr(s, &d1, &d2, u);
1514  if (u[0]) {
1515  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1516  lappendstr(defs_list, buf);
1517  }
1518  }
1519  ITERATE (q, nrnpointers) {
1520  s = SYM(q);
1521  decode_ustr(s, &d1, &d2, u);
1522  if (u[0]) {
1523  sprintf(buf, "\"%s%s\", \"%s\",\n", s->name, rsuffix, u);
1524  lappendstr(defs_list, buf);
1525  }
1526  }
1527  Lappendstr(defs_list, "0,0\n};\n");
1528 }
1529 
1530 static void var_count(Symbol* s)
1531 {
1532  defs_h(s);
1533  s->used = varcount++;
1534  s->varnum = parraycount;
1535  if (s->subtype & ARRAY) {
1536  parraycount += s->araydim;
1537  }else{
1538  parraycount++;
1539  }
1540 }
1541 
1543 {
1544  Item *q;
1545 
1546  if (s->subtype & ARRAY) {
1547  Sprintf(buf, "#define %s (_p + %d)\n", s->name, parraycount);
1548  q = lappendstr(defs_list, buf);
1549  } else {
1550  Sprintf(buf, "#define %s _p[%d]\n", s->name, parraycount);
1551  q = lappendstr(defs_list, buf);
1552  }
1553  q->itemtype = VERBATIM;
1554 }
1555 
1556 
1557 void nrn_list(Item* q1, Item* q2)
1558 {
1559  List **plist = (List **)0;
1560  Item *q;
1561 
1562  switch (SYM(q1)->type) {
1563  case RANGE:
1564  plist = (List **)0;
1565  for (q = q1->next; q != q2->next; q = q->next) {
1566  SYM(q)->nrntype |= NRNRANGE;
1567  }
1568  break;
1569  case SUFFIX:
1570  plist = (List **)0;
1571  mechname = SYM(q2)->name;
1572  if (strcmp(SYM(q1)->name, "POINT_PROCESS") == 0) {
1573  point_process = 1;
1574  }else if (strcmp(SYM(q1)->name, "ARTIFICIAL_CELL") == 0) {
1575  point_process = 1;
1576  artificial_cell = 1;
1577  }
1578  break;
1579  case ELECTRODE_CURRENT:
1580  electrode_current = 1;
1581  case NONSPECIFIC:
1582  plist = &currents;
1583  for (q = q1->next; q != q2->next; q = q->next) {
1584  SYM(q)->nrntype |= NRNRANGE;
1585  }
1586  break;
1587  case SECTION:
1588  diag("NEURON SECTION variables not implemented", (char *)0);
1589  break;
1590  case GLOBAL:
1591  for (q = q1->next; q != q2->next; q = q->next) {
1592  SYM(q)->nrntype |= NRNGLOBAL | NRNNOTP;
1593  }
1594  plist = (List **)0;
1595  break;
1596  case EXTERNAL:
1597 #if VECTORIZE
1598 threadsafe("Use of EXTERNAL is not thread safe.");
1599 #endif
1600  for (q = q1->next; q != q2->next; q = q->next) {
1601  SYM(q)->nrntype |= NRNEXTRN | NRNNOTP;
1602  }
1603  plist = (List **)0;
1604  break;
1605  case POINTER:
1606 threadsafe("Use of POINTER is not thread safe.");
1607  plist = &nrnpointers;
1608  for (q = q1->next; q != q2->next; q = q->next) {
1609  SYM(q)->nrntype |= NRNNOTP | NRNPOINTER;
1610  }
1611  break;
1612  case BBCOREPOINTER:
1613 threadsafe("Use of BBCOREPOINTER is not thread safe.");
1614  plist = &nrnpointers;
1615  for (q = q1->next; q != q2->next; q = q->next) {
1616  SYM(q)->nrntype |= NRNNOTP | NRNBBCOREPOINTER;
1617  }
1618  use_bbcorepointer = 1;
1619  break;
1620  }
1621  if (plist) {
1622  if (!*plist) {
1623  *plist = newlist();
1624  }
1625  assert (q1 != q2);
1626  movelist(q1->next, q2, *plist);
1627  }
1628 }
1629 
1630 void bablk(int ba, int type, Item* q1, Item* q2)
1631 {
1632  Item* qb, *qv, *q;
1633  qb = insertstr(q1->prev->prev, "/*");
1634  insertstr(q1, "*/\n");
1635  if (!ba_list_) {
1636  ba_list_ = newlist();
1637  }
1638  sprintf(buf, "static void _ba%d(Node*_nd, double* _pp, Datum* _ppd, Datum* _thread, NrnThread* _nt) ", ++ba_index_);
1639  insertstr(q1, buf);
1640  q = q1->next;
1641  vectorize_substitute(insertstr(q, ""), "double* _p; Datum* _ppvar;");
1642  qv = insertstr(q, "_p = _pp; _ppvar = _ppd;\n");
1643  movelist(qb, q2, procfunc);
1644 
1645  ba = (ba == BEFORE) ? 10 : 20; /* BEFORE or AFTER */
1646  ba += (type == BREAKPOINT) ? 1 : 0;
1647  ba += (type == SOLVE) ? 2 : 0;
1648  ba += (type == INITIAL1) ? 3 : 0;
1649  ba += (type == STEP) ? 4 : 0;
1650  lappenditem(ba_list_, qv->next);
1651  lappenditem(ba_list_, q2);
1652  sprintf(buf, "%d", ba);
1653  lappendstr(ba_list_, buf);
1654 }
1655 
1657  Item* q;
1658  int used = 0;
1659  ITERATE(q, useion) {
1660  if (SYM(q) == s) {
1661  used = 1;
1662  }
1663  q = q->next->next->next;
1664  }
1665  return used;
1666 }
1667 
1668 void nrn_use(Item* q1, Item* q2, Item* q3, Item* q4)
1669 {
1670  int used, i;
1671  Item *q, *qr, *qw;
1672  List *readlist, *writelist;
1673  Symbol *ion;
1674 
1675  ion = SYM(q1);
1676  /* is it already used */
1677  used = ion_declared(SYM(q1));
1678  if (used) { /* READ gets promoted to WRITE */
1679  diag("mergeing of neuron models not supported yet", (char *)0);
1680  }else{ /* create all the ionic variables */
1681  Lappendsym(useion, ion);
1682  readlist = newlist();
1683  writelist = newlist();
1684  qr = lappendsym(useion, SYM0);
1685  qw = lappendsym(useion, SYM0);
1686  if (q4) {
1687  lappendstr(useion, STR(q4));
1688  }else{
1689  lappendstr(useion, "-10000.");
1690  }
1691  LST(qr) = readlist;
1692  LST(qw) = writelist;
1693  if (q2) { Item *qt = q2->next;
1694  move(q1->next->next, q2, readlist);
1695  if (q3) {
1696  move(qt->next, q3, writelist);
1697  }
1698  }else if (q3) {
1699  move(q1->next->next, q3, writelist);
1700  }
1701  ITERATE(q, readlist) {
1702  i = iontype(SYM(q)->name, ion->name);
1703  if (i == IONCUR) {
1704  SYM(q)->nrntype |= NRNCURIN;
1705  }else{
1706  SYM(q)->nrntype |= NRNPRANGEIN;
1707  if (i == IONIN || i == IONOUT) {
1708  SYM(q)->nrntype |= IONCONC;
1709  }
1710  }
1711  }
1712  ITERATE(q, writelist) {
1713  i = iontype(SYM(q)->name, ion->name);
1714  if (i == IONCUR) {
1715  if (!currents) {
1716  currents = newlist();
1717  }
1718  Lappendsym(currents, SYM(q));
1719  SYM(q)->nrntype |= NRNCUROUT;
1720  }else{
1721  SYM(q)->nrntype |= NRNPRANGEOUT;
1722  if (i == IONIN || i == IONOUT) {
1723  SYM(q)->nrntype |= IONCONC;
1724  }
1725  }
1726  }
1727  }
1728 }
1729 
1730 int iontype(char* s1, char* s2) /* returns index of variable in ion mechanism */
1731 {
1732  Sprintf(buf, "i%s", s2);
1733  if (strcmp(buf, s1) == 0) {
1734  return IONCUR;
1735  }
1736  Sprintf(buf, "e%s", s2);
1737  if (strcmp(buf, s1) == 0) {
1738  return IONEREV;
1739  }
1740  Sprintf(buf, "%si", s2);
1741  if (strcmp(buf, s1) == 0) {
1742  return IONIN;
1743  }
1744  Sprintf(buf, "%so", s2);
1745  if (strcmp(buf, s1) == 0) {
1746  return IONOUT;
1747  }
1748  Sprintf(buf, "%s is not a valid ionic variable for %s", s1, s2);
1749  diag(buf, (char *)0);
1750  return -1;
1751 }
1752 
1753 static Symbol *ifnew_install(char* name)
1754 {
1755  Symbol *s;
1756 
1757  if ((s = lookup(name)) == SYM0) {
1758  s = install(name, NAME);
1759  parminstall(s, "0", "", "");
1760  }
1761  return s;
1762 }
1763 
1764 void nrndeclare() {
1765  Symbol *s;
1766  Item *q;
1767 
1768  s=lookup("diam"); if (s) {
1769  if (s->nrntype & (NRNRANGE|NRNGLOBAL)) {
1770 diag(s->name, "cannot be a RANGE or GLOBAL variable for this mechanism");
1771  }
1772  s->nrntype |= NRNNOTP|NRNPRANGEIN; diamdec=1;
1773  }
1774  s=lookup("area"); if (s) {
1775  if (s->nrntype & (NRNRANGE|NRNGLOBAL)) {
1776 diag(s->name, "cannot be a RANGE or GLOBAL variable for this mechanism");
1777  }
1778  s->nrntype |= NRNNOTP|NRNPRANGEIN; areadec=1;
1779  }
1780 #if VECTORIZE
1781  if (vectorize) {
1782  s = ifnew_install("v");
1783  s->nrntype = NRNNOTP; /* this is a lie, it goes in at end specially */
1784  }else
1785 #endif
1786  {
1787  s = ifnew_install("v");
1788  s->nrntype |= NRNSTATIC | NRNNOTP;
1789  }
1790  s = ifnew_install("t");
1791  s->nrntype |= NRNEXTRN | NRNNOTP;
1792  s = ifnew_install("dt");
1793  s->nrntype |= NRNEXTRN | NRNNOTP;
1794  vectorize_substitute(lappendstr(defs_list, "\n#define t nrn_threads->_t\n#define dt nrn_threads->_dt\n"), "\n#define t _nt->_t\n#define dt _nt->_dt\n");
1795 
1796  s=lookup("usetable"); if (s) { s->nrntype |= NRNGLOBAL | NRNNOTP;}
1797  s=lookup("celsius");if(s){s->nrntype |= NRNEXTRN | NRNNOTP;}
1798  s=lookup("celcius"); if (s) diag("celcius should be spelled celsius",
1799  (char *)0);
1800 
1801  ITERATE(q, syminorder) {
1802  s = SYM(q);
1803  if (s->type == NAME || s->type == PRIME) {
1804  if (s->subtype & PARM && s->nrntype & NRNRANGE) {
1805  Lappendsym(rangeparm, s);
1806  } else if (s->subtype & STAT) {
1807  s->nrntype |= NRNRANGE;
1808  Lappendsym(rangestate, s);
1809  } else if (s->subtype & DEP && s->nrntype & NRNRANGE) {
1810  Lappendsym(rangedep, s);
1811  }
1812  if (s != indepsym && !s->nrntype) {
1813  if (s->subtype & PARM) {
1814  if (s->usage & EXPLICIT_DECL) {
1815  s->nrntype |= NRNGLOBAL;
1816  s->nrntype |= NRNNOTP;
1817  }else{
1818  s->nrntype |= NRNSTATIC;
1819  s->nrntype |= NRNNOTP;
1820  }
1821  }
1822  }
1823  }
1824  }
1825  /* some ionic variables don't need duplicates known to hoc */
1826  del_range(rangeparm);
1827  del_range(rangestate);
1828  del_range(rangedep);
1829 }
1830 
1831 void del_range(List* range)
1832 {
1833  Item *q, *q1;
1834  Symbol *s;
1835 
1836  for (q = ((Item *)range)->next; q != (Item *)range; q = q1) {
1837  q1 = q->next;
1838  s = SYM(q);
1839  if (s->nrntype & (NRNPRANGEIN | NRNPRANGEOUT)) {
1840  remove(q);
1841  }
1842  }
1843 }
1844 
1845 
1846 void declare_p() {
1847  Item *q;
1848  Symbol* s;
1849 
1850  ITERATE(q, syminorder) {
1851  SYM(q)->used = -1;
1852  }
1853  ITERATE(q, rangeparm) {
1854  var_count(SYM(q));
1855  }
1856  ITERATE(q, rangedep) {
1857  var_count(SYM(q));
1858  }
1859  ITERATE(q, rangestate) {
1860  var_count(SYM(q));
1861  }
1862  ITERATE(q, syminorder) {
1863  if (!(SYM(q)->nrntype & NRNNOTP) && SYM(q)->used < 0) {
1864  var_count(SYM(q));
1865  }
1866  }
1867 #if VECTORIZE
1868  if (vectorize) {
1869  s = ifnew_install("v");
1870  var_count(s);
1871  }
1872 #endif
1873  if (brkpnt_exists) {
1874  s = ifnew_install("_g");
1875  var_count(s);
1876  }
1877  if (debugging_ && net_receive_) {
1878  s = ifnew_install("_tsav");
1879  var_count(s);
1880  }
1881 }
1882 
1884 /* 0 means equation block , 2 means initial block */
1885 {
1886  /*ARGSUSED*/
1887  Item *q, *q1, *qconc;
1888  char* in;
1889  static List *l;
1890 
1891  l = newlist();
1892  ITERATE(q, useion) {
1893  in = SYM(q)->name;
1894  q = q->next;
1895  q = q->next;
1896  qconc = (Item*)0;
1897  ITERATE(q1, LST(q)) {
1898  if (SYM(q1)->nrntype & NRNCUROUT) {
1899  if ( block == 0) {
1900 Sprintf(buf, " _ion_%s += %s", SYM(q1)->name, breakpoint_current(SYM(q1))->name);
1901  Lappendstr(l, buf);
1902  if (point_process) {
1903  Sprintf(buf, "* 1.e2/ (_nd_area);\n");
1904  }else{
1905  Sprintf(buf, ";\n");
1906  }
1907  }else{
1908  buf[0] = '\0';
1909  }
1910  }else{
1911  if (iontype(SYM(q1)->name, in) != IONEREV) {
1912  qconc = q1;
1913  }
1914 Sprintf(buf, " _ion_%s = %s;\n", SYM(q1)->name, SYM(q1)->name);
1915  }
1916  Lappendstr(l, buf);
1917  }
1918  q = q->next;
1919  /* when INITIAL block is called, if it modifies the concentrations
1920  then the reversal potential should be recomputed in case
1921  other mechanisms need the true initial value. This would be
1922  rare since most initial blocks do not depend on erev. Instead
1923  the right value will be present due to fcurrent or cvode f(y).
1924  However, this fastidiousness cant hurt. It just makes ion_style
1925  in effect always at least for initialization.
1926  */
1927  /* sure enough, someone needed to demote the ion_style so
1928  that erev is decoupled from concentrations. So we need
1929  another variable pointing to the ionstyle
1930  */
1931  if (block == 2 && qconc) {
1932  int ic = iontype(SYM(qconc)->name, in);
1933  if (ic == IONIN) {
1934  ic = 1;
1935  }else if (ic == IONOUT) {
1936  ic = 2;
1937  }else{
1938  assert(0);
1939  }
1940 /* first arg is just for the charge, second is pointer to erev, third ard is the style*/
1941  Sprintf(buf, " nrn_wrote_conc(_%s_sym, (&(_ion_%s)) - %d, _style_%s);\n",
1942  in, SYM(qconc)->name, ic, in);
1943  Lappendstr(l, buf);
1944  }
1945  }
1946  return l;
1947 }
1948 
1950 /* 0 means equation block */
1951  /* 2 means ode_spec and ode_matsol blocks */
1952 {
1953  /*ARGSUSED*/
1954  Item *q, *q1;
1955  static List *l;
1956 
1957  l = newlist();
1958  ITERATE(q, useion) {
1959  q = q->next;
1960  ITERATE(q1, LST(q)) {
1961  if (block == 2 && (SYM(q1)->nrntype & IONCONC) && (SYM(q1)->subtype & STAT)) {
1962  continue;
1963  }
1964 Sprintf(buf, " %s = _ion_%s;\n", SYM(q1)->name, SYM(q1)->name);
1965  Lappendstr(l, buf);
1966 if (point_process && (SYM(q1)->nrntype & NRNCURIN)) {
1967 Fprintf(stderr, "WARNING: Dimensions may be wrong for READ %s with POINT_PROCESS\n", SYM(q1)->name);
1968 }
1969  }
1970  q = q->next;
1971  ITERATE(q1, LST(q)) {
1972  if (block == 2 && (SYM(q1)->nrntype & IONCONC) && (SYM(q1)->subtype & STAT)) {
1973  continue;
1974  }
1975  if (SYM(q1)->nrntype & IONCONC) {
1976 Sprintf(buf, " %s = _ion_%s;\n", SYM(q1)->name, SYM(q1)->name);
1977  Lappendstr(l, buf);
1978  }
1979  if (SYM(q1)->subtype & STAT) {
1980 if (SYM(q1)->nrntype & NRNCUROUT) {
1981 Fprintf(stderr, "WARNING: WRITE %s with it a STATE may not be translated correctly\n", SYM(q1)->name);
1982 }
1983  }
1984  }
1985  q = q->next;
1986  }
1987  return l;
1988 }
1989 
1990 int iondef(int* p_pointercount) {
1991  int ioncount, it, need_style;
1992  Item *q, *q1, *q2;
1993  Symbol *sion;
1994  char ionname[256];
1995 
1996  ioncount = 0;
1997  if (point_process) {
1998  ioncount = 2;
1999  q = lappendstr(defs_list, "#define _nd_area *_ppvar[0]._pval\n");
2000  q->itemtype = VERBATIM;
2001  ppvar_semantics(0, "area");
2002  ppvar_semantics(1, "pntproc");
2003  }
2004  ITERATE(q, useion) {
2005  int dcurdef = 0;
2006  if (!uip) {
2007  uip = newlist();
2008  lappendstr(uip, "extern void nrn_update_ion_pointer(Symbol*, Datum*, int, int);\n");
2009  lappendstr(uip, "static void _update_ion_pointer(Datum* _ppvar) {\n");
2010  }
2011  need_style = 0;
2012  sion = SYM(q);
2013  sprintf(ionname, "%s_ion", sion->name);
2014  q=q->next;
2015  ITERATE(q1, LST(q)) {
2016  SYM(q1)->nrntype |= NRNIONFLAG;
2017  Sprintf(buf, "#define _ion_%s *_ppvar[%d]._pval\n",
2018  SYM(q1)->name, ioncount);
2019  q2 = lappendstr(defs_list, buf);
2020  q2->itemtype = VERBATIM;
2021  sprintf(buf, " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, %d);\n",
2022  sion->name, ioncount, iontype(SYM(q1)->name, sion->name));
2023  lappendstr(uip, buf);
2024  SYM(q1)->ioncount_ = ioncount;
2025  ppvar_semantics(ioncount, ionname);
2026  ioncount++;
2027  }
2028  q=q->next;
2029  ITERATE(q1, LST(q)) {
2030  if (SYM(q1)->nrntype & NRNIONFLAG) {
2031  SYM(q1)->nrntype &= ~NRNIONFLAG;
2032  }else{
2033  Sprintf(buf, "#define _ion_%s *_ppvar[%d]._pval\n",
2034  SYM(q1)->name, ioncount);
2035  q2 = lappendstr(defs_list, buf);
2036  q2->itemtype = VERBATIM;
2037  sprintf(buf, " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, %d);\n",
2038  sion->name, ioncount, iontype(SYM(q1)->name, sion->name));
2039  lappendstr(uip, buf);
2040  SYM(q1)->ioncount_ = ioncount;
2041  ppvar_semantics(ioncount, ionname);
2042  ioncount++;
2043  }
2044  it = iontype(SYM(q1)->name, sion->name);
2045  if (it == IONCUR) {
2046  dcurdef = 1;
2047 Sprintf(buf, "#define _ion_di%sdv\t*_ppvar[%d]._pval\n", sion->name, ioncount);
2048  q2 = lappendstr(defs_list, buf);
2049  q2->itemtype = VERBATIM;
2050  sprintf(buf, " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, 4);\n",
2051  sion->name, ioncount);
2052  lappendstr(uip, buf);
2053  ppvar_semantics(ioncount, ionname);
2054  ioncount++;
2055  }
2056  if (it == IONIN || it == IONOUT) { /* would have wrote_ion_conc */
2057  need_style = 1;
2058  }
2059  }
2060  if (need_style) {
2061 Sprintf(buf, "#define _style_%s\t*((int*)_ppvar[%d]._pvoid)\n", sion->name, ioncount);
2062  q2 = lappendstr(defs_list, buf);
2063  q2->itemtype = VERBATIM;
2064  sprintf(buf, "#%s", ionname);
2065  ppvar_semantics(ioncount, buf);
2066  ioncount++;
2067  }
2068  q=q->next;
2069  if (!dcurdef && ldifuslist) {
2070 Sprintf(buf, "#define _ion_di%sdv\t*_ppvar[%d]._pval\n", sion->name, ioncount);
2071  q2 = lappendstr(defs_list, buf);
2072  q2->itemtype = VERBATIM;
2073  sprintf(buf, " nrn_update_ion_pointer(_%s_sym, _ppvar, %d, 4);\n",
2074  sion->name, ioncount);
2075  lappendstr(uip, buf);
2076  ppvar_semantics(ioncount, ionname);
2077  ioncount++;
2078  }
2079  }
2080  *p_pointercount = 0;
2081  ITERATE(q, nrnpointers) {
2082  sion = SYM(q);
2083  Sprintf(buf, "#define %s *_ppvar[%d]._pval\n",
2084  sion->name, ioncount + *p_pointercount);
2085  sion->used = ioncount + *p_pointercount;
2086  q2 = lappendstr(defs_list, buf);
2087  q2->itemtype = VERBATIM;
2088  Sprintf(buf, "#define _p_%s _ppvar[%d]._pval\n",
2089  sion->name, ioncount + *p_pointercount);
2090  sion->used = ioncount + *p_pointercount;
2091  q2 = lappendstr(defs_list, buf);
2092  q2->itemtype = VERBATIM;
2093  if (sion->nrntype & NRNPOINTER) {
2094  ppvar_semantics(ioncount + *p_pointercount, "pointer");
2095  }else{
2096  ppvar_semantics(ioncount + *p_pointercount, "bbcorepointer");
2097  }
2098  (*p_pointercount)++;
2099  }
2100 
2101  if (diamdec) { /* must be last */
2102  Sprintf(buf, "#define diam *_ppvar[%d]._pval\n", ioncount + *p_pointercount);
2103  q2 = lappendstr(defs_list, buf);
2104  q2->itemtype = VERBATIM;
2105  } /* notice that ioncount is not incremented */
2106  if (areadec) { /* must be last, if we add any more the administrative
2107  procedures must be redone */
2108  Sprintf(buf, "#define area *_ppvar[%d]._pval\n", ioncount+ *p_pointercount + diamdec);
2109  q2 = lappendstr(defs_list, buf);
2110  q2->itemtype = VERBATIM;
2111  } /* notice that ioncount is not incremented */
2112  if (uip) { lappendstr(uip, "}\n"); }
2113  return ioncount;
2114 }
2115 
2116 void ppvar_semantics(int i, const char* name) {
2117  Item* q;
2118  if (!ppvar_semantics_) { ppvar_semantics_ = newlist(); }
2119  q = Lappendstr(ppvar_semantics_, const_cast<char*>(name)); //TODO - ugly but ok for now
2120  q->itemtype = (short)i;
2121 }
2122 
2124 {
2125  Item *q, *q1, *qbrak;
2126  static List *l;
2127  char *strion;
2128 
2129  l = newlist();
2130  qbrak = lappendstr(l, "\t{");
2131  ITERATE(q, useion) {
2132  strion = SYM(q)->name;
2133  q = q->next;
2134  q = q->next;
2135  ITERATE(q1, LST(q)) {
2136  if (SYM(q1)->nrntype & NRNCUROUT) {
2137  Sprintf(buf, " _di%s = %s;\n",
2138  strion, SYM(q1)->name);
2139  Lappendstr(l, buf);
2140  Sprintf(buf, "double _di%s;\n", strion);
2141  Insertstr(qbrak->next, buf);
2142  }
2143  }
2144  q = q->next;
2145  }
2146  return l;
2147 }
2148 
2149 List *end_dion_stmt(char* strdel)
2150 {
2151  Item *q, *q1;
2152  static List *l;
2153  char *strion;
2154 
2155  l = newlist();
2156  ITERATE(q, useion) {
2157  strion = SYM(q)->name;
2158  q = q->next;
2159  q = q->next;
2160  ITERATE(q1, LST(q)) {
2161  if (SYM(q1)->nrntype & NRNCUROUT) {
2162 Sprintf(buf, " _ion_di%sdv += (_di%s - %s)/%s",
2163  strion, strion, SYM(q1)->name, strdel);
2164  Lappendstr(l, buf);
2165  if (point_process) {
2166  Lappendstr(l, "* 1.e2/ (_nd_area);\n");
2167  }else{
2168  Lappendstr(l, ";\n");
2169  }
2170  }
2171  }
2172  q = q->next;
2173  }
2174  Lappendstr(l, "\t}\n");
2175  return l;
2176 }
2177 
2178 void ion_promote(Item* qion)
2179 {
2180  Item* q;
2181  char* in;
2182  int conc, rev;
2183  int type;
2184  conc = 0;
2185  rev = 0;
2186  in = SYM(qion)->name;
2187  ITERATE(q, LST(qion->next)) { /* check READ */
2188  type = iontype(SYM(q)->name, in);
2189  if (type == IONIN || type == IONOUT) {
2190  conc = 1;
2191  }
2192  if (type == IONEREV) {
2193  rev = 1;
2194  }
2195  }
2196  ITERATE(q, LST(qion->next->next)) { /* promote if WRITE */
2197  type = iontype(SYM(q)->name, in);
2198  if (type == IONIN) {
2199  Lappendstr(defs_list, "nrn_check_conc_write(_prop, prop_ion, 1);\n");
2200  conc = 3;
2201  }
2202  if (type == IONOUT) {
2203  Lappendstr(defs_list, "nrn_check_conc_write(_prop, prop_ion, 0);\n");
2204  conc = 3;
2205  }
2206  if (type == IONEREV) {
2207  rev = 3;
2208  }
2209  }
2210  if (conc || rev) {
2211  Sprintf(buf, "nrn_promote(prop_ion, %d, %d);\n", conc, rev);
2212  Lappendstr(defs_list, buf);
2213  }
2214 }
2215 
2216 #define NRNFIX(arg) if (strcmp(n, arg) == 0) e=1;
2217 
2219  int e;
2220  char* n;
2221  if (s->assigned_to_ == 0) {
2222  s->assigned_to_ = 1;
2223  }
2224  if (protect_) {
2225  s->assigned_to_ = 2;
2226  }
2227  e = 0;
2228  n = s->name;
2229  NRNFIX("area");
2230  NRNFIX("diam");
2231  NRNFIX("t");
2232  NRNFIX("dt");
2233  NRNFIX("celsius");
2234  if (e) {
2235 diag(s->name, "is a special NEURON variable that should not be\n assigned a value\
2236  in a model description file\n");
2237  }
2238 }
2239 
2240 #if CVODE
2241 
2242 static int cvode_valid_, using_cvode;
2243 static int cvode_num_, cvode_neq_;
2244 static Symbol* cvode_fun_;
2245 
2246 void slist_data(Symbol* s, int indx, int findx) {
2247  /* format: number of pairs, followed by findx, indx pairs */
2248  int* pi;
2249  int i, n;
2250  if (s->slist_info_) {
2251  /* i'd use realloc but to avoid portability problems */
2252  /* this probably will never get executed anyway */
2253  n = s->slist_info_[0] + 1;
2254  pi = (int*)emalloc((1 + 2*n)*sizeof(int));
2255  for (i=2*(n-1); i > 0; --i) {
2256  pi[i] = s->slist_info_[i];
2257  }
2258  free(s->slist_info_);
2259  s->slist_info_ = pi;
2260  pi[0] = n;
2261  pi[2*n-1] = findx;
2262  pi[2*n] = indx;
2263  }else{
2264  s->slist_info_ = pi = (int*)emalloc(3*sizeof(int));
2265  pi[0] = 1;
2266  pi[1] = findx;
2267  pi[2] = indx;
2268  }
2269 }
2270 
2271 int slist_search(int n, Symbol* s) {
2272  int i, *pi;
2273  pi = s->slist_info_;
2274 if (pi == (int*)0) {
2275  diag(s->name, "not really a STATE; Ie. No differential equation for it.\n");
2276 }
2277  assert(pi);
2278  for (i=0; i < pi[0]; ++i) {
2279  if (pi[1+2*i] == n) {
2280  return pi[2+2*i];
2281  }
2282  }
2283  assert(0);
2284  return 0;
2285 }
2286 
2287 static void cvode_conc_map() {
2288  /* pv index is slist index, ppd index is to the concentration
2289  pointer to the ion concentration is eg. &(ion_cai). Unfortunately
2290  the slist index has nothing to do with the _p array index.
2291  To recover the slist index, an slist_index list was made for
2292  every slist which consists of an slist ordered list of state symbols
2293  */
2294  /*
2295  also must handle case where user WRITE cai but cai is not a STATE
2296  since inefficiency occurs due to inability to set eca when
2297  states are predicted
2298  */
2299  Item* q, *q1, *q2, *q3;
2300  int sindex;
2301  ITERATE(q, useion) {
2302  q = q->next;
2303  q = q->next;
2304  ITERATE(q1, LST(q)) {
2305  if (SYM(q1)->nrntype & IONCONC) {
2306  if ((SYM(q1)->subtype & STAT)) {
2307  sindex = slist_search(cvode_num_, SYM(q1));
2308  sprintf(buf, "\t_pv[%d] = &(_ion_%s);\n",
2309  sindex, SYM(q1)->name);
2311  }else{ /* not a STATE but WRITE it*/
2312 /*its got to have an assignment in a SOLVE block and that assignment
2313 better not depend on intermediate variables that depend on states
2314 because we will assign cai using only that statement prior to
2315 calling the nernst equation code.
2316 */
2317  int b = 0;
2318  if (!ion_synonym) {
2319  ion_synonym = newlist();
2320  }
2321  ITERATE(q2, procfunc) {
2322  if (q2->itemtype == SYMBOL && SYM(q2) == SYM(q1)) {
2323  q3 = q2->next;
2324  if (q3->itemtype == SYMBOL && strcmp(SYM(q3)->name, "=") == 0) {
2325 /*printf(" found reference to %s = ...\n", SYM(q2)->name);*/
2326  sprintf(buf, "_ion_%s = ", SYM(q2)->name);
2327  lappendstr(ion_synonym, buf);
2328  for (q3 = q3->next; q3 != procfunc->prev; q3 = q3->next) {
2329  lappenditem(ion_synonym, q3);
2330  if (q3->itemtype == SYMBOL && SYM(q3) == semi) {
2331 #if 0
2332  if (q3->itemtype == STRING && strchr(STR(q3), ';')) {
2333  char* e, *s = stralloc(STR(q3), (char*)0);
2334  e = strchr(s, ';');
2335  *e = '\0';
2336  sprintf(buf, "%s;\n", s);
2337 printf("|%s||%s||%s|\n",STR(q3), s, buf);
2338  lappendstr(ion_synonym, buf);
2339 #endif
2340  b = 1;
2341  break;
2342  }
2343  }
2344  break;
2345  }
2346  }
2347  }
2348  if (b == 0) {
2349 diag(SYM(q1)->name, "is WRITE but is not a STATE and has no assignment statement");
2350  }
2351  }
2352  }
2353  }
2354  q = q->next;
2355  }
2356 }
2357 
2358 void out_nt_ml_frag(List* p) {
2359  vectorize_substitute(lappendstr(p, " Datum* _thread;\n"), " double* _p; Datum* _ppvar; Datum* _thread;\n");
2360  Lappendstr(p, " Node* _nd; double _v; int _iml, _cntml;\n\
2361  _cntml = _ml->_nodecount;\n\
2362  _thread = _ml->_thread;\n\
2363  for (_iml = 0; _iml < _cntml; ++_iml) {\n\
2364  _p = _ml->_data[_iml]; _ppvar = _ml->_pdata[_iml];\n\
2365  _nd = _ml->_nodelist[_iml];\n\
2366  v = NODEV(_nd);\n\
2367 ");
2368 }
2369 
2370 void cvode_emit_interface() {
2371  List* lst;
2372  Item* q, *q1;
2373  if (cvode_not_allowed) {
2374  Lappendstr(defs_list, "\n\
2375 static int _ode_count(int);\n");
2376  sprintf(buf, "\n\
2377 static int _ode_count(int _type){ hoc_execerror(\"%s\", \"cannot be used with CVODE\"); return 0;}\n",
2378  mechname);
2380  }else if (cvode_emit) {
2381 
2382  Lappendstr(defs_list, "\n\
2383 static int _ode_count(int);\n\
2384 static void _ode_map(int, double**, double**, double*, Datum*, double*, int);\n\
2385 static void _ode_spec(NrnThread*, _Memb_list*, int);\n\
2386 static void _ode_matsol(NrnThread*, _Memb_list*, int);\n\
2387 ");
2388  sprintf(buf, "\n\
2389 static int _ode_count(int _type){ return %d;}\n",
2390  cvode_neq_);
2392  sprintf(buf, "\n#define _cvode_ieq _ppvar[%d]._i\n",cvode_ieq_index);
2393  Lappendstr(defs_list, buf);
2394 
2395  if (cvode_fun_->subtype == PROCED) {
2397  }else{
2398  Lappendstr(procfunc, "\nstatic void _ode_spec(NrnThread* _nt, _Memb_list* _ml, int _type) {\n");
2400  lst = get_ion_variables(1);
2401  if (lst->next->itemtype) movelist(lst->next, lst->prev, procfunc);
2402  sprintf(buf," _ode_spec%d", cvode_num_);
2404  vectorize_substitute(lappendstr(procfunc, "();\n"), "(_p, _ppvar, _thread, _nt);\n");
2405  lst = set_ion_variables(1);
2406  if (lst->next->itemtype) movelist(lst->next, lst->prev, procfunc);
2407  Lappendstr(procfunc, "}}\n");
2408 
2409  Lappendstr(procfunc, "\n\
2410 static void _ode_map(int _ieq, double** _pv, double** _pvdot, double* _pp, Datum* _ppd, double* _atol, int _type) {");
2412  double* _p; Datum* _ppvar;\n");
2413  sprintf(buf, "\
2414  int _i; _p = _pp; _ppvar = _ppd;\n\
2415  _cvode_ieq = _ieq;\n\
2416  for (_i=0; _i < %d; ++_i) {\n\
2417  _pv[_i] = _pp + _slist%d[_i]; _pvdot[_i] = _pp + _dlist%d[_i];\n\
2418  _cvode_abstol(_atollist, _atol, _i);\n\
2419  }\n",
2420  cvode_neq_, cvode_num_, cvode_num_);
2422 /* need to take care of case where a state is an ion concentration. Replace
2423 the _pp pointer with a pointer to the actual ion model's concentration */
2424  cvode_conc_map();
2425  Lappendstr(procfunc, "}\n");
2426  if (ion_synonym) {
2427  Lappendstr(defs_list, "static void _ode_synonym(int, double**, Datum**);\n");
2428  Lappendstr(procfunc, "\
2429 static void _ode_synonym(int _cnt, double** _pp, Datum** _ppd) {");
2431  double* _p; Datum* _ppvar;\n");
2432  Lappendstr(procfunc, "\
2433  int _i; \n\
2434  for (_i=0; _i < _cnt; ++_i) {_p = _pp[_i]; _ppvar = _ppd[_i];\n");
2435  movelist(ion_synonym->next, ion_synonym->prev, procfunc);
2436  Lappendstr(procfunc, "}}\n");
2437  }
2438 
2439  sprintf(buf, "static void _ode_matsol_instance%d(_threadargsproto_);\n", cvode_num_);
2440  Lappendstr(defs_list, buf);
2441  sprintf(buf, "\nstatic void _ode_matsol_instance%d(_threadargsproto_) {\n", cvode_num_);
2443  if (cvode_fun_->subtype == KINF) {
2444  int i = cvode_num_;
2445 sprintf(buf, "_cvode_sparse(&_cvsparseobj%d, %d, _dlist%d, _p, _ode_matsol%d, &_coef%d);\n",
2446  i, cvode_neq_, i, i, i);
2448 sprintf(buf, "_cvode_sparse_thread(&_thread[_cvspth%d]._pvoid, %d, _dlist%d, _p, _ode_matsol%d, _ppvar, _thread, _nt);\n",
2449  i, cvode_neq_, i, i);
2451  }else{
2452  sprintf(buf, "_ode_matsol%d", cvode_num_);
2454  vectorize_substitute(lappendstr(procfunc, "();\n"), "(_p, _ppvar, _thread, _nt);\n");
2455  }
2456  Lappendstr(procfunc, "}\n");
2457  Lappendstr(procfunc, "\nstatic void _ode_matsol(NrnThread* _nt, _Memb_list* _ml, int _type) {\n");
2459  lst = get_ion_variables(1);
2460  if (lst->next->itemtype) movelist(lst->next, lst->prev, procfunc);
2461  sprintf(buf, "_ode_matsol_instance%d(_threadargs_);\n", cvode_num_);
2463  Lappendstr(procfunc, "}}\n");
2464  }
2465  /* handle the state_discontinuities (obsolete in NET_RECEIVE)*/
2466  if (state_discon_list_) ITERATE(q, state_discon_list_) {
2467  Symbol* s;
2468  int sindex;
2469  q1 = ITM(q);
2470  s = SYM(q1);
2471  if (q1->itemtype == SYMBOL && (s->subtype & STAT)) {
2472  sindex = slist_search(cvode_num_, s);
2473  sprintf(buf, "_cvode_ieq + %d, &", sindex);
2474  replacstr(q1->prev, buf);
2475  }
2476  }
2477  }
2478 }
2479 
2480 void cvode_proced_emit() {
2481  sprintf(buf, "\n\
2482 static void _ode_spec(Node* _nd, double* _pp, Datum* _ppd) {\n\
2483  _p = _pp; _ppvar = _ppd; v = NODEV(_nd);\n\
2484  %s();\n}\n",
2485  cvode_fun_->name);
2486 
2488  sprintf(buf, "\n\
2489 static void _ode_map(int _ieq, double** _pv, doubl** _pvdot, double* _pp){}\n");
2491 
2492  Lappendstr(procfunc, "\n\
2493 static void _ode_matsol(Node* _nd, double* _pp, Datum* _ppd){}\n");
2494 }
2495 
2496 void cvode_interface(Symbol* fun, int num, int neq) {
2497  /* if only one then allowed and emit */
2498  cvode_valid_ = 1;
2499  cvode_not_allowed = (using_cvode++) ? 1 : 0;
2500  cvode_emit = !cvode_not_allowed;
2501  cvode_num_ = num;
2502  cvode_neq_ = neq;
2503  cvode_fun_ = fun;
2504  if (cvode_fun_->subtype == PROCED) {
2505  cvode_emit = 0;
2506  return;
2507  }
2508  Sprintf(buf, "\n\
2509 static int _ode_spec%d(_threadargsproto_);\n\
2510 /*static int _ode_matsol%d(_threadargsproto_);*/\n\
2511 ", num, num);
2513 }
2514 
2515 void cvode_valid() {
2516  static int once;
2517  if (!cvode_valid_ && !once++) {
2518  Fprintf(stderr, "Notice: This mechanism cannot be used with CVODE\n");
2519  cvode_not_allowed = 1;
2520  }
2521  cvode_valid_ = 0;
2522 }
2523 
2524 void cvode_rw_cur(char* b) {
2525  /* if a current is READ and WRITE then call the correct _ode_spec
2526  since it may compute some aspect of the current */
2527  Item* q, *q1;
2528  int type;
2529  Symbol* sion;
2530  b[0] = '\0';
2531  ITERATE(q, useion) {
2532  sion = SYM(q);
2533  q = q->next;
2534  ITERATE (q1, LST(q)) {
2535  type = SYM(q1)->nrntype;
2536  if ((type & NRNCURIN) && (type & NRNCUROUT)) {
2537  if (!cvode_not_allowed && cvode_emit) {
2538  if (vectorize) {
2539 sprintf(b, "if (_nt->_vcv) { _ode_spec%d(_p, _ppvar, _thread, _nt); }\n", cvode_num_);
2540  }else{
2541 sprintf(b, "if (_nt->_vcv) { _ode_spec%d(); }\n", cvode_num_);
2542  }
2543  return;
2544  }
2545  }
2546  }
2547  q = q->next;
2548  q = q->next;
2549  }
2550 }
2551 #endif
2552 
2553 void net_receive(Item* qarg, Item* qp1, Item* qp2, Item* qstmt, Item* qend)
2554 {
2555  Item* q, *q1;
2556  Symbol* s;
2557  int i, b;
2558  char snew[256];
2559  if (net_receive_) {
2560  diag("Only one NET_RECEIVE block allowed", (char*)0);
2561  }
2562  if (!point_process) {
2563  diag("NET_RECEIVE can only exist in a POINT_PROCESS", (char*)0);
2564  }
2565  net_receive_ = 1;
2566  deltokens(qp1, qp2);
2567  insertstr(qstmt, "(Point_process* _pnt, double* _args, double _lflag)");
2568  i = 0;
2569  ITERATE(q1, qarg) if (q1->next != qarg) { /* skip last "flag" arg */
2570  s = SYM(q1);
2571  sprintf(snew, "_args[%d]", i);
2572  ++i;
2573  for (q = qstmt; q != qend; q = q->next) {
2574  if (q->itemtype == SYMBOL && SYM(q) == s) {
2575  replacstr(q, snew);
2576  }
2577  }
2578  }
2579  net_send_delivered_ = qstmt;
2580  q = insertstr(qstmt, "\n{");
2581  vectorize_substitute(q, "\n{ double* _p; Datum* _ppvar; Datum* _thread; NrnThread* _nt;\n");
2582  if (watch_seen_) {
2583  insertstr(qstmt, " int _watch_rm = 0;\n");
2584  }
2585  q = insertstr(qstmt, " _p = _pnt->_prop->param; _ppvar = _pnt->_prop->dparam;\n");
2586  vectorize_substitute(insertstr(q, ""), " _thread = (Datum*)0; _nt = (NrnThread*)_pnt->_vnt;");
2587  if (debugging_) {
2588  if (0) {
2589  insertstr(qstmt, " assert(_tsav <= t); _tsav = t;");
2590  }else{
2591  insertstr(qstmt, " if (_tsav > t){ extern char* hoc_object_name(); hoc_execerror(hoc_object_name(_pnt->ob), \":Event arrived out of order. Must call ParallelContext.set_maxstep AFTER assigning minimum NetCon.delay\");}\n _tsav = t;");
2592  }
2593  }
2594  insertstr(qend, "}");
2595  if (!artificial_cell) {
2596  Symbol* ions[10]; int j, nion=0;
2597  /* v can be changed in the NET_RECEIVE block since it is
2598  called between integrator steps and before a re_init
2599  But no need to do so if it is not used.
2600  */
2601  Symbol* vsym = lookup("v");
2602  netrec_need_v = 1;
2603  for (q = qstmt; q != qend; q = q->next) {
2604  if (q->itemtype == SYMBOL && SYM(q) == vsym) {
2605  insertstr(qstmt, " v = NODEV(_pnt->node);\n");
2606  insertstr(qend, "\n NODEV(_pnt->node) = v;\n");
2607  netrec_need_v = 0;
2608  break;
2609  }
2610  }
2611  /* if an ion concentration
2612  is mentioned then we need to get the relevant value
2613  on entry and possibly set a value on exit
2614  Do not allow mention of reversal potential or current
2615  */
2616  for (q = qstmt; q != qend; q = q->next) {
2617  if (q->itemtype == SYMBOL && SYM(q)->type == NAME) {
2618  s = SYM(q);
2619  if ((s->nrntype & (NRNPRANGEIN | NRNPRANGEOUT)) == 0) {
2620  continue;
2621  }
2622  if ((s->nrntype & IONCONC) == 0) {
2623 diag(s->name, ":only concentrations can be mentioned in a NET_RECEIVE block");
2624  }
2625  /* distinct only */
2626  for (j=0; j < nion; ++j) {
2627  if (s == ions[j]) {
2628  break;
2629  }
2630  }
2631  if (j == nion) {
2632  if (nion >= 10) {
2633 diag("too many ions mentioned in NET_RECEIVE block (limit 10", (char*)0);
2634  }
2635  ions[nion] = s;
2636  ++nion;
2637  }
2638  }
2639  }
2640  for (j = 0; j < nion; ++j) {
2641  sprintf(buf, "%s %s = _ion_%s;\n", (j==0)?"\n":"", ions[j]->name, ions[j]->name);
2642  insertstr(qstmt, buf);
2643  }
2644  for (j = 0; j < nion; ++j) {
2645  if (ions[j]->subtype & STAT) {
2646  sprintf(buf, "%s _ion_%s = %s;\n", (j==0)?"\n":"", ions[j]->name, ions[j]->name);
2647  insertstr(qend, buf);
2648  }
2649  }
2650  }
2651  if (i > 0) {
2652  net_receive_ = i;
2653  }
2654  if (net_init_q1_) {
2655  movelist(net_init_q1_, net_init_q2_, procfunc);
2656  }
2657 }
2658 
2659 void net_init(Item* qinit, Item* qp2)
2660 {
2661  /* qinit=INITIAL { stmtlist qp2=} */
2662  replacstr(qinit, "\nstatic void _net_init(Point_process* _pnt, double* _args, double _lflag)");
2663  sprintf(buf, " _p = _pnt->_prop->param; _ppvar = _pnt->_prop->dparam;\n");
2665  double* _p = _pnt->_prop->param;\n\
2666  Datum* _ppvar = _pnt->_prop->dparam;\n\
2667  Datum* _thread = (Datum*)0;\n\
2668  NrnThread* _nt = (NrnThread*)_pnt->_vnt;\n\
2669 ");
2670  if (net_init_q1_) {
2671  diag("NET_RECEIVE block can contain only one INITIAL block", (char*)0);
2672  }
2673  net_init_q1_ = qinit;
2674  net_init_q2_ = qp2;
2675 }
2676 
2677 void fornetcon(Item* keyword, Item* par1, Item* args, Item* par2, Item* stmt, Item* qend)
2678 {
2679  Item* q, *q1;
2680  Symbol* s;
2681  char snew[256];
2682  int i;
2683  /* follows net_receive pretty closely */
2684  ++for_netcons_;
2685  deltokens(par1, par2);
2686  i = for_netcons_;
2687  sprintf(buf, "{int _ifn%d, _nfn%d; double* _fnargs%d, **_fnargslist%d;\n\
2688 \t_nfn%d = _nrn_netcon_args(_ppvar[_fnc_index]._pvoid, &_fnargslist%d);\n\
2689 \tfor (_ifn%d = 0; _ifn%d < _nfn%d; ++_ifn%d) {\n",
2690  i,i,i,i,i,i,i,i,i,i);
2691  replacstr(keyword, buf);
2692  sprintf(buf, "\t _fnargs%d = _fnargslist%d[_ifn%d];\n", i,i,i);
2693  insertstr(keyword->next, buf);
2694  insertstr(qend->next, "\t}}\n");
2695  i = 0;
2696  ITERATE(q1, args) {
2697  s = SYM(q1);
2698  sprintf(snew, "_fnargs%d[%d]", for_netcons_, i);
2699  ++i;
2700  for (q = stmt; q != qend; q = q->next) {
2701  if (q->itemtype == SYMBOL && SYM(q) == s) {
2702  replacstr(q, snew);
2703  }
2704  }
2705  }
2706 }
2707 
2709  Symbol* s;
2710  int i;
2711  Item* q;
2712  SYMLISTITER { /* globals are now global with respect to C as well as hoc */
2713  s = SYM(q);
2714  if (s->nrntype & (NRNGLOBAL) && s->assigned_to_ == 1) {
2715  sprintf(buf, "Assignment to the GLOBAL variable, \"%s\", is not thread safe", s->name);
2716  threadsafe(buf);
2717  }
2718  }
2719 }
2720 
2721 
2722 void threadsafe_seen(Item* q1, Item* q2) {
2723  Item* q;
2724  assert_threadsafe = 1;
2725  if (q2) {
2726  for (q = q1->next; q != q2->next; q = q->next) {
2727  SYM(q)->assigned_to_ = 2;
2728  }
2729  }
2730 }
2731 
2732 void conductance_hint(int blocktype, Item* q1, Item* q2) {
2733  Item* q;
2734  if (blocktype != BREAKPOINT) {
2735  diag("CONDUCTANCE can only appear in BREAKPOINT block", (char*)0);
2736  }
2737  if (!conductance_) {
2738  conductance_ = newlist();
2739  }
2740  lappendsym(conductance_, SYM(q1->next));
2741  if (q2 != q1->next) {
2742  Symbol* s = SYM(q2);
2743  if (!ion_declared(s)) {
2744  diag(s->name, "not declared as USEION in NEURON block");
2745  }
2746  lappendsym(conductance_, s);
2747  }else{
2748  lappendsym(conductance_, SYM0);
2749  }
2750  deltokens(q1, q2);
2751 }
2752 
2753 void possible_local_current(int blocktype, List* symlist) {
2754  Item* q; Item* q2;
2755  if (blocktype != BREAKPOINT) { return; }
2756  ITERATE(q, currents) {
2757  ITERATE(q2, symlist) {
2758  char* n = SYM(q2)->name + 2; /* start after the _l */
2759  if (strcmp(SYM(q)->name, n) == 0) {
2760  if (!breakpoint_local_current_) {
2761  breakpoint_local_current_ = newlist();
2762  }
2763  lappendsym(breakpoint_local_current_, SYM(q));
2764  lappendsym(breakpoint_local_current_, SYM(q2));
2765  }
2766  }
2767  }
2768 }
2769 
2771  if (breakpoint_local_current_) {
2772  Item* q;
2773  ITERATE(q, breakpoint_local_current_) {
2774  if (SYM(q) == s) {
2775  return SYM(q->next);
2776  }
2777  }
2778  }
2779  return s;
2780 }
#define PARM
Definition: modl.h:190
List * currents
Definition: nocpout.cpp:140
void deltokens(Item *q1, Item *q2)
Definition: list.cpp:219
static List * uip
Definition: nocpout.cpp:148
static int areadec
Definition: nocpout.cpp:155
char * stralloc(char *buf, char *rel)
Definition: list.cpp:208
#define Lappendsym
Definition: model.h:259
void decode_ustr(Symbol *sym, double *pg1, double *pg2, char *s)
Definition: nocpout.cpp:1431
void nrn_var_assigned(Symbol *s)
Definition: nocpout.cpp:2218
void chk_thread_safe()
Definition: nocpout.cpp:2708
short itemtype
Definition: model.h:16
#define KINF
Definition: model.h:132
#define assert(ex)
Definition: hocassrt.h:26
List * get_ion_variables(int)
Definition: nocpout.cpp:1949
void parout()
Definition: nocpout.cpp:225
short type
Definition: cabvars.h:10
void nrn_list(Item *q1, Item *q2)
Definition: nocpout.cpp:1557
int protect_include_
Definition: parsact.cpp:28
#define IONEREV
Definition: nocpout.cpp:104
void net_init(Item *qinit, Item *qp2)
Definition: nocpout.cpp:2659
void nrn_use(Item *q1, Item *q2, Item *q3, Item *q4)
Definition: nocpout.cpp:1668
#define DERF
Definition: model.h:125
List * watch_alloc
Definition: parsact.cpp:16
List * constructorfunc
Definition: init.cpp:193
char * finname
Definition: model.cpp:38
void nrndeclare()
Definition: nocpout.cpp:1764
int usage
Definition: model.h:66
#define PROCED
Definition: model.h:120
List * syminorder
Definition: nocpout.cpp:122
void bablk(int ba, int type, Item *q1, Item *q2)
Definition: nocpout.cpp:1630
short type
Definition: model.h:58
#define NRNFIX(arg)
Definition: nocpout.cpp:2216
#define diag(s)
Definition: fmenu.cpp:188
int cvode_not_allowed
#define DEP
Definition: model.h:116
#define ITERATE(itm, lst)
Definition: model.h:25
#define SYM(q)
Definition: model.h:86
int iontype(char *s1, char *s2)
Definition: nocpout.cpp:1730
void threadsafe_seen(Item *q1, Item *q2)
Definition: nocpout.cpp:2722
static Symbol * ifnew_install(char *name)
Definition: nocpout.cpp:1753
void possible_local_current(int blocktype, List *symlist)
Definition: nocpout.cpp:2753
void cvode_emit_interface()
#define NRNPOINTER
Definition: nocpout.cpp:100
#define NRNPRANGEIN
Definition: nocpout.cpp:92
size_t p
Item * lappendsym(List *list, Symbol *sym)
Definition: list.cpp:161
#define NRNCURIN
Definition: nocpout.cpp:89
int decode_limits(Symbol *sym, double *pg1, double *pg2)
Definition: nocpout.cpp:1382
static List * rangedep
Definition: nocpout.cpp:145
char * modprefix
Definition: modl.cpp:57
void defs_h(Symbol *)
Definition: nocpout.cpp:1542
#define IONCUR
Definition: nocpout.cpp:107
char * name
Definition: model.h:72
#define NRN_BUFSIZE
Definition: model.h:13
Symbol * breakpoint_current(Symbol *s)
Definition: nocpout.cpp:2770
struct Item * prev
Definition: model.h:20
#define Fprintf
Definition: model.h:249
Item * next(Item *item)
Definition: list.cpp:95
#define SYMBOL
Definition: model.h:102
struct Item * next
Definition: model.h:19
List * set_ion_variables(int)
Definition: nocpout.cpp:1883
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
void cvode_proced_emit()
static int varcount
Definition: nocpout.cpp:207
static List * ba_list_
Definition: nocpout.cpp:172
#define NRNIONFLAG
Definition: nocpout.cpp:97
void units_reg()
Definition: nocpout.cpp:1478
static int for_netcons_
Definition: nocpout.cpp:168
List * breakpoint_local_current_
Definition: nocpout.cpp:143
#define e
Definition: passive0.cpp:24
static int ppvar_cnt
Definition: nocpout.cpp:165
int netrec_need_v
#define SUFFIX
Definition: units.cpp:58
Definition: model.h:15
List * toplocal_
Definition: nocpout.cpp:129
#define Insertstr
Definition: model.h:255
int net_receive_
#define install
Definition: redef.h:82
static char * brkpnt_str_
Definition: nocpout.cpp:112
int const size_t const size_t n
Definition: nrngsl.h:12
char * nmodl_version_
Definition: nocpout.cpp:11
void parminstall(Symbol *n, char *num, char *units, char *limits)
Definition: parsact.cpp:161
static char * rsuffix
Definition: nocpout.cpp:150
static void ppvar_semantics(int, const char *)
Definition: nocpout.cpp:2116
int check_tables_threads(List *)
Definition: parsact.cpp:555
void movelist(Item *q1, Item *q2, List *s)
Definition: list.cpp:245
_CONST char * s
Definition: system.cpp:74
int slist_search(int listnum, Symbol *s)
#define ARRAY
Definition: model.h:118
static List * rangestate
Definition: nocpout.cpp:146
static int indx
Definition: deriv.cpp:240
static int parraycount
Definition: nocpout.cpp:207
Item * lappendstr(List *list, char *str)
Definition: list.cpp:149
int decode_tolerance(Symbol *sym, double *pg1)
Definition: nocpout.cpp:1407
#define printf
Definition: mwprefix.h:26
void cvode_interface(Symbol *fun, int num, int neq)
List * procfunc
Definition: init.cpp:9
int
Definition: nrnmusic.cpp:71
List * symlist[]
Definition: symbol.cpp:8
int iondef(int *)
Definition: nocpout.cpp:1990
#define NRNNOTP
Definition: nocpout.cpp:96
void vectorize_substitute(Item *q, char *str)
int protect_
Definition: parsact.cpp:27
int electrode_current
Definition: nocpout.cpp:125
static int use_bbcorepointer
Definition: nocpout.cpp:156
Symbol * indepsym
Definition: declare.cpp:11
#define STRING
Definition: bbslsrv.cpp:9
void net_receive(Item *qarg, Item *qp1, Item *qp2, Item *qstmt, Item *qend)
Definition: nocpout.cpp:2553
List * conductance_
Definition: nocpout.cpp:142
List * thread_mem_init_list
Definition: nocpout.cpp:128
int point_process
Definition: nocpout.cpp:152
#define cnt
Definition: spt2queue.cpp:19
void ldifusreg()
Definition: nocpout.cpp:1302
void fornetcon(Item *keyword, Item *par1, Item *args, Item *par2, Item *stmt, Item *qend)
Definition: nocpout.cpp:2677
static Symbol * vsym
Definition: occvode.cpp:49
void ion_promote(Item *)
Definition: nocpout.cpp:2178
size_t j
void indepinstall(Symbol *n, char *from, char *to, char *with, Item *qstart, char *units, int scop)
Definition: parsact.cpp:238
fprintf(stderr, "Don't know the location of params at %p\, pp)
static int diamdec
Definition: nocpout.cpp:154
#define NRNCUROUT
Definition: nocpout.cpp:90
static void var_count(Symbol *s)
Definition: nocpout.cpp:1530
Definition: model.h:57
void threadsafe(char *)
Definition: parsact.cpp:1180
int debugging_
static Item * net_init_q1_
Definition: nocpout.cpp:169
char * name
Definition: init.cpp:16
int nmodl_text
Definition: modl.cpp:67
char * reprime()
#define LST(q)
Definition: model.h:90
char * emalloc(unsigned n)
Definition: list.cpp:189
void * element
Definition: model.h:18
List * newlist()
Definition: list.cpp:50
virtual void move(const Event &e)
Definition: ocinput.h:19
void cvode_valid()
List * defs_list
Definition: nocpout.cpp:124
#define FUNCT
Definition: model.h:119
int assert_threadsafe
List * begin_dion_stmt()
Definition: nocpout.cpp:2123
#define Lappendstr
Definition: model.h:260
NMODL parser global flags / functions.
static int ba_index_
Definition: nocpout.cpp:171
#define lookup
Definition: redef.h:90
long subtype
Definition: model.h:59
Item * lappenditem(List *list, Item *item)
Definition: list.cpp:167
#define NRNBBCOREPOINTER
Definition: nocpout.cpp:102
List * indeplist
Definition: parsact.cpp:15
#define IONIN
Definition: nocpout.cpp:105
#define EXPLICIT_DECL
Definition: model.h:137
void declare_p()
Definition: nocpout.cpp:1846
#define IONDCUR
Definition: nocpout.cpp:108
List * destructorfunc
Definition: init.cpp:193
int used
Definition: model.h:65
void conductance_hint(int blocktype, Item *q1, Item *q2)
Definition: nocpout.cpp:2732
static char * mechname
Definition: nocpout.cpp:151
#define STR(q)
Definition: model.h:87
#define NRNRANGE
Definition: nocpout.cpp:91
int vectorize
Item * insertstr(Item *item, char *str)
Definition: list.cpp:108
void warn_ignore(Symbol *s)
Definition: nocpout.cpp:1288
#define IONOUT
Definition: nocpout.cpp:106
int araydim
Definition: model.h:67
void freelist(List **plist)
Definition: list.cpp:61
static List * rangeparm
Definition: nocpout.cpp:144
long subtype
Definition: init.cpp:122
#define i
Definition: md1redef.h:12
Symbol * semi
Definition: init.cpp:11
Symbol * scop_indep
Definition: declare.cpp:12
void nrninit()
Definition: nocpout.cpp:209
#define SYMLISTITER
Definition: nocpout.cpp:197
List * thread_cleanup_list
Definition: nocpout.cpp:127
int thread_data_index
Definition: nocpout.cpp:126
List * ldifuslist
Definition: kinetic.cpp:82
#define Linsertstr
Definition: model.h:258
char buf[512]
Definition: init.cpp:13
void out_nt_ml_frag(List *)
#define STAT
Definition: model.h:117
static Item * net_init_q2_
Definition: nocpout.cpp:170
void replacstr(Item *q, char *s)
Definition: list.cpp:250
static List * nrnpointers
Definition: nocpout.cpp:147
#define NRNPRANGEOUT
Definition: nocpout.cpp:93
void cvode_rw_cur(char *)
int artificial_cell
Definition: nocpout.cpp:153
#define Sprintf
Definition: model.h:248
static char suffix[256]
Definition: nocpout.cpp:149
int brkpnt_exists
union Symbol::@18 u
#define SYM0
Definition: model.h:74
int ion_declared(Symbol *s)
Definition: nocpout.cpp:1656
#define NRNGLOBAL
Definition: nocpout.cpp:94
Symbol * stepsym
Definition: parsact.cpp:14
size_t q
#define INDEP
Definition: model.h:115
#define IONCONC
Definition: nocpout.cpp:101
void slist_data(Symbol *s, int indx, int findx)
#define NRNSTATIC
Definition: nocpout.cpp:95
List * end_dion_stmt(char *strdel)
Definition: nocpout.cpp:2149
int varnum
Definition: model.h:69
char * str
Definition: model.h:63
return NULL
Definition: cabcode.cpp:461
List * useion
Definition: nocpout.cpp:141
void del_range(List *)
Definition: nocpout.cpp:1831
List * plotlist
Definition: nocpout.cpp:123
static List * ppvar_semantics_
Definition: nocpout.cpp:166
#define ITM(q)
Definition: model.h:88
#define NRNEXTRN
Definition: nocpout.cpp:88