NEURON
code.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /* /local/src/master/nrn/src/oc/code.cpp,v 1.37 1999/07/03 14:20:21 hines Exp */
3 
4 #include "backtrace_utils.h"
5 #include "bbslsrv2.h"
6 #include "cabcode.h"
7 #include "code.h"
8 #include "hocstr.h"
9 #include "parse.hpp"
10 #include "ocfunc.h"
11 #include "ocmisc.h"
12 #include "oc_ansi.h"
13 #include "hocparse.h"
14 #include "equation.h"
15 #include <nrnmpi.h>
16 #include "nrnfilewrap.h"
17 #include "utils/enumerate.h"
18 
19 
20 #include "options.h"
21 #include "section.h"
22 
23 #include <cerrno>
24 #include <cmath>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <vector>
28 #include <variant>
29 #include <sstream>
30 
31 
33 extern void bbs_handle();
34 #define BBSPOLL \
35  if (--bbs_poll_ == 0) { \
36  bbs_handle(); \
37  }
38 
39 int nrn_isecstack();
40 
41 extern void debugzz(Inst*);
43 
44 // array indices on the stack have their own type to help with determining when
45 // a compiled fragment of HOC code is processing a variable whose number of
46 // dimensions was changed.
48  stack_ndim_datum(int ndim) {
49  i = ndim;
50  }
51  int i;
52 };
53 std::ostream& operator<<(std::ostream& os, const stack_ndim_datum& d) {
54  os << d.i;
55  return os;
56 }
57 
58 using StackDatum = std::variant<double,
59  Symbol*,
60  int,
62  Object**,
63  Object*,
64  char**,
66  std::nullptr_t>;
67 
68 /** @brief The stack.
69  *
70  * It would be nice to use std::stack, but it seems that for now its API is too
71  * restrictive.
72  */
73 static std::vector<StackDatum> stack{};
74 
75 #define NPROG 50000
76 Inst* hoc_prog; /* the machine */
77 Inst* hoc_progp; /* next free spot for code generation */
78 Inst* hoc_pc; /* program counter during execution */
79 Inst* hoc_progbase; /* start of current subprogram */
80 Inst* hoc_prog_parse_recover; /* start after parse error */
81 int hoc_returning; /* 1 if return stmt seen, 2 if break, 3 if continue */
82 /* 4 if stop */
83 namespace nrn::oc {
84 struct frame { /* proc/func call stack frame */
85  Symbol* sp; /* symbol table entry */
86  Inst* retpc; /* where to resume after return */
87  StackDatum* argn; /* n-th argument on stack */
88  int nargs; /* number of arguments */
89  Inst* iter_stmt_begin; /* Iterator statement starts here */
90  Object* iter_stmt_ob; /* context of Iterator statement */
91  Object* ob; /* for stack frame debug message */
92 };
93 } // namespace nrn::oc
95 #define NFRAME 512 /* default size */
96 static Frame *frame, *fp, *framelast; /* first, frame pointer, last */
97 
98 /* temporary object references come from this pool. This allows the
99 stack to be aware if it is storing a temporary. We are trying to
100 solve problems of objrefs on the stack changing the object they point
101 to and also a failure of garbage collection since temporary objrefs have
102 not, in the past, been reffed or unreffed.
103 The first problem is easily solved without much efficiency loss
104 by having the stack store the object pointer instead of the objref pointer.
105 
106 Garbage collection is implemented by reffing any object that is placed
107 on the stack via hoc_push_object (and thus borrows the use of the
108 type OBJECTTMP) It is then the responsibility of everything that
109 pops an object to determine whether the object should be unreffed.
110 This is also done on error recovery and when the stack frame is popped.
111 I hate the efficiency loss but it is not as bad as it could be
112 since most popping occurs when the stack frame is popped and in this
113 case it is faster to check for OBJECTTMP than if the returned Object**
114 is from the pool.
115 */
116 #define DEBUG_GARBAGE 1
117 #define TOBJ_POOL_SIZE 50
119 static int obj_pool_index_;
120 static int tobj_count; /* how many stack pushes of OBJECTTMP have been reffed*/
121 
122 /*
123 Here is the old comment on the function when it was in hoc_oop.cpp.
124 
125 At this time we are dealing uniformly with object variables and cannot
126 deal cleanly with objects. Eventually it may be possible to put an
127 object pointer on the stack but not now. Try to avoid using "functions
128 which return new objects" as arguments to other functions. If this is
129 done then it may happen that when the stack pointer is finally used it
130 may point to a different object than when it was put on the stack.
131 Things are safe when a temp_objvar is finally removed from the stack.
132 Memory leakage will occur if a temp_objvar is passed as an arg but never
133 assigned to a full fledged object variable. ie its reference count is 0
134 but unref will never be called on it.
135 The danger is illustrated with
136  proc p(obj.func_returning_object()) { // $o1 is on the stack
137  print $o1 // correct object
138  for i=0,100 {
139  o = obj.func_returning_different_object()
140  print i, $o1 //when i=50 $o1 will be different
141  }
142  }
143 In this case one should first assign $o1 to another object variable
144 and then use that object variable exclusively instead of $o1.
145 This also prevent leakage of the object pointed to by $o1.
146 
147 If this ever becomes a problem then it is not too difficult to
148 implement objects on the stack with garbage collection.
149 */
150 
153  Object** const tobj{hoc_temp_obj_pool_ + obj_pool_index_};
154  *tobj = obj;
155  return tobj;
156 }
157 
158 /* should be called after finished with pointer from a popobj */
159 
162  --tobj_count;
163  hoc_obj_unref(*p);
164  }
165 }
166 
167 /*
168 vec.c.x[0] used freed memory because the temporary vector was unreffed
169 after the x pointer was put on the stack but before it was evaluated.
170 The hoc_pop_defer replaces the nopop in in hoc_object_component handling
171 of a cplus steer method (which pushes a double pointer). The corresponding
172 hoc_unref_defer takes place in hoc_object_eval after evaluating
173 the pointer. This should take care of the most common (itself very rare)
174 problem. However it still would not in general
175 take care of the purposeless passing
176 of &vec.c.x[0] as an argument to a function since intervening pop_defer/unref_defer
177 pairs could take place.
178 */
180 
182  if (unref_defer_) {
183 #if 0
184  printf("hoc_unref_defer %s %d\n", hoc_object_name(unref_defer_), unref_defer_->refcount);
185 #endif
187  unref_defer_ = nullptr;
188  }
189 }
190 
191 namespace {
192 /** @brief Return the (variant) value at depth i in the stack.
193  *
194  * i = 0 is the top/most-recently-pushed element of the stack.
195  */
196 StackDatum& get_stack_entry_variant(std::size_t i) {
197  assert(!stack.empty());
198  return *std::next(stack.rbegin(), i);
199 }
200 
201 template <class... Ts>
202 struct overloaded: Ts... {
203  using Ts::operator()...;
204 };
205 template <class... Ts>
206 overloaded(Ts...) -> overloaded<Ts...>;
207 
208 template <typename T>
209 [[noreturn]] void report_type_mismatch(StackDatum const& entry) {
210  std::visit(
211  [](auto const& val) {
212  assert((!std::is_same_v<std::decay_t<decltype(val)>, T>) );
213  std::ostringstream oss;
214  oss << "bad stack access: expecting " << cxx_demangle(typeid(T).name()) << "; really "
215  << cxx_demangle(typeid(decltype(val)).name());
216  if constexpr (!std::is_same_v<std::decay_t<decltype(val)>, std::nullptr_t>) {
217  oss << ' ' << val;
218  }
219  // extra info for some types
220  overloaded{[&oss](Object* o) { oss << " -> " << hoc_object_name(o); },
221  [&oss](Object** o) {
222  if (o) {
223  oss << " -> " << hoc_object_name(*o);
224  }
225  },
226  [&oss](Symbol* sym) {
227  if (sym) {
228  oss << " -> " << sym->name;
229  }
230  },
231  [&oss](stack_ndim_datum& d) { oss << " -> ndim " << d.i; },
232  [&oss](std::nullptr_t) { oss << " already unreffed on stack"; },
233  [](auto const&) {}}(val);
234  hoc_execerror(oss.str().c_str(), nullptr);
235  },
236  entry);
237  throw std::logic_error("report_type_mismatch");
238 }
239 
240 template <typename T>
241 void check_type(StackDatum const& entry) {
242  if (!std::holds_alternative<T>(entry)) {
243  report_type_mismatch<T>(entry);
244  }
245 }
246 
247 template <typename T>
248 T& cast(StackDatum& entry) {
249  check_type<T>(entry);
250  return std::get<T>(entry);
251 }
252 template <typename T>
253 T const& cast(StackDatum const& entry) {
254  check_type<T>(entry);
255  return std::get<T>(entry);
256 }
257 } // namespace
258 
259 // Defined and explicitly instantiated to keep the StackDatum type private to this file.
260 template <typename T>
261 T const& hoc_look_inside_stack(int i) {
262  return cast<T>(get_stack_entry_variant(i));
263 }
264 template double const& hoc_look_inside_stack(int);
265 template Symbol* const& hoc_look_inside_stack(int);
266 template Object** const& hoc_look_inside_stack(int);
267 template Object* const& hoc_look_inside_stack(int);
268 namespace {
269 bool stack_entry_is_tmpobject(StackDatum const& entry) {
270  return std::holds_alternative<Object*>(entry);
271 }
272 bool stack_entry_is_tmpobject(std::size_t i) {
273  return stack_entry_is_tmpobject(get_stack_entry_variant(i));
274 }
275 
276 void unref_if_tmpobject(StackDatum& entry) {
277  if (stack_entry_is_tmpobject(entry)) {
278  auto* o = std::get<Object*>(entry);
279  --tobj_count;
280  hoc_obj_unref(o);
281  entry = nullptr; // STKOBJ_UNREF;
282  }
283 }
284 
285 int get_legacy_int_type(StackDatum const& entry) {
286  if (std::holds_alternative<char**>(entry)) {
287  return STRING;
288  } else if (std::holds_alternative<neuron::container::generic_data_handle>(entry)) {
289  return VAR;
290  } else if (std::holds_alternative<double>(entry)) {
291  return NUMBER;
292  } else if (std::holds_alternative<Object**>(entry)) {
293  return OBJECTVAR;
294  } else if (std::holds_alternative<Object*>(entry)) {
295  return OBJECTTMP;
296  } else if (std::holds_alternative<int>(entry)) {
297  return USERINT;
298  } else if (std::holds_alternative<Symbol*>(entry)) {
299  return SYMBOL;
300  } else if (std::holds_alternative<std::nullptr_t>(entry)) {
301  return STKOBJ_UNREF;
302  } else {
303  throw std::runtime_error("get_legacy_int_type");
304  }
305 }
306 } // namespace
307 
308 /** Get the type of the top entry.
309  */
311  return get_legacy_int_type(get_stack_entry_variant(0));
312 }
313 
315  return std::holds_alternative<stack_ndim_datum>(get_stack_entry_variant(0));
316 }
317 
319  if (unref_defer_) {
320  hoc_unref_defer();
321  }
322  if (stack.empty()) {
323  hoc_execerror("stack underflow", nullptr);
324  }
325  if (hoc_stack_type() == OBJECTTMP) {
326  unref_defer_ = hoc_look_inside_stack<Object*>(0);
327  if (unref_defer_) {
329  }
330  }
331  hoc_nopop();
332 }
333 
334 /* should be called on each OBJECTTMP on the stack after adjusting the
335 stack pointer downward */
336 
337 void hoc_stkobj_unref(Object* o, int stkindex) {
338  // stkindex refers to the value, stkindex+1 refers to the legacy type
339  // information for it
340  auto& entry = stack[stkindex];
341  if (stack_entry_is_tmpobject(entry)) {
342  --tobj_count;
343  hoc_obj_unref(o);
344  entry = nullptr; // STKOBJ_UNREF;
345  }
346 }
347 
348 /* check the args of the frame and unref any of type OBJECTTMP */
349 static void frameobj_clean(Frame* f) {
350  if (f->nargs == 0) {
351  return;
352  }
353  StackDatum* s = f->argn + 1;
354  for (int i = f->nargs - 1; i >= 0; --i) {
355  --s;
356  unref_if_tmpobject(*s);
357  }
358 }
359 
360 /* unref items on the stack frame associated with localobj in case of error */
361 static void frame_objauto_recover_on_err(Frame* ff) { /* only on error */
362  // for all frames deeper than the one we are restoring to
363  for (Frame* f = fp; f > ff; --f) {
364  Symbol* sp = f->sp;
365  if (sp->type == MECHANISM) {
366  // Possible to reach this code path via the frame push in
367  // NrnProperty::NrnProperty(const char* name) with the
368  // extracellular mechanism Symbol
369  continue;
370  }
371  if (!sp->u.u_proc) { // Skip if the procedure is not defined
372  continue;
373  }
374  // argn is the nargs argument on the stack.
375  // stkp is the last localobj slot pair on the stack.
376  StackDatum* stkp = f->argn + sp->u.u_proc->nauto;
377  assert(!stack.empty());
378  assert(stkp >= &stack.front());
379  assert(stkp <= &stack.back());
380  for (int i = sp->u.u_proc->nobjauto - 1; i >= 0; --i) {
381  auto* ob = cast<Object*>(stkp[-i]);
382  hoc_obj_unref(ob);
383  /* Note that these AUTOOBJECT stack locations have an itemtype that
384  are left over from the previous stack usage of that location.
385  Regardless of that itemtype (e.g. OBJECTTMP), these did NOT
386  increment tobj_count so we need to guarantee that the subsequent
387  stack_obtmp_recover_on_err does not inadvertently free it again
388  by setting the itemtype to a non OBJECTTMP value. I hope this is
389  the only place where stack space was used in which no item type
390  was specified.
391  We are doing this here which happens rarely to avoid having to
392  set them when the stack obj pointers are zeroed.
393  */
394  // stkp[-2 * i + 1].i = 0;
395  }
396  }
397 }
398 
399 static void stack_obtmp_recover_on_err(int tcnt) {
400  if (tobj_count > tcnt) {
401  // unref tmpobjects from the top of the stack until we have the right number left
402  for (const auto&& [index, stkp]: renumerate(stack)) {
403  if (stack_entry_is_tmpobject(stkp)) {
404  hoc_stkobj_unref(std::get<Object*>(stkp), index);
405  if (tobj_count == tcnt) {
406  return;
407  }
408  } else if (std::holds_alternative<std::nullptr_t>(stkp)) {
409  printf("OBJECTTMP at stack index %ld already unreffed\n", index);
410  }
411  }
412  }
413 }
414 
415 // create space for stack and code
417  if (hoc_nframe == 0) {
418  hoc_nframe = NFRAME;
419  }
420  if (hoc_nstack == 0) {
421  // Default stack size
422  hoc_nstack = 1000;
423  }
424  stack.reserve(hoc_nstack);
425  hoc_progp = hoc_progbase = hoc_prog = (Inst*) emalloc(sizeof(Inst) * NPROG);
426  fp = frame = (Frame*) emalloc(sizeof(Frame) * hoc_nframe);
429 }
430 
431 #define MAXINITFCNS 10
432 static int maxinitfcns;
434 
435 /** @brief Print up to the 10 most-recently-pushed elements on the stack.
436  */
437 void hoc_prstack() {
438  std::size_t i{};
439  std::ostringstream oss;
440  oss << "interpreter stack: " << stack.size() << '\n';
441  for (auto&& stkp: reverse(stack)) {
442  if (i > 10) {
443  oss << " ...\n";
444  break;
445  }
446  std::visit(
447  [i, &oss](auto& value) {
448  oss << ' ' << i << ' ';
449  if constexpr (std::is_same_v<std::decay_t<decltype(value)>, std::nullptr_t>) {
450  oss << "nullptr";
451  } else {
452  oss << value;
453  }
454  oss << ' ' << cxx_demangle(typeid(decltype(value)).name()) << '\n';
455  },
456  stkp);
457  ++i;
458  }
459  Printf(oss.str().c_str());
460 }
461 
463  /* modules that may have to be cleaned up after an hoc_execerror */
464  if (maxinitfcns < MAXINITFCNS) {
465  initfcns[maxinitfcns++] = pf;
466  } else {
467  fprintf(stderr, "increase definition for MAXINITFCNS\n");
468  nrn_exit(1);
469  }
470 }
471 
472 // initialize for code generation
473 void hoc_initcode() {
474  int i;
475  errno = 0;
476  if (hoc_errno_count > 5) {
477  fprintf(stderr, "errno set %d times on last execution\n", hoc_errno_count);
478  }
479  hoc_errno_count = 0;
482  hoc_unref_defer();
483 
485  if (tobj_count) {
487 #if DEBUG_GARBAGE
488  if (tobj_count) {
489  printf("initcode failed with %d left\n", tobj_count);
490  }
491 #endif
492  tobj_count = 0;
493  }
494  fp = frame;
496  hoc_returning = 0;
497  hoc_do_equation = 0;
498  for (i = 0; i < maxinitfcns; ++i) {
499  (*initfcns[i])();
500  }
501  nrn_initcode(); /* special requirements for NEURON */
502 }
503 
504 
505 static Frame* rframe;
506 static std::size_t rstack;
507 static const char* parsestr;
508 
509 void oc_save_code(Inst** a1,
510  Inst** a2,
511  std::size_t& a3,
512  Frame** a4,
513  int* a5,
514  int* a6,
515  Inst** a7,
516  Frame** a8,
517  std::size_t& a9,
518  Symlist** a10,
519  Inst** a11,
520  int* a12) {
521  *a1 = hoc_progbase;
522  *a2 = hoc_progp;
523  a3 = stack.size();
524  *a4 = fp;
525  *a5 = hoc_returning;
526  *a6 = hoc_do_equation;
527  *a7 = pc;
528  *a8 = rframe;
529  a9 = rstack;
530  *a10 = hoc_p_symlist;
531  *a11 = hoc_prog_parse_recover;
532  *a12 = tobj_count;
533 }
534 
536  Inst** a2,
537  std::size_t& a3,
538  Frame** a4,
539  int* a5,
540  int* a6,
541  Inst** a7,
542  Frame** a8,
543  std::size_t& a9,
544  Symlist** a10,
545  Inst** a11,
546  int* a12) {
547  hoc_progbase = *a1;
548  hoc_progp = *a2;
550  if (tobj_count > *a12) {
552 #if DEBUG_GARBAGE
553  if (tobj_count != *a12) {
554  printf("oc_restore_code tobj_count=%d should be %d\n", tobj_count, *a12);
555  }
556 #endif
557  }
558  if (a3 > stack.size()) {
559  hoc_execerror("oc_restore_code cannot summon stack entries from nowhere", nullptr);
560  }
561  stack.resize(a3);
562  fp = *a4;
563  hoc_returning = *a5;
564  hoc_do_equation = *a6;
565  pc = *a7;
566  rframe = *a8;
567  rstack = a9;
568  hoc_p_symlist = *a10;
569  hoc_prog_parse_recover = *a11;
570 }
571 
572 int hoc_strgets_need(void) {
573  return strlen(parsestr);
574 }
575 
576 char* hoc_strgets(char* cbuf, int nc) { /* getc for a string, used by parser */
577  strncpy(cbuf, parsestr, nc);
578  if (*parsestr == '\0') {
579  return (char*) 0;
580  } else {
581  return cbuf;
582  }
583 }
584 
585 // initialize for recursive code generation
586 static void rinitcode() {
587  errno = 0;
588  hoc_errno_count = 0;
591  if (rstack > stack.size()) {
592  hoc_execerror("rinitcode cannot create stack entries from nowhere", nullptr);
593  }
594  stack.resize(rstack);
595  fp = rframe;
597  if (hoc_returning != 4) { /* if stop not seen */
598  hoc_returning = 0;
599  }
600  hoc_do_equation = 0;
601 }
602 
604  /* can recursively parse and execute what is in cbuf.
605  may parse single tokens. called from hoc_oc(str).
606  All these parse and execute routines should be combined into
607  a single method robust method. The pipeflag method has become
608  encrusted with too many irrelevant mechanisms. There is no longer
609  anything sacred about the cbuf. The only requiremnent is to tell
610  the get line function where to get its string.
611  */
612  int yret;
613 
614  Frame *sframe, *sfp;
615  Inst *sprogbase, *sprogp, *spc, *sprog_parse_recover;
616  Symlist* sp_symlist;
617  std::size_t sstack{}, sstackp{};
618 
619  if (yystart) {
620  sframe = rframe;
621  sfp = fp;
622  sprogbase = hoc_progbase;
623  sprogp = hoc_progp;
624  spc = pc, sprog_parse_recover = hoc_prog_parse_recover;
625  sstackp = stack.size();
626  sstack = rstack;
627  sp_symlist = hoc_p_symlist;
628  rframe = fp;
629  rstack = stack.size();
631  hoc_p_symlist = (Symlist*) 0;
632  rinitcode();
633  }
634  if (hoc_in_yyparse) {
635  hoc_execerror("Cannot reenter parser.",
636  "Maybe you were in the middle of a direct command.");
637  }
638  yret = yyparse();
639  switch (yret) {
640  case 1:
642  rinitcode();
643  break;
644  case -3:
645  hoc_execerror("incomplete statement parse not allowed\n", nullptr);
646  default:
647  break;
648  }
649  if (yystart) {
650  rframe = sframe; // restore the old value
651  fp = sfp;
652  hoc_progbase = sprogbase;
653  hoc_progp = sprogp;
654  pc = spc;
655  hoc_prog_parse_recover = sprog_parse_recover;
656  if (sstackp > stack.size()) {
657  hoc_execerror("hoc_ParseExec cannot summon entries from nowhere", nullptr);
658  }
659  stack.resize(sstackp);
660  rstack = sstack;
661  hoc_p_symlist = sp_symlist;
662  }
663 
664  return yret;
665 }
666 
667 int hoc_xopen_run(Symbol* sp, const char* str) { /*recursively parse and execute for xopen*/
668  /* if sp != 0 then parse string and save code */
669  /* without executing. Note str must be a 'list'*/
670  int n = 0;
671  Frame *sframe = rframe, *sfp = fp;
672  Inst *sprogbase = hoc_progbase, *sprogp = hoc_progp, *spc = pc,
673  *sprog_parse_recover = hoc_prog_parse_recover;
674  Symlist* sp_symlist = hoc_p_symlist;
675  std::size_t sstack{rstack}, sstackp{stack.size()};
676  rframe = fp;
677  rstack = stack.size();
679  hoc_p_symlist = (Symlist*) 0;
680 
681  if (sp == (Symbol*) 0) {
682  for (rinitcode(); hoc_yyparse(); rinitcode())
684  } else {
685  int savpipeflag;
686  rinitcode();
687  savpipeflag = hoc_pipeflag;
688  hoc_pipeflag = 2;
689  parsestr = str;
690  if (!hoc_yyparse()) {
691  hoc_execerror("Nothing to parse", (char*) 0);
692  }
693  n = (int) (hoc_progp - hoc_progbase);
694  hoc_pipeflag = savpipeflag;
695  hoc_define(sp);
696  rinitcode();
697  }
698  rframe = sframe;
699  fp = sfp;
700  hoc_progbase = sprogbase;
701  hoc_progp = sprogp;
702  pc = spc;
703  hoc_prog_parse_recover = sprog_parse_recover;
704  if (sstackp > stack.size()) {
705  hoc_execerror("hoc_xopen_run cannot summon entries from nowhere", nullptr);
706  }
707  stack.resize(sstackp);
708  rstack = sstack;
709  hoc_p_symlist = sp_symlist;
710  return n;
711 }
712 
713 #define HOC_TEMP_CHARPTR_SIZE 128
715 static int istmp = 0;
716 
717 char** hoc_temp_charptr(void) {
719  return stmp + istmp;
720 }
721 
722 int hoc_is_temp_charptr(char** cpp) {
723  if (cpp >= stmp && cpp < stmp + HOC_TEMP_CHARPTR_SIZE) {
724  return 1;
725  }
726  return 0;
727 }
728 
729 namespace {
730 /** @brief Pop the top of the stack, ignoring its type.
731  */
732 void pop_value() noexcept {
733  if (stack.empty()) {
734  hoc_execerror("stack underflow", nullptr);
735  }
736  stack.pop_back();
737 }
738 
739 /** @brief Pop and return the top of the stack, with type checking.
740  */
741 template <typename T>
742 T pop_value() {
743  if (stack.empty()) {
744  hoc_execerror("stack underflow", nullptr);
745  }
746  if (std::holds_alternative<T>(stack.back())) {
747  auto rval = std::move(stack.back());
748  stack.pop_back();
749  return std::get<T>(std::move(rval));
750  } else {
751  report_type_mismatch<T>(stack.back());
752  }
753 }
754 
755 /** @brief Push a value to the top of the stack.
756  */
757 template <typename T>
758 void push_value(T value) {
759  if (stack.size() == stack.capacity()) {
760  hoc_execerror("Stack too deep.", "Increase with -NSTACK stacksize option");
761  }
762  stack.emplace_back(std::move(value));
763 }
764 
765 // Get the type and value of the nth argument
766 StackDatum& get_argument(int narg) {
767  if (narg > fp->nargs) {
768  hoc_execerror(fp->sp->name, "not enough arguments");
769  }
770  return fp->argn[narg - fp->nargs];
771 }
772 } // namespace
773 
775  return hoc_stack_type();
776 }
777 
778 // push double onto stack
779 void hoc_pushx(double d) {
780  push_value(d);
781 }
782 
783 // push pointer to object pointer onto stack
784 void hoc_pushobj(Object** d) {
786  hoc_push_object(*d);
787  } else {
788  push_value(d);
789  }
790 }
791 
792 // push pointer to object onto stack
794  push_value(d);
795  hoc_obj_ref(d);
796  ++tobj_count;
797 }
798 
799 // push pointer to string pointer onto stack
800 void hoc_pushstr(char** d) {
801  push_value(d);
802 }
803 
804 // code for pushing a symbols string
806  Symbol* s{(hoc_pc++)->sym};
807  if (!s) {
808  hoc_pushstr(nullptr);
809  } else if (s->type == CSTRING) {
810  hoc_pushstr(&(s->u.cstr));
811  } else {
812  Object* obsav{};
813  Objectdata* odsav{};
814  Symlist* slsav{};
815  if (s->cpublic == 2) {
816  s = s->u.sym;
817  odsav = hoc_objectdata_save();
818  obsav = hoc_thisobject;
819  slsav = hoc_symlist;
821  hoc_thisobject = 0;
823  }
824  hoc_pushstr(OPSTR(s));
825  if (obsav) {
827  hoc_thisobject = obsav;
828  hoc_symlist = slsav;
829  }
830  }
831 }
832 
833 // push double pointer onto stack
834 void hoc_pushpx(double* d) {
835  // Trying to promote a raw pointer to a data handle is expensive, so don't
836  // do that every time we push a double* onto the stack.
838 }
839 
840 // push symbol pointer onto stack
841 void hoc_pushs(Symbol* d) {
842  push_value(d);
843 }
844 
845 /* push integer onto stack */
846 void hoc_pushi(int d) {
847  push_value(d);
848 }
849 
851  push_value(std::move(handle));
852 }
853 
854 /* push index onto stack */
855 void hoc_push_ndim(int d) {
856  push_value(stack_ndim_datum(d));
857 }
858 
859 // type of nth arg
860 int hoc_argtype(int narg) {
861  return get_legacy_int_type(get_argument(narg));
862 }
863 
865  return (hoc_argtype(narg) == NUMBER);
866 }
867 
869  return (hoc_argtype(narg) == VAR);
870 }
871 
873  return (hoc_argtype(narg) == STRING);
874 }
875 
877  auto const type = hoc_argtype(narg);
878  return (type == OBJECTVAR || type == OBJECTTMP);
879 }
880 
882  return (hoc_argtype(narg) == OBJECTTMP);
883 }
884 
885 Object* hoc_obj_look_inside_stack(int i) { /* stack pointer at depth i; i=0 is top */
886  auto const& entry = get_stack_entry_variant(i);
887  return std::visit(
888  overloaded{[](Object* o) { return o; },
889  [](Object** o) { return *o; },
890  [](auto const& val) -> Object* {
891  throw std::runtime_error(
892  "hoc_obj_look_inside_stack expects Object* or Object** but found " +
893  cxx_demangle(typeid(val).name()));
894  }},
895  entry);
896 }
897 
898 int hoc_inside_stacktype(int i) { /* 0 is top */
899  return get_legacy_int_type(get_stack_entry_variant(i));
900 }
901 
902 // pop double and return top elem from stack
903 double hoc_xpop() {
904  return pop_value<double>();
905 }
906 
907 namespace neuron {
908 /** @brief hoc_get_arg<generic_data_handle>()
909  */
910 container::generic_data_handle oc::detail::hoc_get_arg_helper<container::generic_data_handle>::impl(
911  std::size_t narg) {
912  return cast<container::generic_data_handle>(get_argument(narg));
913 }
914 /** @brief hoc_pop<generic_data_handle>()
915  */
916 container::generic_data_handle oc::detail::hoc_pop_helper<container::generic_data_handle>::impl() {
917  return pop_value<neuron::container::generic_data_handle>();
918 }
919 } // namespace neuron
920 
921 // pop double pointer and return top elem from stack
922 double* hoc_pxpop() {
923  // All pointers are actually stored on the stack as data handles
924  return static_cast<double*>(hoc_pop<neuron::container::data_handle<double>>());
925 }
926 
927 // pop symbol pointer and return top elem from stack
929  return pop_value<Symbol*>();
930 }
931 
932 // pop array index and return top elem from stack
934  return pop_value<stack_ndim_datum>().i;
935 }
936 
937 /** @brief Pop pointer to object pointer and return top elem from stack.
938  *
939  * When using objpop, after dealing with the pointer, one should call
940  * hoc_tobj_unref(pobj) in order to prevent memory leakage since the object may
941  * have been reffed when it was pushed on the stack.
942  */
944  if (stack_entry_is_tmpobject(0)) {
945  return hoc_temp_objptr(pop_value<Object*>());
946  }
947  return pop_value<Object**>();
948 }
949 
951  --tobj_count;
952  hoc_obj_unref(o);
953 }
954 
955 // pop object and return top elem from stack, the return value is wrapped up in
956 // a unique_ptr that calls TmpObjectDeleter::operator() from its destructor.
958  return TmpObject{pop_value<Object*>()};
959 }
960 
961 // pop pointer to string pointer and return top elem from stack
962 char** hoc_strpop() {
963  return pop_value<char**>();
964 }
965 
966 // pop symbol pointer and return top elem from stack
967 int hoc_ipop() {
968  return pop_value<int>();
969 }
970 
971 // just pop the stack without returning anything
972 void hoc_nopop() {
973  auto const& top_entry = get_stack_entry_variant(0);
974  if (stack_entry_is_tmpobject(top_entry)) { // OBJECTTMP
975  // TODO this should be handled by the destructor of the variant member
976  // corresponding to OBJECTTMP
977  // TODO double check this
978  hoc_stkobj_unref(std::get<Object*>(top_entry), stack.size() - 1);
979  }
980  pop_value();
981 }
982 
983 // push constant onto stack
985  hoc_pushx(*((pc++)->sym)->u.pnum);
986 }
987 
988 // push zero onto stack
989 void hoc_pushzero() {
990  hoc_pushx(0.);
991 }
992 
993 // push variable onto stack
994 void hoc_varpush() {
995  hoc_pushs((pc++)->sym);
996 }
997 
998 #define relative(pc) (pc + (pc)->i)
999 
1000 void hoc_forcode(void) {
1001  double d;
1002  Inst* savepc = pc; /* loop body */
1003  int isec;
1004 
1005  isec = nrn_isecstack();
1006  hoc_execute(savepc + 3); /* condition */
1007  d = hoc_xpop();
1008  while (d) {
1009  hoc_execute(relative(savepc)); /* body */
1010  if (hoc_returning) {
1011  nrn_secstack(isec);
1012  }
1013  if (hoc_returning == 1 || hoc_returning == 4) /* return or stop */
1014  break;
1015  else if (hoc_returning == 2) /* break */
1016  {
1017  hoc_returning = 0;
1018  break;
1019  } else /* continue */
1020  hoc_returning = 0;
1021  if ((savepc + 2)->i) /* diff between while and for */
1022  hoc_execute(relative(savepc + 2)); /* increment */
1023  hoc_execute(savepc + 3);
1024  d = hoc_xpop();
1025  }
1026  if (!hoc_returning)
1027  pc = relative(savepc + 1); /* next statement */
1028 }
1029 
1030 void hoc_shortfor(void) {
1031  Inst* savepc = pc;
1032  double begin, end, *pval = 0;
1033  Symbol* sym;
1034  int isec;
1035 
1036  end = hoc_xpop() + hoc_epsilon;
1037  begin = hoc_xpop();
1038  sym = hoc_spop();
1039 
1040  switch (sym->type) {
1041  case UNDEF:
1042  hoc_execerror(sym->name, "undefined variable");
1043  case VAR:
1044  if (!is_array(*sym)) {
1045  if (sym->subtype == USERINT) {
1046  hoc_execerror("integer iteration variable", sym->name);
1047  } else if (sym->subtype == USERDOUBLE) {
1048  pval = sym->u.pval;
1049  } else {
1050  pval = OPVAL(sym);
1051  }
1052  break;
1053  } else {
1054  if (sym->subtype == USERINT)
1055  hoc_execerror("integer iteration variable", sym->name);
1056  else if (sym->subtype == USERDOUBLE)
1057  pval = sym->u.pval + hoc_araypt(sym, SYMBOL);
1058  else
1059  pval = OPVAL(sym) + hoc_araypt(sym, OBJECTVAR);
1060  }
1061  break;
1062  case AUTO: {
1063  pval = &(cast<double>(fp->argn[sym->u.u_auto]));
1064  } break;
1065  default:
1066  hoc_execerror("for loop non-variable", sym->name);
1067  }
1068  isec = nrn_isecstack();
1069  for (*pval = begin; *pval <= end; *pval += 1.) {
1070  hoc_execute(relative(savepc));
1071  if (hoc_returning) {
1072  nrn_secstack(isec);
1073  }
1074  if (hoc_returning == 1 || hoc_returning == 4) {
1075  break;
1076  } else if (hoc_returning == 2) {
1077  hoc_returning = 0;
1078  break;
1079  } else {
1080  hoc_returning = 0;
1081  }
1082  }
1083  if (!hoc_returning)
1084  pc = relative(savepc + 1);
1085 }
1086 
1087 void hoc_iterator(void) {
1088  /* pc is ITERATOR symbol, argcount, stmtbegin, stmtend */
1089  /* for testing hoc_execute stmt once */
1090  Symbol* sym;
1091  int argcount;
1092  Inst *stmtbegin, *stmtend;
1093 
1094  sym = (pc++)->sym;
1095  argcount = (pc++)->i;
1096  stmtbegin = relative(pc);
1097  stmtend = relative(pc + 1);
1098  ;
1099  hoc_iterator_object(sym, argcount, stmtbegin, stmtend, hoc_thisobject);
1100 }
1101 
1102 void hoc_iterator_object(Symbol* sym, int argcount, Inst* beginpc, Inst* endpc, Object* ob) {
1103  fp++;
1104  if (fp >= framelast) {
1105  fp--;
1106  hoc_execerror(sym->name, "call nested too deeply, increase with -NFRAME framesize option");
1107  }
1108  fp->sp = sym;
1109  fp->nargs = argcount;
1110  fp->retpc = endpc;
1111  fp->argn = &stack.back();
1112  for (auto i = 0; i < sym->u.u_proc->nauto; ++i) {
1113  // last sym->u.u_proc->nobjauto of these are objects
1114  if (sym->u.u_proc->nauto - i <= sym->u.u_proc->nobjauto) {
1115  push_value(static_cast<Object*>(nullptr));
1116  } else {
1117  push_value(0.0);
1118  }
1119  }
1120  fp->iter_stmt_begin = beginpc;
1121  fp->iter_stmt_ob = ob;
1122  fp->ob = ob;
1123  hoc_execute(sym->u.u_proc->defn.in);
1124  hoc_nopop(); /* 0.0 from the procret() */
1125  if (hoc_returning != 4) {
1126  hoc_returning = 0;
1127  }
1128 }
1129 
1131  Inst* pcsav;
1132  Object* ob;
1133  Object* obsav;
1134  Objectdata* obdsav;
1135  Symlist* slsav;
1136  int isec;
1137  Frame* iter_f = fp; /* iterator frame */
1138  Frame* ef = fp - 1; /* iterator statement frame */
1139  fp++; /* execution frame */
1140 
1141  fp->sp = iter_f->sp;
1142  fp->ob = iter_f->ob;
1143  if (ef != frame) {
1144  /*SUPPRESS 26*/
1145  fp->argn = ef->argn;
1146  fp->nargs = ef->nargs;
1147  } else { /* top. only for stack trace */
1148  fp->argn = 0;
1149  fp->nargs = 0;
1150  }
1151 
1152  ob = iter_f->iter_stmt_ob;
1153  obsav = hoc_thisobject;
1154  obdsav = hoc_objectdata_save();
1155  slsav = hoc_symlist;
1156  hoc_thisobject = ob;
1157  if (ob) {
1158  hoc_objectdata = ob->u.dataspace;
1160  } else {
1163  }
1164 
1165  pcsav = pc;
1166  isec = nrn_isecstack();
1167  hoc_execute(iter_f->iter_stmt_begin);
1168  pc = pcsav;
1170  hoc_thisobject = obsav;
1171  hoc_symlist = slsav;
1172  --fp;
1173  if (hoc_returning) {
1174  nrn_secstack(isec);
1175  }
1176  switch (hoc_returning) {
1177  case 1: /* return means not only return from iter but return from
1178  the procedure containing the iter statement */
1179  hoc_execerror("return from within an iterator statement not allowed.",
1180  "Set a flag and use break.");
1181  case 2: /* break means return from iter */
1182  hoc_procret();
1183  break;
1184  case 3: /* continue means go on from iter as though nothing happened*/
1185  hoc_returning = 0;
1186  break;
1187  }
1188 }
1189 
1190 static void for_segment2(Symbol* sym, int mode) {
1191  /* symbol on stack; statement pointed to by pc
1192  continuation pointed to by pc+1. template used is shortfor in code.cpp
1193  of hoc system.
1194  */
1195  int i, imax;
1196  Inst* savepc = pc;
1197  double *pval = 0, dx;
1198  int isec;
1199 
1200  switch (sym->type) {
1201  case UNDEF:
1202  hoc_execerror(sym->name, "undefined variable");
1203  case VAR:
1204  if (!is_array(*sym)) {
1205  if (sym->subtype == USERINT) {
1206  hoc_execerror("integer iteration variable", sym->name);
1207  } else if (sym->subtype == USERDOUBLE) {
1208  pval = sym->u.pval;
1209  } else {
1210  pval = OPVAL(sym);
1211  }
1212  break;
1213  } else {
1214  if (sym->subtype == USERINT)
1215  hoc_execerror("integer iteration variable", sym->name);
1216  else if (sym->subtype == USERDOUBLE)
1217  pval = sym->u.pval + hoc_araypt(sym, SYMBOL);
1218  else
1219  pval = OPVAL(sym) + hoc_araypt(sym, OBJECTVAR);
1220  }
1221  break;
1222  case AUTO: {
1223  auto& entry = fp->argn[sym->u.u_auto];
1224  entry = 0.0; // update the active entry
1225  pval = &(cast<double>(entry));
1226  } break;
1227  default:
1228  hoc_execerror("for loop non-variable", sym->name);
1229  }
1230  imax = segment_limits(&dx);
1231  {
1232  if (mode == 0) {
1233  i = 1;
1234  *pval = dx / 2.;
1235  } else {
1236  i = 0;
1237  *pval = 0.;
1238  }
1239  isec = nrn_isecstack();
1240  for (; i <= imax; i++) {
1241  if (i == imax) {
1242  if (mode == 0) {
1243  continue;
1244  }
1245  *pval = 1.;
1246  }
1247  hoc_execute(relative(savepc));
1248  if (hoc_returning) {
1249  nrn_secstack(isec);
1250  }
1251  if (hoc_returning == 1 || hoc_returning == 4) {
1252  break;
1253  } else if (hoc_returning == 2) {
1254  hoc_returning = 0;
1255  break;
1256  } else {
1257  hoc_returning = 0;
1258  }
1259  if (i == 0) {
1260  *pval += dx / 2.;
1261  } else if (i < imax) {
1262  *pval += dx;
1263  }
1264  }
1265  }
1266  if (!hoc_returning)
1267  pc = relative(savepc + 1);
1268 }
1269 
1270 void for_segment(void) {
1271  for_segment2(hoc_spop(), 1);
1272 }
1273 
1274 void for_segment1(void) {
1275  Symbol* sym;
1276  double d;
1277  int mode;
1278  d = hoc_xpop();
1279  sym = hoc_spop();
1280  mode = (fabs(d) < hoc_epsilon) ? 0 : 1;
1281  for_segment2(sym, mode);
1282 }
1283 
1284 void hoc_ifcode(void) {
1285  double d;
1286  Inst* savepc = pc; /* then part */
1287 
1288  hoc_execute(savepc + 3); /* condition */
1289  d = hoc_xpop();
1290  if (d)
1291  hoc_execute(relative(savepc));
1292  else if ((savepc + 1)->i) /* else part? */
1293  hoc_execute(relative(savepc + 1));
1294  if (!hoc_returning)
1295  pc = relative(savepc + 2); /* next stmt */
1296 }
1297 
1298 void hoc_Break(void) /* break statement */
1299 {
1300  hoc_returning = 2;
1301 }
1302 
1303 void hoc_Continue(void) /* continue statement */
1304 {
1305  hoc_returning = 3;
1306 }
1307 
1308 void hoc_Stop(void) /* stop statement */
1309 {
1310  hoc_returning = 4;
1311 }
1312 
1313 void hoc_define(Symbol* sp) { /* put func/proc in symbol table */
1314  Inst *inst, *newinst;
1315 
1316  if (sp->u.u_proc->defn.in != STOP)
1317  free((char*) sp->u.u_proc->defn.in);
1318  hoc_free_list(&(sp->u.u_proc->list));
1319  sp->u.u_proc->list = hoc_p_symlist;
1320  hoc_p_symlist = (Symlist*) 0;
1321  sp->u.u_proc->size = (unsigned) (hoc_progp - hoc_progbase);
1322  sp->u.u_proc->defn.in = (Inst*) emalloc((unsigned) (hoc_progp - hoc_progbase) * sizeof(Inst));
1323  newinst = sp->u.u_proc->defn.in;
1324  for (inst = hoc_progbase; inst != hoc_progp;)
1325  *newinst++ = *inst++;
1326  hoc_progp = hoc_progbase; /* next code starts here */
1327 }
1328 
1329 // print the call sequence on an hoc_execerror
1330 void frame_debug() {
1331  Frame* f;
1332  int i, j;
1333  char id[10];
1334 
1335  if (nrnmpi_numprocs_world > 1) {
1336  Sprintf(id, "%d ", nrnmpi_myid_world);
1337  } else {
1338  id[0] = '\0';
1339  }
1340  for (i = 5, f = fp; f != frame && --i; f = f - 1) { /* print only to depth of 5 */
1341  for (j = i; j; j--) {
1342  Fprintf(stderr, " ");
1343  }
1344  if (f->ob) {
1345  Fprintf(stderr, "%s%s.%s(", id, hoc_object_name(f->ob), f->sp->name); // error
1346  } else {
1347  Fprintf(stderr, "%s%s(", id, f->sp->name);
1348  }
1349  for (j = 1; j <= f->nargs;) {
1350  auto const& entry = f->argn[j - f->nargs];
1351  std::visit(overloaded{[](double val) { Fprintf(stderr, "%g", val); },
1352  [](char** pstr) {
1353  const char* s = *pstr;
1354  if (strlen(s) > 15) {
1355  Fprintf(stderr, "\"%.10s...\"", s);
1356  } else {
1357  Fprintf(stderr, "\"%s\"", s);
1358  }
1359  },
1360  [](Object** pobj) {
1361  Fprintf(stderr, "%s", hoc_object_name(*pobj));
1362  },
1363  [](auto const&) { Fprintf(stderr, "..."); }},
1364  entry);
1365  if (++j <= f->nargs) {
1366  Fprintf(stderr, ", ");
1367  }
1368  }
1369  Fprintf(stderr, ")\n");
1370  }
1371  if (i <= 0) {
1372  Fprintf(stderr, "and others\n");
1373  }
1374 }
1375 
1376 void hoc_push_frame(Symbol* sp, int narg) { /* helpful for explicit function calls */
1377  if (++fp >= framelast) {
1378  --fp;
1379  hoc_execerror(sp->name, "call nested too deeply, increase with -NFRAME framesize option");
1380  }
1381  fp->sp = sp;
1382  fp->nargs = narg;
1383  fp->argn = &stack.back(); // last argument
1384  fp->ob = hoc_thisobject;
1385 }
1386 
1387 void hoc_pop_frame(void) {
1388  int i;
1389  frameobj_clean(fp);
1390  for (i = 0; i < fp->nargs; i++) {
1391  // pop arguments
1392  hoc_nopop();
1393  }
1394  --fp;
1395 }
1396 
1397 // call a function
1398 void hoc_call() {
1399  int isec;
1400  Symbol* sp = pc[0].sym; /* symbol table entry */
1401  /* for function */
1402  if (++fp >= framelast) {
1403  --fp;
1404  hoc_execerror(sp->name, "call nested too deeply, increase with -NFRAME framesize option");
1405  }
1406  fp->sp = sp;
1407  fp->nargs = pc[1].i;
1408  fp->retpc = pc + 2;
1409  fp->ob = hoc_thisobject;
1410  fp->argn = &stack.back(); // last argument
1411  BBSPOLL
1412  isec = nrn_isecstack();
1413  if (sp->type == FUN_BLTIN || sp->type == OBJECTFUNC || sp->type == STRINGFUNC) {
1414  // Push slots for auto
1415  for (auto i = 0; i < sp->u.u_proc->nauto; ++i) {
1416  push_value(0.0);
1417  }
1418  (sp->u.u_proc->defn.pf)();
1419  if (hoc_errno_check()) {
1420  hoc_warning("errno set during call of", sp->name);
1421  }
1422  } else if ((sp->type == FUNCTION || sp->type == PROCEDURE || sp->type == HOCOBJFUNCTION) &&
1423  sp->u.u_proc->defn.in != STOP) {
1424  // Push slots for auto
1425  for (auto i = 0; i < sp->u.u_proc->nauto; ++i) {
1426  // last sym->u.u_proc->nobjauto of these are objects
1427  if (sp->u.u_proc->nauto - i <= sp->u.u_proc->nobjauto) {
1428  push_value(static_cast<Object*>(nullptr));
1429  } else {
1430  push_value(0.0);
1431  }
1432  }
1433  if (sp->cpublic == 2) {
1434  Objectdata* odsav = hoc_objectdata_save();
1435  Object* obsav = hoc_thisobject;
1436  Symlist* slsav = hoc_symlist;
1437 
1439  hoc_thisobject = 0;
1441 
1442  hoc_execute(sp->u.u_proc->defn.in);
1443 
1445  hoc_thisobject = obsav;
1446  hoc_symlist = slsav;
1447  } else {
1448  hoc_execute(sp->u.u_proc->defn.in);
1449  }
1450  /* the autoobject pointers were unreffed at the ret() */
1451 
1452  } else {
1453  hoc_execerror(sp->name, "undefined function");
1454  }
1455  if (hoc_returning) {
1456  nrn_secstack(isec);
1457  }
1458  if (hoc_returning != 4) { /*if not stopping */
1459  hoc_returning = 0;
1460  }
1461 }
1462 
1464  /*fake it so c code can call functions that ret() */
1465  /* but these functions better not ask for any arguments */
1466  /* don't forget a double is left on the stack and returning = 1 */
1467  /* use the symbol for the function as the argument, only requirement
1468  which is always true is that it has no local variables pushed on
1469  the stack so nauto=0 and nobjauto=0 */
1470  ++fp;
1471  fp->sp = s;
1472  fp->nargs = 0;
1473  fp->retpc = pc;
1474  fp->ob = nullptr;
1475 }
1476 
1477 double hoc_call_func(Symbol* s, int narg) {
1479  return hoc_xpop();
1480 }
1481 
1483  /* call the symbol as a function, The args better be pushed on the stack
1484  first arg first. */
1485  if (s->type == BLTIN) {
1486  hoc_pushx((*(s->u.ptr))(xpop()));
1487  } else {
1488  Inst* pcsav;
1489  Inst fc[4];
1490  fc[0].pf = hoc_call;
1491  fc[1].sym = s;
1492  fc[2].i = narg;
1493  fc[3].in = STOP;
1494 
1495  pcsav = hoc_pc;
1496  hoc_execute(fc);
1497  hoc_pc = pcsav;
1498  }
1499 }
1500 
1501 /* common return from func, proc, or iterator */
1502 void hoc_ret() {
1503  // unref all the auto object pointers
1504  for (int i = fp->sp->u.u_proc->nobjauto - 1; i >= 0; --i) {
1505  // this is going from the deepest automatic object in the stack to the shallowest
1506  // should this decremenet tobj_count?
1507  hoc_obj_unref(hoc_look_inside_stack<Object*>(i)); //
1508  }
1509  // Pop off the autos
1510  for (auto i = 0; i < fp->sp->u.u_proc->nauto; ++i) {
1511  pop_value();
1512  }
1513  frameobj_clean(fp);
1514  for (int i = 0; i < fp->nargs; i++) {
1515  // pop arguments
1516  hoc_nopop();
1517  }
1518  hoc_pc = fp->retpc;
1519  --fp;
1520  hoc_returning = 1;
1521 }
1522 
1523 void hoc_funcret(void) /* return from a function */
1524 {
1525  double d;
1526  if (fp->sp->type != FUNCTION)
1527  hoc_execerror(fp->sp->name, "(proc or iterator) returns value");
1528  d = hoc_xpop(); /* preserve function return value */
1529  hoc_ret();
1530  hoc_pushx(d);
1531 }
1532 
1533 void hoc_procret(void) /* return from a procedure */
1534 {
1535  if (fp->sp->type == FUNCTION)
1536  hoc_execerror(fp->sp->name, "(func) returns no value");
1537  if (fp->sp->type == HOCOBJFUNCTION)
1538  hoc_execerror(fp->sp->name, "(obfunc) returns no value");
1539  hoc_ret();
1540  hoc_pushx(0.); /*will be popped immediately; necessary because caller
1541  may have compiled it as a function*/
1542 }
1543 
1544 void hocobjret(void) /* return from a hoc level obfunc */
1545 {
1546  Object** d;
1547  if (fp->sp->type != HOCOBJFUNCTION)
1548  hoc_execerror(fp->sp->name, "objfunc returns objref");
1549  d = hoc_objpop(); /* preserve function return value */
1550  Object* o = *d; // safe to deref here even if d points to localobj on stack.
1551  if (o) {
1552  o->refcount++;
1553  }
1554  // d may point to an Object* on the stack, ie. localobj name.
1555  // if so, d after ret() would point outside the stack,
1556  // so it cannot be dereferenced without a sanitizer error on the mac.
1557  hoc_ret();
1558  /*make a temp and ref it in case autoobj returned since ret would
1559  have unreffed it*/
1560  hoc_push_object(o);
1561 
1562  if (o) {
1563  o->refcount--;
1564  }
1565  hoc_tobj_unref(d); // only dereferences d if points into the hoc_temp_obj_pool_
1566 }
1567 
1568 void hoc_Numarg(void) {
1569  int narg;
1570  Frame* f = fp - 1;
1571  if (f == frame) {
1572  narg = 0;
1573  } else {
1574  narg = f->nargs;
1575  }
1576  hoc_ret();
1577  hoc_pushx((double) narg);
1578 }
1579 
1580 void hoc_Argtype() {
1581  int iarg, itype = 0;
1582  Frame* f = fp - 1;
1583  if (f == frame) {
1584  hoc_execerror("argtype can only be called in a func or proc", 0);
1585  }
1586  iarg = (int) chkarg(1, -1000., 100000.);
1587  if (iarg > f->nargs || iarg < 1) {
1588  itype = -1;
1589  } else {
1590  auto const& entry = f->argn[iarg - f->nargs];
1591  itype =
1592  std::visit(overloaded{[](double) { return 0; },
1593  [](Object*) { return 1; },
1594  [](Object**) { return 1; },
1595  [](char**) { return 2; },
1596  [](neuron::container::generic_data_handle const&) { return 3; },
1597  [](auto const& x) -> int {
1598  throw std::runtime_error(
1599  "hoc_Argtype didn't expect argument of type " +
1600  cxx_demangle(typeid(decltype(x)).name()));
1601  }},
1602  entry);
1603  }
1604  hoc_retpushx(itype);
1605 }
1606 
1607 int ifarg(int narg) { /* true if there is an nth argument */
1608  if (narg > fp->nargs)
1609  return 0;
1610  return 1;
1611 }
1612 
1613 // return pointer to nth argument
1615  auto const& arg_entry = get_argument(narg);
1616  if (stack_entry_is_tmpobject(arg_entry)) {
1617  return hoc_temp_objptr(std::get<Object*>(arg_entry));
1618  }
1619  return cast<Object**>(arg_entry);
1620 }
1621 
1622 // return pointer to nth argument
1623 char** hoc_pgargstr(int narg) {
1624  return std::visit(overloaded{[](char** pstr) { return pstr; },
1625  [](Symbol* sym) {
1626  if (sym->type == CSTRING) {
1627  return &sym->u.cstr;
1628  } else if (sym->type == STRING) {
1629  return OPSTR(sym);
1630  } else {
1631  hoc_execerror("Expecting string argument", nullptr);
1632  }
1633  },
1634  [](auto const&) -> char** {
1635  hoc_execerror("Expecting string argument", nullptr);
1636  }},
1637  get_argument(narg));
1638 }
1639 
1640 // return pointer to nth argument
1641 double* hoc_getarg(int narg) {
1642  auto& arg_entry = get_argument(narg);
1643  auto& value = cast<double>(arg_entry);
1644  return &value;
1645 }
1646 
1647 int hoc_argindex(void) {
1648  int j = (int) hoc_xpop();
1649  if (j < 1) {
1650  hoc_execerror("arg index i < 1", 0);
1651  }
1652  return j;
1653 }
1654 
1655 // push argument onto stack
1656 void hoc_arg() {
1657  int i = (pc++)->i;
1658  if (i == 0) {
1659  i = hoc_argindex();
1660  }
1661  hoc_pushx(*hoc_getarg(i));
1662 }
1663 
1664 void hoc_stringarg(void) /* push string arg onto stack */
1665 {
1666  int i;
1667  i = (pc++)->i;
1668  if (i == 0) {
1669  i = hoc_argindex();
1670  }
1672 }
1673 
1674 double hoc_opasgn(int op, double dest, double src) {
1675  switch (op) {
1676  case '+':
1677  return dest + src;
1678  case '*':
1679  return dest * src;
1680  case '-':
1681  return dest - src;
1682  case '/':
1683  if (src == 0.) {
1684  hoc_execerror("Divide by 0", (char*) 0);
1685  }
1686  return dest / src;
1687  default:
1688  return src;
1689  }
1690 }
1691 
1692 void hoc_argassign(void) /* store top of stack in argument */
1693 {
1694  double d;
1695  int i, op;
1696  i = (pc++)->i;
1697  if (i == 0) {
1698  i = hoc_argindex();
1699  }
1700  op = (pc++)->i;
1701  d = hoc_xpop();
1702  if (op) {
1703  d = hoc_opasgn(op, *getarg(i), d);
1704  }
1705  hoc_pushx(d); /* leave value on stack */
1706  *getarg(i) = d;
1707 }
1708 
1709 void hoc_argrefasgn(void) {
1710  double d, *pd;
1711  int i, j, op;
1712  i = (pc++)->i;
1713  j = (pc++)->i;
1714  if (i == 0) {
1715  i = hoc_argindex();
1716  }
1717  op = (pc++)->i;
1718  d = hoc_xpop();
1719  if (j) {
1720  j = (int) (hoc_xpop() + hoc_epsilon);
1721  }
1722  pd = hoc_pgetarg(i);
1723  if (op) {
1724  d = hoc_opasgn(op, pd[j], d);
1725  }
1726  hoc_pushx(d); /* leave value on stack */
1727  pd[j] = d;
1728 }
1729 
1730 void hoc_argref(void) {
1731  int i, j;
1732  double* pd;
1733  i = (pc++)->i;
1734  j = (pc++)->i;
1735  if (i == 0) {
1736  i = hoc_argindex();
1737  }
1738  pd = hoc_pgetarg(i);
1739  if (!pd) {
1740  hoc_execerr_ext("hoc argument %d is an invalid datahandle\n", i);
1741  }
1742  if (j) {
1743  j = (int) (hoc_xpop() + hoc_epsilon);
1744  }
1745  hoc_pushx(pd[j]);
1746 }
1747 
1748 
1749 void hoc_argrefarg(void) {
1750  double* pd;
1751  int i;
1752  i = (pc++)->i;
1753  if (i == 0) {
1754  i = hoc_argindex();
1755  }
1756  pd = hoc_pgetarg(i);
1757  hoc_pushpx(pd);
1758 }
1759 
1760 void hoc_bltin(void) /* evaluate built-in on top of stack */
1761 {
1762  double d;
1763  d = hoc_xpop();
1764  d = (*((pc++)->sym->u.ptr))(d);
1765  hoc_pushx(d);
1766 }
1767 
1768 Symbol* hoc_get_symbol(const char* var) {
1769  Symlist* sl = (Symlist*) 0;
1770  Symbol *prc, *sym;
1771  Inst* last;
1772  prc = hoc_parse_stmt(var, &sl);
1773  hoc_run_stmt(prc);
1774 
1775  last = (Inst*) prc->u.u_proc->defn.in + prc->u.u_proc->size - 1;
1776  if (last[-2].pf == hoc_eval) {
1777  sym = last[-3].sym;
1778  } else if (last[-3].pf == rangepoint || last[-3].pf == rangevareval) {
1779  sym = last[-2].sym;
1780  } else if (last[-4].pf == hoc_object_eval) {
1781  sym = last[-10].sym;
1782  } else {
1783  sym = (Symbol*) 0;
1784  }
1785  hoc_free_list(&sl);
1786  return sym;
1787 }
1788 
1789 Symbol* hoc_get_last_pointer_symbol(void) { /* hard to imagine a kludgier function*/
1790  Symbol* sym = (Symbol*) 0;
1791  Inst* pcv;
1792  int istop = 0;
1793  for (pcv = pc; pcv; --pcv) {
1794  if (pcv->pf == hoc_ob_pointer) {
1795  if (pcv[-2].sym) {
1796  sym = pcv[-2].sym; /* e.g. &ExpSyn[0].A */
1797  } else {
1798  sym = pcv[-6].sym; /* e.g. & Cell[0].soma.v(.5) */
1799  }
1800  break;
1801  } else if (pcv->pf == hoc_evalpointer) {
1802  sym = pcv[-1].sym;
1803  break;
1804  } else if (pcv->pf == rangevarevalpointer) {
1805  sym = pcv[1].sym;
1806  break;
1807  } else if (pcv->in == STOP) {
1808  /* hopefully only got here from python. Give up on second STOP*/
1809  if (istop++ == 1) {
1810  break;
1811  }
1812  }
1813  }
1814  return sym;
1815 }
1816 
1817 void hoc_autoobject(void) { /* AUTOOBJ symbol at pc+1. */
1818  /* pointer to object pointer left on stack */
1819  Symbol* obs;
1820 #if PDEBUG
1821  printf("code for hoc_autoobject()\n");
1822 #endif
1823  obs = (pc++)->sym;
1824  hoc_pushobj(&(cast<Object*>(fp->argn[obs->u.u_auto])));
1825 }
1826 
1827 void hoc_eval(void) /* evaluate variable on stack */
1828 {
1829  Objectdata* odsav;
1830  Object* obsav = 0;
1831  Symlist* slsav;
1832  double d = 0.0;
1833  Symbol* sym;
1834  sym = hoc_spop();
1835  if (sym->cpublic == 2) {
1836  sym = sym->u.sym;
1837  odsav = hoc_objectdata_save();
1838  obsav = hoc_thisobject;
1839  slsav = hoc_symlist;
1841  hoc_thisobject = 0;
1843  }
1844  switch (sym->type) {
1845  case UNDEF:
1846  hoc_execerror("undefined variable", sym->name);
1847  case VAR:
1848  if (!is_array(*sym)) {
1849  if (hoc_do_equation && sym->s_varn > 0 && hoc_access[sym->s_varn] == 0) {
1851  hoc_var_access = sym->s_varn;
1852  }
1853  switch (sym->subtype) {
1854  case USERDOUBLE:
1855  d = *(sym->u.pval);
1856  break;
1857  case USERINT:
1858  d = (double) (*(sym->u.pvalint));
1859  break;
1860  case USERPROPERTY:
1861  d = cable_prop_eval(sym);
1862  break;
1863  case USERFLOAT:
1864  d = (double) (*(sym->u.pvalfloat));
1865  break;
1866  default:
1867  d = *(OPVAL(sym));
1868  break;
1869  }
1870  } else {
1871  switch (sym->subtype) {
1872  case USERDOUBLE:
1873  d = (sym->u.pval)[hoc_araypt(sym, SYMBOL)];
1874  break;
1875  case USERINT:
1876  d = (sym->u.pvalint)[hoc_araypt(sym, SYMBOL)];
1877  break;
1878  case USERFLOAT:
1879  d = (sym->u.pvalfloat)[hoc_araypt(sym, SYMBOL)];
1880  break;
1881  default:
1882  d = (OPVAL(sym))[hoc_araypt(sym, OBJECTVAR)];
1883  break;
1884  }
1885  }
1886  break;
1887  case AUTO:
1888  d = cast<double>(fp->argn[sym->u.u_auto]);
1889  break;
1890  default:
1891  hoc_execerror("attempt to evaluate a non-variable", sym->name);
1892  }
1893 
1894  if (obsav) {
1896  hoc_thisobject = obsav;
1897  hoc_symlist = slsav;
1898  }
1899  hoc_pushx(d);
1900 }
1901 
1902 // leave pointer to variable on stack
1904  Objectdata* odsav;
1905  Object* obsav = 0;
1906  Symlist* slsav;
1907  double* d = 0;
1908  //*cable_prop_eval_pointer();
1909  Symbol* sym;
1910  sym = hoc_spop();
1911  if (sym->cpublic == 2) {
1912  sym = sym->u.sym;
1913  odsav = hoc_objectdata_save();
1914  obsav = hoc_thisobject;
1915  slsav = hoc_symlist;
1917  hoc_thisobject = 0;
1919  }
1920  switch (sym->type) {
1921  case UNDEF:
1922  hoc_execerror("undefined variable", sym->name);
1923  case VAR:
1924  if (!is_array(*sym)) {
1925  switch (sym->subtype) {
1926  case USERDOUBLE:
1927  d = sym->u.pval;
1928  break;
1929  case USERINT:
1930  case USERFLOAT:
1931  hoc_execerror("can use pointer only to doubles", sym->name);
1932  break;
1933  case USERPROPERTY:
1934  d = cable_prop_eval_pointer(sym);
1935  break;
1936  default:
1937  d = OPVAL(sym);
1938  break;
1939  }
1940  } else {
1941  switch (sym->subtype) {
1942  case USERDOUBLE:
1943  d = sym->u.pval + hoc_araypt(sym, SYMBOL);
1944  break;
1945  case USERINT:
1946  case USERFLOAT:
1947  hoc_execerror("can use pointer only to doubles", sym->name);
1948  break;
1949  default:
1950  d = OPVAL(sym) + hoc_araypt(sym, OBJECTVAR);
1951  break;
1952  }
1953  }
1954  break;
1955  case AUTO: {
1956  d = &(cast<double>(fp->argn[sym->u.u_auto]));
1957  } break;
1958  default:
1959  hoc_execerror("attempt to evaluate pointer to a non-variable", sym->name);
1960  }
1961  if (obsav) {
1963  hoc_thisobject = obsav;
1964  hoc_symlist = slsav;
1965  }
1966  hoc_pushpx(d);
1967 }
1968 
1969 void hoc_add(void) /* add top two elems on stack */
1970 {
1971  double d1, d2;
1972  d2 = hoc_xpop();
1973  d1 = hoc_xpop();
1974  d1 += d2;
1975  hoc_pushx(d1);
1976 }
1977 
1978 void hoc_sub(void) /* subtract top two elems on stack */
1979 {
1980  double d1, d2;
1981  d2 = hoc_xpop();
1982  d1 = hoc_xpop();
1983  d1 -= d2;
1984  hoc_pushx(d1);
1985 }
1986 
1987 void hoc_mul(void) /* multiply top two elems on stack */
1988 {
1989  double d1, d2;
1990  d2 = hoc_xpop();
1991  d1 = hoc_xpop();
1992  d1 *= d2;
1993  hoc_pushx(d1);
1994 }
1995 
1996 void hoc_div(void) /* divide top two elems on stack */
1997 {
1998  double d1, d2;
1999  d2 = hoc_xpop();
2000  if (d2 == 0.0)
2001  hoc_execerror("division by zero", (char*) 0);
2002  d1 = hoc_xpop();
2003  d1 /= d2;
2004  hoc_pushx(d1);
2005 }
2006 
2007 void hoc_cyclic(void) /* the modulus function */
2008 {
2009  double d1, d2;
2010  double r, q;
2011  d2 = hoc_xpop();
2012  if (d2 <= 0.)
2013  hoc_execerror("a%b, b<=0", (char*) 0);
2014  d1 = hoc_xpop();
2015  r = d1;
2016  if (r >= d2) {
2017  q = floor(d1 / d2);
2018  r = d1 - q * d2;
2019  } else if (r <= -d2) {
2020  q = floor(-d1 / d2);
2021  r = d1 + q * d2;
2022  }
2023  if (r > d2) {
2024  r = r - d2;
2025  }
2026  if (r < 0.) {
2027  r = r + d2;
2028  }
2029 
2030  hoc_pushx(r);
2031 }
2032 
2033 // negate top element on stack
2034 void hoc_negate() {
2035  double const d = hoc_xpop();
2036  hoc_pushx(-d);
2037 }
2038 
2039 void hoc_gt(void) {
2040  double d1, d2;
2041  d2 = hoc_xpop();
2042  d1 = hoc_xpop();
2043  d1 = (double) (d1 > d2 + hoc_epsilon);
2044  hoc_pushx(d1);
2045 }
2046 
2047 void hoc_lt() {
2048  double d1, d2;
2049  d2 = hoc_xpop();
2050  d1 = hoc_xpop();
2051  d1 = (double) (d1 < d2 - hoc_epsilon);
2052  hoc_pushx(d1);
2053 }
2054 
2055 void hoc_ge(void) {
2056  double d1, d2;
2057  d2 = hoc_xpop();
2058  d1 = hoc_xpop();
2059  d1 = (double) (d1 >= d2 - hoc_epsilon);
2060  hoc_pushx(d1);
2061 }
2062 
2063 void hoc_le(void) {
2064  double d1, d2;
2065  d2 = hoc_xpop();
2066  d1 = hoc_xpop();
2067  d1 = (double) (d1 <= d2 + hoc_epsilon);
2068  hoc_pushx(d1);
2069 }
2070 
2071 void hoc_eq() {
2072  /* auto const& entry1 = */ get_stack_entry_variant(0);
2073  auto const& entry2 = get_stack_entry_variant(1);
2074  auto const type2 = get_legacy_int_type(entry2);
2075  double result{};
2076  switch (type2) {
2077  case NUMBER: {
2078  double d2{hoc_xpop()};
2079  double d1{hoc_xpop()};
2080  result = d1 <= d2 + hoc_epsilon && d1 >= d2 - hoc_epsilon;
2081  } break;
2082  case STRING:
2083  result = (strcmp(*hoc_strpop(), *hoc_strpop()) == 0);
2084  break;
2085  case OBJECTTMP:
2086  case OBJECTVAR: {
2087  Object** o1{hoc_objpop()};
2088  Object** o2{hoc_objpop()};
2089  result = (*o1 == *o2);
2090  hoc_tobj_unref(o1);
2091  hoc_tobj_unref(o2);
2092  } break;
2093  default:
2094  hoc_execerror("don't know how to compare these types", nullptr);
2095  }
2096  hoc_pushx(result);
2097 }
2098 
2099 void hoc_ne() {
2100  auto const& entry1 = get_stack_entry_variant(0);
2101  /* auto const& entry2 = */ get_stack_entry_variant(1);
2102  auto const type1 = get_legacy_int_type(entry1);
2103  double result{};
2104  switch (type1) {
2105  case NUMBER: {
2106  double d2{hoc_xpop()};
2107  double d1{hoc_xpop()};
2108  result = (d1 < d2 - hoc_epsilon || d1 > d2 + hoc_epsilon);
2109  } break;
2110  case STRING:
2111  result = (strcmp(*hoc_strpop(), *hoc_strpop()) != 0);
2112  break;
2113  case OBJECTTMP:
2114  case OBJECTVAR: {
2115  Object** o1{hoc_objpop()};
2116  Object** o2{hoc_objpop()};
2117  result = (*o1 != *o2);
2118  hoc_tobj_unref(o1);
2119  hoc_tobj_unref(o2);
2120  } break;
2121  default:
2122  hoc_execerror("don't know how to compare these types", nullptr);
2123  }
2124  hoc_pushx(result);
2125 }
2126 
2127 void hoc_and() {
2128  double const d2{hoc_xpop()};
2129  double const d1{hoc_xpop()};
2130  double const result = d1 != 0.0 && d2 != 0.0;
2131  hoc_pushx(result);
2132 }
2133 
2134 void hoc_or(void) {
2135  double d1, d2;
2136  d2 = hoc_xpop();
2137  d1 = hoc_xpop();
2138  d1 = (double) (d1 != 0.0 || d2 != 0.0);
2139  hoc_pushx(d1);
2140 }
2141 
2142 void hoc_not(void) {
2143  double d;
2144  d = hoc_xpop();
2145  d = (double) (d == 0.0);
2146  hoc_pushx(d);
2147 }
2148 
2149 // arg1 raised to arg2
2150 void hoc_power() {
2151  double d1, d2;
2152  d2 = hoc_xpop();
2153  d1 = hoc_xpop();
2154  d1 = hoc_Pow(d1, d2);
2155  hoc_pushx(d1);
2156 }
2157 
2158 // assign result of execute to top symbol
2159 void hoc_assign() {
2160  Objectdata* odsav;
2161  Object* obsav = 0;
2162  Symlist* slsav;
2163  int op;
2164  Symbol* sym;
2165  double d2;
2166  op = (pc++)->i;
2167  sym = hoc_spop();
2168  if (sym->cpublic == 2) {
2169  sym = sym->u.sym;
2170  odsav = hoc_objectdata_save();
2171  obsav = hoc_thisobject;
2172  slsav = hoc_symlist;
2174  hoc_thisobject = 0;
2176  }
2177  d2 = hoc_xpop();
2178  switch (sym->type) {
2179  case UNDEF:
2180  hoc_execerror(sym->name, "undefined variable");
2181  case VAR:
2182  if (!is_array(*sym)) {
2183  switch (sym->subtype) {
2184  case USERDOUBLE:
2185  if (op) {
2186  d2 = hoc_opasgn(op, *(sym->u.pval), d2);
2187  }
2188  *(sym->u.pval) = d2;
2189  break;
2190  case USERINT:
2191  if (op) {
2192  d2 = hoc_opasgn(op, (double) (*(sym->u.pvalint)), d2);
2193  }
2194  *(sym->u.pvalint) = (int) (d2 + hoc_epsilon);
2195  break;
2196  case USERPROPERTY:
2197  cable_prop_assign(sym, &d2, op);
2198  break;
2199  case USERFLOAT:
2200  if (op) {
2201  d2 = hoc_opasgn(op, (double) (*(sym->u.pvalfloat)), d2);
2202  }
2203  *(sym->u.pvalfloat) = (float) (d2);
2204  break;
2205  default:
2206  if (op) {
2207  d2 = hoc_opasgn(op, *(OPVAL(sym)), d2);
2208  }
2209  *(OPVAL(sym)) = d2;
2210  break;
2211  }
2212  } else {
2213  int ind;
2214  switch (sym->subtype) {
2215  case USERDOUBLE:
2216  ind = hoc_araypt(sym, SYMBOL);
2217  if (op) {
2218  d2 = hoc_opasgn(op, (sym->u.pval)[ind], d2);
2219  }
2220  (sym->u.pval)[ind] = d2;
2221  break;
2222  case USERINT:
2223  ind = hoc_araypt(sym, SYMBOL);
2224  if (op) {
2225  d2 = hoc_opasgn(op, (double) ((sym->u.pvalint)[ind]), d2);
2226  }
2227  (sym->u.pvalint)[ind] = (int) (d2 + hoc_epsilon);
2228  break;
2229  case USERFLOAT:
2230  ind = hoc_araypt(sym, SYMBOL);
2231  if (op) {
2232  d2 = hoc_opasgn(op, (double) ((sym->u.pvalfloat)[ind]), d2);
2233  }
2234  (sym->u.pvalfloat)[ind] = (float) d2;
2235  break;
2236  default:
2237  ind = hoc_araypt(sym, OBJECTVAR);
2238  if (op) {
2239  d2 = hoc_opasgn(op, (OPVAL(sym))[ind], d2);
2240  }
2241  (OPVAL(sym))[ind] = d2;
2242  break;
2243  }
2244  }
2245  break;
2246  case AUTO:
2247  if (op) {
2248  d2 = hoc_opasgn(op, cast<double>(fp->argn[sym->u.u_auto]), d2);
2249  }
2250  fp->argn[sym->u.u_auto] = d2;
2251  break;
2252  default:
2253  hoc_execerror("assignment to non-variable", sym->name);
2254  }
2255  if (obsav) {
2257  hoc_thisobject = obsav;
2258  hoc_symlist = slsav;
2259  }
2260  hoc_pushx(d2);
2261 }
2262 
2263 void hoc_assign_str(char** cpp, const char* buf) {
2264  char* s = *cpp;
2265  *cpp = (char*) emalloc((unsigned) (strlen(buf) + 1));
2266  Strcpy(*cpp, buf);
2267  if (s) {
2268  hoc_free_string(s);
2269  }
2270 }
2271 
2272 void hoc_assstr(void) { /* assign string on top to stack - 1 */
2273  char **ps1, **ps2;
2274 
2275  ps1 = hoc_strpop();
2276  ps2 = hoc_strpop();
2277  hoc_assign_str(ps2, *ps1);
2278 }
2279 
2280 // returns array string for multiple dimensions
2281 char* hoc_araystr(Symbol* sym, int index, Objectdata* obd) {
2282  static char name[100];
2283  char* cp = name + 100;
2284  char buf[20];
2285  int i, n, j, n1;
2286 
2287  *--cp = '\0';
2288  if (is_array(*sym)) {
2289  Arrayinfo* a;
2290  if (sym->subtype == 0) {
2291  a = obd[sym->u.oboff + 1].arayinfo;
2292  } else {
2293  a = sym->arayinfo;
2294  }
2295  for (i = a->nsub - 1; i >= 0; --i) {
2296  n = a->sub[i];
2297  j = index % n;
2298  index /= n;
2299  Sprintf(buf, "%d", j);
2300  n1 = strlen(buf);
2301  assert(n1 + 2 < cp - name);
2302  *--cp = ']';
2303  for (j = n1 - 1; j >= 0; --j) {
2304  *--cp = buf[j];
2305  }
2306  *--cp = '[';
2307  }
2308  }
2309  return cp;
2310 }
2311 
2312 // Raise error if compile time number of dimensions differs from
2313 // execution time number of dimensions. Program next item is Symbol*.
2314 static void ndim_chk_helper(int ndim) {
2315  Symbol* sp = (pc++)->sym;
2316  int ndim_now = sp->arayinfo ? sp->arayinfo->nsub : 0;
2317  if (ndim_now != ndim) {
2318  hoc_execerr_ext("array dimension of %s now %d (at compile time it was %d)",
2319  sp->name,
2320  ndim_now,
2321  ndim);
2322  }
2323  // if this is missing when hoc_araypt is called, it means the symbol
2324  // was compiled as a scalar.
2325  hoc_push_ndim(ndim);
2326 }
2327 
2329  ndim_chk_helper(1);
2330 }
2332  ndim_chk_helper(2);
2333 }
2335  int ndim = (pc++)->i;
2336  ndim_chk_helper(ndim);
2337 }
2338 
2339 // return subscript - subs in reverse order on stack
2340 int hoc_araypt(Symbol* sp, int type) {
2341  Arrayinfo* const aray{type == OBJECTVAR ? OPARINFO(sp) : sp->arayinfo};
2342  int total{};
2343  int ndim{0};
2344  if (hoc_stack_type_is_ndim()) { // if sp compiled as scalar
2345  ndim = hoc_pop_ndim(); // do not raise error here but below.
2346  }
2347  if (ndim != aray->nsub) {
2348  hoc_execerr_ext("array dimension of %s now %d (at compile time it was %d)",
2349  sp->name,
2350  aray->nsub,
2351  ndim);
2352  }
2353  for (int i = 0; i < aray->nsub; ++i) {
2354  int const d = hoc_look_inside_stack<double>(aray->nsub - 1 - i) + hoc_epsilon;
2355  if (d < 0 || d >= aray->sub[i]) {
2357  "subscript %d index %d of %s out of range %d", i, d, sp->name, aray->sub[i]);
2358  }
2359  total = total * (aray->sub[i]) + d;
2360  }
2361  for (int i = 0; i < aray->nsub; ++i) {
2362  hoc_nopop();
2363  }
2364  int varn;
2365  if (hoc_do_equation && sp->s_varn != 0 && (varn = (aray->a_varn)[total]) != 0 &&
2366  hoc_access[varn] == 0) {
2367  hoc_access[varn] = hoc_var_access;
2368  hoc_var_access = varn;
2369  }
2370  return total;
2371 }
2372 
2373 // pop top value from stack, print it
2374 void hoc_print() {
2375  Printf("\t");
2376  hoc_prexpr();
2377  Printf("\n");
2378 }
2379 
2380 // print numeric value
2381 void hoc_prexpr() {
2382  static HocStr* s;
2383  char* ss;
2384  Object** pob;
2385 
2386  if (!s)
2387  s = hocstr_create(256);
2388  switch (hoc_stacktype()) {
2389  case NUMBER:
2390  std::snprintf(s->buf, s->size + 1, "%.8g ", hoc_xpop());
2391  break;
2392  case STRING:
2393  ss = *(hoc_strpop());
2394  hocstr_resize(s, strlen(ss) + 1);
2395  std::snprintf(s->buf, s->size + 1, "%s ", ss);
2396  break;
2397  case OBJECTTMP:
2398  case OBJECTVAR:
2399  pob = hoc_objpop();
2400  std::snprintf(s->buf, s->size + 1, "%s ", hoc_object_name(*pob));
2401  hoc_tobj_unref(pob);
2402  break;
2403  default:
2404  hoc_execerror("Don't know how to print this type\n", nullptr);
2405  }
2406  hoc_plprint(s->buf);
2407 }
2408 
2409 void hoc_prstr(void) /* print string value */
2410 {
2411  static HocStr* s;
2412  char** cpp;
2413  if (!s)
2414  s = hocstr_create(256);
2415  cpp = hoc_strpop();
2416  hocstr_resize(s, strlen(*cpp) + 10);
2417  std::snprintf(s->buf, s->size + 1, "%s", *cpp);
2418  hoc_plprint(s->buf);
2419 }
2420 
2421 /*-----------------------------------------------------------------*/
2423 /* Added 15-JUN-90 by JCW. This routine deletes a
2424 "defined-on-the-fly" variable from the symbol
2425 list. */
2426 /* modified greatly by Hines. Very unsafe in general. */
2427 {
2428 #if 1
2429  /* copy address of the symbol that will be deleted */
2430  Symbol* doomed = (pc++)->sym;
2431 
2432  /* hoc_execerror("delete_symbol doesn't work right now.", (char *)0);*/
2433  if (doomed->type == UNDEF)
2434  fprintf(stderr, "%s: no such variable\n", doomed->name);
2435  else if (doomed->defined_on_the_fly == 0)
2436  fprintf(stderr, "%s: can't be deleted\n", doomed->name);
2437  else {
2438  extern void hoc_free_symspace(Symbol*);
2439  hoc_free_symspace(doomed);
2440  }
2441 #endif
2442 }
2443 
2444 /*----------------------------------------------------------*/
2445 
2446 void hoc_newline(void) /* print newline */
2447 {
2448  hoc_plprint("\n");
2449 }
2450 
2451 void hoc_varread(void) /* read into variable */
2452 {
2453  double d = 0.0;
2454  extern NrnFILEWrap* hoc_fin;
2455  Symbol* var = (pc++)->sym;
2456 
2457  assert(var->cpublic != 2);
2458  if (!((var->type == VAR || var->type == UNDEF) && !is_array(*var) && var->subtype == NOTUSER)) {
2459  hoc_execerror(var->name, "is not a scalar variable");
2460  }
2461 Again:
2462  switch (nrn_fw_fscanf(hoc_fin, "%lf", OPVAL(var))) {
2463  case EOF:
2464  if (hoc_moreinput())
2465  goto Again;
2466  d = *(OPVAL(var)) = 0.0;
2467  break;
2468  case 0:
2469  hoc_execerror("non-number read into", var->name);
2470  break;
2471  default:
2472  d = 1.0;
2473  break;
2474  }
2475  var->type = VAR;
2476  hoc_pushx(d);
2477 }
2478 
2479 
2480 static Inst* codechk(void) {
2481  if (hoc_progp >= hoc_prog + NPROG - 1)
2482  hoc_execerror("procedure too big", (char*) 0);
2483  if (hoc_zzdebug)
2484  debugzz(hoc_progp);
2485  return hoc_progp++;
2486 }
2487 
2488 Inst* hoc_Code(Pfrv f) { /* install one instruction or operand */
2489  hoc_progp->pf = f;
2490  return codechk();
2491 }
2492 
2493 Inst* hoc_codei(int f) {
2494  hoc_progp->pf = NULL; /* zero high order bits to avoid debugzz problem */
2495  hoc_progp->i = f;
2496  return codechk();
2497 }
2498 
2499 Inst* hoc_codeptr(void* vp) {
2500  hoc_progp->ptr = vp;
2501  return codechk();
2502 }
2503 
2505  hoc_progp->sym = f;
2506  IGNORE(codechk());
2507 }
2508 
2509 void hoc_codein(Inst* f) {
2510  hoc_progp->in = f;
2511  IGNORE(codechk());
2512 }
2513 
2514 void hoc_insertcode(Inst* begin, Inst* end, Pfrv f) {
2515  Inst* i;
2516  for (i = end - 1; i != begin; i--) {
2517  *i = *(i - 1);
2518  }
2519  begin->pf = f;
2520 
2521  if (hoc_zzdebug) {
2522  Inst* p;
2523  printf("insert code: what follows is the entire code so far\n");
2524  for (p = hoc_prog; p < hoc_progp; ++p) {
2525  debugzz(p);
2526  }
2527  printf("end of insert code debugging\n");
2528  }
2529 }
2530 
2531 void hoc_execute(Inst* p) /* run the machine */
2532 {
2533  Inst* pcsav;
2534 
2535  BBSPOLL
2536  for (pc = p; pc->in != STOP && !hoc_returning;) {
2537  if (hoc_intset)
2538  hoc_execerror("interrupted", (char*) 0);
2539  /* (*((pc++)->pf))(); DEC 5000 increments pc after the return!*/
2540  pcsav = pc++;
2541  (*((pcsav)->pf))();
2542  }
2543 }
int cxx_demangle(const char *symbol, char **funcname, size_t *funcname_sz)
#define STRING
Definition: bbslsrv.cpp:9
void rangevareval(void)
Definition: cabcode.cpp:1373
int segment_limits(double *pdx)
Definition: cabcode.cpp:1784
void nrn_secstack(int i)
Definition: cabcode.cpp:89
void rangevarevalpointer()
Definition: cabcode.cpp:1339
double cable_prop_eval(Symbol *sym)
Definition: cabcode.cpp:1447
void cable_prop_assign(Symbol *sym, double *pd, int op)
Definition: cabcode.cpp:1512
void nrn_initcode(void)
Definition: cabcode.cpp:107
double * cable_prop_eval_pointer(Symbol *sym)
Definition: cabcode.cpp:1461
void rangepoint(void)
Definition: cabcode.cpp:1382
int bbs_poll_
Definition: code.cpp:32
void hoc_pushzero()
Definition: code.cpp:989
static Frame * frame
Definition: code.cpp:96
static Inst * codechk(void)
Definition: code.cpp:2480
#define BBSPOLL
Definition: code.cpp:34
void hoc_argref(void)
Definition: code.cpp:1730
Inst * hoc_prog_parse_recover
Definition: code.cpp:80
static void frameobj_clean(Frame *f)
Definition: code.cpp:349
void hoc_arg()
Definition: code.cpp:1656
void hoc_and()
Definition: code.cpp:2127
void hoc_prexpr()
Definition: code.cpp:2381
void hoc_power()
Definition: code.cpp:2150
void hoc_ge(void)
Definition: code.cpp:2055
void hoc_Break(void)
Definition: code.cpp:1298
void for_segment1(void)
Definition: code.cpp:1274
void hoc_Stop(void)
Definition: code.cpp:1308
Inst * hoc_Code(Pfrv f)
Definition: code.cpp:2488
void hoc_cyclic(void)
Definition: code.cpp:2007
void hoc_ne()
Definition: code.cpp:2099
Inst * hoc_codei(int f)
Definition: code.cpp:2493
void hoc_delete_symbol(void)
Definition: code.cpp:2422
static char * stmp[HOC_TEMP_CHARPTR_SIZE]
Definition: code.cpp:714
static Frame * rframe
Definition: code.cpp:505
void hoc_argassign(void)
Definition: code.cpp:1692
#define HOC_TEMP_CHARPTR_SIZE
Definition: code.cpp:713
void oc_save_code(Inst **a1, Inst **a2, std::size_t &a3, Frame **a4, int *a5, int *a6, Inst **a7, Frame **a8, std::size_t &a9, Symlist **a10, Inst **a11, int *a12)
Definition: code.cpp:509
static Object ** hoc_temp_obj_pool_
Definition: code.cpp:118
static void for_segment2(Symbol *sym, int mode)
Definition: code.cpp:1190
static int tobj_count
Definition: code.cpp:120
void hoc_varpush()
Definition: code.cpp:994
void hoc_call()
Definition: code.cpp:1398
void hoc_init_space()
Definition: code.cpp:416
static void rinitcode()
Definition: code.cpp:586
Symbol * hoc_get_last_pointer_symbol(void)
Definition: code.cpp:1789
std::variant< double, Symbol *, int, stack_ndim_datum, Object **, Object *, char **, neuron::container::generic_data_handle, std::nullptr_t > StackDatum
Definition: code.cpp:66
static void ndim_chk_helper(int ndim)
Definition: code.cpp:2314
#define TOBJ_POOL_SIZE
Definition: code.cpp:117
static int maxinitfcns
Definition: code.cpp:432
#define MAXINITFCNS
Definition: code.cpp:431
void hoc_gt(void)
Definition: code.cpp:2039
void hoc_prstr(void)
Definition: code.cpp:2409
Inst * hoc_progp
Definition: code.cpp:77
void hoc_iterator_stmt()
Definition: code.cpp:1130
static Pfrv initfcns[MAXINITFCNS]
Definition: code.cpp:433
char * hoc_strgets(char *cbuf, int nc)
Definition: code.cpp:576
static Frame * fp
Definition: code.cpp:96
void hoc_div(void)
Definition: code.cpp:1996
static std::size_t rstack
Definition: code.cpp:506
void hoc_eq()
Definition: code.cpp:2071
void hoc_shortfor(void)
Definition: code.cpp:1030
void hocobjret(void)
Definition: code.cpp:1544
void hoc_assign()
Definition: code.cpp:2159
void hoc_codein(Inst *f)
Definition: code.cpp:2509
void hoc_lt()
Definition: code.cpp:2047
void hoc_evalpointer()
Definition: code.cpp:1903
int nrn_isecstack()
Definition: cabcode.cpp:85
void hoc_bltin(void)
Definition: code.cpp:1760
void hoc_eval(void)
Definition: code.cpp:1827
void hoc_mul(void)
Definition: code.cpp:1987
void hoc_varread(void)
Definition: code.cpp:2451
void oc_restore_code(Inst **a1, Inst **a2, std::size_t &a3, Frame **a4, int *a5, int *a6, Inst **a7, Frame **a8, std::size_t &a9, Symlist **a10, Inst **a11, int *a12)
Definition: code.cpp:535
void hoc_ifcode(void)
Definition: code.cpp:1284
void hoc_push_string()
Definition: code.cpp:805
void hoc_add(void)
Definition: code.cpp:1969
void hoc_unref_defer()
Definition: code.cpp:181
void hoc_argrefasgn(void)
Definition: code.cpp:1709
void hoc_constpush()
Definition: code.cpp:984
void hoc_chk_sym_has_ndim1()
Definition: code.cpp:2328
void hoc_iterator_object(Symbol *sym, int argcount, Inst *beginpc, Inst *endpc, Object *ob)
Definition: code.cpp:1102
void hoc_Argtype()
Definition: code.cpp:1580
void hoc_Numarg(void)
Definition: code.cpp:1568
void hoc_stringarg(void)
Definition: code.cpp:1664
void hoc_on_init_register(Pfrv pf)
Definition: code.cpp:462
static void frame_objauto_recover_on_err(Frame *ff)
Definition: code.cpp:361
int hoc_strgets_need(void)
Definition: code.cpp:572
void hoc_procret(void)
Definition: code.cpp:1533
void hoc_forcode(void)
Definition: code.cpp:1000
void hoc_sub(void)
Definition: code.cpp:1978
void hoc_Continue(void)
Definition: code.cpp:1303
static int obj_pool_index_
Definition: code.cpp:119
std::ostream & operator<<(std::ostream &os, const stack_ndim_datum &d)
Definition: code.cpp:53
Inst * hoc_prog
Definition: code.cpp:76
#define relative(pc)
Definition: code.cpp:998
void hoc_iterator(void)
Definition: code.cpp:1087
void hoc_codesym(Symbol *f)
Definition: code.cpp:2504
HocReturnType hoc_return_type_code
Definition: code.cpp:42
static int istmp
Definition: code.cpp:715
#define NFRAME
Definition: code.cpp:95
#define NPROG
Definition: code.cpp:75
Inst * hoc_codeptr(void *vp)
Definition: code.cpp:2499
void debugzz(Inst *)
Definition: debug.cpp:32
static Frame * framelast
Definition: code.cpp:96
static const char * parsestr
Definition: code.cpp:507
void hoc_autoobject(void)
Definition: code.cpp:1817
void bbs_handle()
Definition: bbssrvmpi.cpp:210
void for_segment(void)
Definition: code.cpp:1270
static std::vector< StackDatum > stack
The stack.
Definition: code.cpp:73
static Object * unref_defer_
Definition: code.cpp:179
void hoc_negate()
Definition: code.cpp:2034
void hoc_chk_sym_has_ndim2()
Definition: code.cpp:2331
void hoc_newline(void)
Definition: code.cpp:2446
void hoc_argrefarg(void)
Definition: code.cpp:1749
static void stack_obtmp_recover_on_err(int tcnt)
Definition: code.cpp:399
void hoc_assstr(void)
Definition: code.cpp:2272
void hoc_insertcode(Inst *begin, Inst *end, Pfrv f)
Definition: code.cpp:2514
void hoc_not(void)
Definition: code.cpp:2142
void hoc_print()
Definition: code.cpp:2374
void hoc_or(void)
Definition: code.cpp:2134
void hoc_le(void)
Definition: code.cpp:2063
void hoc_execute(Inst *p)
Definition: code.cpp:2531
void hoc_chk_sym_has_ndim()
Definition: code.cpp:2334
Inst * hoc_progbase
Definition: code.cpp:79
void hoc_define(Symbol *sp)
Definition: code.cpp:1313
Inst * hoc_pc
Definition: code.cpp:78
void hoc_funcret(void)
Definition: code.cpp:1523
HocReturnType
Definition: code.h:2
void hoc_object_eval(void)
Definition: hoc_oop.cpp:1341
void hoc_ob_pointer(void)
#define pval
Definition: md1redef.h:40
#define i
Definition: md1redef.h:19
int hoc_zzdebug
Definition: debug.cpp:19
#define yyparse
Definition: difeqdef.h:4
constexpr auto reverse(T &&iterable)
Definition: enumerate.h:62
constexpr auto renumerate(T &&iterable)
Definition: enumerate.h:120
int hoc_var_access
Definition: nonlin.cpp:13
int * hoc_access
Definition: nonlin.cpp:12
int hoc_do_equation
Definition: nonlin.cpp:11
double chkarg(int, double low, double high)
Definition: code2.cpp:626
double hoc_epsilon
Definition: hoc_init.cpp:221
char buf[512]
Definition: init.cpp:13
@ NUMBER
type of ast::Number
int hoc_is_object_arg(int narg)
Definition: code.cpp:876
double hoc_xpop()
Definition: code.cpp:903
void hoc_push_frame(Symbol *sp, int narg)
Definition: code.cpp:1376
void hoc_plprint(const char *)
Definition: plot.cpp:97
void hoc_prstack()
Print up to the 10 most-recently-pushed elements on the stack.
Definition: code.cpp:437
void frame_debug()
Definition: code.cpp:1330
void hoc_push_ndim(int d)
Definition: code.cpp:855
void hoc_run_stmt(Symbol *sym)
Definition: code2.cpp:672
Object ** hoc_objgetarg(int narg)
Definition: code.cpp:1614
void hoc_pushstr(char **d)
Definition: code.cpp:800
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Definition: fileio.cpp:828
double * hoc_getarg(int narg)
Definition: code.cpp:1641
double hoc_call_func(Symbol *s, int narg)
Definition: code.cpp:1477
Symbol * hoc_get_symbol(const char *var)
Definition: code.cpp:1768
int hoc_argindex(void)
Definition: code.cpp:1647
char ** hoc_strpop()
Definition: code.cpp:962
Object * hoc_obj_look_inside_stack(int i)
Definition: code.cpp:885
int hoc_returning
Definition: code.cpp:81
void hoc_ret()
Definition: code.cpp:1502
void hoc_pushpx(double *d)
Definition: code.cpp:834
std::unique_ptr< Object, TmpObjectDeleter > TmpObject
Definition: oc_ansi.h:264
int hoc_inside_stacktype(int i)
Definition: code.cpp:898
void hoc_pushobj(Object **d)
Definition: code.cpp:784
Object ** hoc_objpop()
Pop pointer to object pointer and return top elem from stack.
Definition: code.cpp:943
int hoc_errno_check(void)
Definition: math.cpp:257
void hoc_free_string(char *)
Definition: symbol.cpp:290
int hoc_ParseExec(int yystart)
Definition: code.cpp:603
int hoc_stack_type()
Get the type of the top entry.
Definition: code.cpp:310
void hoc_pushs(Symbol *d)
Definition: code.cpp:841
int hoc_is_str_arg(int narg)
Definition: code.cpp:872
int hoc_stacktype()
Definition: code.cpp:774
int hoc_is_temp_charptr(char **cpp)
Definition: code.cpp:722
double * hoc_pxpop()
Definition: code.cpp:922
bool hoc_stack_type_is_ndim()
Definition: code.cpp:314
Objectdata * hoc_objectdata
Definition: hoc_oop.cpp:122
void hoc_assign_str(char **cpp, const char *buf)
Definition: code.cpp:2263
Object ** hoc_temp_objptr(Object *obj)
Definition: code.cpp:151
int hoc_argtype(int narg)
Definition: code.cpp:860
double hoc_opasgn(int op, double dest, double src)
Definition: code.cpp:1674
void hoc_tobj_unref(Object **p)
Definition: code.cpp:160
int hoc_ipop()
Definition: code.cpp:967
int hoc_is_double_arg(int narg)
Definition: code.cpp:864
void hoc_free_list(Symlist **)
Definition: symbol.cpp:254
int ifarg(int narg)
Definition: code.cpp:1607
char ** hoc_temp_charptr(void)
Definition: code.cpp:717
int hoc_xopen_run(Symbol *sp, const char *str)
Definition: code.cpp:667
void hoc_retpushx(double x)
Definition: hocusr.cpp:154
void hoc_pop_defer()
Definition: code.cpp:318
int hoc_pop_ndim()
Definition: code.cpp:933
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1844
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:73
void hoc_fake_call(Symbol *s)
Definition: code.cpp:1463
void hoc_stkobj_unref(Object *o, int stkindex)
Definition: code.cpp:337
void hoc_initcode()
Definition: code.cpp:473
void hoc_pushx(double d)
Definition: code.cpp:779
Symbol * hoc_spop()
Definition: code.cpp:928
double * hoc_pgetarg(int narg)
Definition: oc_ansi.h:253
int hoc_araypt(Symbol *sp, int type)
Definition: code.cpp:2340
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:868
void hoc_pop_frame(void)
Definition: code.cpp:1387
T const & hoc_look_inside_stack(int i)
Get the stack entry at depth i.
Definition: code.cpp:261
void hoc_nopop()
Definition: code.cpp:972
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1881
void hoc_call_func_result_on_stack(Symbol *s, int narg)
Definition: code.cpp:1482
void hoc_pushi(int d)
Definition: code.cpp:846
Symbol * hoc_parse_stmt(const char *str, Symlist **psymlist)
Definition: code2.cpp:679
char * hoc_araystr(Symbol *sym, int index, Objectdata *obd)
Definition: code.cpp:2281
void hoc_push_object(Object *d)
Definition: code.cpp:793
int hoc_is_tempobj_arg(int narg)
Definition: code.cpp:881
void hoc_push(neuron::container::generic_data_handle handle)
Definition: code.cpp:850
TmpObject hoc_pop_object()
Definition: code.cpp:957
char ** hoc_pgargstr(int narg)
Definition: code.cpp:1623
int hoc_intset
Definition: hoc.cpp:162
HocStr * hocstr_create(size_t size)
Definition: hoc.cpp:828
int hoc_yyparse(void)
Definition: hoc.cpp:1429
int hoc_in_yyparse
Definition: hoc.cpp:1427
int yystart
Definition: hoc.cpp:609
void hocstr_resize(HocStr *hs, size_t n)
Definition: hoc.cpp:847
int hoc_pipeflag
Definition: hoc.cpp:120
int hoc_moreinput()
Definition: hoc.cpp:1022
Objectdata * hoc_objectdata_restore(Objectdata *obdsav)
Definition: hoc_oop.cpp:142
Objectdata * hoc_objectdata_save(void)
Definition: hoc_oop.cpp:132
#define assert(ex)
Definition: hocassrt.h:24
#define USERPROPERTY
Definition: hocdec.h:85
#define USERFLOAT
Definition: hocdec.h:86
#define USERDOUBLE
Definition: hocdec.h:84
#define NOTUSER
Definition: hocdec.h:82
#define getarg
Definition: hocdec.h:17
#define OBJECTTMP
Definition: hocdec.h:88
void(* Pfrv)(void)
Definition: hocdec.h:31
#define OPARINFO(sym)
Definition: hocdec.h:239
bool is_array(const Symbol &sym)
Definition: hocdec.h:136
#define STKOBJ_UNREF
Definition: hocdec.h:89
#define USERINT
Definition: hocdec.h:83
#define OPSTR(sym)
Definition: hocdec.h:235
#define OPVAL(sym)
Definition: hocdec.h:234
#define STOP
Definition: hocdec.h:57
Symlist * hoc_p_symlist
Definition: symbol.cpp:35
static int narg()
Definition: ivocvect.cpp:121
Symlist * hoc_top_level_symlist
Definition: code2.cpp:677
Object * hoc_thisobject
Definition: hoc_oop.cpp:121
long hoc_nstack
Definition: ivocmain.cpp:6
long hoc_nframe
Definition: ivocmain.cpp:6
double var(InputIterator begin, InputIterator end)
Definition: ivocvect.h:108
double hoc_Pow(double x, double y)
Definition: math.cpp:219
#define SYMBOL
Definition: model.h:91
#define IGNORE(arg)
Definition: model.h:224
#define Strcpy
Definition: model.h:215
floor
Definition: extdef.h:4
printf
Definition: extdef.h:5
fabs
Definition: extdef.h:3
const char * name
Definition: init.cpp:16
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
Item * next(Item *item)
Definition: list.cpp:89
void nrn_exit(int err)
Definition: nrnoc_aux.cpp:30
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
static void * emalloc(size_t size)
Definition: mpispike.cpp:30
int hoc_errno_count
Definition: nrnoc_aux.cpp:23
void hoc_warning(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:44
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
constexpr do_not_search_t do_not_search
Definition: data_handle.hpp:11
In mechanism libraries, cannot use auto const token = nrn_ensure_model_data_are_sorted(); because the...
Definition: tnode.hpp:17
int Sprintf(char(&buf)[N], const char *fmt, Args &&... args)
Redirect sprintf to snprintf if the buffer size can be deduced.
Definition: wrap_sprintf.h:14
if(ncell==0)
Definition: cellorder.cpp:785
Definition: code.cpp:83
#define nrn_fw_fscanf
Definition: nrnfilewrap.h:18
FILE NrnFILEWrap
Definition: nrnfilewrap.h:8
int const size_t const size_t n
Definition: nrngsl.h:10
#define FUNCTION(a, b)
Definition: nrngsl.h:5
size_t q
size_t p
size_t j
s
Definition: multisend.cpp:521
short index
Definition: cabvars.h:11
short type
Definition: cabvars.h:10
FILE * hoc_fin
Definition: hoc.cpp:152
Symlist * hoc_symlist
Definition: symbol.cpp:34
Objectdata * hoc_top_level_data
Definition: hoc_oop.cpp:123
int nrnmpi_numprocs_world
int nrnmpi_myid_world
HOC interpreter function declarations (included by hocdec.h)
static uint32_t value
Definition: scoprand.cpp:25
#define xpop
Definition: section.h:36
#define pc
Definition: section.h:37
#define NULL
Definition: spdefs.h:105
void hoc_free_symspace(Symbol *)
Definition: symbol.cpp:166
int nsub
Definition: hocdec.h:61
int sub[1]
Definition: hocdec.h:63
Definition: hocstr.h:6
Definition: hocdec.h:173
Objectdata * dataspace
Definition: hocdec.h:177
int refcount
Definition: hocdec.h:174
cTemplate * ctemplate
Definition: hocdec.h:180
union Object::@47 u
int nauto
Definition: hocdec.h:71
Inst defn
Definition: hocdec.h:67
unsigned long size
Definition: hocdec.h:68
Symlist * list
Definition: hocdec.h:69
int nobjauto
Definition: hocdec.h:72
Definition: model.h:47
Proc * u_proc
Definition: hocdec.h:120
union Symbol::@28 u
short cpublic
Definition: hocdec.h:107
int u_auto
Definition: hocdec.h:118
short type
Definition: model.h:48
int * pvalint
Definition: hocdec.h:116
long subtype
Definition: model.h:49
float * pvalfloat
Definition: hocdec.h:117
Symbol * sym
Definition: hocdec.h:127
unsigned s_varn
Definition: hocdec.h:129
char * name
Definition: model.h:61
double * pval
Definition: hocdec.h:112
int oboff
Definition: hocdec.h:111
Arrayinfo * arayinfo
Definition: hocdec.h:130
short defined_on_the_fly
Definition: hocdec.h:108
Definition: hocdec.h:75
void operator()(Object *) const
Definition: code.cpp:950
Symlist * symtable
Definition: hocdec.h:148
Non-template stable handle to a generic value.
Symbol * sp
Definition: code.cpp:85
StackDatum * argn
Definition: code.cpp:87
Inst * retpc
Definition: code.cpp:86
Inst * iter_stmt_begin
Definition: code.cpp:89
Object * iter_stmt_ob
Definition: code.cpp:90
Object * ob
Definition: code.cpp:91
stack_ndim_datum(int ndim)
Definition: code.cpp:48
Definition: hocdec.h:42
Pfrv pf
Definition: hocdec.h:43
int i
Definition: hocdec.h:54
Symbol * sym
Definition: hocdec.h:52
void * ptr
Definition: hocdec.h:53
Inst * in
Definition: hocdec.h:51
Arrayinfo * arayinfo
Definition: hocdec.h:169
int Fprintf(FILE *stream, const char *fmt, Args... args)
Definition: logger.hpp:8
int Printf(const char *fmt, Args... args)
Definition: logger.hpp:18