PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/src/nmodl/parsact.c

https://bitbucket.org/nrnhines/nrn
C | 1225 lines | 1027 code | 75 blank | 123 comment | 211 complexity | 1661afc6be74f1785bc60ecaad3e9e76 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0
  1. #include <../../nmodlconf.h>
  2. /*
  3. * some parse actions to reduce size of parse.y the installation routines can
  4. * also be used, e.g. in sens to automattically construct variables
  5. */
  6. #include <stdlib.h>
  7. #include "modl.h"
  8. #include "parse1.h"
  9. Symbol *scop_indep; /* independent used by SCoP */
  10. Symbol *indepsym; /* only one independent variable */
  11. Symbol *stepsym; /* one or fewer stepped variables */
  12. List *indeplist; /* FROM TO WITH START UNITS */
  13. extern List *syminorder; /* Order in which variables are output to
  14. * .var file */
  15. #if CVODE
  16. extern List* state_discon_list_;
  17. extern int net_send_seen_;
  18. extern int net_event_seen_;
  19. extern int watch_seen_;
  20. #endif
  21. int protect_;
  22. int protect_include_;
  23. extern Item* vectorize_replacement_item(Item*);
  24. extern int artificial_cell;
  25. extern int vectorize;
  26. extern int assert_threadsafe;
  27. static int type_change();
  28. static long previous_subtype; /* subtype at the sym->level */
  29. static char *previous_str; /* u.str on last install */
  30. void explicit_decl(level, q)
  31. int level;
  32. Item *q;
  33. {
  34. /* used to be inside parse1.y without the lastvars condition
  35. Without the condition it served two purposes.
  36. 1) variables explicitly declared were so marked so that they
  37. would appear first in the .var file. Unmarked variables
  38. appear last.
  39. 2) Give error message if a variable was explicitly declared
  40. more than once.
  41. Now, the merge program produces declaration blocks from
  42. submodels with a prepended LAST_VARS keyword. This implies
  43. 1) that variables in such blocks should appear last (if they
  44. don't appear at the top level) and
  45. 2) multiple declarations are not errors.
  46. Hence we merely enclose the old code in an if statement
  47. The question arises, on multiple declarations, which value
  48. does the .var file get. In the current implementation it
  49. is the last one seen. If this is not right (and a better
  50. method would be keep the value declared closest to the root)
  51. then it will be the responsibility of merge to delete
  52. multiple declarations.
  53. */
  54. /* Solving the multiple declaration problem.
  55. merge now gives the level number of the declaration with
  56. the root file having level number 0, all its submodels having
  57. level number 1, submodels of level 1 submodels having level 2,
  58. etc. The rule is that the lowest level declaration is used.
  59. If two declarations exist at the same level then it is an
  60. error unless their u.str are identical. Since, by the time
  61. this routine is called the latest declaration has already been
  62. installed, each installation routine saves the previous u.str
  63. in a static variable. Also a new field is added to the
  64. symbol structure to keep track of its level. At this time
  65. we retain the EXPLICIT_DECL field for explicit declarations
  66. at the root level. The default level when the symbol is
  67. allocated is 100.
  68. */
  69. Symbol *sym;
  70. sym = SYM(q);
  71. if (!level) { /* No multiple declarations at the root level and
  72. the symbol is marked explicitly declared */
  73. if (sym->usage & EXPLICIT_DECL) {
  74. diag("Multiple declaration of ", sym->name);
  75. }
  76. sym->usage |= EXPLICIT_DECL;
  77. }
  78. /* this ensures that declared PRIMES will appear in .var file */
  79. sym->usage |= DEP;
  80. if (level >= sym->level) {
  81. assert(previous_str);
  82. }
  83. /* resolve possible type conflicts */
  84. if (type_change(sym, level)) {
  85. return;
  86. }
  87. /* resolve which declaration takes precedence */
  88. if (level < sym->level) { /* new one takes precedence */
  89. sym->level = level;
  90. }else if (level > sym->level) { /* old one takes precedence */
  91. sym->u.str = previous_str;
  92. }else if (strcmp(sym->u.str, previous_str) != 0) { /* not identical */
  93. diag(sym->name, " has different values at same level");
  94. }
  95. }
  96. /* restricted type changes are allowed in hierarchical models with each
  97. one producing a message. Notice that multiple declarations at level 0 are
  98. caught as errors in the function above. */
  99. static int type_change(sym, level) /*return 1 if type change, 0 otherwise*/
  100. Symbol *sym;
  101. {
  102. long s, d, c;
  103. s = sym->subtype & STAT;
  104. d = sym->subtype & DEP;
  105. c = sym->subtype & PARM;
  106. if (s && c) {
  107. sym->subtype &= ~c;
  108. Fprintf(stderr, "Notice: %s is promoted from a PARAMETER to a STATE\n", sym->name);
  109. if (previous_subtype & STAT) {
  110. sym->u.str = previous_str;
  111. }
  112. }else if (s && d) {
  113. sym->subtype &= ~d;
  114. Fprintf(stderr, "WARNING: %s is promoted from an ASSIGNED to a STATE\n", sym->name);
  115. if (previous_subtype & STAT) {
  116. sym->u.str = previous_str;
  117. }
  118. }else if (d && c) {
  119. sym->subtype &= ~c;
  120. Fprintf(stderr, "Notice: %s is promoted from a PARAMETER to an ASSIGNED\n", sym->name);
  121. if (previous_subtype & DEP) {
  122. sym->u.str = previous_str;
  123. }
  124. }else{
  125. return 0;
  126. }
  127. if (level < sym->level) {
  128. sym->level = level;
  129. }
  130. return 1;
  131. }
  132. void parm_array_install(n, num, units, limits, index)
  133. Symbol *n;
  134. char *num, *units, *limits;
  135. {
  136. char buf[NRN_BUFSIZE];
  137. previous_subtype = n->subtype;
  138. previous_str = n->u.str;
  139. if (n->u.str == (char *) 0)
  140. Lappendsym(syminorder, n);
  141. n->subtype |= PARM;
  142. n->subtype |= ARRAY;
  143. n->araydim = index;
  144. Sprintf(buf, "[%d]\n%s\n%s\n%s\n", index, num, units, limits);
  145. n->u.str = stralloc(buf, (char *) 0);
  146. }
  147. void parminstall(n, num, units, limits)
  148. Symbol *n;
  149. char *num, *units, *limits;
  150. {
  151. char buf[NRN_BUFSIZE];
  152. previous_subtype = n->subtype;
  153. previous_str = n->u.str;
  154. if (n->u.str == (char *) 0)
  155. Lappendsym(syminorder, n);
  156. n->subtype |= PARM;
  157. Sprintf(buf, "\n%s\n%s\n%s\n", num, units, limits);
  158. n->u.str = stralloc(buf, (char *) 0);
  159. }
  160. /* often we want to install a parameter by default but only
  161. if the user hasn't declared it herself.
  162. */
  163. Symbol *ifnew_parminstall(name, num, units, limits)
  164. char *name, *num, *units, *limits;
  165. {
  166. Symbol *s;
  167. if ((s = lookup(name)) == SYM0) {
  168. s = install(name, NAME);
  169. parminstall(s, num, units, limits);
  170. }
  171. if (!(s->subtype)) {
  172. /* can happen when PRIME used in MATCH */
  173. parminstall(s, num, units, limits);
  174. }
  175. if (!(s->subtype & (PARM | STEP1))) {
  176. /* special case is scop_indep can be a PARM but not indepsym */
  177. if (scop_indep == indepsym || s != scop_indep) {
  178. diag(s->name, " can't be declared a parameter by default");
  179. }
  180. }
  181. return s;
  182. }
  183. void steppedinstall(n, q1, q2, units)
  184. Symbol *n;
  185. Item *q1, *q2;
  186. char *units;
  187. {
  188. int i;
  189. char buf[NRN_BUFSIZE];
  190. static int seestep = 0;
  191. previous_subtype = n->subtype;
  192. previous_str = n->u.str;
  193. if (seestep) {
  194. diag("Only one STEPPED variable can be defined", (char *) 0);
  195. }
  196. seestep = 1;
  197. stepsym = n;
  198. i = 0;
  199. Strcpy(buf, "\n");
  200. Strcat(buf, STR(q1));
  201. while (q1 != q2) {
  202. q1 = q1->next;
  203. Strcat(buf, SYM(q1)->name); /* , is a symbol */
  204. q1 = q1->next;
  205. Strcat(buf, STR(q1));
  206. i++;
  207. if (i > 5) {
  208. diag("Maximum of 5 steps in a stepped variable",
  209. (char *) 0);
  210. }
  211. }
  212. Strcat(buf, "\n");
  213. Strcat(buf, units);
  214. Strcat(buf, "\n");
  215. n->subtype |= STEP1;
  216. n->u.str = stralloc(buf, (char *) 0);
  217. }
  218. static char *indepunits = "";
  219. #if NMODL
  220. int using_default_indep;
  221. #endif
  222. void indepinstall(n, from, to, with, qstart, units, scop)
  223. Symbol *n;
  224. char *from, *to, *with, *units;
  225. Item *qstart; /* ITEM0 if not present */
  226. int scop; /*1 if declaring the scop independent*/
  227. {
  228. char buf[NRN_BUFSIZE];
  229. /* scop_indep may turn out to be different from indepsym. If this is the case
  230. then indepsym will be a constant in the .var file (see parout.c).
  231. If they are the same, then u.str gets the info from SCOP.
  232. */
  233. if (!scop) {
  234. #if NMODL
  235. if (using_default_indep) {
  236. using_default_indep = 0;
  237. if (indepsym != n) {
  238. indepsym->subtype &= ~INDEP;
  239. parminstall(indepsym, "0", "ms", "");
  240. }
  241. indepsym = (Symbol*)0;
  242. }
  243. #endif
  244. if (indepsym) {
  245. diag("Only one independent variable can be defined", (char *) 0);
  246. }
  247. indeplist = newlist();
  248. Lappendstr(indeplist, from);
  249. Lappendstr(indeplist, to);
  250. Lappendstr(indeplist, with);
  251. if (qstart) {
  252. Lappendstr(indeplist, STR(qstart));
  253. }else{
  254. Lappendstr(indeplist, from);
  255. }
  256. Lappendstr(indeplist, units);
  257. n->subtype |= INDEP;
  258. indepunits = stralloc(units, (char *) 0);
  259. if (n != scop_indep) {
  260. Sprintf(buf, "\n%s*%s(%s)\n%s\n", from, to, with, units);
  261. n->u.str = stralloc(buf, (char *) 0);
  262. }
  263. indepsym = n;
  264. if (!scop_indep) {
  265. scop_indep = indepsym;
  266. }
  267. }else{
  268. n->subtype |= INDEP;
  269. Sprintf(buf, "\n%s*%s(%s)\n%s\n", from, to, with, units);
  270. n->u.str = stralloc(buf, (char *) 0);
  271. scop_indep = n;
  272. }
  273. }
  274. /*
  275. * installation of dependent and state variables type 0 -- dependent; 1 --
  276. * state index 0 -- scalar; otherwise -- array qs -- item pointer to START
  277. * const string makeconst 0 -- do not make a default constant for state 1 --
  278. * make sure name0 exists For states Dname and name0 are normally created.
  279. * However Dname will not appear in the .var file unless it is used -- see
  280. * parout.c.
  281. */
  282. void depinstall(type, n, index, from, to, units, qs, makeconst, abstol)
  283. int type, index, makeconst;
  284. Symbol *n;
  285. char *from, *to, *units, *abstol;
  286. Item *qs;
  287. {
  288. char buf[NRN_BUFSIZE], *pstr;
  289. int c;
  290. if (!type && strlen(abstol)>0) {
  291. printf("abstol = |%s|\n", abstol);
  292. diag(n, "tolerance can be specified only for a STATE");
  293. }
  294. pstr = n->u.str; /* make it work even if recursive */
  295. if (n->u.str == (char *) 0)
  296. Lappendsym(syminorder, n);
  297. if (type) {
  298. n->subtype |= STAT;
  299. c = ':';
  300. statdefault(n, index, units, qs, makeconst);
  301. } else {
  302. n->subtype |= DEP;
  303. c = ';';
  304. if (qs) {
  305. diag("START not legal except in STATE block", (char *) 0);
  306. }
  307. }
  308. if (index) {
  309. Sprintf(buf, "[%d]\n%s%c%s\n%s\n%s\n", index, from, c, to, units, abstol);
  310. n->araydim = index;
  311. n->subtype |= ARRAY;
  312. } else {
  313. Sprintf(buf, "\n%s%c%s\n%s\n%s\n", from, c, to, units, abstol);
  314. }
  315. n->u.str = stralloc(buf, (char *) 0);
  316. previous_subtype = n->subtype;
  317. previous_str = pstr;
  318. }
  319. void statdefault(n, index, units, qs, makeconst)
  320. Symbol *n;
  321. int index, makeconst;
  322. char *units;
  323. Item *qs;
  324. {
  325. char nam[30], *un;
  326. Symbol *s;
  327. if (n->type != NAME && n->type != PRIME) {
  328. diag(n->name, " can't be a STATE");
  329. }
  330. if (makeconst) {
  331. Sprintf(nam, "%s0", n->name);
  332. s = ifnew_parminstall(nam, "0", units, "");
  333. if (qs) { /*replace with proper default*/
  334. parminstall(s, STR(qs), units, "");
  335. }
  336. }
  337. Sprintf(nam, "%s/%s", units, indepunits);
  338. un = stralloc(nam, (char *) 0);
  339. Sprintf(nam, "D%s", n->name);
  340. if ((s = lookup(nam)) == SYM0) { /* install the prime as a DEP */
  341. s = install(nam, PRIME);
  342. depinstall(0, s, index, "0", "1", un, ITEM0, 0, "");
  343. }
  344. }
  345. /* the problem is that qpar->next may already have a _p, ..., _nt
  346. vectorize_substitute, and qpar->next is often normally "" instead of ')'
  347. for the no arg case.
  348. */
  349. static int func_arg_examine(Item* qpar, Item* qend) {
  350. Item* q;
  351. int b = 1; /* real args exist case */
  352. q = qpar->next;
  353. if (q->itemtype == SYMBOL && strcmp(SYM(q)->name, ")") == 0) {
  354. b = 0; /* definitely no arg */
  355. }
  356. if (q->itemtype == STRING && strcmp(STR(q), "") == 0) {
  357. if (vectorize_replacement_item(q)) {
  358. b = 2; /* _p,..._nt already there */
  359. } else if (q->next->itemtype == SYMBOL && strcmp(SYM(q->next)->name, ")") == 0) {
  360. b = 0; /* definitely no arg */
  361. }
  362. }
  363. return b;
  364. }
  365. void vectorize_scan_for_func(Item* q1, Item* q2) {
  366. Item* q, *qq;
  367. int b;
  368. return;
  369. for (q = q1; q != q2; q = q->next) {
  370. if (q->itemtype == SYMBOL) {
  371. Symbol* s = SYM(q);
  372. if ((s->usage & FUNCT) && !(s->subtype & (EXTDEF))) {
  373. if (q->next->itemtype == SYMBOL && strcmp(SYM(q->next)->name, "(") == 0) {
  374. int b = func_arg_examine(q->next, q2);
  375. if (b == 0) { /* no args */
  376. vectorize_substitute(q->next, "(_p, _ppvar, _thread, _nt");
  377. }else if (b == 1) { /* real args */
  378. vectorize_substitute(q->next, "(_p, _ppvar, _thread, _nt,");
  379. } /* else no _p.._nt already there */
  380. }
  381. }
  382. }
  383. }
  384. }
  385. void defarg(q1, q2) /* copy arg list and define as doubles */
  386. Item *q1, *q2;
  387. {
  388. Item *q3, *q;
  389. if (q1->next == q2) {
  390. #if VECTORIZE
  391. vectorize_substitute(insertstr(q2, ""), "_threadargsproto_");
  392. #endif
  393. return;
  394. }
  395. for (q = q1->next; q != q2; q = q->next) {
  396. if (strcmp(SYM(q)->name, ",") != 0) {
  397. insertstr(q, "double");
  398. }
  399. }
  400. #if VECTORIZE
  401. vectorize_substitute(insertstr(q1->next, ""), "_threadargsprotocomma_");
  402. #endif
  403. }
  404. void lag_stmt(q1, blocktype) /* LAG name1 BY name2 */
  405. Item *q1;
  406. int blocktype;
  407. {
  408. Symbol *name1, *name2, *lagval;
  409. /*ARGSUSED*/
  410. /* parse */
  411. name1 = SYM(q1->next);
  412. delete(q1->next);
  413. delete(q1->next);
  414. name2 = SYM(q1->next);
  415. delete(q1->next);
  416. name1->usage |= DEP;
  417. name2->usage |= DEP;
  418. /* check */
  419. if (!indepsym) {
  420. diag("INDEPENDENT variable must be declared to process",
  421. " the LAG statement");
  422. }
  423. if (!(name1->subtype & (DEP | STAT))) {
  424. diag(name1->name, " not a STATE or DEPENDENT variable");
  425. }
  426. if (!(name2->subtype & (PARM | nmodlCONST))) {
  427. diag(name2->name, " not a CONSTANT or PARAMETER");
  428. }
  429. Sprintf(buf, "lag_%s_%s", name1->name, name2->name);
  430. if (lookup(buf)) {
  431. diag(buf, " already in use");
  432. }
  433. /* create */
  434. lagval = install(buf, NAME);
  435. lagval->usage |= DEP;
  436. lagval->subtype |= DEP;
  437. if (name1->subtype & ARRAY) {
  438. lagval->subtype |= ARRAY;
  439. lagval->araydim = name1->araydim;
  440. }
  441. if (lagval->subtype & ARRAY) {
  442. Sprintf(buf, "static double *%s;\n", lagval->name);
  443. Linsertstr(procfunc, buf);
  444. Sprintf(buf, "%s = lag(%s, %s, %s, %d);\n", lagval->name,
  445. name1->name, indepsym->name, name2->name, lagval->araydim);
  446. }else{
  447. Sprintf(buf, "static double %s;\n", lagval->name);
  448. Linsertstr(procfunc, buf);
  449. Sprintf(buf, "%s = *lag(&(%s), %s, %s, 0);\n", lagval->name,
  450. name1->name, indepsym->name, name2->name);
  451. }
  452. replacstr(q1, buf);
  453. }
  454. void queue_stmt(q1, q2)
  455. Item *q1, *q2;
  456. {
  457. Symbol *s;
  458. static int first=1;
  459. if (first) {
  460. first = 0;
  461. Linsertstr(initfunc, "initqueue();\n");
  462. }
  463. if (SYM(q1)->type == PUTQ) {
  464. replacstr(q1, "enqueue(");
  465. }else{
  466. replacstr(q1, "dequeue(");
  467. }
  468. s = SYM(q2);
  469. s->usage |= DEP;
  470. if (!(s->subtype)) {
  471. diag(s->name, " not declared");
  472. }
  473. if (s->subtype & ARRAY) {
  474. Sprintf(buf, "%s, %d);\n", s->name, s->araydim);
  475. }else{
  476. Sprintf(buf, "&(%s), 1);\n", s->name);
  477. }
  478. replacstr(q2, buf);
  479. }
  480. void add_reset_args(q)
  481. Item *q;
  482. {
  483. static int reset_fun_cnt=0;
  484. reset_fun_cnt++;
  485. Sprintf(buf, "&_reset, &_freset%d,", reset_fun_cnt);
  486. Insertstr(q->next, buf);
  487. Sprintf(buf, "static double _freset%d;\n", reset_fun_cnt);
  488. Lappendstr(firstlist, buf);
  489. }
  490. void add_nrnthread_arg(q)
  491. Item *q;
  492. {
  493. vectorize_substitute(insertstr(q->next, "nrn_threads,"), "_nt,");
  494. }
  495. /* table manipulation */
  496. /* arglist must have exactly one argument
  497. tablist contains 1) list of names to be looked up (must be empty if
  498. qtype is FUNCTION and nonempty if qtype is PROCEDURE).
  499. 2) From expression list
  500. 3) To expression list
  501. 4) With integer string
  502. 5) DEPEND list as list of names
  503. The qname does not have a _l if a function. The arg names all have _l
  504. prefixes.
  505. */
  506. /* checking and creation of table has been moved to separate function called
  507. static _check_func.
  508. */
  509. /* to allow vectorization the table functions are separated into
  510. name robust function. makes sure
  511. table is uptodate (calls check_name)
  512. _check_name if table not up to date then builds table
  513. _f_name analytic
  514. _n_name table lookup with no checking if usetable=1
  515. otherwise calls _f_name.
  516. */
  517. static List* check_table_statements;
  518. static Symbol* last_func_using_table;
  519. void check_tables() {
  520. /* for threads do this differently */
  521. if (check_table_statements) {
  522. fprintf(fcout, "\n#if %d\n", 0);
  523. printlist(check_table_statements);
  524. fprintf(fcout, "#endif\n");
  525. }
  526. }
  527. /* this way we can make sure the tables are up to date in the main thread
  528. at critical points in the finitialize, nrn_fixed_step, etc. The only
  529. requirement is that the function that generates the table not use
  530. any except GLOBAL parameters and assigned vars not requiring
  531. an initial value, because we are probably going to
  532. call this with nonsense _p, _ppvar, and _thread
  533. */
  534. static List* check_table_thread_list;
  535. int check_tables_threads(List* p) {
  536. Item* q;
  537. if (check_table_thread_list) {
  538. ITERATE(q, check_table_thread_list) {
  539. sprintf(buf, "\nstatic void %s(double*, Datum*, Datum*, _NrnThread*);", STR(q));
  540. lappendstr(p, buf);
  541. }
  542. lappendstr(p, "\nstatic void _check_table_thread(double* _p, Datum* _ppvar, Datum* _thread, _NrnThread* _nt, int _type) {\n");
  543. ITERATE(q, check_table_thread_list) {
  544. sprintf(buf, " %s(_p, _ppvar, _thread, _nt);\n", STR(q));
  545. lappendstr(p, buf);
  546. }
  547. lappendstr(p, "}\n");
  548. return 1;
  549. }
  550. return 0;
  551. }
  552. void table_massage(tablist, qtype, qname, arglist)
  553. List *tablist, *arglist;
  554. Item *qtype, *qname;
  555. {
  556. Symbol *fsym, *s, *arg=0;
  557. char* fname;
  558. List *table, *from, *to, *depend;
  559. int type, ntab;
  560. Item *q;
  561. if (!tablist) {
  562. return;
  563. }
  564. fsym = SYM(qname);
  565. last_func_using_table = fsym;
  566. fname = fsym->name;
  567. table = LST(q = tablist->next);
  568. from = LST(q = q->next);
  569. to = LST(q = q->next);
  570. ntab = atoi(STR(q = q->next));
  571. depend = LST(q = q->next);
  572. type = SYM(qtype)->type;
  573. ifnew_parminstall("usetable", "1", "", "0 1");
  574. if (!check_table_statements) {
  575. check_table_statements = newlist();
  576. }
  577. sprintf(buf, "_check_%s();\n", fname);
  578. q = lappendstr(check_table_statements, buf);
  579. sprintf(buf, "_check_%s(_p, _ppvar, _thread, _nt);\n", fname);
  580. vectorize_substitute(q, buf);
  581. /*checking*/
  582. if (type == FUNCTION1) {
  583. if (table) {
  584. diag("TABLE stmt in FUNCTION cannot have a table name list", (char *)0);
  585. }
  586. table = newlist();
  587. Lappendsym(table, fsym);
  588. }else{
  589. if (!table) {
  590. diag("TABLE stmt in PROCEDURE must have a table name list", (char *)0);
  591. }
  592. }
  593. if (arglist->next == arglist || arglist->next->next != arglist) {
  594. diag("FUNCTION or PROCEDURE containing a TABLE stmt\n",
  595. "must have exactly one argument");
  596. }else{
  597. arg = SYM(arglist->next);
  598. }
  599. if (!depend) {
  600. depend = newlist();
  601. }
  602. /*translation*/
  603. /* new name for original function */
  604. Sprintf(buf, "_f_%s", fname);
  605. SYM(qname) = install(buf, fsym->type);
  606. SYM(qname)->subtype = fsym->subtype;
  607. SYM(qname)->varnum = fsym->varnum;
  608. if (type == FUNCTION1) {
  609. fsym->subtype |= FUNCT;
  610. Sprintf(buf, "static double _n_%s(double);\n", fname);
  611. q = linsertstr(procfunc, buf);
  612. #if VECTORIZE
  613. Sprintf(buf, "static double _n_%s(_threadargsprotocomma_ double _lv);\n", fname);
  614. vectorize_substitute(q, buf);
  615. #endif
  616. }else{
  617. fsym->subtype |= PROCED;
  618. Sprintf(buf, "static void _n_%s(double);\n", fname);
  619. q = linsertstr(procfunc, buf);
  620. #if VECTORIZE
  621. Sprintf(buf, "static void _n_%s(_threadargsprotocomma_ double _lv);\n", fname);
  622. vectorize_substitute(q, buf);
  623. #endif
  624. }
  625. fsym->usage |= FUNCT;
  626. /* declare communication between func and check_func */
  627. Sprintf(buf, "static double _mfac_%s, _tmin_%s;\n",
  628. fname, fname);
  629. Lappendstr(procfunc, buf);
  630. /* create the check function */
  631. if (!check_table_thread_list) {
  632. check_table_thread_list = newlist();
  633. }
  634. sprintf(buf, "_check_%s", fname);
  635. lappendstr(check_table_thread_list, buf);
  636. Sprintf(buf, "static void _check_%s();\n", fname);
  637. q = insertstr(procfunc, buf);
  638. vectorize_substitute(q, "");
  639. Sprintf(buf, "static void _check_%s() {\n", fname);
  640. q = lappendstr(procfunc, buf);
  641. Sprintf(buf, "static void _check_%s(double* _p, Datum* _ppvar, Datum* _thread, _NrnThread* _nt) {\n", fname);
  642. vectorize_substitute(q, buf);
  643. Lappendstr(procfunc, " static int _maktable=1; int _i, _j, _ix = 0;\n");
  644. Lappendstr(procfunc, " double _xi, _tmax;\n");
  645. ITERATE(q, depend) {
  646. Sprintf(buf, " static double _sav_%s;\n", SYM(q)->name);
  647. Lappendstr(procfunc, buf);
  648. }
  649. lappendstr(procfunc, " if (!usetable) {return;}\n");
  650. /*allocation*/
  651. ITERATE(q, table) {
  652. s = SYM(q);
  653. if (s->subtype & ARRAY) {
  654. Sprintf(buf, " for (_i=0; _i < %d; _i++) {\
  655. _t_%s[_i] = makevector(%d*sizeof(double)); }\n", s->araydim, s->name, ntab+1);
  656. }else{
  657. Sprintf(buf, " _t_%s = makevector(%d*sizeof(double));\n",
  658. s->name, ntab+1);
  659. }
  660. Lappendstr(initlist, buf);
  661. }
  662. /* check dependency */
  663. ITERATE(q, depend) {
  664. Sprintf(buf, " if (_sav_%s != %s) { _maktable = 1;}\n",
  665. SYM(q)->name, SYM(q)->name);
  666. Lappendstr(procfunc, buf);
  667. }
  668. /* make the table */
  669. Lappendstr(procfunc, " if (_maktable) { double _x, _dx; _maktable=0;\n");
  670. Sprintf(buf, " _tmin_%s = ", fname);
  671. Lappendstr(procfunc, buf);
  672. move(from->next, from->prev, procfunc);
  673. Sprintf(buf, ";\n _tmax = ");
  674. Lappendstr(procfunc, buf);
  675. move(to->next, to->prev, procfunc);
  676. Lappendstr(procfunc, ";\n");
  677. Sprintf(buf," _dx = (_tmax - _tmin_%s)/%d.; _mfac_%s = 1./_dx;\n",
  678. fname, ntab, fname);
  679. Lappendstr(procfunc, buf);
  680. Sprintf(buf," for (_i=0, _x=_tmin_%s; _i < %d; _x += _dx, _i++) {\n",
  681. fname, ntab+1);
  682. Lappendstr(procfunc, buf);
  683. if (type == FUNCTION1) {
  684. ITERATE(q, table) {
  685. s = SYM(q);
  686. Sprintf(buf, " _t_%s[_i] = _f_%s(_x);\n", s->name, fname);
  687. Lappendstr(procfunc, buf);
  688. #if VECTORIZE
  689. Sprintf(buf, " _t_%s[_i] = _f_%s(_p, _ppvar, _thread, _nt, _x);\n", s->name, fname);
  690. vectorize_substitute(procfunc->prev, buf);
  691. #endif
  692. }
  693. }else{
  694. Sprintf(buf, " _f_%s(_x);\n", fname);
  695. Lappendstr(procfunc, buf);
  696. #if VECTORIZE
  697. Sprintf(buf, " _f_%s(_p, _ppvar, _thread, _nt, _x);\n", fname);
  698. vectorize_substitute(procfunc->prev, buf);
  699. #endif
  700. ITERATE(q, table) {
  701. s = SYM(q);
  702. if (s->subtype & ARRAY) {
  703. Sprintf(buf, " for (_j = 0; _j < %d; _j++) { _t_%s[_j][_i] = %s[_j];\n}",
  704. s->araydim, s->name, s->name);
  705. }else{
  706. Sprintf(buf, " _t_%s[_i] = %s;\n", s->name, s->name);
  707. }
  708. Lappendstr(procfunc, buf);
  709. }
  710. }
  711. Lappendstr(procfunc, " }\n"); /*closes loop over _i index*/
  712. /* save old dependency values */
  713. ITERATE(q, depend) {
  714. s = SYM(q);
  715. Sprintf(buf, " _sav_%s = %s;\n", s->name, s->name);
  716. Lappendstr(procfunc, buf);
  717. }
  718. Lappendstr(procfunc, " }\n"); /* closes if(maktable)) */
  719. Lappendstr(procfunc, "}\n\n");
  720. /* create the new function (steers to analytic or table) */
  721. /*declaration*/
  722. if (type == FUNCTION1) {
  723. #define GLOBFUNC 1
  724. #if !GLOBFUNC
  725. Lappendstr(procfunc, "static int");
  726. #endif
  727. Lappendstr(procfunc, "double");
  728. }else{
  729. Lappendstr(procfunc, "static int");
  730. }
  731. Sprintf(buf, "%s(double %s){",
  732. fname, arg->name);
  733. Lappendstr(procfunc, buf);
  734. #if VECTORIZE
  735. Sprintf(buf, "%s(double* _p, Datum* _ppvar, Datum* _thread, _NrnThread* _nt, double %s) {",
  736. fname, arg->name);
  737. vectorize_substitute(procfunc->prev, buf);
  738. #endif
  739. /* check the table */
  740. Sprintf(buf, "_check_%s();\n", fname);
  741. q = lappendstr(procfunc, buf);
  742. #if VECTORIZE
  743. Sprintf(buf, "\n#if 0\n_check_%s(_p, _ppvar, _thread, _nt);\n#endif\n", fname);
  744. vectorize_substitute(q, buf);
  745. #endif
  746. if (type == FUNCTION1) {
  747. Lappendstr(procfunc, "return");
  748. }
  749. Sprintf(buf, "_n_%s(%s);\n", fname, arg->name);
  750. Lappendstr(procfunc, buf);
  751. #if VECTORIZE
  752. Sprintf(buf, "_n_%s(_p, _ppvar, _thread, _nt, %s);\n", fname, arg->name);
  753. vectorize_substitute(procfunc->prev, buf);
  754. #endif
  755. if (type != FUNCTION1) {
  756. Lappendstr(procfunc, "return 0;\n");
  757. }
  758. Lappendstr(procfunc, "}\n\n"); /* end of new function */
  759. /* _n_name function for table lookup with no checking */
  760. if (type == FUNCTION1) {
  761. Lappendstr(procfunc, "static double");
  762. }else{
  763. Lappendstr(procfunc, "static void");
  764. }
  765. Sprintf(buf, "_n_%s(double %s){",
  766. fname, arg->name);
  767. Lappendstr(procfunc, buf);
  768. #if VECTORIZE
  769. Sprintf(buf, "_n_%s(double* _p, Datum* _ppvar, Datum* _thread, _NrnThread* _nt, double %s){",
  770. fname, arg->name);
  771. vectorize_substitute(procfunc->prev, buf);
  772. #endif
  773. Lappendstr(procfunc, "int _i, _j;\n");
  774. Lappendstr(procfunc, "double _xi, _theta;\n");
  775. /* usetable */
  776. Lappendstr(procfunc, "if (!usetable) {\n");
  777. if (type == FUNCTION1) {
  778. Lappendstr(procfunc, "return");
  779. }
  780. Sprintf(buf, "_f_%s(%s);", fname, arg->name);
  781. Lappendstr(procfunc, buf);
  782. #if VECTORIZE
  783. Sprintf(buf, "_f_%s(_p, _ppvar, _thread, _nt, %s);", fname, arg->name);
  784. vectorize_substitute(procfunc->prev, buf);
  785. #endif
  786. if (type != FUNCTION1) {
  787. Lappendstr(procfunc, "return;");
  788. }
  789. Lappendstr(procfunc, "\n}\n");
  790. /* table lookup */
  791. Sprintf(buf, "_xi = _mfac_%s * (%s - _tmin_%s);\n",
  792. fname, arg->name, fname);
  793. Lappendstr(procfunc, buf);
  794. Lappendstr(procfunc, "if (isnan(_xi)) {\n");
  795. if (type == FUNCTION1) {
  796. Lappendstr(procfunc, " return _xi; }\n");
  797. }else{
  798. ITERATE(q, table) {
  799. s = SYM(q);
  800. if (s->subtype & ARRAY) {
  801. Sprintf(buf, " for (_j = 0; _j < %d; _j++) { %s[_j] = _xi;\n}",
  802. s->araydim, s->name);
  803. }else{
  804. Sprintf(buf, " %s = _xi;\n", s->name);
  805. }
  806. Lappendstr(procfunc, buf);
  807. }
  808. Lappendstr(procfunc, " return;\n }\n");
  809. }
  810. Lappendstr(procfunc, "if (_xi <= 0.) {\n");
  811. if (type == FUNCTION1) {
  812. Sprintf(buf, "return _t_%s[0];\n", SYM(table->next)->name);
  813. Lappendstr(procfunc, buf);
  814. }else{
  815. ITERATE(q, table) {
  816. s = SYM(q);
  817. if (s->subtype & ARRAY) {
  818. Sprintf(buf, "for (_j = 0; _j < %d; _j++) { %s[_j] = _t_%s[_j][0];\n}",
  819. s->araydim, s->name, s->name);
  820. }else{
  821. Sprintf(buf, "%s = _t_%s[0];\n", s->name, s->name);
  822. }
  823. Lappendstr(procfunc, buf);
  824. }
  825. Lappendstr(procfunc, "return;");
  826. }
  827. Lappendstr(procfunc, "}\n");
  828. Sprintf(buf, "if (_xi >= %d.) {\n", ntab);
  829. Lappendstr(procfunc, buf);
  830. if (type == FUNCTION1) {
  831. Sprintf(buf, "return _t_%s[%d];\n", SYM(table->next)->name, ntab);
  832. Lappendstr(procfunc, buf);
  833. }else{
  834. ITERATE(q, table) {
  835. s = SYM(q);
  836. if (s->subtype & ARRAY) {
  837. Sprintf(buf, "for (_j = 0; _j < %d; _j++) { %s[_j] = _t_%s[_j][%d];\n}",
  838. s->araydim, s->name, s->name, ntab);
  839. }else{
  840. Sprintf(buf, "%s = _t_%s[%d];\n", s->name, s->name, ntab);
  841. }
  842. Lappendstr(procfunc, buf);
  843. }
  844. Lappendstr(procfunc, "return;");
  845. }
  846. Lappendstr(procfunc, "}\n");
  847. /* table interpolation */
  848. Lappendstr(procfunc, "_i = (int) _xi;\n");
  849. if (type == FUNCTION1) {
  850. s = SYM(table->next);
  851. Sprintf(buf, "return _t_%s[_i] + (_xi - (double)_i)*(_t_%s[_i+1] - _t_%s[_i]);\n",
  852. s->name, s->name, s->name);
  853. Lappendstr(procfunc, buf);
  854. }else{
  855. Lappendstr(procfunc, "_theta = _xi - (double)_i;\n");
  856. ITERATE(q, table) {
  857. s = SYM(q);
  858. if (s->subtype & ARRAY) {
  859. Sprintf(buf, "for (_j = 0; _j < %d; _j++) {double *_t = _t_%s[_j];",
  860. s->araydim, s->name);
  861. Lappendstr(procfunc, buf);
  862. Sprintf(buf, "%s[_j] = _t[_i] + _theta*(_t[_i+1] - _t[_i]);}\n",
  863. s->name);
  864. }else{
  865. Sprintf(buf, "%s = _t_%s[_i] + _theta*(_t_%s[_i+1] - _t_%s[_i]);\n",
  866. s->name, s->name, s->name, s->name);
  867. }
  868. Lappendstr(procfunc, buf);
  869. }
  870. }
  871. Lappendstr(procfunc, "}\n\n"); /* end of new function */
  872. /* table declaration */
  873. ITERATE(q, table) {
  874. s = SYM(q);
  875. if (s->subtype & ARRAY) {
  876. Sprintf(buf, "static double *_t_%s[%d];\n",
  877. s->name, s->araydim);
  878. }else{
  879. Sprintf(buf, "static double *_t_%s;\n", s->name);
  880. }
  881. Lappendstr(firstlist, buf);
  882. }
  883. /*cleanup*/
  884. freelist(&table);
  885. freelist(&depend);
  886. freelist(&from);
  887. freelist(&to);
  888. }
  889. #if HMODL || NMODL
  890. void hocfunchack(Symbol* n, Item* qpar1, Item* qpar2, int hack)
  891. {
  892. #if NOCMODL
  893. extern int point_process;
  894. #endif
  895. Item *q;
  896. int i;
  897. #if VECTORIZE
  898. Item* qp=0;
  899. #endif
  900. if (point_process) {
  901. Sprintf(buf, "\nstatic double _hoc_%s(void* _vptr) {\n double _r;\n", n->name);
  902. }else{
  903. Sprintf(buf, "\nstatic void _hoc_%s(void) {\n double _r;\n", n->name);
  904. }
  905. Lappendstr(procfunc, buf);
  906. vectorize_substitute(lappendstr(procfunc, ""), "\
  907. double* _p; Datum* _ppvar; Datum* _thread; _NrnThread* _nt;\n\
  908. ");
  909. if (point_process) {
  910. vectorize_substitute(lappendstr(procfunc, " _hoc_setdata(_vptr);\n"), "\
  911. _p = ((Point_process*)_vptr)->_prop->param;\n\
  912. _ppvar = ((Point_process*)_vptr)->_prop->dparam;\n\
  913. _thread = _extcall_thread;\n\
  914. _nt = (_NrnThread*)((Point_process*)_vptr)->_vnt;\n\
  915. ");
  916. }else{
  917. vectorize_substitute(lappendstr(procfunc, ""), "\
  918. if (_extcall_prop) {_p = _extcall_prop->param; _ppvar = _extcall_prop->dparam;}else{ _p = (double*)0; _ppvar = (Datum*)0; }\n\
  919. _thread = _extcall_thread;\n\
  920. _nt = nrn_threads;\n\
  921. ");
  922. }
  923. #if VECTORIZE
  924. if (n == last_func_using_table) {
  925. qp = lappendstr(procfunc, "");
  926. sprintf(buf,"\n#if 1\n _check_%s(_p, _ppvar, _thread, _nt);\n#endif\n", n->name);
  927. vectorize_substitute(qp, buf);
  928. }
  929. #endif
  930. if (n->subtype & FUNCT) {
  931. Lappendstr(procfunc, "_r = ");
  932. }else{
  933. Lappendstr(procfunc, "_r = 1.;\n");
  934. }
  935. Lappendsym(procfunc, n);
  936. lappendstr(procfunc, "(");
  937. #if VECTORIZE
  938. qp = lappendstr(procfunc, "");
  939. #endif
  940. for (i=0; i < n->varnum; ++i) {
  941. Sprintf(buf, "*getarg(%d)", i+1);
  942. Lappendstr(procfunc, buf);
  943. if (i+1 < n->varnum) {
  944. Lappendstr(procfunc, ",");
  945. }
  946. }
  947. #if NOCMODL
  948. if (point_process) {
  949. Lappendstr(procfunc, ");\n return(_r);\n}\n");
  950. }else
  951. #endif
  952. Lappendstr(procfunc, ");\n hoc_retpushx(_r);\n}\n");
  953. #if VECTORIZE
  954. if (i) {
  955. vectorize_substitute(qp, "_p, _ppvar, _thread, _nt,");
  956. }else if (!hack) {
  957. vectorize_substitute(qp, "_p, _ppvar, _thread, _nt");
  958. }
  959. #endif
  960. }
  961. void hocfunc(n, qpar1, qpar2) /*interface between modl and hoc for proc and func */
  962. Item *qpar1, *qpar2;
  963. Symbol *n;
  964. {
  965. /* Hack prevents FUNCTION_TABLE bug of 'double table_name()' extra args
  966. replacing the double in 'double name(...) */
  967. hocfunchack(n, qpar1, qpar2, 0);
  968. }
  969. #if VECTORIZE
  970. /* ARGSUSED */
  971. void vectorize_use_func(qname, qpar1, qexpr, qpar2, blocktype)
  972. Item* qname, *qpar1, *qexpr, *qpar2;
  973. int blocktype;
  974. {
  975. Item* q;
  976. if (SYM(qname)->subtype & EXTDEF) {
  977. if (strcmp(SYM(qname)->name, "nrn_pointing") == 0) {
  978. Insertstr(qpar1->next, "&");
  979. }else if (strcmp(SYM(qname)->name, "state_discontinuity") == 0) {
  980. #if CVODE
  981. fprintf(stderr, "Notice: Use of state_discontinuity is not thread safe");
  982. vectorize = 0;
  983. if (blocktype == NETRECEIVE) {
  984. Fprintf(stderr, "Notice: Use of state_discontinuity in a NET_RECEIVE block is unnecessary and prevents use of this mechanism in a multithreaded simulation.\n");
  985. }
  986. if (!state_discon_list_) {
  987. state_discon_list_ = newlist();
  988. Linsertstr(procfunc, "extern int state_discon_flag_;\n");
  989. }
  990. lappenditem(state_discon_list_, qpar1->next);
  991. #endif
  992. Insertstr(qpar1->next, "-1, &");
  993. }else if (strcmp(SYM(qname)->name, "net_send") == 0) {
  994. net_send_seen_ = 1;
  995. if (artificial_cell) {
  996. replacstr(qname, "artcell_net_send");
  997. }
  998. Insertstr(qexpr, "t + ");
  999. if (blocktype == NETRECEIVE) {
  1000. Insertstr(qpar1->next, "_tqitem, _args, _pnt,");
  1001. }else if (blocktype == INITIAL1){
  1002. Insertstr(qpar1->next, "_tqitem, (double*)0, _ppvar[1]._pvoid,");
  1003. }else{
  1004. diag("net_send allowed only in INITIAL and NET_RECEIVE blocks", (char*)0);
  1005. }
  1006. }else if (strcmp(SYM(qname)->name, "net_event") == 0) {
  1007. net_event_seen_ = 1;
  1008. if (blocktype == NETRECEIVE) {
  1009. Insertstr(qpar1->next, "_pnt,");
  1010. }else{
  1011. diag("net_event", " only allowed in NET_RECEIVE block");
  1012. }
  1013. }else if (strcmp(SYM(qname)->name, "net_move") == 0) {
  1014. if (artificial_cell) {
  1015. replacstr(qname, "artcell_net_move");
  1016. }
  1017. if (blocktype == NETRECEIVE) {
  1018. Insertstr(qpar1->next, "_tqitem, _pnt,");
  1019. }else{
  1020. diag("net_move", " only allowed in NET_RECEIVE block");
  1021. }
  1022. }
  1023. return;
  1024. }
  1025. #if 1
  1026. if (qexpr) {
  1027. q = insertstr(qpar1->next, "_threadargscomma_");
  1028. }else{
  1029. q = insertstr(qpar1->next, "_threadargs_");
  1030. }
  1031. #else
  1032. q = insertstr(qpar1->next, "");
  1033. if (qexpr) {
  1034. vectorize_substitute(q, "_p, _ppvar, _thread, _nt,");
  1035. }else{
  1036. vectorize_substitute(q, "_p, _ppvar, _thread, _nt");
  1037. }
  1038. #endif
  1039. }
  1040. #endif
  1041. #endif
  1042. void function_table(s, qpar1, qpar2, qb1, qb2) /* s ( ... ) { ... } */
  1043. Symbol* s;
  1044. Item *qpar1, *qpar2, *qb1, *qb2;
  1045. {
  1046. Symbol* t;
  1047. int i;
  1048. Item* q, *q1, *q2;
  1049. for (i=0, q=qpar1->next; q != qpar2; q = q->next) {
  1050. #if VECTORIZE
  1051. if (q->itemtype == STRING || SYM(q)->name[0] != '_') {
  1052. continue;
  1053. }
  1054. #endif
  1055. sprintf(buf, "_arg[%d] = %s;\n", i, SYM(q)->name);
  1056. insertstr(qb2, buf);
  1057. ++i;
  1058. }
  1059. if (i == 0) {
  1060. diag("FUNCTION_TABLE declaration must have one or more arguments:",
  1061. s->name);
  1062. }
  1063. sprintf(buf, "double _arg[%d];\n", i);
  1064. insertstr(qb1->next, buf);
  1065. sprintf(buf, "return hoc_func_table(_ptable_%s, %d, _arg);\n", s->name, i);
  1066. insertstr(qb2, buf);
  1067. insertstr(qb2, "}\n/* "); /* kludge to avoid a bad vectorize_substitute */
  1068. insertstr(qb2->next, " */\n");
  1069. sprintf(buf, "table_%s", s->name);
  1070. t = install(buf, NAME);
  1071. t->subtype |= FUNCT;
  1072. t->usage |= FUNCT;
  1073. t->no_threadargs = 1;
  1074. t->varnum = 0;
  1075. sprintf(buf,"double %s", t->name);
  1076. lappendstr(procfunc, buf);
  1077. q1 = lappendsym(procfunc, SYM(qpar1));
  1078. q2 = lappendsym(procfunc, SYM(qpar2));
  1079. sprintf(buf,"{\n\thoc_spec_table(&_ptable_%s, %d);\n\treturn 0.;\n}\n",
  1080. s->name, i);
  1081. lappendstr(procfunc, buf);
  1082. sprintf(buf, "\nstatic void* _ptable_%s = (void*)0;\n", s->name);
  1083. linsertstr(procfunc, buf);
  1084. hocfunchack(t, q1, q2, 1);
  1085. }
  1086. void watchstmt(par1, dir, par2, flag, blocktype )Item *par1, *dir, *par2, *flag;
  1087. int blocktype;
  1088. {
  1089. if (!watch_seen_) {
  1090. ++watch_seen_;
  1091. }
  1092. if (blocktype != NETRECEIVE) {
  1093. diag("\"WATCH\" statement only allowed in NET_RECEIVE block", (char*)0);
  1094. }
  1095. sprintf(buf, "\nstatic double _watch%d_cond(_pnt) Point_process* _pnt; {\n",
  1096. watch_seen_);
  1097. lappendstr(procfunc, buf);
  1098. vectorize_substitute(lappendstr(procfunc, ""),"\tdouble* _p; Datum* _ppvar; Datum* _thread; _NrnThread* _nt;\n\t_thread= (Datum*)0; _nt = (_NrnThread*)_pnt->_vnt;\n");
  1099. sprintf(buf, "\t_p = _pnt->_prop->param; _ppvar = _pnt->_prop->dparam;\n\tv = NODEV(_pnt->node);\n return ");
  1100. lappendstr(procfunc, buf);
  1101. movelist(par1, par2, procfunc);
  1102. movelist(dir->next, par2, procfunc);
  1103. if (SYM(dir)->name[0] == '<') {
  1104. insertstr(par1, "-(");
  1105. insertstr(par2->next, ")");
  1106. }
  1107. replacstr(dir, ") - (");
  1108. lappendstr(procfunc, ";\n}\n");
  1109. sprintf(buf,
  1110. " _nrn_watch_activate(_watch_array, _watch%d_cond, %d, _pnt, _watch_rm++, %s);\n",
  1111. watch_seen_, watch_seen_, STR(flag));
  1112. replacstr(flag, buf);
  1113. ++watch_seen_;
  1114. }
  1115. void threadsafe(char* s) {
  1116. if (!assert_threadsafe) {
  1117. fprintf(stderr, "Notice: %s\n", s);
  1118. vectorize = 0;
  1119. }
  1120. }
  1121. Item* protect_astmt(Item* q1, Item* q2) { /* PROTECT, ';' */
  1122. Item* q;
  1123. replacstr(q1, "/* PROTECT */_NMODLMUTEXLOCK\n");
  1124. q = insertstr(q2->next, "\n _NMODLMUTEXUNLOCK /* end PROTECT */\n");
  1125. protect_include_ = 1;
  1126. return q;
  1127. }
  1128. void nrnmutex(int on, Item* q) { /* MUTEXLOCK or MUTEXUNLOCK */
  1129. static int toggle = 0;
  1130. if (on == 1) {
  1131. if (toggle != 0) {
  1132. diag("MUTEXLOCK invoked after MUTEXLOCK", (char*)0);
  1133. }
  1134. toggle = 1;
  1135. replacstr(q, "_NMODLMUTEXLOCK\n");
  1136. protect_include_ = 1;
  1137. }else if (on == 0) {
  1138. if (toggle != 1) {
  1139. diag("MUTEXUNLOCK invoked with no earlier MUTEXLOCK", (char*)0);
  1140. }
  1141. toggle = 0;
  1142. replacstr(q, "_NMODLMUTEXUNLOCK\n");
  1143. protect_include_ = 1;
  1144. }else{
  1145. if (toggle != 0) {
  1146. diag("MUTEXUNLOCK not invoked after MUTEXLOCK", (char*)0);
  1147. }
  1148. toggle = 0;
  1149. }
  1150. }