You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4715 lines
172 KiB

  1. /* glpmpl01.c */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  6. * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied
  7. * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
  8. * reserved. E-mail: <mao@gnu.org>.
  9. *
  10. * GLPK is free software: you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************/
  23. #include "glpmpl.h"
  24. #define dmp_get_atomv dmp_get_atom
  25. /**********************************************************************/
  26. /* * * PROCESSING MODEL SECTION * * */
  27. /**********************************************************************/
  28. /*----------------------------------------------------------------------
  29. -- enter_context - enter current token into context queue.
  30. --
  31. -- This routine enters the current token into the context queue. */
  32. void enter_context(MPL *mpl)
  33. { char *image, *s;
  34. if (mpl->token == T_EOF)
  35. image = "_|_";
  36. else if (mpl->token == T_STRING)
  37. image = "'...'";
  38. else
  39. image = mpl->image;
  40. xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
  41. mpl->context[mpl->c_ptr++] = ' ';
  42. if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
  43. for (s = image; *s != '\0'; s++)
  44. { mpl->context[mpl->c_ptr++] = *s;
  45. if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
  46. }
  47. return;
  48. }
  49. /*----------------------------------------------------------------------
  50. -- print_context - print current content of context queue.
  51. --
  52. -- This routine prints current content of the context queue. */
  53. void print_context(MPL *mpl)
  54. { int c;
  55. while (mpl->c_ptr > 0)
  56. { mpl->c_ptr--;
  57. c = mpl->context[0];
  58. memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
  59. mpl->context[CONTEXT_SIZE-1] = (char)c;
  60. }
  61. xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
  62. CONTEXT_SIZE, mpl->context);
  63. return;
  64. }
  65. /*----------------------------------------------------------------------
  66. -- get_char - scan next character from input text file.
  67. --
  68. -- This routine scans a next ASCII character from the input text file.
  69. -- In case of end-of-file, the character is assigned EOF. */
  70. void get_char(MPL *mpl)
  71. { int c;
  72. if (mpl->c == EOF) goto done;
  73. if (mpl->c == '\n') mpl->line++;
  74. c = read_char(mpl);
  75. if (c == EOF)
  76. { if (mpl->c == '\n')
  77. mpl->line--;
  78. else
  79. warning(mpl, "final NL missing before end of file");
  80. }
  81. else if (c == '\n')
  82. ;
  83. else if (isspace(c))
  84. c = ' ';
  85. else if (iscntrl(c))
  86. { enter_context(mpl);
  87. error(mpl, "control character 0x%02X not allowed", c);
  88. }
  89. mpl->c = c;
  90. done: return;
  91. }
  92. /*----------------------------------------------------------------------
  93. -- append_char - append character to current token.
  94. --
  95. -- This routine appends the current character to the current token and
  96. -- then scans a next character. */
  97. void append_char(MPL *mpl)
  98. { xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
  99. if (mpl->imlen == MAX_LENGTH)
  100. { switch (mpl->token)
  101. { case T_NAME:
  102. enter_context(mpl);
  103. error(mpl, "symbolic name %s... too long", mpl->image);
  104. case T_SYMBOL:
  105. enter_context(mpl);
  106. error(mpl, "symbol %s... too long", mpl->image);
  107. case T_NUMBER:
  108. enter_context(mpl);
  109. error(mpl, "numeric literal %s... too long", mpl->image);
  110. case T_STRING:
  111. enter_context(mpl);
  112. error(mpl, "string literal too long");
  113. default:
  114. xassert(mpl != mpl);
  115. }
  116. }
  117. mpl->image[mpl->imlen++] = (char)mpl->c;
  118. mpl->image[mpl->imlen] = '\0';
  119. get_char(mpl);
  120. return;
  121. }
  122. /*----------------------------------------------------------------------
  123. -- get_token - scan next token from input text file.
  124. --
  125. -- This routine scans a next token from the input text file using the
  126. -- standard finite automation technique. */
  127. void get_token(MPL *mpl)
  128. { /* save the current token */
  129. mpl->b_token = mpl->token;
  130. mpl->b_imlen = mpl->imlen;
  131. strcpy(mpl->b_image, mpl->image);
  132. mpl->b_value = mpl->value;
  133. /* if the next token is already scanned, make it current */
  134. if (mpl->f_scan)
  135. { mpl->f_scan = 0;
  136. mpl->token = mpl->f_token;
  137. mpl->imlen = mpl->f_imlen;
  138. strcpy(mpl->image, mpl->f_image);
  139. mpl->value = mpl->f_value;
  140. goto done;
  141. }
  142. loop: /* nothing has been scanned so far */
  143. mpl->token = 0;
  144. mpl->imlen = 0;
  145. mpl->image[0] = '\0';
  146. mpl->value = 0.0;
  147. /* skip any uninteresting characters */
  148. while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
  149. /* recognize and construct the token */
  150. if (mpl->c == EOF)
  151. { /* end-of-file reached */
  152. mpl->token = T_EOF;
  153. }
  154. else if (mpl->c == '#')
  155. { /* comment; skip anything until end-of-line */
  156. while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
  157. goto loop;
  158. }
  159. else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
  160. { /* symbolic name or reserved keyword */
  161. mpl->token = T_NAME;
  162. while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
  163. if (strcmp(mpl->image, "and") == 0)
  164. mpl->token = T_AND;
  165. else if (strcmp(mpl->image, "by") == 0)
  166. mpl->token = T_BY;
  167. else if (strcmp(mpl->image, "cross") == 0)
  168. mpl->token = T_CROSS;
  169. else if (strcmp(mpl->image, "diff") == 0)
  170. mpl->token = T_DIFF;
  171. else if (strcmp(mpl->image, "div") == 0)
  172. mpl->token = T_DIV;
  173. else if (strcmp(mpl->image, "else") == 0)
  174. mpl->token = T_ELSE;
  175. else if (strcmp(mpl->image, "if") == 0)
  176. mpl->token = T_IF;
  177. else if (strcmp(mpl->image, "in") == 0)
  178. mpl->token = T_IN;
  179. #if 1 /* 21/VII-2006 */
  180. else if (strcmp(mpl->image, "Infinity") == 0)
  181. mpl->token = T_INFINITY;
  182. #endif
  183. else if (strcmp(mpl->image, "inter") == 0)
  184. mpl->token = T_INTER;
  185. else if (strcmp(mpl->image, "less") == 0)
  186. mpl->token = T_LESS;
  187. else if (strcmp(mpl->image, "mod") == 0)
  188. mpl->token = T_MOD;
  189. else if (strcmp(mpl->image, "not") == 0)
  190. mpl->token = T_NOT;
  191. else if (strcmp(mpl->image, "or") == 0)
  192. mpl->token = T_OR;
  193. else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
  194. { mpl->token = T_SPTP;
  195. append_char(mpl);
  196. if (mpl->c != 't')
  197. sptp: { enter_context(mpl);
  198. error(mpl, "keyword s.t. incomplete");
  199. }
  200. append_char(mpl);
  201. if (mpl->c != '.') goto sptp;
  202. append_char(mpl);
  203. }
  204. else if (strcmp(mpl->image, "symdiff") == 0)
  205. mpl->token = T_SYMDIFF;
  206. else if (strcmp(mpl->image, "then") == 0)
  207. mpl->token = T_THEN;
  208. else if (strcmp(mpl->image, "union") == 0)
  209. mpl->token = T_UNION;
  210. else if (strcmp(mpl->image, "within") == 0)
  211. mpl->token = T_WITHIN;
  212. }
  213. else if (!mpl->flag_d && isdigit(mpl->c))
  214. { /* numeric literal */
  215. mpl->token = T_NUMBER;
  216. /* scan integer part */
  217. while (isdigit(mpl->c)) append_char(mpl);
  218. /* scan optional fractional part */
  219. if (mpl->c == '.')
  220. { append_char(mpl);
  221. if (mpl->c == '.')
  222. { /* hmm, it is not the fractional part, it is dots that
  223. follow the integer part */
  224. mpl->imlen--;
  225. mpl->image[mpl->imlen] = '\0';
  226. mpl->f_dots = 1;
  227. goto conv;
  228. }
  229. frac: while (isdigit(mpl->c)) append_char(mpl);
  230. }
  231. /* scan optional decimal exponent */
  232. if (mpl->c == 'e' || mpl->c == 'E')
  233. { append_char(mpl);
  234. if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
  235. if (!isdigit(mpl->c))
  236. { enter_context(mpl);
  237. error(mpl, "numeric literal %s incomplete", mpl->image);
  238. }
  239. while (isdigit(mpl->c)) append_char(mpl);
  240. }
  241. /* there must be no letter following the numeric literal */
  242. if (isalpha(mpl->c) || mpl->c == '_')
  243. { enter_context(mpl);
  244. error(mpl, "symbol %s%c... should be enclosed in quotes",
  245. mpl->image, mpl->c);
  246. }
  247. conv: /* convert numeric literal to floating-point */
  248. if (str2num(mpl->image, &mpl->value))
  249. err: { enter_context(mpl);
  250. error(mpl, "cannot convert numeric literal %s to floating-p"
  251. "oint number", mpl->image);
  252. }
  253. }
  254. else if (mpl->c == '\'' || mpl->c == '"')
  255. { /* character string */
  256. int quote = mpl->c;
  257. mpl->token = T_STRING;
  258. get_char(mpl);
  259. for (;;)
  260. { if (mpl->c == '\n' || mpl->c == EOF)
  261. { enter_context(mpl);
  262. error(mpl, "unexpected end of line; string literal incom"
  263. "plete");
  264. }
  265. if (mpl->c == quote)
  266. { get_char(mpl);
  267. if (mpl->c != quote) break;
  268. }
  269. append_char(mpl);
  270. }
  271. }
  272. else if (!mpl->flag_d && mpl->c == '+')
  273. mpl->token = T_PLUS, append_char(mpl);
  274. else if (!mpl->flag_d && mpl->c == '-')
  275. mpl->token = T_MINUS, append_char(mpl);
  276. else if (mpl->c == '*')
  277. { mpl->token = T_ASTERISK, append_char(mpl);
  278. if (mpl->c == '*')
  279. mpl->token = T_POWER, append_char(mpl);
  280. }
  281. else if (mpl->c == '/')
  282. { mpl->token = T_SLASH, append_char(mpl);
  283. if (mpl->c == '*')
  284. { /* comment sequence */
  285. get_char(mpl);
  286. for (;;)
  287. { if (mpl->c == EOF)
  288. { /* do not call enter_context at this point */
  289. error(mpl, "unexpected end of file; comment sequence "
  290. "incomplete");
  291. }
  292. else if (mpl->c == '*')
  293. { get_char(mpl);
  294. if (mpl->c == '/') break;
  295. }
  296. else
  297. get_char(mpl);
  298. }
  299. get_char(mpl);
  300. goto loop;
  301. }
  302. }
  303. else if (mpl->c == '^')
  304. mpl->token = T_POWER, append_char(mpl);
  305. else if (mpl->c == '<')
  306. { mpl->token = T_LT, append_char(mpl);
  307. if (mpl->c == '=')
  308. mpl->token = T_LE, append_char(mpl);
  309. else if (mpl->c == '>')
  310. mpl->token = T_NE, append_char(mpl);
  311. #if 1 /* 11/II-2008 */
  312. else if (mpl->c == '-')
  313. mpl->token = T_INPUT, append_char(mpl);
  314. #endif
  315. }
  316. else if (mpl->c == '=')
  317. { mpl->token = T_EQ, append_char(mpl);
  318. if (mpl->c == '=') append_char(mpl);
  319. }
  320. else if (mpl->c == '>')
  321. { mpl->token = T_GT, append_char(mpl);
  322. if (mpl->c == '=')
  323. mpl->token = T_GE, append_char(mpl);
  324. #if 1 /* 14/VII-2006 */
  325. else if (mpl->c == '>')
  326. mpl->token = T_APPEND, append_char(mpl);
  327. #endif
  328. }
  329. else if (mpl->c == '!')
  330. { mpl->token = T_NOT, append_char(mpl);
  331. if (mpl->c == '=')
  332. mpl->token = T_NE, append_char(mpl);
  333. }
  334. else if (mpl->c == '&')
  335. { mpl->token = T_CONCAT, append_char(mpl);
  336. if (mpl->c == '&')
  337. mpl->token = T_AND, append_char(mpl);
  338. }
  339. else if (mpl->c == '|')
  340. { mpl->token = T_BAR, append_char(mpl);
  341. if (mpl->c == '|')
  342. mpl->token = T_OR, append_char(mpl);
  343. }
  344. else if (!mpl->flag_d && mpl->c == '.')
  345. { mpl->token = T_POINT, append_char(mpl);
  346. if (mpl->f_dots)
  347. { /* dots; the first dot was read on the previous call to the
  348. scanner, so the current character is the second dot */
  349. mpl->token = T_DOTS;
  350. mpl->imlen = 2;
  351. strcpy(mpl->image, "..");
  352. mpl->f_dots = 0;
  353. }
  354. else if (mpl->c == '.')
  355. mpl->token = T_DOTS, append_char(mpl);
  356. else if (isdigit(mpl->c))
  357. { /* numeric literal that begins with the decimal point */
  358. mpl->token = T_NUMBER, append_char(mpl);
  359. goto frac;
  360. }
  361. }
  362. else if (mpl->c == ',')
  363. mpl->token = T_COMMA, append_char(mpl);
  364. else if (mpl->c == ':')
  365. { mpl->token = T_COLON, append_char(mpl);
  366. if (mpl->c == '=')
  367. mpl->token = T_ASSIGN, append_char(mpl);
  368. }
  369. else if (mpl->c == ';')
  370. mpl->token = T_SEMICOLON, append_char(mpl);
  371. else if (mpl->c == '(')
  372. mpl->token = T_LEFT, append_char(mpl);
  373. else if (mpl->c == ')')
  374. mpl->token = T_RIGHT, append_char(mpl);
  375. else if (mpl->c == '[')
  376. mpl->token = T_LBRACKET, append_char(mpl);
  377. else if (mpl->c == ']')
  378. mpl->token = T_RBRACKET, append_char(mpl);
  379. else if (mpl->c == '{')
  380. mpl->token = T_LBRACE, append_char(mpl);
  381. else if (mpl->c == '}')
  382. mpl->token = T_RBRACE, append_char(mpl);
  383. #if 1 /* 11/II-2008 */
  384. else if (mpl->c == '~')
  385. mpl->token = T_TILDE, append_char(mpl);
  386. #endif
  387. else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
  388. { /* symbol */
  389. xassert(mpl->flag_d);
  390. mpl->token = T_SYMBOL;
  391. while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
  392. append_char(mpl);
  393. switch (str2num(mpl->image, &mpl->value))
  394. { case 0:
  395. mpl->token = T_NUMBER;
  396. break;
  397. case 1:
  398. goto err;
  399. case 2:
  400. break;
  401. default:
  402. xassert(mpl != mpl);
  403. }
  404. }
  405. else
  406. { enter_context(mpl);
  407. error(mpl, "character %c not allowed", mpl->c);
  408. }
  409. /* enter the current token into the context queue */
  410. enter_context(mpl);
  411. /* reset the flag, which may be set by indexing_expression() and
  412. is used by expression_list() */
  413. mpl->flag_x = 0;
  414. done: return;
  415. }
  416. /*----------------------------------------------------------------------
  417. -- unget_token - return current token back to input stream.
  418. --
  419. -- This routine returns the current token back to the input stream, so
  420. -- the previously scanned token becomes the current one. */
  421. void unget_token(MPL *mpl)
  422. { /* save the current token, which becomes the next one */
  423. xassert(!mpl->f_scan);
  424. mpl->f_scan = 1;
  425. mpl->f_token = mpl->token;
  426. mpl->f_imlen = mpl->imlen;
  427. strcpy(mpl->f_image, mpl->image);
  428. mpl->f_value = mpl->value;
  429. /* restore the previous token, which becomes the current one */
  430. mpl->token = mpl->b_token;
  431. mpl->imlen = mpl->b_imlen;
  432. strcpy(mpl->image, mpl->b_image);
  433. mpl->value = mpl->b_value;
  434. return;
  435. }
  436. /*----------------------------------------------------------------------
  437. -- is_keyword - check if current token is given non-reserved keyword.
  438. --
  439. -- If the current token is given (non-reserved) keyword, this routine
  440. -- returns non-zero. Otherwise zero is returned. */
  441. int is_keyword(MPL *mpl, char *keyword)
  442. { return
  443. mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
  444. }
  445. /*----------------------------------------------------------------------
  446. -- is_reserved - check if current token is reserved keyword.
  447. --
  448. -- If the current token is a reserved keyword, this routine returns
  449. -- non-zero. Otherwise zero is returned. */
  450. int is_reserved(MPL *mpl)
  451. { return
  452. mpl->token == T_AND && mpl->image[0] == 'a' ||
  453. mpl->token == T_BY ||
  454. mpl->token == T_CROSS ||
  455. mpl->token == T_DIFF ||
  456. mpl->token == T_DIV ||
  457. mpl->token == T_ELSE ||
  458. mpl->token == T_IF ||
  459. mpl->token == T_IN ||
  460. mpl->token == T_INTER ||
  461. mpl->token == T_LESS ||
  462. mpl->token == T_MOD ||
  463. mpl->token == T_NOT && mpl->image[0] == 'n' ||
  464. mpl->token == T_OR && mpl->image[0] == 'o' ||
  465. mpl->token == T_SYMDIFF ||
  466. mpl->token == T_THEN ||
  467. mpl->token == T_UNION ||
  468. mpl->token == T_WITHIN;
  469. }
  470. /*----------------------------------------------------------------------
  471. -- make_code - generate pseudo-code (basic routine).
  472. --
  473. -- This routine generates specified pseudo-code. It is assumed that all
  474. -- other translator routines use this basic routine. */
  475. CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
  476. { CODE *code;
  477. DOMAIN *domain;
  478. DOMAIN_BLOCK *block;
  479. ARG_LIST *e;
  480. /* generate pseudo-code */
  481. code = alloc(CODE);
  482. code->op = op;
  483. code->vflag = 0; /* is inherited from operand(s) */
  484. /* copy operands and also make them referring to the pseudo-code
  485. being generated, because the latter becomes the parent for all
  486. its operands */
  487. memset(&code->arg, '?', sizeof(OPERANDS));
  488. switch (op)
  489. { case O_NUMBER:
  490. code->arg.num = arg->num;
  491. break;
  492. case O_STRING:
  493. code->arg.str = arg->str;
  494. break;
  495. case O_INDEX:
  496. code->arg.index.slot = arg->index.slot;
  497. code->arg.index.next = arg->index.next;
  498. break;
  499. case O_MEMNUM:
  500. case O_MEMSYM:
  501. for (e = arg->par.list; e != NULL; e = e->next)
  502. { xassert(e->x != NULL);
  503. xassert(e->x->up == NULL);
  504. e->x->up = code;
  505. code->vflag |= e->x->vflag;
  506. }
  507. code->arg.par.par = arg->par.par;
  508. code->arg.par.list = arg->par.list;
  509. break;
  510. case O_MEMSET:
  511. for (e = arg->set.list; e != NULL; e = e->next)
  512. { xassert(e->x != NULL);
  513. xassert(e->x->up == NULL);
  514. e->x->up = code;
  515. code->vflag |= e->x->vflag;
  516. }
  517. code->arg.set.set = arg->set.set;
  518. code->arg.set.list = arg->set.list;
  519. break;
  520. case O_MEMVAR:
  521. for (e = arg->var.list; e != NULL; e = e->next)
  522. { xassert(e->x != NULL);
  523. xassert(e->x->up == NULL);
  524. e->x->up = code;
  525. code->vflag |= e->x->vflag;
  526. }
  527. code->arg.var.var = arg->var.var;
  528. code->arg.var.list = arg->var.list;
  529. #if 1 /* 15/V-2010 */
  530. code->arg.var.suff = arg->var.suff;
  531. #endif
  532. break;
  533. #if 1 /* 15/V-2010 */
  534. case O_MEMCON:
  535. for (e = arg->con.list; e != NULL; e = e->next)
  536. { xassert(e->x != NULL);
  537. xassert(e->x->up == NULL);
  538. e->x->up = code;
  539. code->vflag |= e->x->vflag;
  540. }
  541. code->arg.con.con = arg->con.con;
  542. code->arg.con.list = arg->con.list;
  543. code->arg.con.suff = arg->con.suff;
  544. break;
  545. #endif
  546. case O_TUPLE:
  547. case O_MAKE:
  548. for (e = arg->list; e != NULL; e = e->next)
  549. { xassert(e->x != NULL);
  550. xassert(e->x->up == NULL);
  551. e->x->up = code;
  552. code->vflag |= e->x->vflag;
  553. }
  554. code->arg.list = arg->list;
  555. break;
  556. case O_SLICE:
  557. xassert(arg->slice != NULL);
  558. code->arg.slice = arg->slice;
  559. break;
  560. case O_IRAND224:
  561. case O_UNIFORM01:
  562. case O_NORMAL01:
  563. case O_GMTIME:
  564. code->vflag = 1;
  565. break;
  566. case O_CVTNUM:
  567. case O_CVTSYM:
  568. case O_CVTLOG:
  569. case O_CVTTUP:
  570. case O_CVTLFM:
  571. case O_PLUS:
  572. case O_MINUS:
  573. case O_NOT:
  574. case O_ABS:
  575. case O_CEIL:
  576. case O_FLOOR:
  577. case O_EXP:
  578. case O_LOG:
  579. case O_LOG10:
  580. case O_SQRT:
  581. case O_SIN:
  582. case O_COS:
  583. case O_ATAN:
  584. case O_ROUND:
  585. case O_TRUNC:
  586. case O_CARD:
  587. case O_LENGTH:
  588. /* unary operation */
  589. xassert(arg->arg.x != NULL);
  590. xassert(arg->arg.x->up == NULL);
  591. arg->arg.x->up = code;
  592. code->vflag |= arg->arg.x->vflag;
  593. code->arg.arg.x = arg->arg.x;
  594. break;
  595. case O_ADD:
  596. case O_SUB:
  597. case O_LESS:
  598. case O_MUL:
  599. case O_DIV:
  600. case O_IDIV:
  601. case O_MOD:
  602. case O_POWER:
  603. case O_ATAN2:
  604. case O_ROUND2:
  605. case O_TRUNC2:
  606. case O_UNIFORM:
  607. if (op == O_UNIFORM) code->vflag = 1;
  608. case O_NORMAL:
  609. if (op == O_NORMAL) code->vflag = 1;
  610. case O_CONCAT:
  611. case O_LT:
  612. case O_LE:
  613. case O_EQ:
  614. case O_GE:
  615. case O_GT:
  616. case O_NE:
  617. case O_AND:
  618. case O_OR:
  619. case O_UNION:
  620. case O_DIFF:
  621. case O_SYMDIFF:
  622. case O_INTER:
  623. case O_CROSS:
  624. case O_IN:
  625. case O_NOTIN:
  626. case O_WITHIN:
  627. case O_NOTWITHIN:
  628. case O_SUBSTR:
  629. case O_STR2TIME:
  630. case O_TIME2STR:
  631. /* binary operation */
  632. xassert(arg->arg.x != NULL);
  633. xassert(arg->arg.x->up == NULL);
  634. arg->arg.x->up = code;
  635. code->vflag |= arg->arg.x->vflag;
  636. xassert(arg->arg.y != NULL);
  637. xassert(arg->arg.y->up == NULL);
  638. arg->arg.y->up = code;
  639. code->vflag |= arg->arg.y->vflag;
  640. code->arg.arg.x = arg->arg.x;
  641. code->arg.arg.y = arg->arg.y;
  642. break;
  643. case O_DOTS:
  644. case O_FORK:
  645. case O_SUBSTR3:
  646. /* ternary operation */
  647. xassert(arg->arg.x != NULL);
  648. xassert(arg->arg.x->up == NULL);
  649. arg->arg.x->up = code;
  650. code->vflag |= arg->arg.x->vflag;
  651. xassert(arg->arg.y != NULL);
  652. xassert(arg->arg.y->up == NULL);
  653. arg->arg.y->up = code;
  654. code->vflag |= arg->arg.y->vflag;
  655. if (arg->arg.z != NULL)
  656. { xassert(arg->arg.z->up == NULL);
  657. arg->arg.z->up = code;
  658. code->vflag |= arg->arg.z->vflag;
  659. }
  660. code->arg.arg.x = arg->arg.x;
  661. code->arg.arg.y = arg->arg.y;
  662. code->arg.arg.z = arg->arg.z;
  663. break;
  664. case O_MIN:
  665. case O_MAX:
  666. /* n-ary operation */
  667. for (e = arg->list; e != NULL; e = e->next)
  668. { xassert(e->x != NULL);
  669. xassert(e->x->up == NULL);
  670. e->x->up = code;
  671. code->vflag |= e->x->vflag;
  672. }
  673. code->arg.list = arg->list;
  674. break;
  675. case O_SUM:
  676. case O_PROD:
  677. case O_MINIMUM:
  678. case O_MAXIMUM:
  679. case O_FORALL:
  680. case O_EXISTS:
  681. case O_SETOF:
  682. case O_BUILD:
  683. /* iterated operation */
  684. domain = arg->loop.domain;
  685. xassert(domain != NULL);
  686. if (domain->code != NULL)
  687. { xassert(domain->code->up == NULL);
  688. domain->code->up = code;
  689. code->vflag |= domain->code->vflag;
  690. }
  691. for (block = domain->list; block != NULL; block =
  692. block->next)
  693. { xassert(block->code != NULL);
  694. xassert(block->code->up == NULL);
  695. block->code->up = code;
  696. code->vflag |= block->code->vflag;
  697. }
  698. if (arg->loop.x != NULL)
  699. { xassert(arg->loop.x->up == NULL);
  700. arg->loop.x->up = code;
  701. code->vflag |= arg->loop.x->vflag;
  702. }
  703. code->arg.loop.domain = arg->loop.domain;
  704. code->arg.loop.x = arg->loop.x;
  705. break;
  706. default:
  707. xassert(op != op);
  708. }
  709. /* set other attributes of the pseudo-code */
  710. code->type = type;
  711. code->dim = dim;
  712. code->up = NULL;
  713. code->valid = 0;
  714. memset(&code->value, '?', sizeof(VALUE));
  715. return code;
  716. }
  717. /*----------------------------------------------------------------------
  718. -- make_unary - generate pseudo-code for unary operation.
  719. --
  720. -- This routine generates pseudo-code for unary operation. */
  721. CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
  722. { CODE *code;
  723. OPERANDS arg;
  724. xassert(x != NULL);
  725. arg.arg.x = x;
  726. code = make_code(mpl, op, &arg, type, dim);
  727. return code;
  728. }
  729. /*----------------------------------------------------------------------
  730. -- make_binary - generate pseudo-code for binary operation.
  731. --
  732. -- This routine generates pseudo-code for binary operation. */
  733. CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
  734. int dim)
  735. { CODE *code;
  736. OPERANDS arg;
  737. xassert(x != NULL);
  738. xassert(y != NULL);
  739. arg.arg.x = x;
  740. arg.arg.y = y;
  741. code = make_code(mpl, op, &arg, type, dim);
  742. return code;
  743. }
  744. /*----------------------------------------------------------------------
  745. -- make_ternary - generate pseudo-code for ternary operation.
  746. --
  747. -- This routine generates pseudo-code for ternary operation. */
  748. CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
  749. int type, int dim)
  750. { CODE *code;
  751. OPERANDS arg;
  752. xassert(x != NULL);
  753. xassert(y != NULL);
  754. /* third operand can be NULL */
  755. arg.arg.x = x;
  756. arg.arg.y = y;
  757. arg.arg.z = z;
  758. code = make_code(mpl, op, &arg, type, dim);
  759. return code;
  760. }
  761. /*----------------------------------------------------------------------
  762. -- numeric_literal - parse reference to numeric literal.
  763. --
  764. -- This routine parses primary expression using the syntax:
  765. --
  766. -- <primary expression> ::= <numeric literal> */
  767. CODE *numeric_literal(MPL *mpl)
  768. { CODE *code;
  769. OPERANDS arg;
  770. xassert(mpl->token == T_NUMBER);
  771. arg.num = mpl->value;
  772. code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
  773. get_token(mpl /* <numeric literal> */);
  774. return code;
  775. }
  776. /*----------------------------------------------------------------------
  777. -- string_literal - parse reference to string literal.
  778. --
  779. -- This routine parses primary expression using the syntax:
  780. --
  781. -- <primary expression> ::= <string literal> */
  782. CODE *string_literal(MPL *mpl)
  783. { CODE *code;
  784. OPERANDS arg;
  785. xassert(mpl->token == T_STRING);
  786. arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  787. strcpy(arg.str, mpl->image);
  788. code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
  789. get_token(mpl /* <string literal> */);
  790. return code;
  791. }
  792. /*----------------------------------------------------------------------
  793. -- create_arg_list - create empty operands list.
  794. --
  795. -- This routine creates operands list, which is initially empty. */
  796. ARG_LIST *create_arg_list(MPL *mpl)
  797. { ARG_LIST *list;
  798. xassert(mpl == mpl);
  799. list = NULL;
  800. return list;
  801. }
  802. /*----------------------------------------------------------------------
  803. -- expand_arg_list - append operand to operands list.
  804. --
  805. -- This routine appends new operand to specified operands list. */
  806. ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
  807. { ARG_LIST *tail, *temp;
  808. xassert(x != NULL);
  809. /* create new operands list entry */
  810. tail = alloc(ARG_LIST);
  811. tail->x = x;
  812. tail->next = NULL;
  813. /* and append it to the operands list */
  814. if (list == NULL)
  815. list = tail;
  816. else
  817. { for (temp = list; temp->next != NULL; temp = temp->next);
  818. temp->next = tail;
  819. }
  820. return list;
  821. }
  822. /*----------------------------------------------------------------------
  823. -- arg_list_len - determine length of operands list.
  824. --
  825. -- This routine returns the number of operands in operands list. */
  826. int arg_list_len(MPL *mpl, ARG_LIST *list)
  827. { ARG_LIST *temp;
  828. int len;
  829. xassert(mpl == mpl);
  830. len = 0;
  831. for (temp = list; temp != NULL; temp = temp->next) len++;
  832. return len;
  833. }
  834. /*----------------------------------------------------------------------
  835. -- subscript_list - parse subscript list.
  836. --
  837. -- This routine parses subscript list using the syntax:
  838. --
  839. -- <subscript list> ::= <subscript>
  840. -- <subscript list> ::= <subscript list> , <subscript>
  841. -- <subscript> ::= <expression 5> */
  842. ARG_LIST *subscript_list(MPL *mpl)
  843. { ARG_LIST *list;
  844. CODE *x;
  845. list = create_arg_list(mpl);
  846. for (;;)
  847. { /* parse subscript expression */
  848. x = expression_5(mpl);
  849. /* convert it to symbolic type, if necessary */
  850. if (x->type == A_NUMERIC)
  851. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  852. /* check that now the expression is of symbolic type */
  853. if (x->type != A_SYMBOLIC)
  854. error(mpl, "subscript expression has invalid type");
  855. xassert(x->dim == 0);
  856. /* and append it to the subscript list */
  857. list = expand_arg_list(mpl, list, x);
  858. /* check a token that follows the subscript expression */
  859. if (mpl->token == T_COMMA)
  860. get_token(mpl /* , */);
  861. else if (mpl->token == T_RBRACKET)
  862. break;
  863. else
  864. error(mpl, "syntax error in subscript list");
  865. }
  866. return list;
  867. }
  868. #if 1 /* 15/V-2010 */
  869. /*----------------------------------------------------------------------
  870. -- object_reference - parse reference to named object.
  871. --
  872. -- This routine parses primary expression using the syntax:
  873. --
  874. -- <primary expression> ::= <dummy index>
  875. -- <primary expression> ::= <set name>
  876. -- <primary expression> ::= <set name> [ <subscript list> ]
  877. -- <primary expression> ::= <parameter name>
  878. -- <primary expression> ::= <parameter name> [ <subscript list> ]
  879. -- <primary expression> ::= <variable name> <suffix>
  880. -- <primary expression> ::= <variable name> [ <subscript list> ]
  881. -- <suffix>
  882. -- <primary expression> ::= <constraint name> <suffix>
  883. -- <primary expression> ::= <constraint name> [ <subscript list> ]
  884. -- <suffix>
  885. -- <dummy index> ::= <symbolic name>
  886. -- <set name> ::= <symbolic name>
  887. -- <parameter name> ::= <symbolic name>
  888. -- <variable name> ::= <symbolic name>
  889. -- <constraint name> ::= <symbolic name>
  890. -- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
  891. CODE *object_reference(MPL *mpl)
  892. { AVLNODE *node;
  893. DOMAIN_SLOT *slot;
  894. SET *set;
  895. PARAMETER *par;
  896. VARIABLE *var;
  897. CONSTRAINT *con;
  898. ARG_LIST *list;
  899. OPERANDS arg;
  900. CODE *code;
  901. char *name;
  902. int dim, suff;
  903. /* find the object in the symbolic name table */
  904. xassert(mpl->token == T_NAME);
  905. node = avl_find_node(mpl->tree, mpl->image);
  906. if (node == NULL)
  907. error(mpl, "%s not defined", mpl->image);
  908. /* check the object type and obtain its dimension */
  909. switch (avl_get_node_type(node))
  910. { case A_INDEX:
  911. /* dummy index */
  912. slot = (DOMAIN_SLOT *)avl_get_node_link(node);
  913. name = slot->name;
  914. dim = 0;
  915. break;
  916. case A_SET:
  917. /* model set */
  918. set = (SET *)avl_get_node_link(node);
  919. name = set->name;
  920. dim = set->dim;
  921. /* if a set object is referenced in its own declaration and
  922. the dimen attribute is not specified yet, use dimen 1 by
  923. default */
  924. if (set->dimen == 0) set->dimen = 1;
  925. break;
  926. case A_PARAMETER:
  927. /* model parameter */
  928. par = (PARAMETER *)avl_get_node_link(node);
  929. name = par->name;
  930. dim = par->dim;
  931. break;
  932. case A_VARIABLE:
  933. /* model variable */
  934. var = (VARIABLE *)avl_get_node_link(node);
  935. name = var->name;
  936. dim = var->dim;
  937. break;
  938. case A_CONSTRAINT:
  939. /* model constraint or objective */
  940. con = (CONSTRAINT *)avl_get_node_link(node);
  941. name = con->name;
  942. dim = con->dim;
  943. break;
  944. default:
  945. xassert(node != node);
  946. }
  947. get_token(mpl /* <symbolic name> */);
  948. /* parse optional subscript list */
  949. if (mpl->token == T_LBRACKET)
  950. { /* subscript list is specified */
  951. if (dim == 0)
  952. error(mpl, "%s cannot be subscripted", name);
  953. get_token(mpl /* [ */);
  954. list = subscript_list(mpl);
  955. if (dim != arg_list_len(mpl, list))
  956. error(mpl, "%s must have %d subscript%s rather than %d",
  957. name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
  958. xassert(mpl->token == T_RBRACKET);
  959. get_token(mpl /* ] */);
  960. }
  961. else
  962. { /* subscript list is not specified */
  963. if (dim != 0)
  964. error(mpl, "%s must be subscripted", name);
  965. list = create_arg_list(mpl);
  966. }
  967. /* parse optional suffix */
  968. if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
  969. suff = DOT_NONE;
  970. else
  971. suff = DOT_VAL;
  972. if (mpl->token == T_POINT)
  973. { get_token(mpl /* . */);
  974. if (mpl->token != T_NAME)
  975. error(mpl, "invalid use of period");
  976. if (!(avl_get_node_type(node) == A_VARIABLE ||
  977. avl_get_node_type(node) == A_CONSTRAINT))
  978. error(mpl, "%s cannot have a suffix", name);
  979. if (strcmp(mpl->image, "lb") == 0)
  980. suff = DOT_LB;
  981. else if (strcmp(mpl->image, "ub") == 0)
  982. suff = DOT_UB;
  983. else if (strcmp(mpl->image, "status") == 0)
  984. suff = DOT_STATUS;
  985. else if (strcmp(mpl->image, "val") == 0)
  986. suff = DOT_VAL;
  987. else if (strcmp(mpl->image, "dual") == 0)
  988. suff = DOT_DUAL;
  989. else
  990. error(mpl, "suffix .%s invalid", mpl->image);
  991. get_token(mpl /* suffix */);
  992. }
  993. /* generate pseudo-code to take value of the object */
  994. switch (avl_get_node_type(node))
  995. { case A_INDEX:
  996. arg.index.slot = slot;
  997. arg.index.next = slot->list;
  998. code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
  999. slot->list = code;
  1000. break;
  1001. case A_SET:
  1002. arg.set.set = set;
  1003. arg.set.list = list;
  1004. code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
  1005. set->dimen);
  1006. break;
  1007. case A_PARAMETER:
  1008. arg.par.par = par;
  1009. arg.par.list = list;
  1010. if (par->type == A_SYMBOLIC)
  1011. code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
  1012. else
  1013. code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
  1014. break;
  1015. case A_VARIABLE:
  1016. if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
  1017. || suff == DOT_DUAL))
  1018. error(mpl, "invalid reference to status, primal value, o"
  1019. "r dual value of variable %s above solve statement",
  1020. var->name);
  1021. arg.var.var = var;
  1022. arg.var.list = list;
  1023. arg.var.suff = suff;
  1024. code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
  1025. A_FORMULA : A_NUMERIC, 0);
  1026. break;
  1027. case A_CONSTRAINT:
  1028. if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
  1029. || suff == DOT_DUAL))
  1030. error(mpl, "invalid reference to status, primal value, o"
  1031. "r dual value of %s %s above solve statement",
  1032. con->type == A_CONSTRAINT ? "constraint" : "objective"
  1033. , con->name);
  1034. arg.con.con = con;
  1035. arg.con.list = list;
  1036. arg.con.suff = suff;
  1037. code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
  1038. break;
  1039. default:
  1040. xassert(node != node);
  1041. }
  1042. return code;
  1043. }
  1044. #endif
  1045. /*----------------------------------------------------------------------
  1046. -- numeric_argument - parse argument passed to built-in function.
  1047. --
  1048. -- This routine parses an argument passed to numeric built-in function
  1049. -- using the syntax:
  1050. --
  1051. -- <arg> ::= <expression 5> */
  1052. CODE *numeric_argument(MPL *mpl, char *func)
  1053. { CODE *x;
  1054. x = expression_5(mpl);
  1055. /* convert the argument to numeric type, if necessary */
  1056. if (x->type == A_SYMBOLIC)
  1057. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  1058. /* check that now the argument is of numeric type */
  1059. if (x->type != A_NUMERIC)
  1060. error(mpl, "argument for %s has invalid type", func);
  1061. xassert(x->dim == 0);
  1062. return x;
  1063. }
  1064. #if 1 /* 15/VII-2006 */
  1065. CODE *symbolic_argument(MPL *mpl, char *func)
  1066. { CODE *x;
  1067. x = expression_5(mpl);
  1068. /* convert the argument to symbolic type, if necessary */
  1069. if (x->type == A_NUMERIC)
  1070. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  1071. /* check that now the argument is of symbolic type */
  1072. if (x->type != A_SYMBOLIC)
  1073. error(mpl, "argument for %s has invalid type", func);
  1074. xassert(x->dim == 0);
  1075. return x;
  1076. }
  1077. #endif
  1078. #if 1 /* 15/VII-2006 */
  1079. CODE *elemset_argument(MPL *mpl, char *func)
  1080. { CODE *x;
  1081. x = expression_9(mpl);
  1082. if (x->type != A_ELEMSET)
  1083. error(mpl, "argument for %s has invalid type", func);
  1084. xassert(x->dim > 0);
  1085. return x;
  1086. }
  1087. #endif
  1088. /*----------------------------------------------------------------------
  1089. -- function_reference - parse reference to built-in function.
  1090. --
  1091. -- This routine parses primary expression using the syntax:
  1092. --
  1093. -- <primary expression> ::= abs ( <arg> )
  1094. -- <primary expression> ::= ceil ( <arg> )
  1095. -- <primary expression> ::= floor ( <arg> )
  1096. -- <primary expression> ::= exp ( <arg> )
  1097. -- <primary expression> ::= log ( <arg> )
  1098. -- <primary expression> ::= log10 ( <arg> )
  1099. -- <primary expression> ::= max ( <arg list> )
  1100. -- <primary expression> ::= min ( <arg list> )
  1101. -- <primary expression> ::= sqrt ( <arg> )
  1102. -- <primary expression> ::= sin ( <arg> )
  1103. -- <primary expression> ::= cos ( <arg> )
  1104. -- <primary expression> ::= atan ( <arg> )
  1105. -- <primary expression> ::= atan2 ( <arg> , <arg> )
  1106. -- <primary expression> ::= round ( <arg> )
  1107. -- <primary expression> ::= round ( <arg> , <arg> )
  1108. -- <primary expression> ::= trunc ( <arg> )
  1109. -- <primary expression> ::= trunc ( <arg> , <arg> )
  1110. -- <primary expression> ::= Irand224 ( )
  1111. -- <primary expression> ::= Uniform01 ( )
  1112. -- <primary expression> ::= Uniform ( <arg> , <arg> )
  1113. -- <primary expression> ::= Normal01 ( )
  1114. -- <primary expression> ::= Normal ( <arg> , <arg> )
  1115. -- <primary expression> ::= card ( <arg> )
  1116. -- <primary expression> ::= length ( <arg> )
  1117. -- <primary expression> ::= substr ( <arg> , <arg> )
  1118. -- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
  1119. -- <primary expression> ::= str2time ( <arg> , <arg> )
  1120. -- <primary expression> ::= time2str ( <arg> , <arg> )
  1121. -- <primary expression> ::= gmtime ( )
  1122. -- <arg list> ::= <arg>
  1123. -- <arg list> ::= <arg list> , <arg> */
  1124. CODE *function_reference(MPL *mpl)
  1125. { CODE *code;
  1126. OPERANDS arg;
  1127. int op;
  1128. char func[15+1];
  1129. /* determine operation code */
  1130. xassert(mpl->token == T_NAME);
  1131. if (strcmp(mpl->image, "abs") == 0)
  1132. op = O_ABS;
  1133. else if (strcmp(mpl->image, "ceil") == 0)
  1134. op = O_CEIL;
  1135. else if (strcmp(mpl->image, "floor") == 0)
  1136. op = O_FLOOR;
  1137. else if (strcmp(mpl->image, "exp") == 0)
  1138. op = O_EXP;
  1139. else if (strcmp(mpl->image, "log") == 0)
  1140. op = O_LOG;
  1141. else if (strcmp(mpl->image, "log10") == 0)
  1142. op = O_LOG10;
  1143. else if (strcmp(mpl->image, "sqrt") == 0)
  1144. op = O_SQRT;
  1145. else if (strcmp(mpl->image, "sin") == 0)
  1146. op = O_SIN;
  1147. else if (strcmp(mpl->image, "cos") == 0)
  1148. op = O_COS;
  1149. else if (strcmp(mpl->image, "atan") == 0)
  1150. op = O_ATAN;
  1151. else if (strcmp(mpl->image, "min") == 0)
  1152. op = O_MIN;
  1153. else if (strcmp(mpl->image, "max") == 0)
  1154. op = O_MAX;
  1155. else if (strcmp(mpl->image, "round") == 0)
  1156. op = O_ROUND;
  1157. else if (strcmp(mpl->image, "trunc") == 0)
  1158. op = O_TRUNC;
  1159. else if (strcmp(mpl->image, "Irand224") == 0)
  1160. op = O_IRAND224;
  1161. else if (strcmp(mpl->image, "Uniform01") == 0)
  1162. op = O_UNIFORM01;
  1163. else if (strcmp(mpl->image, "Uniform") == 0)
  1164. op = O_UNIFORM;
  1165. else if (strcmp(mpl->image, "Normal01") == 0)
  1166. op = O_NORMAL01;
  1167. else if (strcmp(mpl->image, "Normal") == 0)
  1168. op = O_NORMAL;
  1169. else if (strcmp(mpl->image, "card") == 0)
  1170. op = O_CARD;
  1171. else if (strcmp(mpl->image, "length") == 0)
  1172. op = O_LENGTH;
  1173. else if (strcmp(mpl->image, "substr") == 0)
  1174. op = O_SUBSTR;
  1175. else if (strcmp(mpl->image, "str2time") == 0)
  1176. op = O_STR2TIME;
  1177. else if (strcmp(mpl->image, "time2str") == 0)
  1178. op = O_TIME2STR;
  1179. else if (strcmp(mpl->image, "gmtime") == 0)
  1180. op = O_GMTIME;
  1181. else
  1182. error(mpl, "function %s unknown", mpl->image);
  1183. /* save symbolic name of the function */
  1184. strcpy(func, mpl->image);
  1185. xassert(strlen(func) < sizeof(func));
  1186. get_token(mpl /* <symbolic name> */);
  1187. /* check the left parenthesis that follows the function name */
  1188. xassert(mpl->token == T_LEFT);
  1189. get_token(mpl /* ( */);
  1190. /* parse argument list */
  1191. if (op == O_MIN || op == O_MAX)
  1192. { /* min and max allow arbitrary number of arguments */
  1193. arg.list = create_arg_list(mpl);
  1194. /* parse argument list */
  1195. for (;;)
  1196. { /* parse argument and append it to the operands list */
  1197. arg.list = expand_arg_list(mpl, arg.list,
  1198. numeric_argument(mpl, func));
  1199. /* check a token that follows the argument */
  1200. if (mpl->token == T_COMMA)
  1201. get_token(mpl /* , */);
  1202. else if (mpl->token == T_RIGHT)
  1203. break;
  1204. else
  1205. error(mpl, "syntax error in argument list for %s", func);
  1206. }
  1207. }
  1208. else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
  1209. O_NORMAL01 || op == O_GMTIME)
  1210. { /* Irand224, Uniform01, Normal01, gmtime need no arguments */
  1211. if (mpl->token != T_RIGHT)
  1212. error(mpl, "%s needs no arguments", func);
  1213. }
  1214. else if (op == O_UNIFORM || op == O_NORMAL)
  1215. { /* Uniform and Normal need two arguments */
  1216. /* parse the first argument */
  1217. arg.arg.x = numeric_argument(mpl, func);
  1218. /* check a token that follows the first argument */
  1219. if (mpl->token == T_COMMA)
  1220. ;
  1221. else if (mpl->token == T_RIGHT)
  1222. error(mpl, "%s needs two arguments", func);
  1223. else
  1224. error(mpl, "syntax error in argument for %s", func);
  1225. get_token(mpl /* , */);
  1226. /* parse the second argument */
  1227. arg.arg.y = numeric_argument(mpl, func);
  1228. /* check a token that follows the second argument */
  1229. if (mpl->token == T_COMMA)
  1230. error(mpl, "%s needs two argument", func);
  1231. else if (mpl->token == T_RIGHT)
  1232. ;
  1233. else
  1234. error(mpl, "syntax error in argument for %s", func);
  1235. }
  1236. else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
  1237. { /* atan, round, and trunc need one or two arguments */
  1238. /* parse the first argument */
  1239. arg.arg.x = numeric_argument(mpl, func);
  1240. /* parse the second argument, if specified */
  1241. if (mpl->token == T_COMMA)
  1242. { switch (op)
  1243. { case O_ATAN: op = O_ATAN2; break;
  1244. case O_ROUND: op = O_ROUND2; break;
  1245. case O_TRUNC: op = O_TRUNC2; break;
  1246. default: xassert(op != op);
  1247. }
  1248. get_token(mpl /* , */);
  1249. arg.arg.y = numeric_argument(mpl, func);
  1250. }
  1251. /* check a token that follows the last argument */
  1252. if (mpl->token == T_COMMA)
  1253. error(mpl, "%s needs one or two arguments", func);
  1254. else if (mpl->token == T_RIGHT)
  1255. ;
  1256. else
  1257. error(mpl, "syntax error in argument for %s", func);
  1258. }
  1259. else if (op == O_SUBSTR)
  1260. { /* substr needs two or three arguments */
  1261. /* parse the first argument */
  1262. arg.arg.x = symbolic_argument(mpl, func);
  1263. /* check a token that follows the first argument */
  1264. if (mpl->token == T_COMMA)
  1265. ;
  1266. else if (mpl->token == T_RIGHT)
  1267. error(mpl, "%s needs two or three arguments", func);
  1268. else
  1269. error(mpl, "syntax error in argument for %s", func);
  1270. get_token(mpl /* , */);
  1271. /* parse the second argument */
  1272. arg.arg.y = numeric_argument(mpl, func);
  1273. /* parse the third argument, if specified */
  1274. if (mpl->token == T_COMMA)
  1275. { op = O_SUBSTR3;
  1276. get_token(mpl /* , */);
  1277. arg.arg.z = numeric_argument(mpl, func);
  1278. }
  1279. /* check a token that follows the last argument */
  1280. if (mpl->token == T_COMMA)
  1281. error(mpl, "%s needs two or three arguments", func);
  1282. else if (mpl->token == T_RIGHT)
  1283. ;
  1284. else
  1285. error(mpl, "syntax error in argument for %s", func);
  1286. }
  1287. else if (op == O_STR2TIME)
  1288. { /* str2time needs two arguments, both symbolic */
  1289. /* parse the first argument */
  1290. arg.arg.x = symbolic_argument(mpl, func);
  1291. /* check a token that follows the first argument */
  1292. if (mpl->token == T_COMMA)
  1293. ;
  1294. else if (mpl->token == T_RIGHT)
  1295. error(mpl, "%s needs two arguments", func);
  1296. else
  1297. error(mpl, "syntax error in argument for %s", func);
  1298. get_token(mpl /* , */);
  1299. /* parse the second argument */
  1300. arg.arg.y = symbolic_argument(mpl, func);
  1301. /* check a token that follows the second argument */
  1302. if (mpl->token == T_COMMA)
  1303. error(mpl, "%s needs two argument", func);
  1304. else if (mpl->token == T_RIGHT)
  1305. ;
  1306. else
  1307. error(mpl, "syntax error in argument for %s", func);
  1308. }
  1309. else if (op == O_TIME2STR)
  1310. { /* time2str needs two arguments, numeric and symbolic */
  1311. /* parse the first argument */
  1312. arg.arg.x = numeric_argument(mpl, func);
  1313. /* check a token that follows the first argument */
  1314. if (mpl->token == T_COMMA)
  1315. ;
  1316. else if (mpl->token == T_RIGHT)
  1317. error(mpl, "%s needs two arguments", func);
  1318. else
  1319. error(mpl, "syntax error in argument for %s", func);
  1320. get_token(mpl /* , */);
  1321. /* parse the second argument */
  1322. arg.arg.y = symbolic_argument(mpl, func);
  1323. /* check a token that follows the second argument */
  1324. if (mpl->token == T_COMMA)
  1325. error(mpl, "%s needs two argument", func);
  1326. else if (mpl->token == T_RIGHT)
  1327. ;
  1328. else
  1329. error(mpl, "syntax error in argument for %s", func);
  1330. }
  1331. else
  1332. { /* other functions need one argument */
  1333. if (op == O_CARD)
  1334. arg.arg.x = elemset_argument(mpl, func);
  1335. else if (op == O_LENGTH)
  1336. arg.arg.x = symbolic_argument(mpl, func);
  1337. else
  1338. arg.arg.x = numeric_argument(mpl, func);
  1339. /* check a token that follows the argument */
  1340. if (mpl->token == T_COMMA)
  1341. error(mpl, "%s needs one argument", func);
  1342. else if (mpl->token == T_RIGHT)
  1343. ;
  1344. else
  1345. error(mpl, "syntax error in argument for %s", func);
  1346. }
  1347. /* make pseudo-code to call the built-in function */
  1348. if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
  1349. code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
  1350. else
  1351. code = make_code(mpl, op, &arg, A_NUMERIC, 0);
  1352. /* the reference ends with the right parenthesis */
  1353. xassert(mpl->token == T_RIGHT);
  1354. get_token(mpl /* ) */);
  1355. return code;
  1356. }
  1357. /*----------------------------------------------------------------------
  1358. -- create_domain - create empty domain.
  1359. --
  1360. -- This routine creates empty domain, which is initially empty, i.e.
  1361. -- has no domain blocks. */
  1362. DOMAIN *create_domain(MPL *mpl)
  1363. { DOMAIN *domain;
  1364. domain = alloc(DOMAIN);
  1365. domain->list = NULL;
  1366. domain->code = NULL;
  1367. return domain;
  1368. }
  1369. /*----------------------------------------------------------------------
  1370. -- create_block - create empty domain block.
  1371. --
  1372. -- This routine creates empty domain block, which is initially empty,
  1373. -- i.e. has no domain slots. */
  1374. DOMAIN_BLOCK *create_block(MPL *mpl)
  1375. { DOMAIN_BLOCK *block;
  1376. block = alloc(DOMAIN_BLOCK);
  1377. block->list = NULL;
  1378. block->code = NULL;
  1379. block->backup = NULL;
  1380. block->next = NULL;
  1381. return block;
  1382. }
  1383. /*----------------------------------------------------------------------
  1384. -- append_block - append domain block to specified domain.
  1385. --
  1386. -- This routine adds given domain block to the end of the block list of
  1387. -- specified domain. */
  1388. void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
  1389. { DOMAIN_BLOCK *temp;
  1390. xassert(mpl == mpl);
  1391. xassert(domain != NULL);
  1392. xassert(block != NULL);
  1393. xassert(block->next == NULL);
  1394. if (domain->list == NULL)
  1395. domain->list = block;
  1396. else
  1397. { for (temp = domain->list; temp->next != NULL; temp =
  1398. temp->next);
  1399. temp->next = block;
  1400. }
  1401. return;
  1402. }
  1403. /*----------------------------------------------------------------------
  1404. -- append_slot - create and append new slot to domain block.
  1405. --
  1406. -- This routine creates new domain slot and adds it to the end of slot
  1407. -- list of specified domain block.
  1408. --
  1409. -- The parameter name is symbolic name of the dummy index associated
  1410. -- with the slot (the character string must be allocated). NULL means
  1411. -- the dummy index is not explicitly specified.
  1412. --
  1413. -- The parameter code is pseudo-code for computing symbolic value, at
  1414. -- which the dummy index is bounded. NULL means the dummy index is free
  1415. -- in the domain scope. */
  1416. DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
  1417. CODE *code)
  1418. { DOMAIN_SLOT *slot, *temp;
  1419. xassert(block != NULL);
  1420. slot = alloc(DOMAIN_SLOT);
  1421. slot->name = name;
  1422. slot->code = code;
  1423. slot->value = NULL;
  1424. slot->list = NULL;
  1425. slot->next = NULL;
  1426. if (block->list == NULL)
  1427. block->list = slot;
  1428. else
  1429. { for (temp = block->list; temp->next != NULL; temp =
  1430. temp->next);
  1431. temp->next = slot;
  1432. }
  1433. return slot;
  1434. }
  1435. /*----------------------------------------------------------------------
  1436. -- expression_list - parse expression list.
  1437. --
  1438. -- This routine parses a list of one or more expressions enclosed into
  1439. -- the parentheses using the syntax:
  1440. --
  1441. -- <primary expression> ::= ( <expression list> )
  1442. -- <expression list> ::= <expression 13>
  1443. -- <expression list> ::= <expression 13> , <expression list>
  1444. --
  1445. -- Note that this construction may have three different meanings:
  1446. --
  1447. -- 1. If <expression list> consists of only one expression, <primary
  1448. -- expression> is a parenthesized expression, which may be of any
  1449. -- valid type (not necessarily 1-tuple).
  1450. --
  1451. -- 2. If <expression list> consists of several expressions separated by
  1452. -- commae, where no expression is undeclared symbolic name, <primary
  1453. -- expression> is a n-tuple.
  1454. --
  1455. -- 3. If <expression list> consists of several expressions separated by
  1456. -- commae, where at least one expression is undeclared symbolic name
  1457. -- (that denotes a dummy index), <primary expression> is a slice and
  1458. -- can be only used as constituent of indexing expression. */
  1459. #define max_dim 20
  1460. /* maximal number of components allowed within parentheses */
  1461. CODE *expression_list(MPL *mpl)
  1462. { CODE *code;
  1463. OPERANDS arg;
  1464. struct { char *name; CODE *code; } list[1+max_dim];
  1465. int flag_x, next_token, dim, j, slice = 0;
  1466. xassert(mpl->token == T_LEFT);
  1467. /* the flag, which allows recognizing undeclared symbolic names
  1468. as dummy indices, will be automatically reset by get_token(),
  1469. so save it before scanning the next token */
  1470. flag_x = mpl->flag_x;
  1471. get_token(mpl /* ( */);
  1472. /* parse <expression list> */
  1473. for (dim = 1; ; dim++)
  1474. { if (dim > max_dim)
  1475. error(mpl, "too many components within parentheses");
  1476. /* current component of <expression list> can be either dummy
  1477. index or expression */
  1478. if (mpl->token == T_NAME)
  1479. { /* symbolic name is recognized as dummy index only if:
  1480. the flag, which allows that, is set, and
  1481. the name is followed by comma or right parenthesis, and
  1482. the name is undeclared */
  1483. get_token(mpl /* <symbolic name> */);
  1484. next_token = mpl->token;
  1485. unget_token(mpl);
  1486. if (!(flag_x &&
  1487. (next_token == T_COMMA || next_token == T_RIGHT) &&
  1488. avl_find_node(mpl->tree, mpl->image) == NULL))
  1489. { /* this is not dummy index */
  1490. goto expr;
  1491. }
  1492. /* all dummy indices within the same slice must have unique
  1493. symbolic names */
  1494. for (j = 1; j < dim; j++)
  1495. { if (list[j].name != NULL && strcmp(list[j].name,
  1496. mpl->image) == 0)
  1497. error(mpl, "duplicate dummy index %s not allowed",
  1498. mpl->image);
  1499. }
  1500. /* current component of <expression list> is dummy index */
  1501. list[dim].name
  1502. = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  1503. strcpy(list[dim].name, mpl->image);
  1504. list[dim].code = NULL;
  1505. get_token(mpl /* <symbolic name> */);
  1506. /* <expression list> is a slice, because at least one dummy
  1507. index has appeared */
  1508. slice = 1;
  1509. /* note that the context ( <dummy index> ) is not allowed,
  1510. i.e. in this case <primary expression> is considered as
  1511. a parenthesized expression */
  1512. if (dim == 1 && mpl->token == T_RIGHT)
  1513. error(mpl, "%s not defined", list[dim].name);
  1514. }
  1515. else
  1516. expr: { /* current component of <expression list> is expression */
  1517. code = expression_13(mpl);
  1518. /* if the current expression is followed by comma or it is
  1519. not the very first expression, entire <expression list>
  1520. is n-tuple or slice, in which case the current expression
  1521. should be converted to symbolic type, if necessary */
  1522. if (mpl->token == T_COMMA || dim > 1)
  1523. { if (code->type == A_NUMERIC)
  1524. code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
  1525. /* now the expression must be of symbolic type */
  1526. if (code->type != A_SYMBOLIC)
  1527. error(mpl, "component expression has invalid type");
  1528. xassert(code->dim == 0);
  1529. }
  1530. list[dim].name = NULL;
  1531. list[dim].code = code;
  1532. }
  1533. /* check a token that follows the current component */
  1534. if (mpl->token == T_COMMA)
  1535. get_token(mpl /* , */);
  1536. else if (mpl->token == T_RIGHT)
  1537. break;
  1538. else
  1539. error(mpl, "right parenthesis missing where expected");
  1540. }
  1541. /* generate pseudo-code for <primary expression> */
  1542. if (dim == 1 && !slice)
  1543. { /* <primary expression> is a parenthesized expression */
  1544. code = list[1].code;
  1545. }
  1546. else if (!slice)
  1547. { /* <primary expression> is a n-tuple */
  1548. arg.list = create_arg_list(mpl);
  1549. for (j = 1; j <= dim; j++)
  1550. arg.list = expand_arg_list(mpl, arg.list, list[j].code);
  1551. code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
  1552. }
  1553. else
  1554. { /* <primary expression> is a slice */
  1555. arg.slice = create_block(mpl);
  1556. for (j = 1; j <= dim; j++)
  1557. append_slot(mpl, arg.slice, list[j].name, list[j].code);
  1558. /* note that actually pseudo-codes with op = O_SLICE are never
  1559. evaluated */
  1560. code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
  1561. }
  1562. get_token(mpl /* ) */);
  1563. /* if <primary expression> is a slice, there must be the keyword
  1564. 'in', which follows the right parenthesis */
  1565. if (slice && mpl->token != T_IN)
  1566. error(mpl, "keyword in missing where expected");
  1567. /* if the slice flag is set and there is the keyword 'in', which
  1568. follows <primary expression>, the latter must be a slice */
  1569. if (flag_x && mpl->token == T_IN && !slice)
  1570. { if (dim == 1)
  1571. error(mpl, "syntax error in indexing expression");
  1572. else
  1573. error(mpl, "0-ary slice not allowed");
  1574. }
  1575. return code;
  1576. }
  1577. /*----------------------------------------------------------------------
  1578. -- literal set - parse literal set.
  1579. --
  1580. -- This routine parses literal set using the syntax:
  1581. --
  1582. -- <literal set> ::= { <member list> }
  1583. -- <member list> ::= <member expression>
  1584. -- <member list> ::= <member list> , <member expression>
  1585. -- <member expression> ::= <expression 5>
  1586. --
  1587. -- It is assumed that the left curly brace and the very first member
  1588. -- expression that follows it are already parsed. The right curly brace
  1589. -- remains unscanned on exit. */
  1590. CODE *literal_set(MPL *mpl, CODE *code)
  1591. { OPERANDS arg;
  1592. int j;
  1593. xassert(code != NULL);
  1594. arg.list = create_arg_list(mpl);
  1595. /* parse <member list> */
  1596. for (j = 1; ; j++)
  1597. { /* all member expressions must be n-tuples; so, if the current
  1598. expression is not n-tuple, convert it to 1-tuple */
  1599. if (code->type == A_NUMERIC)
  1600. code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
  1601. if (code->type == A_SYMBOLIC)
  1602. code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
  1603. /* now the expression must be n-tuple */
  1604. if (code->type != A_TUPLE)
  1605. error(mpl, "member expression has invalid type");
  1606. /* all member expressions must have identical dimension */
  1607. if (arg.list != NULL && arg.list->x->dim != code->dim)
  1608. error(mpl, "member %d has %d component%s while member %d ha"
  1609. "s %d component%s",
  1610. j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
  1611. j, code->dim, code->dim == 1 ? "" : "s");
  1612. /* append the current expression to the member list */
  1613. arg.list = expand_arg_list(mpl, arg.list, code);
  1614. /* check a token that follows the current expression */
  1615. if (mpl->token == T_COMMA)
  1616. get_token(mpl /* , */);
  1617. else if (mpl->token == T_RBRACE)
  1618. break;
  1619. else
  1620. error(mpl, "syntax error in literal set");
  1621. /* parse the next expression that follows the comma */
  1622. code = expression_5(mpl);
  1623. }
  1624. /* generate pseudo-code for <literal set> */
  1625. code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
  1626. return code;
  1627. }
  1628. /*----------------------------------------------------------------------
  1629. -- indexing_expression - parse indexing expression.
  1630. --
  1631. -- This routine parses indexing expression using the syntax:
  1632. --
  1633. -- <indexing expression> ::= <literal set>
  1634. -- <indexing expression> ::= { <indexing list> }
  1635. -- <indexing expression> ::= { <indexing list> : <logical expression> }
  1636. -- <indexing list> ::= <indexing element>
  1637. -- <indexing list> ::= <indexing list> , <indexing element>
  1638. -- <indexing element> ::= <basic expression>
  1639. -- <indexing element> ::= <dummy index> in <basic expression>
  1640. -- <indexing element> ::= <slice> in <basic expression>
  1641. -- <dummy index> ::= <symbolic name>
  1642. -- <slice> ::= ( <expression list> )
  1643. -- <basic expression> ::= <expression 9>
  1644. -- <logical expression> ::= <expression 13>
  1645. --
  1646. -- This routine creates domain for <indexing expression>, where each
  1647. -- domain block corresponds to <indexing element>, and each domain slot
  1648. -- corresponds to individual indexing position. */
  1649. DOMAIN *indexing_expression(MPL *mpl)
  1650. { DOMAIN *domain;
  1651. DOMAIN_BLOCK *block;
  1652. DOMAIN_SLOT *slot;
  1653. CODE *code;
  1654. xassert(mpl->token == T_LBRACE);
  1655. get_token(mpl /* { */);
  1656. if (mpl->token == T_RBRACE)
  1657. error(mpl, "empty indexing expression not allowed");
  1658. /* create domain to be constructed */
  1659. domain = create_domain(mpl);
  1660. /* parse either <member list> or <indexing list> that follows the
  1661. left brace */
  1662. for (;;)
  1663. { /* domain block for <indexing element> is not created yet */
  1664. block = NULL;
  1665. /* pseudo-code for <basic expression> is not generated yet */
  1666. code = NULL;
  1667. /* check a token, which <indexing element> begins with */
  1668. if (mpl->token == T_NAME)
  1669. { /* it is a symbolic name */
  1670. int next_token;
  1671. char *name;
  1672. /* symbolic name is recognized as dummy index only if it is
  1673. followed by the keyword 'in' and not declared */
  1674. get_token(mpl /* <symbolic name> */);
  1675. next_token = mpl->token;
  1676. unget_token(mpl);
  1677. if (!(next_token == T_IN &&
  1678. avl_find_node(mpl->tree, mpl->image) == NULL))
  1679. { /* this is not dummy index; the symbolic name begins an
  1680. expression, which is either <basic expression> or the
  1681. very first <member expression> in <literal set> */
  1682. goto expr;
  1683. }
  1684. /* create domain block with one slot, which is assigned the
  1685. dummy index */
  1686. block = create_block(mpl);
  1687. name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  1688. strcpy(name, mpl->image);
  1689. append_slot(mpl, block, name, NULL);
  1690. get_token(mpl /* <symbolic name> */);
  1691. /* the keyword 'in' is already checked above */
  1692. xassert(mpl->token == T_IN);
  1693. get_token(mpl /* in */);
  1694. /* <basic expression> that follows the keyword 'in' will be
  1695. parsed below */
  1696. }
  1697. else if (mpl->token == T_LEFT)
  1698. { /* it is the left parenthesis; parse expression that begins
  1699. with this parenthesis (the flag is set in order to allow
  1700. recognizing slices; see the routine expression_list) */
  1701. mpl->flag_x = 1;
  1702. code = expression_9(mpl);
  1703. if (code->op != O_SLICE)
  1704. { /* this is either <basic expression> or the very first
  1705. <member expression> in <literal set> */
  1706. goto expr;
  1707. }
  1708. /* this is a slice; besides the corresponding domain block
  1709. is already created by expression_list() */
  1710. block = code->arg.slice;
  1711. code = NULL; /* <basic expression> is not parsed yet */
  1712. /* the keyword 'in' following the slice is already checked
  1713. by expression_list() */
  1714. xassert(mpl->token == T_IN);
  1715. get_token(mpl /* in */);
  1716. /* <basic expression> that follows the keyword 'in' will be
  1717. parsed below */
  1718. }
  1719. expr: /* parse expression that follows either the keyword 'in' (in
  1720. which case it can be <basic expression) or the left brace
  1721. (in which case it can be <basic expression> as well as the
  1722. very first <member expression> in <literal set>); note that
  1723. this expression can be already parsed above */
  1724. if (code == NULL) code = expression_9(mpl);
  1725. /* check the type of the expression just parsed */
  1726. if (code->type != A_ELEMSET)
  1727. { /* it is not <basic expression> and therefore it can only
  1728. be the very first <member expression> in <literal set>;
  1729. however, then there must be no dummy index neither slice
  1730. between the left brace and this expression */
  1731. if (block != NULL)
  1732. error(mpl, "domain expression has invalid type");
  1733. /* parse the rest part of <literal set> and make this set
  1734. be <basic expression>, i.e. the construction {a, b, c}
  1735. is parsed as it were written as {A}, where A = {a, b, c}
  1736. is a temporary elemental set */
  1737. code = literal_set(mpl, code);
  1738. }
  1739. /* now pseudo-code for <basic set> has been built */
  1740. xassert(code != NULL);
  1741. xassert(code->type == A_ELEMSET);
  1742. xassert(code->dim > 0);
  1743. /* if domain block for the current <indexing element> is still
  1744. not created, create it for fake slice of the same dimension
  1745. as <basic set> */
  1746. if (block == NULL)
  1747. { int j;
  1748. block = create_block(mpl);
  1749. for (j = 1; j <= code->dim; j++)
  1750. append_slot(mpl, block, NULL, NULL);
  1751. }
  1752. /* number of indexing positions in <indexing element> must be
  1753. the same as dimension of n-tuples in basic set */
  1754. { int dim = 0;
  1755. for (slot = block->list; slot != NULL; slot = slot->next)
  1756. dim++;
  1757. if (dim != code->dim)
  1758. error(mpl,"%d %s specified for set of dimension %d",
  1759. dim, dim == 1 ? "index" : "indices", code->dim);
  1760. }
  1761. /* store pseudo-code for <basic set> in the domain block */
  1762. xassert(block->code == NULL);
  1763. block->code = code;
  1764. /* and append the domain block to the domain */
  1765. append_block(mpl, domain, block);
  1766. /* the current <indexing element> has been completely parsed;
  1767. include all its dummy indices into the symbolic name table
  1768. to make them available for referencing from expressions;
  1769. implicit declarations of dummy indices remain valid while
  1770. the corresponding domain scope is valid */
  1771. for (slot = block->list; slot != NULL; slot = slot->next)
  1772. if (slot->name != NULL)
  1773. { AVLNODE *node;
  1774. xassert(avl_find_node(mpl->tree, slot->name) == NULL);
  1775. node = avl_insert_node(mpl->tree, slot->name);
  1776. avl_set_node_type(node, A_INDEX);
  1777. avl_set_node_link(node, (void *)slot);
  1778. }
  1779. /* check a token that follows <indexing element> */
  1780. if (mpl->token == T_COMMA)
  1781. get_token(mpl /* , */);
  1782. else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
  1783. break;
  1784. else
  1785. error(mpl, "syntax error in indexing expression");
  1786. }
  1787. /* parse <logical expression> that follows the colon */
  1788. if (mpl->token == T_COLON)
  1789. { get_token(mpl /* : */);
  1790. code = expression_13(mpl);
  1791. /* convert the expression to logical type, if necessary */
  1792. if (code->type == A_SYMBOLIC)
  1793. code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
  1794. if (code->type == A_NUMERIC)
  1795. code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
  1796. /* now the expression must be of logical type */
  1797. if (code->type != A_LOGICAL)
  1798. error(mpl, "expression following colon has invalid type");
  1799. xassert(code->dim == 0);
  1800. domain->code = code;
  1801. /* the right brace must follow the logical expression */
  1802. if (mpl->token != T_RBRACE)
  1803. error(mpl, "syntax error in indexing expression");
  1804. }
  1805. get_token(mpl /* } */);
  1806. return domain;
  1807. }
  1808. /*----------------------------------------------------------------------
  1809. -- close_scope - close scope of indexing expression.
  1810. --
  1811. -- The routine closes the scope of indexing expression specified by its
  1812. -- domain and thereby makes all dummy indices introduced in the indexing
  1813. -- expression no longer available for referencing. */
  1814. void close_scope(MPL *mpl, DOMAIN *domain)
  1815. { DOMAIN_BLOCK *block;
  1816. DOMAIN_SLOT *slot;
  1817. AVLNODE *node;
  1818. xassert(domain != NULL);
  1819. /* remove all dummy indices from the symbolic names table */
  1820. for (block = domain->list; block != NULL; block = block->next)
  1821. { for (slot = block->list; slot != NULL; slot = slot->next)
  1822. { if (slot->name != NULL)
  1823. { node = avl_find_node(mpl->tree, slot->name);
  1824. xassert(node != NULL);
  1825. xassert(avl_get_node_type(node) == A_INDEX);
  1826. avl_delete_node(mpl->tree, node);
  1827. }
  1828. }
  1829. }
  1830. return;
  1831. }
  1832. /*----------------------------------------------------------------------
  1833. -- iterated_expression - parse iterated expression.
  1834. --
  1835. -- This routine parses primary expression using the syntax:
  1836. --
  1837. -- <primary expression> ::= <iterated expression>
  1838. -- <iterated expression> ::= sum <indexing expression> <expression 3>
  1839. -- <iterated expression> ::= prod <indexing expression> <expression 3>
  1840. -- <iterated expression> ::= min <indexing expression> <expression 3>
  1841. -- <iterated expression> ::= max <indexing expression> <expression 3>
  1842. -- <iterated expression> ::= exists <indexing expression>
  1843. -- <expression 12>
  1844. -- <iterated expression> ::= forall <indexing expression>
  1845. -- <expression 12>
  1846. -- <iterated expression> ::= setof <indexing expression> <expression 5>
  1847. --
  1848. -- Note that parsing "integrand" depends on the iterated operator. */
  1849. #if 1 /* 07/IX-2008 */
  1850. static void link_up(CODE *code)
  1851. { /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
  1852. where i and k are dummy indices defined out of the iterated
  1853. expression, we should link up pseudo-code for computing i+1
  1854. and k-1 to pseudo-code for computing the iterated expression;
  1855. this is needed to invalidate current value of the iterated
  1856. expression once i or k have been changed */
  1857. DOMAIN_BLOCK *block;
  1858. DOMAIN_SLOT *slot;
  1859. for (block = code->arg.loop.domain->list; block != NULL;
  1860. block = block->next)
  1861. { for (slot = block->list; slot != NULL; slot = slot->next)
  1862. { if (slot->code != NULL)
  1863. { xassert(slot->code->up == NULL);
  1864. slot->code->up = code;
  1865. }
  1866. }
  1867. }
  1868. return;
  1869. }
  1870. #endif
  1871. CODE *iterated_expression(MPL *mpl)
  1872. { CODE *code;
  1873. OPERANDS arg;
  1874. int op;
  1875. char opstr[8];
  1876. /* determine operation code */
  1877. xassert(mpl->token == T_NAME);
  1878. if (strcmp(mpl->image, "sum") == 0)
  1879. op = O_SUM;
  1880. else if (strcmp(mpl->image, "prod") == 0)
  1881. op = O_PROD;
  1882. else if (strcmp(mpl->image, "min") == 0)
  1883. op = O_MINIMUM;
  1884. else if (strcmp(mpl->image, "max") == 0)
  1885. op = O_MAXIMUM;
  1886. else if (strcmp(mpl->image, "forall") == 0)
  1887. op = O_FORALL;
  1888. else if (strcmp(mpl->image, "exists") == 0)
  1889. op = O_EXISTS;
  1890. else if (strcmp(mpl->image, "setof") == 0)
  1891. op = O_SETOF;
  1892. else
  1893. error(mpl, "operator %s unknown", mpl->image);
  1894. strcpy(opstr, mpl->image);
  1895. xassert(strlen(opstr) < sizeof(opstr));
  1896. get_token(mpl /* <symbolic name> */);
  1897. /* check the left brace that follows the operator name */
  1898. xassert(mpl->token == T_LBRACE);
  1899. /* parse indexing expression that controls iterating */
  1900. arg.loop.domain = indexing_expression(mpl);
  1901. /* parse "integrand" expression and generate pseudo-code */
  1902. switch (op)
  1903. { case O_SUM:
  1904. case O_PROD:
  1905. case O_MINIMUM:
  1906. case O_MAXIMUM:
  1907. arg.loop.x = expression_3(mpl);
  1908. /* convert the integrand to numeric type, if necessary */
  1909. if (arg.loop.x->type == A_SYMBOLIC)
  1910. arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
  1911. A_NUMERIC, 0);
  1912. /* now the integrand must be of numeric type or linear form
  1913. (the latter is only allowed for the sum operator) */
  1914. if (!(arg.loop.x->type == A_NUMERIC ||
  1915. op == O_SUM && arg.loop.x->type == A_FORMULA))
  1916. err: error(mpl, "integrand following %s{...} has invalid type"
  1917. , opstr);
  1918. xassert(arg.loop.x->dim == 0);
  1919. /* generate pseudo-code */
  1920. code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
  1921. break;
  1922. case O_FORALL:
  1923. case O_EXISTS:
  1924. arg.loop.x = expression_12(mpl);
  1925. /* convert the integrand to logical type, if necessary */
  1926. if (arg.loop.x->type == A_SYMBOLIC)
  1927. arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
  1928. A_NUMERIC, 0);
  1929. if (arg.loop.x->type == A_NUMERIC)
  1930. arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
  1931. A_LOGICAL, 0);
  1932. /* now the integrand must be of logical type */
  1933. if (arg.loop.x->type != A_LOGICAL) goto err;
  1934. xassert(arg.loop.x->dim == 0);
  1935. /* generate pseudo-code */
  1936. code = make_code(mpl, op, &arg, A_LOGICAL, 0);
  1937. break;
  1938. case O_SETOF:
  1939. arg.loop.x = expression_5(mpl);
  1940. /* convert the integrand to 1-tuple, if necessary */
  1941. if (arg.loop.x->type == A_NUMERIC)
  1942. arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
  1943. A_SYMBOLIC, 0);
  1944. if (arg.loop.x->type == A_SYMBOLIC)
  1945. arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
  1946. A_TUPLE, 1);
  1947. /* now the integrand must be n-tuple */
  1948. if (arg.loop.x->type != A_TUPLE) goto err;
  1949. xassert(arg.loop.x->dim > 0);
  1950. /* generate pseudo-code */
  1951. code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
  1952. break;
  1953. default:
  1954. xassert(op != op);
  1955. }
  1956. /* close the scope of the indexing expression */
  1957. close_scope(mpl, arg.loop.domain);
  1958. #if 1 /* 07/IX-2008 */
  1959. link_up(code);
  1960. #endif
  1961. return code;
  1962. }
  1963. /*----------------------------------------------------------------------
  1964. -- domain_arity - determine arity of domain.
  1965. --
  1966. -- This routine returns arity of specified domain, which is number of
  1967. -- its free dummy indices. */
  1968. int domain_arity(MPL *mpl, DOMAIN *domain)
  1969. { DOMAIN_BLOCK *block;
  1970. DOMAIN_SLOT *slot;
  1971. int arity;
  1972. xassert(mpl == mpl);
  1973. arity = 0;
  1974. for (block = domain->list; block != NULL; block = block->next)
  1975. for (slot = block->list; slot != NULL; slot = slot->next)
  1976. if (slot->code == NULL) arity++;
  1977. return arity;
  1978. }
  1979. /*----------------------------------------------------------------------
  1980. -- set_expression - parse set expression.
  1981. --
  1982. -- This routine parses primary expression using the syntax:
  1983. --
  1984. -- <primary expression> ::= { }
  1985. -- <primary expression> ::= <indexing expression> */
  1986. CODE *set_expression(MPL *mpl)
  1987. { CODE *code;
  1988. OPERANDS arg;
  1989. xassert(mpl->token == T_LBRACE);
  1990. get_token(mpl /* { */);
  1991. /* check a token that follows the left brace */
  1992. if (mpl->token == T_RBRACE)
  1993. { /* it is the right brace, so the resultant is an empty set of
  1994. dimension 1 */
  1995. arg.list = NULL;
  1996. /* generate pseudo-code to build the resultant set */
  1997. code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
  1998. get_token(mpl /* } */);
  1999. }
  2000. else
  2001. { /* the next token begins an indexing expression */
  2002. unget_token(mpl);
  2003. arg.loop.domain = indexing_expression(mpl);
  2004. arg.loop.x = NULL; /* integrand is not used */
  2005. /* close the scope of the indexing expression */
  2006. close_scope(mpl, arg.loop.domain);
  2007. /* generate pseudo-code to build the resultant set */
  2008. code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
  2009. domain_arity(mpl, arg.loop.domain));
  2010. #if 1 /* 07/IX-2008 */
  2011. link_up(code);
  2012. #endif
  2013. }
  2014. return code;
  2015. }
  2016. /*----------------------------------------------------------------------
  2017. -- branched_expression - parse conditional expression.
  2018. --
  2019. -- This routine parses primary expression using the syntax:
  2020. --
  2021. -- <primary expression> ::= <branched expression>
  2022. -- <branched expression> ::= if <logical expression> then <expression 9>
  2023. -- <branched expression> ::= if <logical expression> then <expression 9>
  2024. -- else <expression 9>
  2025. -- <logical expression> ::= <expression 13> */
  2026. CODE *branched_expression(MPL *mpl)
  2027. { CODE *code, *x, *y, *z;
  2028. xassert(mpl->token == T_IF);
  2029. get_token(mpl /* if */);
  2030. /* parse <logical expression> that follows 'if' */
  2031. x = expression_13(mpl);
  2032. /* convert the expression to logical type, if necessary */
  2033. if (x->type == A_SYMBOLIC)
  2034. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2035. if (x->type == A_NUMERIC)
  2036. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2037. /* now the expression must be of logical type */
  2038. if (x->type != A_LOGICAL)
  2039. error(mpl, "expression following if has invalid type");
  2040. xassert(x->dim == 0);
  2041. /* the keyword 'then' must follow the logical expression */
  2042. if (mpl->token != T_THEN)
  2043. error(mpl, "keyword then missing where expected");
  2044. get_token(mpl /* then */);
  2045. /* parse <expression> that follows 'then' and check its type */
  2046. y = expression_9(mpl);
  2047. if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
  2048. y->type == A_ELEMSET || y->type == A_FORMULA))
  2049. error(mpl, "expression following then has invalid type");
  2050. /* if the expression that follows the keyword 'then' is elemental
  2051. set, the keyword 'else' cannot be omitted; otherwise else-part
  2052. is optional */
  2053. if (mpl->token != T_ELSE)
  2054. { if (y->type == A_ELEMSET)
  2055. error(mpl, "keyword else missing where expected");
  2056. z = NULL;
  2057. goto skip;
  2058. }
  2059. get_token(mpl /* else */);
  2060. /* parse <expression> that follow 'else' and check its type */
  2061. z = expression_9(mpl);
  2062. if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
  2063. z->type == A_ELEMSET || z->type == A_FORMULA))
  2064. error(mpl, "expression following else has invalid type");
  2065. /* convert to identical types, if necessary */
  2066. if (y->type == A_FORMULA || z->type == A_FORMULA)
  2067. { if (y->type == A_SYMBOLIC)
  2068. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2069. if (y->type == A_NUMERIC)
  2070. y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
  2071. if (z->type == A_SYMBOLIC)
  2072. z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
  2073. if (z->type == A_NUMERIC)
  2074. z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
  2075. }
  2076. if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
  2077. { if (y->type == A_NUMERIC)
  2078. y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
  2079. if (z->type == A_NUMERIC)
  2080. z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
  2081. }
  2082. /* now both expressions must have identical types */
  2083. if (y->type != z->type)
  2084. error(mpl, "expressions following then and else have incompati"
  2085. "ble types");
  2086. /* and identical dimensions */
  2087. if (y->dim != z->dim)
  2088. error(mpl, "expressions following then and else have different"
  2089. " dimensions %d and %d, respectively", y->dim, z->dim);
  2090. skip: /* generate pseudo-code to perform branching */
  2091. code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
  2092. return code;
  2093. }
  2094. /*----------------------------------------------------------------------
  2095. -- primary_expression - parse primary expression.
  2096. --
  2097. -- This routine parses primary expression using the syntax:
  2098. --
  2099. -- <primary expression> ::= <numeric literal>
  2100. -- <primary expression> ::= Infinity
  2101. -- <primary expression> ::= <string literal>
  2102. -- <primary expression> ::= <dummy index>
  2103. -- <primary expression> ::= <set name>
  2104. -- <primary expression> ::= <set name> [ <subscript list> ]
  2105. -- <primary expression> ::= <parameter name>
  2106. -- <primary expression> ::= <parameter name> [ <subscript list> ]
  2107. -- <primary expression> ::= <variable name>
  2108. -- <primary expression> ::= <variable name> [ <subscript list> ]
  2109. -- <primary expression> ::= <built-in function> ( <argument list> )
  2110. -- <primary expression> ::= ( <expression list> )
  2111. -- <primary expression> ::= <iterated expression>
  2112. -- <primary expression> ::= { }
  2113. -- <primary expression> ::= <indexing expression>
  2114. -- <primary expression> ::= <branched expression>
  2115. --
  2116. -- For complete list of syntactic rules for <primary expression> see
  2117. -- comments to the corresponding parsing routines. */
  2118. CODE *primary_expression(MPL *mpl)
  2119. { CODE *code;
  2120. if (mpl->token == T_NUMBER)
  2121. { /* parse numeric literal */
  2122. code = numeric_literal(mpl);
  2123. }
  2124. #if 1 /* 21/VII-2006 */
  2125. else if (mpl->token == T_INFINITY)
  2126. { /* parse "infinity" */
  2127. OPERANDS arg;
  2128. arg.num = DBL_MAX;
  2129. code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
  2130. get_token(mpl /* Infinity */);
  2131. }
  2132. #endif
  2133. else if (mpl->token == T_STRING)
  2134. { /* parse string literal */
  2135. code = string_literal(mpl);
  2136. }
  2137. else if (mpl->token == T_NAME)
  2138. { int next_token;
  2139. get_token(mpl /* <symbolic name> */);
  2140. next_token = mpl->token;
  2141. unget_token(mpl);
  2142. /* check a token that follows <symbolic name> */
  2143. switch (next_token)
  2144. { case T_LBRACKET:
  2145. /* parse reference to subscripted object */
  2146. code = object_reference(mpl);
  2147. break;
  2148. case T_LEFT:
  2149. /* parse reference to built-in function */
  2150. code = function_reference(mpl);
  2151. break;
  2152. case T_LBRACE:
  2153. /* parse iterated expression */
  2154. code = iterated_expression(mpl);
  2155. break;
  2156. default:
  2157. /* parse reference to unsubscripted object */
  2158. code = object_reference(mpl);
  2159. break;
  2160. }
  2161. }
  2162. else if (mpl->token == T_LEFT)
  2163. { /* parse parenthesized expression */
  2164. code = expression_list(mpl);
  2165. }
  2166. else if (mpl->token == T_LBRACE)
  2167. { /* parse set expression */
  2168. code = set_expression(mpl);
  2169. }
  2170. else if (mpl->token == T_IF)
  2171. { /* parse conditional expression */
  2172. code = branched_expression(mpl);
  2173. }
  2174. else if (is_reserved(mpl))
  2175. { /* other reserved keywords cannot be used here */
  2176. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  2177. }
  2178. else
  2179. error(mpl, "syntax error in expression");
  2180. return code;
  2181. }
  2182. /*----------------------------------------------------------------------
  2183. -- error_preceding - raise error if preceding operand has wrong type.
  2184. --
  2185. -- This routine is called to raise error if operand that precedes some
  2186. -- infix operator has invalid type. */
  2187. void error_preceding(MPL *mpl, char *opstr)
  2188. { error(mpl, "operand preceding %s has invalid type", opstr);
  2189. /* no return */
  2190. }
  2191. /*----------------------------------------------------------------------
  2192. -- error_following - raise error if following operand has wrong type.
  2193. --
  2194. -- This routine is called to raise error if operand that follows some
  2195. -- infix operator has invalid type. */
  2196. void error_following(MPL *mpl, char *opstr)
  2197. { error(mpl, "operand following %s has invalid type", opstr);
  2198. /* no return */
  2199. }
  2200. /*----------------------------------------------------------------------
  2201. -- error_dimension - raise error if operands have different dimension.
  2202. --
  2203. -- This routine is called to raise error if two operands of some infix
  2204. -- operator have different dimension. */
  2205. void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
  2206. { error(mpl, "operands preceding and following %s have different di"
  2207. "mensions %d and %d, respectively", opstr, dim1, dim2);
  2208. /* no return */
  2209. }
  2210. /*----------------------------------------------------------------------
  2211. -- expression_0 - parse expression of level 0.
  2212. --
  2213. -- This routine parses expression of level 0 using the syntax:
  2214. --
  2215. -- <expression 0> ::= <primary expression> */
  2216. CODE *expression_0(MPL *mpl)
  2217. { CODE *code;
  2218. code = primary_expression(mpl);
  2219. return code;
  2220. }
  2221. /*----------------------------------------------------------------------
  2222. -- expression_1 - parse expression of level 1.
  2223. --
  2224. -- This routine parses expression of level 1 using the syntax:
  2225. --
  2226. -- <expression 1> ::= <expression 0>
  2227. -- <expression 1> ::= <expression 0> <power> <expression 1>
  2228. -- <expression 1> ::= <expression 0> <power> <expression 2>
  2229. -- <power> ::= ^ | ** */
  2230. CODE *expression_1(MPL *mpl)
  2231. { CODE *x, *y;
  2232. char opstr[8];
  2233. x = expression_0(mpl);
  2234. if (mpl->token == T_POWER)
  2235. { strcpy(opstr, mpl->image);
  2236. xassert(strlen(opstr) < sizeof(opstr));
  2237. if (x->type == A_SYMBOLIC)
  2238. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2239. if (x->type != A_NUMERIC)
  2240. error_preceding(mpl, opstr);
  2241. get_token(mpl /* ^ | ** */);
  2242. if (mpl->token == T_PLUS || mpl->token == T_MINUS)
  2243. y = expression_2(mpl);
  2244. else
  2245. y = expression_1(mpl);
  2246. if (y->type == A_SYMBOLIC)
  2247. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2248. if (y->type != A_NUMERIC)
  2249. error_following(mpl, opstr);
  2250. x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
  2251. }
  2252. return x;
  2253. }
  2254. /*----------------------------------------------------------------------
  2255. -- expression_2 - parse expression of level 2.
  2256. --
  2257. -- This routine parses expression of level 2 using the syntax:
  2258. --
  2259. -- <expression 2> ::= <expression 1>
  2260. -- <expression 2> ::= + <expression 1>
  2261. -- <expression 2> ::= - <expression 1> */
  2262. CODE *expression_2(MPL *mpl)
  2263. { CODE *x;
  2264. if (mpl->token == T_PLUS)
  2265. { get_token(mpl /* + */);
  2266. x = expression_1(mpl);
  2267. if (x->type == A_SYMBOLIC)
  2268. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2269. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2270. error_following(mpl, "+");
  2271. x = make_unary(mpl, O_PLUS, x, x->type, 0);
  2272. }
  2273. else if (mpl->token == T_MINUS)
  2274. { get_token(mpl /* - */);
  2275. x = expression_1(mpl);
  2276. if (x->type == A_SYMBOLIC)
  2277. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2278. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2279. error_following(mpl, "-");
  2280. x = make_unary(mpl, O_MINUS, x, x->type, 0);
  2281. }
  2282. else
  2283. x = expression_1(mpl);
  2284. return x;
  2285. }
  2286. /*----------------------------------------------------------------------
  2287. -- expression_3 - parse expression of level 3.
  2288. --
  2289. -- This routine parses expression of level 3 using the syntax:
  2290. --
  2291. -- <expression 3> ::= <expression 2>
  2292. -- <expression 3> ::= <expression 3> * <expression 2>
  2293. -- <expression 3> ::= <expression 3> / <expression 2>
  2294. -- <expression 3> ::= <expression 3> div <expression 2>
  2295. -- <expression 3> ::= <expression 3> mod <expression 2> */
  2296. CODE *expression_3(MPL *mpl)
  2297. { CODE *x, *y;
  2298. x = expression_2(mpl);
  2299. for (;;)
  2300. { if (mpl->token == T_ASTERISK)
  2301. { if (x->type == A_SYMBOLIC)
  2302. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2303. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2304. error_preceding(mpl, "*");
  2305. get_token(mpl /* * */);
  2306. y = expression_2(mpl);
  2307. if (y->type == A_SYMBOLIC)
  2308. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2309. if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
  2310. error_following(mpl, "*");
  2311. if (x->type == A_FORMULA && y->type == A_FORMULA)
  2312. error(mpl, "multiplication of linear forms not allowed");
  2313. if (x->type == A_NUMERIC && y->type == A_NUMERIC)
  2314. x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
  2315. else
  2316. x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
  2317. }
  2318. else if (mpl->token == T_SLASH)
  2319. { if (x->type == A_SYMBOLIC)
  2320. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2321. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2322. error_preceding(mpl, "/");
  2323. get_token(mpl /* / */);
  2324. y = expression_2(mpl);
  2325. if (y->type == A_SYMBOLIC)
  2326. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2327. if (y->type != A_NUMERIC)
  2328. error_following(mpl, "/");
  2329. if (x->type == A_NUMERIC)
  2330. x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
  2331. else
  2332. x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
  2333. }
  2334. else if (mpl->token == T_DIV)
  2335. { if (x->type == A_SYMBOLIC)
  2336. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2337. if (x->type != A_NUMERIC)
  2338. error_preceding(mpl, "div");
  2339. get_token(mpl /* div */);
  2340. y = expression_2(mpl);
  2341. if (y->type == A_SYMBOLIC)
  2342. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2343. if (y->type != A_NUMERIC)
  2344. error_following(mpl, "div");
  2345. x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
  2346. }
  2347. else if (mpl->token == T_MOD)
  2348. { if (x->type == A_SYMBOLIC)
  2349. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2350. if (x->type != A_NUMERIC)
  2351. error_preceding(mpl, "mod");
  2352. get_token(mpl /* mod */);
  2353. y = expression_2(mpl);
  2354. if (y->type == A_SYMBOLIC)
  2355. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2356. if (y->type != A_NUMERIC)
  2357. error_following(mpl, "mod");
  2358. x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
  2359. }
  2360. else
  2361. break;
  2362. }
  2363. return x;
  2364. }
  2365. /*----------------------------------------------------------------------
  2366. -- expression_4 - parse expression of level 4.
  2367. --
  2368. -- This routine parses expression of level 4 using the syntax:
  2369. --
  2370. -- <expression 4> ::= <expression 3>
  2371. -- <expression 4> ::= <expression 4> + <expression 3>
  2372. -- <expression 4> ::= <expression 4> - <expression 3>
  2373. -- <expression 4> ::= <expression 4> less <expression 3> */
  2374. CODE *expression_4(MPL *mpl)
  2375. { CODE *x, *y;
  2376. x = expression_3(mpl);
  2377. for (;;)
  2378. { if (mpl->token == T_PLUS)
  2379. { if (x->type == A_SYMBOLIC)
  2380. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2381. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2382. error_preceding(mpl, "+");
  2383. get_token(mpl /* + */);
  2384. y = expression_3(mpl);
  2385. if (y->type == A_SYMBOLIC)
  2386. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2387. if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
  2388. error_following(mpl, "+");
  2389. if (x->type == A_NUMERIC && y->type == A_FORMULA)
  2390. x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
  2391. if (x->type == A_FORMULA && y->type == A_NUMERIC)
  2392. y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
  2393. x = make_binary(mpl, O_ADD, x, y, x->type, 0);
  2394. }
  2395. else if (mpl->token == T_MINUS)
  2396. { if (x->type == A_SYMBOLIC)
  2397. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2398. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2399. error_preceding(mpl, "-");
  2400. get_token(mpl /* - */);
  2401. y = expression_3(mpl);
  2402. if (y->type == A_SYMBOLIC)
  2403. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2404. if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
  2405. error_following(mpl, "-");
  2406. if (x->type == A_NUMERIC && y->type == A_FORMULA)
  2407. x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
  2408. if (x->type == A_FORMULA && y->type == A_NUMERIC)
  2409. y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
  2410. x = make_binary(mpl, O_SUB, x, y, x->type, 0);
  2411. }
  2412. else if (mpl->token == T_LESS)
  2413. { if (x->type == A_SYMBOLIC)
  2414. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2415. if (x->type != A_NUMERIC)
  2416. error_preceding(mpl, "less");
  2417. get_token(mpl /* less */);
  2418. y = expression_3(mpl);
  2419. if (y->type == A_SYMBOLIC)
  2420. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2421. if (y->type != A_NUMERIC)
  2422. error_following(mpl, "less");
  2423. x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
  2424. }
  2425. else
  2426. break;
  2427. }
  2428. return x;
  2429. }
  2430. /*----------------------------------------------------------------------
  2431. -- expression_5 - parse expression of level 5.
  2432. --
  2433. -- This routine parses expression of level 5 using the syntax:
  2434. --
  2435. -- <expression 5> ::= <expression 4>
  2436. -- <expression 5> ::= <expression 5> & <expression 4> */
  2437. CODE *expression_5(MPL *mpl)
  2438. { CODE *x, *y;
  2439. x = expression_4(mpl);
  2440. for (;;)
  2441. { if (mpl->token == T_CONCAT)
  2442. { if (x->type == A_NUMERIC)
  2443. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  2444. if (x->type != A_SYMBOLIC)
  2445. error_preceding(mpl, "&");
  2446. get_token(mpl /* & */);
  2447. y = expression_4(mpl);
  2448. if (y->type == A_NUMERIC)
  2449. y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
  2450. if (y->type != A_SYMBOLIC)
  2451. error_following(mpl, "&");
  2452. x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
  2453. }
  2454. else
  2455. break;
  2456. }
  2457. return x;
  2458. }
  2459. /*----------------------------------------------------------------------
  2460. -- expression_6 - parse expression of level 6.
  2461. --
  2462. -- This routine parses expression of level 6 using the syntax:
  2463. --
  2464. -- <expression 6> ::= <expression 5>
  2465. -- <expression 6> ::= <expression 5> .. <expression 5>
  2466. -- <expression 6> ::= <expression 5> .. <expression 5> by
  2467. -- <expression 5> */
  2468. CODE *expression_6(MPL *mpl)
  2469. { CODE *x, *y, *z;
  2470. x = expression_5(mpl);
  2471. if (mpl->token == T_DOTS)
  2472. { if (x->type == A_SYMBOLIC)
  2473. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2474. if (x->type != A_NUMERIC)
  2475. error_preceding(mpl, "..");
  2476. get_token(mpl /* .. */);
  2477. y = expression_5(mpl);
  2478. if (y->type == A_SYMBOLIC)
  2479. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2480. if (y->type != A_NUMERIC)
  2481. error_following(mpl, "..");
  2482. if (mpl->token == T_BY)
  2483. { get_token(mpl /* by */);
  2484. z = expression_5(mpl);
  2485. if (z->type == A_SYMBOLIC)
  2486. z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
  2487. if (z->type != A_NUMERIC)
  2488. error_following(mpl, "by");
  2489. }
  2490. else
  2491. z = NULL;
  2492. x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
  2493. }
  2494. return x;
  2495. }
  2496. /*----------------------------------------------------------------------
  2497. -- expression_7 - parse expression of level 7.
  2498. --
  2499. -- This routine parses expression of level 7 using the syntax:
  2500. --
  2501. -- <expression 7> ::= <expression 6>
  2502. -- <expression 7> ::= <expression 7> cross <expression 6> */
  2503. CODE *expression_7(MPL *mpl)
  2504. { CODE *x, *y;
  2505. x = expression_6(mpl);
  2506. for (;;)
  2507. { if (mpl->token == T_CROSS)
  2508. { if (x->type != A_ELEMSET)
  2509. error_preceding(mpl, "cross");
  2510. get_token(mpl /* cross */);
  2511. y = expression_6(mpl);
  2512. if (y->type != A_ELEMSET)
  2513. error_following(mpl, "cross");
  2514. x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
  2515. x->dim + y->dim);
  2516. }
  2517. else
  2518. break;
  2519. }
  2520. return x;
  2521. }
  2522. /*----------------------------------------------------------------------
  2523. -- expression_8 - parse expression of level 8.
  2524. --
  2525. -- This routine parses expression of level 8 using the syntax:
  2526. --
  2527. -- <expression 8> ::= <expression 7>
  2528. -- <expression 8> ::= <expression 8> inter <expression 7> */
  2529. CODE *expression_8(MPL *mpl)
  2530. { CODE *x, *y;
  2531. x = expression_7(mpl);
  2532. for (;;)
  2533. { if (mpl->token == T_INTER)
  2534. { if (x->type != A_ELEMSET)
  2535. error_preceding(mpl, "inter");
  2536. get_token(mpl /* inter */);
  2537. y = expression_7(mpl);
  2538. if (y->type != A_ELEMSET)
  2539. error_following(mpl, "inter");
  2540. if (x->dim != y->dim)
  2541. error_dimension(mpl, "inter", x->dim, y->dim);
  2542. x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
  2543. }
  2544. else
  2545. break;
  2546. }
  2547. return x;
  2548. }
  2549. /*----------------------------------------------------------------------
  2550. -- expression_9 - parse expression of level 9.
  2551. --
  2552. -- This routine parses expression of level 9 using the syntax:
  2553. --
  2554. -- <expression 9> ::= <expression 8>
  2555. -- <expression 9> ::= <expression 9> union <expression 8>
  2556. -- <expression 9> ::= <expression 9> diff <expression 8>
  2557. -- <expression 9> ::= <expression 9> symdiff <expression 8> */
  2558. CODE *expression_9(MPL *mpl)
  2559. { CODE *x, *y;
  2560. x = expression_8(mpl);
  2561. for (;;)
  2562. { if (mpl->token == T_UNION)
  2563. { if (x->type != A_ELEMSET)
  2564. error_preceding(mpl, "union");
  2565. get_token(mpl /* union */);
  2566. y = expression_8(mpl);
  2567. if (y->type != A_ELEMSET)
  2568. error_following(mpl, "union");
  2569. if (x->dim != y->dim)
  2570. error_dimension(mpl, "union", x->dim, y->dim);
  2571. x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
  2572. }
  2573. else if (mpl->token == T_DIFF)
  2574. { if (x->type != A_ELEMSET)
  2575. error_preceding(mpl, "diff");
  2576. get_token(mpl /* diff */);
  2577. y = expression_8(mpl);
  2578. if (y->type != A_ELEMSET)
  2579. error_following(mpl, "diff");
  2580. if (x->dim != y->dim)
  2581. error_dimension(mpl, "diff", x->dim, y->dim);
  2582. x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
  2583. }
  2584. else if (mpl->token == T_SYMDIFF)
  2585. { if (x->type != A_ELEMSET)
  2586. error_preceding(mpl, "symdiff");
  2587. get_token(mpl /* symdiff */);
  2588. y = expression_8(mpl);
  2589. if (y->type != A_ELEMSET)
  2590. error_following(mpl, "symdiff");
  2591. if (x->dim != y->dim)
  2592. error_dimension(mpl, "symdiff", x->dim, y->dim);
  2593. x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
  2594. }
  2595. else
  2596. break;
  2597. }
  2598. return x;
  2599. }
  2600. /*----------------------------------------------------------------------
  2601. -- expression_10 - parse expression of level 10.
  2602. --
  2603. -- This routine parses expression of level 10 using the syntax:
  2604. --
  2605. -- <expression 10> ::= <expression 9>
  2606. -- <expression 10> ::= <expression 9> <rho> <expression 9>
  2607. -- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
  2608. -- within | not within | ! within */
  2609. CODE *expression_10(MPL *mpl)
  2610. { CODE *x, *y;
  2611. int op = -1;
  2612. char opstr[16];
  2613. x = expression_9(mpl);
  2614. strcpy(opstr, "");
  2615. switch (mpl->token)
  2616. { case T_LT:
  2617. op = O_LT; break;
  2618. case T_LE:
  2619. op = O_LE; break;
  2620. case T_EQ:
  2621. op = O_EQ; break;
  2622. case T_GE:
  2623. op = O_GE; break;
  2624. case T_GT:
  2625. op = O_GT; break;
  2626. case T_NE:
  2627. op = O_NE; break;
  2628. case T_IN:
  2629. op = O_IN; break;
  2630. case T_WITHIN:
  2631. op = O_WITHIN; break;
  2632. case T_NOT:
  2633. strcpy(opstr, mpl->image);
  2634. get_token(mpl /* not | ! */);
  2635. if (mpl->token == T_IN)
  2636. op = O_NOTIN;
  2637. else if (mpl->token == T_WITHIN)
  2638. op = O_NOTWITHIN;
  2639. else
  2640. error(mpl, "invalid use of %s", opstr);
  2641. strcat(opstr, " ");
  2642. break;
  2643. default:
  2644. goto done;
  2645. }
  2646. strcat(opstr, mpl->image);
  2647. xassert(strlen(opstr) < sizeof(opstr));
  2648. switch (op)
  2649. { case O_EQ:
  2650. case O_NE:
  2651. #if 1 /* 02/VIII-2008 */
  2652. case O_LT:
  2653. case O_LE:
  2654. case O_GT:
  2655. case O_GE:
  2656. #endif
  2657. if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
  2658. error_preceding(mpl, opstr);
  2659. get_token(mpl /* <rho> */);
  2660. y = expression_9(mpl);
  2661. if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
  2662. error_following(mpl, opstr);
  2663. if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
  2664. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  2665. if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
  2666. y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
  2667. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2668. break;
  2669. #if 0 /* 02/VIII-2008 */
  2670. case O_LT:
  2671. case O_LE:
  2672. case O_GT:
  2673. case O_GE:
  2674. if (x->type == A_SYMBOLIC)
  2675. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2676. if (x->type != A_NUMERIC)
  2677. error_preceding(mpl, opstr);
  2678. get_token(mpl /* <rho> */);
  2679. y = expression_9(mpl);
  2680. if (y->type == A_SYMBOLIC)
  2681. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2682. if (y->type != A_NUMERIC)
  2683. error_following(mpl, opstr);
  2684. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2685. break;
  2686. #endif
  2687. case O_IN:
  2688. case O_NOTIN:
  2689. if (x->type == A_NUMERIC)
  2690. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  2691. if (x->type == A_SYMBOLIC)
  2692. x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
  2693. if (x->type != A_TUPLE)
  2694. error_preceding(mpl, opstr);
  2695. get_token(mpl /* <rho> */);
  2696. y = expression_9(mpl);
  2697. if (y->type != A_ELEMSET)
  2698. error_following(mpl, opstr);
  2699. if (x->dim != y->dim)
  2700. error_dimension(mpl, opstr, x->dim, y->dim);
  2701. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2702. break;
  2703. case O_WITHIN:
  2704. case O_NOTWITHIN:
  2705. if (x->type != A_ELEMSET)
  2706. error_preceding(mpl, opstr);
  2707. get_token(mpl /* <rho> */);
  2708. y = expression_9(mpl);
  2709. if (y->type != A_ELEMSET)
  2710. error_following(mpl, opstr);
  2711. if (x->dim != y->dim)
  2712. error_dimension(mpl, opstr, x->dim, y->dim);
  2713. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2714. break;
  2715. default:
  2716. xassert(op != op);
  2717. }
  2718. done: return x;
  2719. }
  2720. /*----------------------------------------------------------------------
  2721. -- expression_11 - parse expression of level 11.
  2722. --
  2723. -- This routine parses expression of level 11 using the syntax:
  2724. --
  2725. -- <expression 11> ::= <expression 10>
  2726. -- <expression 11> ::= not <expression 10>
  2727. -- <expression 11> ::= ! <expression 10> */
  2728. CODE *expression_11(MPL *mpl)
  2729. { CODE *x;
  2730. char opstr[8];
  2731. if (mpl->token == T_NOT)
  2732. { strcpy(opstr, mpl->image);
  2733. xassert(strlen(opstr) < sizeof(opstr));
  2734. get_token(mpl /* not | ! */);
  2735. x = expression_10(mpl);
  2736. if (x->type == A_SYMBOLIC)
  2737. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2738. if (x->type == A_NUMERIC)
  2739. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2740. if (x->type != A_LOGICAL)
  2741. error_following(mpl, opstr);
  2742. x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
  2743. }
  2744. else
  2745. x = expression_10(mpl);
  2746. return x;
  2747. }
  2748. /*----------------------------------------------------------------------
  2749. -- expression_12 - parse expression of level 12.
  2750. --
  2751. -- This routine parses expression of level 12 using the syntax:
  2752. --
  2753. -- <expression 12> ::= <expression 11>
  2754. -- <expression 12> ::= <expression 12> and <expression 11>
  2755. -- <expression 12> ::= <expression 12> && <expression 11> */
  2756. CODE *expression_12(MPL *mpl)
  2757. { CODE *x, *y;
  2758. char opstr[8];
  2759. x = expression_11(mpl);
  2760. for (;;)
  2761. { if (mpl->token == T_AND)
  2762. { strcpy(opstr, mpl->image);
  2763. xassert(strlen(opstr) < sizeof(opstr));
  2764. if (x->type == A_SYMBOLIC)
  2765. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2766. if (x->type == A_NUMERIC)
  2767. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2768. if (x->type != A_LOGICAL)
  2769. error_preceding(mpl, opstr);
  2770. get_token(mpl /* and | && */);
  2771. y = expression_11(mpl);
  2772. if (y->type == A_SYMBOLIC)
  2773. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2774. if (y->type == A_NUMERIC)
  2775. y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
  2776. if (y->type != A_LOGICAL)
  2777. error_following(mpl, opstr);
  2778. x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
  2779. }
  2780. else
  2781. break;
  2782. }
  2783. return x;
  2784. }
  2785. /*----------------------------------------------------------------------
  2786. -- expression_13 - parse expression of level 13.
  2787. --
  2788. -- This routine parses expression of level 13 using the syntax:
  2789. --
  2790. -- <expression 13> ::= <expression 12>
  2791. -- <expression 13> ::= <expression 13> or <expression 12>
  2792. -- <expression 13> ::= <expression 13> || <expression 12> */
  2793. CODE *expression_13(MPL *mpl)
  2794. { CODE *x, *y;
  2795. char opstr[8];
  2796. x = expression_12(mpl);
  2797. for (;;)
  2798. { if (mpl->token == T_OR)
  2799. { strcpy(opstr, mpl->image);
  2800. xassert(strlen(opstr) < sizeof(opstr));
  2801. if (x->type == A_SYMBOLIC)
  2802. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2803. if (x->type == A_NUMERIC)
  2804. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2805. if (x->type != A_LOGICAL)
  2806. error_preceding(mpl, opstr);
  2807. get_token(mpl /* or | || */);
  2808. y = expression_12(mpl);
  2809. if (y->type == A_SYMBOLIC)
  2810. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2811. if (y->type == A_NUMERIC)
  2812. y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
  2813. if (y->type != A_LOGICAL)
  2814. error_following(mpl, opstr);
  2815. x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
  2816. }
  2817. else
  2818. break;
  2819. }
  2820. return x;
  2821. }
  2822. /*----------------------------------------------------------------------
  2823. -- set_statement - parse set statement.
  2824. --
  2825. -- This routine parses set statement using the syntax:
  2826. --
  2827. -- <set statement> ::= set <symbolic name> <alias> <domain>
  2828. -- <attributes> ;
  2829. -- <alias> ::= <empty>
  2830. -- <alias> ::= <string literal>
  2831. -- <domain> ::= <empty>
  2832. -- <domain> ::= <indexing expression>
  2833. -- <attributes> ::= <empty>
  2834. -- <attributes> ::= <attributes> , dimen <numeric literal>
  2835. -- <attributes> ::= <attributes> , within <expression 9>
  2836. -- <attributes> ::= <attributes> , := <expression 9>
  2837. -- <attributes> ::= <attributes> , default <expression 9>
  2838. --
  2839. -- Commae in <attributes> are optional and may be omitted anywhere. */
  2840. SET *set_statement(MPL *mpl)
  2841. { SET *set;
  2842. int dimen_used = 0;
  2843. xassert(is_keyword(mpl, "set"));
  2844. get_token(mpl /* set */);
  2845. /* symbolic name must follow the keyword 'set' */
  2846. if (mpl->token == T_NAME)
  2847. ;
  2848. else if (is_reserved(mpl))
  2849. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  2850. else
  2851. error(mpl, "symbolic name missing where expected");
  2852. /* there must be no other object with the same name */
  2853. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  2854. error(mpl, "%s multiply declared", mpl->image);
  2855. /* create model set */
  2856. set = alloc(SET);
  2857. set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  2858. strcpy(set->name, mpl->image);
  2859. set->alias = NULL;
  2860. set->dim = 0;
  2861. set->domain = NULL;
  2862. set->dimen = 0;
  2863. set->within = NULL;
  2864. set->assign = NULL;
  2865. set->option = NULL;
  2866. set->gadget = NULL;
  2867. set->data = 0;
  2868. set->array = NULL;
  2869. get_token(mpl /* <symbolic name> */);
  2870. /* parse optional alias */
  2871. if (mpl->token == T_STRING)
  2872. { set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  2873. strcpy(set->alias, mpl->image);
  2874. get_token(mpl /* <string literal> */);
  2875. }
  2876. /* parse optional indexing expression */
  2877. if (mpl->token == T_LBRACE)
  2878. { set->domain = indexing_expression(mpl);
  2879. set->dim = domain_arity(mpl, set->domain);
  2880. }
  2881. /* include the set name in the symbolic names table */
  2882. { AVLNODE *node;
  2883. node = avl_insert_node(mpl->tree, set->name);
  2884. avl_set_node_type(node, A_SET);
  2885. avl_set_node_link(node, (void *)set);
  2886. }
  2887. /* parse the list of optional attributes */
  2888. for (;;)
  2889. { if (mpl->token == T_COMMA)
  2890. get_token(mpl /* , */);
  2891. else if (mpl->token == T_SEMICOLON)
  2892. break;
  2893. if (is_keyword(mpl, "dimen"))
  2894. { /* dimension of set members */
  2895. int dimen;
  2896. get_token(mpl /* dimen */);
  2897. if (!(mpl->token == T_NUMBER &&
  2898. 1.0 <= mpl->value && mpl->value <= 20.0 &&
  2899. floor(mpl->value) == mpl->value))
  2900. error(mpl, "dimension must be integer between 1 and 20");
  2901. dimen = (int)(mpl->value + 0.5);
  2902. if (dimen_used)
  2903. error(mpl, "at most one dimension attribute allowed");
  2904. if (set->dimen > 0)
  2905. error(mpl, "dimension %d conflicts with dimension %d alr"
  2906. "eady determined", dimen, set->dimen);
  2907. set->dimen = dimen;
  2908. dimen_used = 1;
  2909. get_token(mpl /* <numeric literal> */);
  2910. }
  2911. else if (mpl->token == T_WITHIN || mpl->token == T_IN)
  2912. { /* restricting superset */
  2913. WITHIN *within, *temp;
  2914. if (mpl->token == T_IN && !mpl->as_within)
  2915. { warning(mpl, "keyword in understood as within");
  2916. mpl->as_within = 1;
  2917. }
  2918. get_token(mpl /* within */);
  2919. /* create new restricting superset list entry and append it
  2920. to the within-list */
  2921. within = alloc(WITHIN);
  2922. within->code = NULL;
  2923. within->next = NULL;
  2924. if (set->within == NULL)
  2925. set->within = within;
  2926. else
  2927. { for (temp = set->within; temp->next != NULL; temp =
  2928. temp->next);
  2929. temp->next = within;
  2930. }
  2931. /* parse an expression that follows 'within' */
  2932. within->code = expression_9(mpl);
  2933. if (within->code->type != A_ELEMSET)
  2934. error(mpl, "expression following within has invalid type"
  2935. );
  2936. xassert(within->code->dim > 0);
  2937. /* check/set dimension of set members */
  2938. if (set->dimen == 0) set->dimen = within->code->dim;
  2939. if (set->dimen != within->code->dim)
  2940. error(mpl, "set expression following within must have di"
  2941. "mension %d rather than %d",
  2942. set->dimen, within->code->dim);
  2943. }
  2944. else if (mpl->token == T_ASSIGN)
  2945. { /* assignment expression */
  2946. if (!(set->assign == NULL && set->option == NULL &&
  2947. set->gadget == NULL))
  2948. err: error(mpl, "at most one := or default/data allowed");
  2949. get_token(mpl /* := */);
  2950. /* parse an expression that follows ':=' */
  2951. set->assign = expression_9(mpl);
  2952. if (set->assign->type != A_ELEMSET)
  2953. error(mpl, "expression following := has invalid type");
  2954. xassert(set->assign->dim > 0);
  2955. /* check/set dimension of set members */
  2956. if (set->dimen == 0) set->dimen = set->assign->dim;
  2957. if (set->dimen != set->assign->dim)
  2958. error(mpl, "set expression following := must have dimens"
  2959. "ion %d rather than %d",
  2960. set->dimen, set->assign->dim);
  2961. }
  2962. else if (is_keyword(mpl, "default"))
  2963. { /* expression for default value */
  2964. if (!(set->assign == NULL && set->option == NULL)) goto err;
  2965. get_token(mpl /* := */);
  2966. /* parse an expression that follows 'default' */
  2967. set->option = expression_9(mpl);
  2968. if (set->option->type != A_ELEMSET)
  2969. error(mpl, "expression following default has invalid typ"
  2970. "e");
  2971. xassert(set->option->dim > 0);
  2972. /* check/set dimension of set members */
  2973. if (set->dimen == 0) set->dimen = set->option->dim;
  2974. if (set->dimen != set->option->dim)
  2975. error(mpl, "set expression following default must have d"
  2976. "imension %d rather than %d",
  2977. set->dimen, set->option->dim);
  2978. }
  2979. #if 1 /* 12/XII-2008 */
  2980. else if (is_keyword(mpl, "data"))
  2981. { /* gadget to initialize the set by data from plain set */
  2982. GADGET *gadget;
  2983. AVLNODE *node;
  2984. int i, k, fff[20];
  2985. if (!(set->assign == NULL && set->gadget == NULL)) goto err;
  2986. get_token(mpl /* data */);
  2987. set->gadget = gadget = alloc(GADGET);
  2988. /* set name must follow the keyword 'data' */
  2989. if (mpl->token == T_NAME)
  2990. ;
  2991. else if (is_reserved(mpl))
  2992. error(mpl, "invalid use of reserved keyword %s",
  2993. mpl->image);
  2994. else
  2995. error(mpl, "set name missing where expected");
  2996. /* find the set in the symbolic name table */
  2997. node = avl_find_node(mpl->tree, mpl->image);
  2998. if (node == NULL)
  2999. error(mpl, "%s not defined", mpl->image);
  3000. if (avl_get_node_type(node) != A_SET)
  3001. err1: error(mpl, "%s not a plain set", mpl->image);
  3002. gadget->set = avl_get_node_link(node);
  3003. if (gadget->set->dim != 0) goto err1;
  3004. if (gadget->set == set)
  3005. error(mpl, "set cannot be initialized by itself");
  3006. /* check and set dimensions */
  3007. if (set->dim >= gadget->set->dimen)
  3008. err2: error(mpl, "dimension of %s too small", mpl->image);
  3009. if (set->dimen == 0)
  3010. set->dimen = gadget->set->dimen - set->dim;
  3011. if (set->dim + set->dimen > gadget->set->dimen)
  3012. goto err2;
  3013. else if (set->dim + set->dimen < gadget->set->dimen)
  3014. error(mpl, "dimension of %s too big", mpl->image);
  3015. get_token(mpl /* set name */);
  3016. /* left parenthesis must follow the set name */
  3017. if (mpl->token == T_LEFT)
  3018. get_token(mpl /* ( */);
  3019. else
  3020. error(mpl, "left parenthesis missing where expected");
  3021. /* parse permutation of component numbers */
  3022. for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
  3023. k = 0;
  3024. for (;;)
  3025. { if (mpl->token != T_NUMBER)
  3026. error(mpl, "component number missing where expected");
  3027. if (str2int(mpl->image, &i) != 0)
  3028. err3: error(mpl, "component number must be integer between "
  3029. "1 and %d", gadget->set->dimen);
  3030. if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
  3031. if (fff[i-1] != 0)
  3032. error(mpl, "component %d multiply specified", i);
  3033. gadget->ind[k++] = i, fff[i-1] = 1;
  3034. xassert(k <= gadget->set->dimen);
  3035. get_token(mpl /* number */);
  3036. if (mpl->token == T_COMMA)
  3037. get_token(mpl /* , */);
  3038. else if (mpl->token == T_RIGHT)
  3039. break;
  3040. else
  3041. error(mpl, "syntax error in data attribute");
  3042. }
  3043. if (k < gadget->set->dimen)
  3044. error(mpl, "there are must be %d components rather than "
  3045. "%d", gadget->set->dimen, k);
  3046. get_token(mpl /* ) */);
  3047. }
  3048. #endif
  3049. else
  3050. error(mpl, "syntax error in set statement");
  3051. }
  3052. /* close the domain scope */
  3053. if (set->domain != NULL) close_scope(mpl, set->domain);
  3054. /* if dimension of set members is still unknown, set it to 1 */
  3055. if (set->dimen == 0) set->dimen = 1;
  3056. /* the set statement has been completely parsed */
  3057. xassert(mpl->token == T_SEMICOLON);
  3058. get_token(mpl /* ; */);
  3059. return set;
  3060. }
  3061. /*----------------------------------------------------------------------
  3062. -- parameter_statement - parse parameter statement.
  3063. --
  3064. -- This routine parses parameter statement using the syntax:
  3065. --
  3066. -- <parameter statement> ::= param <symbolic name> <alias> <domain>
  3067. -- <attributes> ;
  3068. -- <alias> ::= <empty>
  3069. -- <alias> ::= <string literal>
  3070. -- <domain> ::= <empty>
  3071. -- <domain> ::= <indexing expression>
  3072. -- <attributes> ::= <empty>
  3073. -- <attributes> ::= <attributes> , integer
  3074. -- <attributes> ::= <attributes> , binary
  3075. -- <attributes> ::= <attributes> , symbolic
  3076. -- <attributes> ::= <attributes> , <rho> <expression 5>
  3077. -- <attributes> ::= <attributes> , in <expression 9>
  3078. -- <attributes> ::= <attributes> , := <expression 5>
  3079. -- <attributes> ::= <attributes> , default <expression 5>
  3080. -- <rho> ::= < | <= | = | == | >= | > | <> | !=
  3081. --
  3082. -- Commae in <attributes> are optional and may be omitted anywhere. */
  3083. PARAMETER *parameter_statement(MPL *mpl)
  3084. { PARAMETER *par;
  3085. int integer_used = 0, binary_used = 0, symbolic_used = 0;
  3086. xassert(is_keyword(mpl, "param"));
  3087. get_token(mpl /* param */);
  3088. /* symbolic name must follow the keyword 'param' */
  3089. if (mpl->token == T_NAME)
  3090. ;
  3091. else if (is_reserved(mpl))
  3092. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3093. else
  3094. error(mpl, "symbolic name missing where expected");
  3095. /* there must be no other object with the same name */
  3096. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3097. error(mpl, "%s multiply declared", mpl->image);
  3098. /* create model parameter */
  3099. par = alloc(PARAMETER);
  3100. par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3101. strcpy(par->name, mpl->image);
  3102. par->alias = NULL;
  3103. par->dim = 0;
  3104. par->domain = NULL;
  3105. par->type = A_NUMERIC;
  3106. par->cond = NULL;
  3107. par->in = NULL;
  3108. par->assign = NULL;
  3109. par->option = NULL;
  3110. par->data = 0;
  3111. par->defval = NULL;
  3112. par->array = NULL;
  3113. get_token(mpl /* <symbolic name> */);
  3114. /* parse optional alias */
  3115. if (mpl->token == T_STRING)
  3116. { par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3117. strcpy(par->alias, mpl->image);
  3118. get_token(mpl /* <string literal> */);
  3119. }
  3120. /* parse optional indexing expression */
  3121. if (mpl->token == T_LBRACE)
  3122. { par->domain = indexing_expression(mpl);
  3123. par->dim = domain_arity(mpl, par->domain);
  3124. }
  3125. /* include the parameter name in the symbolic names table */
  3126. { AVLNODE *node;
  3127. node = avl_insert_node(mpl->tree, par->name);
  3128. avl_set_node_type(node, A_PARAMETER);
  3129. avl_set_node_link(node, (void *)par);
  3130. }
  3131. /* parse the list of optional attributes */
  3132. for (;;)
  3133. { if (mpl->token == T_COMMA)
  3134. get_token(mpl /* , */);
  3135. else if (mpl->token == T_SEMICOLON)
  3136. break;
  3137. if (is_keyword(mpl, "integer"))
  3138. { if (integer_used)
  3139. error(mpl, "at most one integer allowed");
  3140. if (par->type == A_SYMBOLIC)
  3141. error(mpl, "symbolic parameter cannot be integer");
  3142. if (par->type != A_BINARY) par->type = A_INTEGER;
  3143. integer_used = 1;
  3144. get_token(mpl /* integer */);
  3145. }
  3146. else if (is_keyword(mpl, "binary"))
  3147. bin: { if (binary_used)
  3148. error(mpl, "at most one binary allowed");
  3149. if (par->type == A_SYMBOLIC)
  3150. error(mpl, "symbolic parameter cannot be binary");
  3151. par->type = A_BINARY;
  3152. binary_used = 1;
  3153. get_token(mpl /* binary */);
  3154. }
  3155. else if (is_keyword(mpl, "logical"))
  3156. { if (!mpl->as_binary)
  3157. { warning(mpl, "keyword logical understood as binary");
  3158. mpl->as_binary = 1;
  3159. }
  3160. goto bin;
  3161. }
  3162. else if (is_keyword(mpl, "symbolic"))
  3163. { if (symbolic_used)
  3164. error(mpl, "at most one symbolic allowed");
  3165. if (par->type != A_NUMERIC)
  3166. error(mpl, "integer or binary parameter cannot be symbol"
  3167. "ic");
  3168. /* the parameter may be referenced from expressions given
  3169. in the same parameter declaration, so its type must be
  3170. completed before parsing that expressions */
  3171. if (!(par->cond == NULL && par->in == NULL &&
  3172. par->assign == NULL && par->option == NULL))
  3173. error(mpl, "keyword symbolic must precede any other para"
  3174. "meter attributes");
  3175. par->type = A_SYMBOLIC;
  3176. symbolic_used = 1;
  3177. get_token(mpl /* symbolic */);
  3178. }
  3179. else if (mpl->token == T_LT || mpl->token == T_LE ||
  3180. mpl->token == T_EQ || mpl->token == T_GE ||
  3181. mpl->token == T_GT || mpl->token == T_NE)
  3182. { /* restricting condition */
  3183. CONDITION *cond, *temp;
  3184. char opstr[8];
  3185. /* create new restricting condition list entry and append
  3186. it to the conditions list */
  3187. cond = alloc(CONDITION);
  3188. switch (mpl->token)
  3189. { case T_LT:
  3190. cond->rho = O_LT, strcpy(opstr, mpl->image); break;
  3191. case T_LE:
  3192. cond->rho = O_LE, strcpy(opstr, mpl->image); break;
  3193. case T_EQ:
  3194. cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
  3195. case T_GE:
  3196. cond->rho = O_GE, strcpy(opstr, mpl->image); break;
  3197. case T_GT:
  3198. cond->rho = O_GT, strcpy(opstr, mpl->image); break;
  3199. case T_NE:
  3200. cond->rho = O_NE, strcpy(opstr, mpl->image); break;
  3201. default:
  3202. xassert(mpl->token != mpl->token);
  3203. }
  3204. xassert(strlen(opstr) < sizeof(opstr));
  3205. cond->code = NULL;
  3206. cond->next = NULL;
  3207. if (par->cond == NULL)
  3208. par->cond = cond;
  3209. else
  3210. { for (temp = par->cond; temp->next != NULL; temp =
  3211. temp->next);
  3212. temp->next = cond;
  3213. }
  3214. #if 0 /* 13/VIII-2008 */
  3215. if (par->type == A_SYMBOLIC &&
  3216. !(cond->rho == O_EQ || cond->rho == O_NE))
  3217. error(mpl, "inequality restriction not allowed");
  3218. #endif
  3219. get_token(mpl /* rho */);
  3220. /* parse an expression that follows relational operator */
  3221. cond->code = expression_5(mpl);
  3222. if (!(cond->code->type == A_NUMERIC ||
  3223. cond->code->type == A_SYMBOLIC))
  3224. error(mpl, "expression following %s has invalid type",
  3225. opstr);
  3226. xassert(cond->code->dim == 0);
  3227. /* convert to the parameter type, if necessary */
  3228. if (par->type != A_SYMBOLIC && cond->code->type ==
  3229. A_SYMBOLIC)
  3230. cond->code = make_unary(mpl, O_CVTNUM, cond->code,
  3231. A_NUMERIC, 0);
  3232. if (par->type == A_SYMBOLIC && cond->code->type !=
  3233. A_SYMBOLIC)
  3234. cond->code = make_unary(mpl, O_CVTSYM, cond->code,
  3235. A_SYMBOLIC, 0);
  3236. }
  3237. else if (mpl->token == T_IN || mpl->token == T_WITHIN)
  3238. { /* restricting superset */
  3239. WITHIN *in, *temp;
  3240. if (mpl->token == T_WITHIN && !mpl->as_in)
  3241. { warning(mpl, "keyword within understood as in");
  3242. mpl->as_in = 1;
  3243. }
  3244. get_token(mpl /* in */);
  3245. /* create new restricting superset list entry and append it
  3246. to the in-list */
  3247. in = alloc(WITHIN);
  3248. in->code = NULL;
  3249. in->next = NULL;
  3250. if (par->in == NULL)
  3251. par->in = in;
  3252. else
  3253. { for (temp = par->in; temp->next != NULL; temp =
  3254. temp->next);
  3255. temp->next = in;
  3256. }
  3257. /* parse an expression that follows 'in' */
  3258. in->code = expression_9(mpl);
  3259. if (in->code->type != A_ELEMSET)
  3260. error(mpl, "expression following in has invalid type");
  3261. xassert(in->code->dim > 0);
  3262. if (in->code->dim != 1)
  3263. error(mpl, "set expression following in must have dimens"
  3264. "ion 1 rather than %d", in->code->dim);
  3265. }
  3266. else if (mpl->token == T_ASSIGN)
  3267. { /* assignment expression */
  3268. if (!(par->assign == NULL && par->option == NULL))
  3269. err: error(mpl, "at most one := or default allowed");
  3270. get_token(mpl /* := */);
  3271. /* parse an expression that follows ':=' */
  3272. par->assign = expression_5(mpl);
  3273. /* the expression must be of numeric/symbolic type */
  3274. if (!(par->assign->type == A_NUMERIC ||
  3275. par->assign->type == A_SYMBOLIC))
  3276. error(mpl, "expression following := has invalid type");
  3277. xassert(par->assign->dim == 0);
  3278. /* convert to the parameter type, if necessary */
  3279. if (par->type != A_SYMBOLIC && par->assign->type ==
  3280. A_SYMBOLIC)
  3281. par->assign = make_unary(mpl, O_CVTNUM, par->assign,
  3282. A_NUMERIC, 0);
  3283. if (par->type == A_SYMBOLIC && par->assign->type !=
  3284. A_SYMBOLIC)
  3285. par->assign = make_unary(mpl, O_CVTSYM, par->assign,
  3286. A_SYMBOLIC, 0);
  3287. }
  3288. else if (is_keyword(mpl, "default"))
  3289. { /* expression for default value */
  3290. if (!(par->assign == NULL && par->option == NULL)) goto err;
  3291. get_token(mpl /* default */);
  3292. /* parse an expression that follows 'default' */
  3293. par->option = expression_5(mpl);
  3294. if (!(par->option->type == A_NUMERIC ||
  3295. par->option->type == A_SYMBOLIC))
  3296. error(mpl, "expression following default has invalid typ"
  3297. "e");
  3298. xassert(par->option->dim == 0);
  3299. /* convert to the parameter type, if necessary */
  3300. if (par->type != A_SYMBOLIC && par->option->type ==
  3301. A_SYMBOLIC)
  3302. par->option = make_unary(mpl, O_CVTNUM, par->option,
  3303. A_NUMERIC, 0);
  3304. if (par->type == A_SYMBOLIC && par->option->type !=
  3305. A_SYMBOLIC)
  3306. par->option = make_unary(mpl, O_CVTSYM, par->option,
  3307. A_SYMBOLIC, 0);
  3308. }
  3309. else
  3310. error(mpl, "syntax error in parameter statement");
  3311. }
  3312. /* close the domain scope */
  3313. if (par->domain != NULL) close_scope(mpl, par->domain);
  3314. /* the parameter statement has been completely parsed */
  3315. xassert(mpl->token == T_SEMICOLON);
  3316. get_token(mpl /* ; */);
  3317. return par;
  3318. }
  3319. /*----------------------------------------------------------------------
  3320. -- variable_statement - parse variable statement.
  3321. --
  3322. -- This routine parses variable statement using the syntax:
  3323. --
  3324. -- <variable statement> ::= var <symbolic name> <alias> <domain>
  3325. -- <attributes> ;
  3326. -- <alias> ::= <empty>
  3327. -- <alias> ::= <string literal>
  3328. -- <domain> ::= <empty>
  3329. -- <domain> ::= <indexing expression>
  3330. -- <attributes> ::= <empty>
  3331. -- <attributes> ::= <attributes> , integer
  3332. -- <attributes> ::= <attributes> , binary
  3333. -- <attributes> ::= <attributes> , <rho> <expression 5>
  3334. -- <rho> ::= >= | <= | = | ==
  3335. --
  3336. -- Commae in <attributes> are optional and may be omitted anywhere. */
  3337. VARIABLE *variable_statement(MPL *mpl)
  3338. { VARIABLE *var;
  3339. int integer_used = 0, binary_used = 0;
  3340. xassert(is_keyword(mpl, "var"));
  3341. if (mpl->flag_s)
  3342. error(mpl, "variable statement must precede solve statement");
  3343. get_token(mpl /* var */);
  3344. /* symbolic name must follow the keyword 'var' */
  3345. if (mpl->token == T_NAME)
  3346. ;
  3347. else if (is_reserved(mpl))
  3348. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3349. else
  3350. error(mpl, "symbolic name missing where expected");
  3351. /* there must be no other object with the same name */
  3352. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3353. error(mpl, "%s multiply declared", mpl->image);
  3354. /* create model variable */
  3355. var = alloc(VARIABLE);
  3356. var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3357. strcpy(var->name, mpl->image);
  3358. var->alias = NULL;
  3359. var->dim = 0;
  3360. var->domain = NULL;
  3361. var->type = A_NUMERIC;
  3362. var->lbnd = NULL;
  3363. var->ubnd = NULL;
  3364. var->array = NULL;
  3365. get_token(mpl /* <symbolic name> */);
  3366. /* parse optional alias */
  3367. if (mpl->token == T_STRING)
  3368. { var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3369. strcpy(var->alias, mpl->image);
  3370. get_token(mpl /* <string literal> */);
  3371. }
  3372. /* parse optional indexing expression */
  3373. if (mpl->token == T_LBRACE)
  3374. { var->domain = indexing_expression(mpl);
  3375. var->dim = domain_arity(mpl, var->domain);
  3376. }
  3377. /* include the variable name in the symbolic names table */
  3378. { AVLNODE *node;
  3379. node = avl_insert_node(mpl->tree, var->name);
  3380. avl_set_node_type(node, A_VARIABLE);
  3381. avl_set_node_link(node, (void *)var);
  3382. }
  3383. /* parse the list of optional attributes */
  3384. for (;;)
  3385. { if (mpl->token == T_COMMA)
  3386. get_token(mpl /* , */);
  3387. else if (mpl->token == T_SEMICOLON)
  3388. break;
  3389. if (is_keyword(mpl, "integer"))
  3390. { if (integer_used)
  3391. error(mpl, "at most one integer allowed");
  3392. if (var->type != A_BINARY) var->type = A_INTEGER;
  3393. integer_used = 1;
  3394. get_token(mpl /* integer */);
  3395. }
  3396. else if (is_keyword(mpl, "binary"))
  3397. bin: { if (binary_used)
  3398. error(mpl, "at most one binary allowed");
  3399. var->type = A_BINARY;
  3400. binary_used = 1;
  3401. get_token(mpl /* binary */);
  3402. }
  3403. else if (is_keyword(mpl, "logical"))
  3404. { if (!mpl->as_binary)
  3405. { warning(mpl, "keyword logical understood as binary");
  3406. mpl->as_binary = 1;
  3407. }
  3408. goto bin;
  3409. }
  3410. else if (is_keyword(mpl, "symbolic"))
  3411. error(mpl, "variable cannot be symbolic");
  3412. else if (mpl->token == T_GE)
  3413. { /* lower bound */
  3414. if (var->lbnd != NULL)
  3415. { if (var->lbnd == var->ubnd)
  3416. error(mpl, "both fixed value and lower bound not allo"
  3417. "wed");
  3418. else
  3419. error(mpl, "at most one lower bound allowed");
  3420. }
  3421. get_token(mpl /* >= */);
  3422. /* parse an expression that specifies the lower bound */
  3423. var->lbnd = expression_5(mpl);
  3424. if (var->lbnd->type == A_SYMBOLIC)
  3425. var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
  3426. A_NUMERIC, 0);
  3427. if (var->lbnd->type != A_NUMERIC)
  3428. error(mpl, "expression following >= has invalid type");
  3429. xassert(var->lbnd->dim == 0);
  3430. }
  3431. else if (mpl->token == T_LE)
  3432. { /* upper bound */
  3433. if (var->ubnd != NULL)
  3434. { if (var->ubnd == var->lbnd)
  3435. error(mpl, "both fixed value and upper bound not allo"
  3436. "wed");
  3437. else
  3438. error(mpl, "at most one upper bound allowed");
  3439. }
  3440. get_token(mpl /* <= */);
  3441. /* parse an expression that specifies the upper bound */
  3442. var->ubnd = expression_5(mpl);
  3443. if (var->ubnd->type == A_SYMBOLIC)
  3444. var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
  3445. A_NUMERIC, 0);
  3446. if (var->ubnd->type != A_NUMERIC)
  3447. error(mpl, "expression following <= has invalid type");
  3448. xassert(var->ubnd->dim == 0);
  3449. }
  3450. else if (mpl->token == T_EQ)
  3451. { /* fixed value */
  3452. char opstr[8];
  3453. if (!(var->lbnd == NULL && var->ubnd == NULL))
  3454. { if (var->lbnd == var->ubnd)
  3455. error(mpl, "at most one fixed value allowed");
  3456. else if (var->lbnd != NULL)
  3457. error(mpl, "both lower bound and fixed value not allo"
  3458. "wed");
  3459. else
  3460. error(mpl, "both upper bound and fixed value not allo"
  3461. "wed");
  3462. }
  3463. strcpy(opstr, mpl->image);
  3464. xassert(strlen(opstr) < sizeof(opstr));
  3465. get_token(mpl /* = | == */);
  3466. /* parse an expression that specifies the fixed value */
  3467. var->lbnd = expression_5(mpl);
  3468. if (var->lbnd->type == A_SYMBOLIC)
  3469. var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
  3470. A_NUMERIC, 0);
  3471. if (var->lbnd->type != A_NUMERIC)
  3472. error(mpl, "expression following %s has invalid type",
  3473. opstr);
  3474. xassert(var->lbnd->dim == 0);
  3475. /* indicate that the variable is fixed, not bounded */
  3476. var->ubnd = var->lbnd;
  3477. }
  3478. else if (mpl->token == T_LT || mpl->token == T_GT ||
  3479. mpl->token == T_NE)
  3480. error(mpl, "strict bound not allowed");
  3481. else
  3482. error(mpl, "syntax error in variable statement");
  3483. }
  3484. /* close the domain scope */
  3485. if (var->domain != NULL) close_scope(mpl, var->domain);
  3486. /* the variable statement has been completely parsed */
  3487. xassert(mpl->token == T_SEMICOLON);
  3488. get_token(mpl /* ; */);
  3489. return var;
  3490. }
  3491. /*----------------------------------------------------------------------
  3492. -- constraint_statement - parse constraint statement.
  3493. --
  3494. -- This routine parses constraint statement using the syntax:
  3495. --
  3496. -- <constraint statement> ::= <subject to> <symbolic name> <alias>
  3497. -- <domain> : <constraint> ;
  3498. -- <subject to> ::= <empty>
  3499. -- <subject to> ::= subject to
  3500. -- <subject to> ::= subj to
  3501. -- <subject to> ::= s.t.
  3502. -- <alias> ::= <empty>
  3503. -- <alias> ::= <string literal>
  3504. -- <domain> ::= <empty>
  3505. -- <domain> ::= <indexing expression>
  3506. -- <constraint> ::= <formula> , >= <formula>
  3507. -- <constraint> ::= <formula> , <= <formula>
  3508. -- <constraint> ::= <formula> , = <formula>
  3509. -- <constraint> ::= <formula> , <= <formula> , <= <formula>
  3510. -- <constraint> ::= <formula> , >= <formula> , >= <formula>
  3511. -- <formula> ::= <expression 5>
  3512. --
  3513. -- Commae in <constraint> are optional and may be omitted anywhere. */
  3514. CONSTRAINT *constraint_statement(MPL *mpl)
  3515. { CONSTRAINT *con;
  3516. CODE *first, *second, *third;
  3517. int rho;
  3518. char opstr[8];
  3519. if (mpl->flag_s)
  3520. error(mpl, "constraint statement must precede solve statement")
  3521. ;
  3522. if (is_keyword(mpl, "subject"))
  3523. { get_token(mpl /* subject */);
  3524. if (!is_keyword(mpl, "to"))
  3525. error(mpl, "keyword subject to incomplete");
  3526. get_token(mpl /* to */);
  3527. }
  3528. else if (is_keyword(mpl, "subj"))
  3529. { get_token(mpl /* subj */);
  3530. if (!is_keyword(mpl, "to"))
  3531. error(mpl, "keyword subj to incomplete");
  3532. get_token(mpl /* to */);
  3533. }
  3534. else if (mpl->token == T_SPTP)
  3535. get_token(mpl /* s.t. */);
  3536. /* the current token must be symbolic name of constraint */
  3537. if (mpl->token == T_NAME)
  3538. ;
  3539. else if (is_reserved(mpl))
  3540. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3541. else
  3542. error(mpl, "symbolic name missing where expected");
  3543. /* there must be no other object with the same name */
  3544. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3545. error(mpl, "%s multiply declared", mpl->image);
  3546. /* create model constraint */
  3547. con = alloc(CONSTRAINT);
  3548. con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3549. strcpy(con->name, mpl->image);
  3550. con->alias = NULL;
  3551. con->dim = 0;
  3552. con->domain = NULL;
  3553. con->type = A_CONSTRAINT;
  3554. con->code = NULL;
  3555. con->lbnd = NULL;
  3556. con->ubnd = NULL;
  3557. con->array = NULL;
  3558. get_token(mpl /* <symbolic name> */);
  3559. /* parse optional alias */
  3560. if (mpl->token == T_STRING)
  3561. { con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3562. strcpy(con->alias, mpl->image);
  3563. get_token(mpl /* <string literal> */);
  3564. }
  3565. /* parse optional indexing expression */
  3566. if (mpl->token == T_LBRACE)
  3567. { con->domain = indexing_expression(mpl);
  3568. con->dim = domain_arity(mpl, con->domain);
  3569. }
  3570. /* include the constraint name in the symbolic names table */
  3571. { AVLNODE *node;
  3572. node = avl_insert_node(mpl->tree, con->name);
  3573. avl_set_node_type(node, A_CONSTRAINT);
  3574. avl_set_node_link(node, (void *)con);
  3575. }
  3576. /* the colon must precede the first expression */
  3577. if (mpl->token != T_COLON)
  3578. error(mpl, "colon missing where expected");
  3579. get_token(mpl /* : */);
  3580. /* parse the first expression */
  3581. first = expression_5(mpl);
  3582. if (first->type == A_SYMBOLIC)
  3583. first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
  3584. if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
  3585. error(mpl, "expression following colon has invalid type");
  3586. xassert(first->dim == 0);
  3587. /* relational operator must follow the first expression */
  3588. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  3589. switch (mpl->token)
  3590. { case T_LE:
  3591. case T_GE:
  3592. case T_EQ:
  3593. break;
  3594. case T_LT:
  3595. case T_GT:
  3596. case T_NE:
  3597. error(mpl, "strict inequality not allowed");
  3598. case T_SEMICOLON:
  3599. error(mpl, "constraint must be equality or inequality");
  3600. default:
  3601. goto err;
  3602. }
  3603. rho = mpl->token;
  3604. strcpy(opstr, mpl->image);
  3605. xassert(strlen(opstr) < sizeof(opstr));
  3606. get_token(mpl /* rho */);
  3607. /* parse the second expression */
  3608. second = expression_5(mpl);
  3609. if (second->type == A_SYMBOLIC)
  3610. second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
  3611. if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
  3612. error(mpl, "expression following %s has invalid type", opstr);
  3613. xassert(second->dim == 0);
  3614. /* check a token that follow the second expression */
  3615. if (mpl->token == T_COMMA)
  3616. { get_token(mpl /* , */);
  3617. if (mpl->token == T_SEMICOLON) goto err;
  3618. }
  3619. if (mpl->token == T_LT || mpl->token == T_LE ||
  3620. mpl->token == T_EQ || mpl->token == T_GE ||
  3621. mpl->token == T_GT || mpl->token == T_NE)
  3622. { /* it is another relational operator, therefore the constraint
  3623. is double inequality */
  3624. if (rho == T_EQ || mpl->token != rho)
  3625. error(mpl, "double inequality must be ... <= ... <= ... or "
  3626. "... >= ... >= ...");
  3627. /* the first expression cannot be linear form */
  3628. if (first->type == A_FORMULA)
  3629. error(mpl, "leftmost expression in double inequality cannot"
  3630. " be linear form");
  3631. get_token(mpl /* rho */);
  3632. /* parse the third expression */
  3633. third = expression_5(mpl);
  3634. if (third->type == A_SYMBOLIC)
  3635. third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
  3636. if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
  3637. error(mpl, "rightmost expression in double inequality const"
  3638. "raint has invalid type");
  3639. xassert(third->dim == 0);
  3640. /* the third expression also cannot be linear form */
  3641. if (third->type == A_FORMULA)
  3642. error(mpl, "rightmost expression in double inequality canno"
  3643. "t be linear form");
  3644. }
  3645. else
  3646. { /* the constraint is equality or single inequality */
  3647. third = NULL;
  3648. }
  3649. /* close the domain scope */
  3650. if (con->domain != NULL) close_scope(mpl, con->domain);
  3651. /* convert all expressions to linear form, if necessary */
  3652. if (first->type != A_FORMULA)
  3653. first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
  3654. if (second->type != A_FORMULA)
  3655. second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
  3656. if (third != NULL)
  3657. third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
  3658. /* arrange expressions in the constraint */
  3659. if (third == NULL)
  3660. { /* the constraint is equality or single inequality */
  3661. switch (rho)
  3662. { case T_LE:
  3663. /* first <= second */
  3664. con->code = first;
  3665. con->lbnd = NULL;
  3666. con->ubnd = second;
  3667. break;
  3668. case T_GE:
  3669. /* first >= second */
  3670. con->code = first;
  3671. con->lbnd = second;
  3672. con->ubnd = NULL;
  3673. break;
  3674. case T_EQ:
  3675. /* first = second */
  3676. con->code = first;
  3677. con->lbnd = second;
  3678. con->ubnd = second;
  3679. break;
  3680. default:
  3681. xassert(rho != rho);
  3682. }
  3683. }
  3684. else
  3685. { /* the constraint is double inequality */
  3686. switch (rho)
  3687. { case T_LE:
  3688. /* first <= second <= third */
  3689. con->code = second;
  3690. con->lbnd = first;
  3691. con->ubnd = third;
  3692. break;
  3693. case T_GE:
  3694. /* first >= second >= third */
  3695. con->code = second;
  3696. con->lbnd = third;
  3697. con->ubnd = first;
  3698. break;
  3699. default:
  3700. xassert(rho != rho);
  3701. }
  3702. }
  3703. /* the constraint statement has been completely parsed */
  3704. if (mpl->token != T_SEMICOLON)
  3705. err: error(mpl, "syntax error in constraint statement");
  3706. get_token(mpl /* ; */);
  3707. return con;
  3708. }
  3709. /*----------------------------------------------------------------------
  3710. -- objective_statement - parse objective statement.
  3711. --
  3712. -- This routine parses objective statement using the syntax:
  3713. --
  3714. -- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
  3715. -- <formula> ;
  3716. -- <verb> ::= minimize
  3717. -- <verb> ::= maximize
  3718. -- <alias> ::= <empty>
  3719. -- <alias> ::= <string literal>
  3720. -- <domain> ::= <empty>
  3721. -- <domain> ::= <indexing expression>
  3722. -- <formula> ::= <expression 5> */
  3723. CONSTRAINT *objective_statement(MPL *mpl)
  3724. { CONSTRAINT *obj;
  3725. int type;
  3726. if (is_keyword(mpl, "minimize"))
  3727. type = A_MINIMIZE;
  3728. else if (is_keyword(mpl, "maximize"))
  3729. type = A_MAXIMIZE;
  3730. else
  3731. xassert(mpl != mpl);
  3732. if (mpl->flag_s)
  3733. error(mpl, "objective statement must precede solve statement");
  3734. get_token(mpl /* minimize | maximize */);
  3735. /* symbolic name must follow the verb 'minimize' or 'maximize' */
  3736. if (mpl->token == T_NAME)
  3737. ;
  3738. else if (is_reserved(mpl))
  3739. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3740. else
  3741. error(mpl, "symbolic name missing where expected");
  3742. /* there must be no other object with the same name */
  3743. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3744. error(mpl, "%s multiply declared", mpl->image);
  3745. /* create model objective */
  3746. obj = alloc(CONSTRAINT);
  3747. obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3748. strcpy(obj->name, mpl->image);
  3749. obj->alias = NULL;
  3750. obj->dim = 0;
  3751. obj->domain = NULL;
  3752. obj->type = type;
  3753. obj->code = NULL;
  3754. obj->lbnd = NULL;
  3755. obj->ubnd = NULL;
  3756. obj->array = NULL;
  3757. get_token(mpl /* <symbolic name> */);
  3758. /* parse optional alias */
  3759. if (mpl->token == T_STRING)
  3760. { obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3761. strcpy(obj->alias, mpl->image);
  3762. get_token(mpl /* <string literal> */);
  3763. }
  3764. /* parse optional indexing expression */
  3765. if (mpl->token == T_LBRACE)
  3766. { obj->domain = indexing_expression(mpl);
  3767. obj->dim = domain_arity(mpl, obj->domain);
  3768. }
  3769. /* include the constraint name in the symbolic names table */
  3770. { AVLNODE *node;
  3771. node = avl_insert_node(mpl->tree, obj->name);
  3772. avl_set_node_type(node, A_CONSTRAINT);
  3773. avl_set_node_link(node, (void *)obj);
  3774. }
  3775. /* the colon must precede the objective expression */
  3776. if (mpl->token != T_COLON)
  3777. error(mpl, "colon missing where expected");
  3778. get_token(mpl /* : */);
  3779. /* parse the objective expression */
  3780. obj->code = expression_5(mpl);
  3781. if (obj->code->type == A_SYMBOLIC)
  3782. obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
  3783. if (obj->code->type == A_NUMERIC)
  3784. obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
  3785. if (obj->code->type != A_FORMULA)
  3786. error(mpl, "expression following colon has invalid type");
  3787. xassert(obj->code->dim == 0);
  3788. /* close the domain scope */
  3789. if (obj->domain != NULL) close_scope(mpl, obj->domain);
  3790. /* the objective statement has been completely parsed */
  3791. if (mpl->token != T_SEMICOLON)
  3792. error(mpl, "syntax error in objective statement");
  3793. get_token(mpl /* ; */);
  3794. return obj;
  3795. }
  3796. #if 1 /* 11/II-2008 */
  3797. /***********************************************************************
  3798. * table_statement - parse table statement
  3799. *
  3800. * This routine parses table statement using the syntax:
  3801. *
  3802. * <table statement> ::= <input table statement>
  3803. * <table statement> ::= <output table statement>
  3804. *
  3805. * <input table statement> ::=
  3806. * table <table name> <alias> IN <argument list> :
  3807. * <input set> [ <field list> ] , <input list> ;
  3808. * <alias> ::= <empty>
  3809. * <alias> ::= <string literal>
  3810. * <argument list> ::= <expression 5>
  3811. * <argument list> ::= <argument list> <expression 5>
  3812. * <argument list> ::= <argument list> , <expression 5>
  3813. * <input set> ::= <empty>
  3814. * <input set> ::= <set name> <-
  3815. * <field list> ::= <field name>
  3816. * <field list> ::= <field list> , <field name>
  3817. * <input list> ::= <input item>
  3818. * <input list> ::= <input list> , <input item>
  3819. * <input item> ::= <parameter name>
  3820. * <input item> ::= <parameter name> ~ <field name>
  3821. *
  3822. * <output table statement> ::=
  3823. * table <table name> <alias> <domain> OUT <argument list> :
  3824. * <output list> ;
  3825. * <domain> ::= <indexing expression>
  3826. * <output list> ::= <output item>
  3827. * <output list> ::= <output list> , <output item>
  3828. * <output item> ::= <expression 5>
  3829. * <output item> ::= <expression 5> ~ <field name> */
  3830. TABLE *table_statement(MPL *mpl)
  3831. { TABLE *tab;
  3832. TABARG *last_arg, *arg;
  3833. TABFLD *last_fld, *fld;
  3834. TABIN *last_in, *in;
  3835. TABOUT *last_out, *out;
  3836. AVLNODE *node;
  3837. int nflds;
  3838. char name[MAX_LENGTH+1];
  3839. xassert(is_keyword(mpl, "table"));
  3840. get_token(mpl /* solve */);
  3841. /* symbolic name must follow the keyword table */
  3842. if (mpl->token == T_NAME)
  3843. ;
  3844. else if (is_reserved(mpl))
  3845. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3846. else
  3847. error(mpl, "symbolic name missing where expected");
  3848. /* there must be no other object with the same name */
  3849. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3850. error(mpl, "%s multiply declared", mpl->image);
  3851. /* create data table */
  3852. tab = alloc(TABLE);
  3853. tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3854. strcpy(tab->name, mpl->image);
  3855. get_token(mpl /* <symbolic name> */);
  3856. /* parse optional alias */
  3857. if (mpl->token == T_STRING)
  3858. { tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3859. strcpy(tab->alias, mpl->image);
  3860. get_token(mpl /* <string literal> */);
  3861. }
  3862. else
  3863. tab->alias = NULL;
  3864. /* parse optional indexing expression */
  3865. if (mpl->token == T_LBRACE)
  3866. { /* this is output table */
  3867. tab->type = A_OUTPUT;
  3868. tab->u.out.domain = indexing_expression(mpl);
  3869. if (!is_keyword(mpl, "OUT"))
  3870. error(mpl, "keyword OUT missing where expected");
  3871. get_token(mpl /* OUT */);
  3872. }
  3873. else
  3874. { /* this is input table */
  3875. tab->type = A_INPUT;
  3876. if (!is_keyword(mpl, "IN"))
  3877. error(mpl, "keyword IN missing where expected");
  3878. get_token(mpl /* IN */);
  3879. }
  3880. /* parse argument list */
  3881. tab->arg = last_arg = NULL;
  3882. for (;;)
  3883. { /* create argument list entry */
  3884. arg = alloc(TABARG);
  3885. /* parse argument expression */
  3886. if (mpl->token == T_COMMA || mpl->token == T_COLON ||
  3887. mpl->token == T_SEMICOLON)
  3888. error(mpl, "argument expression missing where expected");
  3889. arg->code = expression_5(mpl);
  3890. /* convert the result to symbolic type, if necessary */
  3891. if (arg->code->type == A_NUMERIC)
  3892. arg->code =
  3893. make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
  3894. /* check that now the result is of symbolic type */
  3895. if (arg->code->type != A_SYMBOLIC)
  3896. error(mpl, "argument expression has invalid type");
  3897. /* add the entry to the end of the list */
  3898. arg->next = NULL;
  3899. if (last_arg == NULL)
  3900. tab->arg = arg;
  3901. else
  3902. last_arg->next = arg;
  3903. last_arg = arg;
  3904. /* argument expression has been parsed */
  3905. if (mpl->token == T_COMMA)
  3906. get_token(mpl /* , */);
  3907. else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
  3908. break;
  3909. }
  3910. xassert(tab->arg != NULL);
  3911. /* argument list must end with colon */
  3912. if (mpl->token == T_COLON)
  3913. get_token(mpl /* : */);
  3914. else
  3915. error(mpl, "colon missing where expected");
  3916. /* parse specific part of the table statement */
  3917. switch (tab->type)
  3918. { case A_INPUT: goto input_table;
  3919. case A_OUTPUT: goto output_table;
  3920. default: xassert(tab != tab);
  3921. }
  3922. input_table:
  3923. /* parse optional set name */
  3924. if (mpl->token == T_NAME)
  3925. { node = avl_find_node(mpl->tree, mpl->image);
  3926. if (node == NULL)
  3927. error(mpl, "%s not defined", mpl->image);
  3928. if (avl_get_node_type(node) != A_SET)
  3929. error(mpl, "%s not a set", mpl->image);
  3930. tab->u.in.set = (SET *)avl_get_node_link(node);
  3931. if (tab->u.in.set->assign != NULL)
  3932. error(mpl, "%s needs no data", mpl->image);
  3933. if (tab->u.in.set->dim != 0)
  3934. error(mpl, "%s must be a simple set", mpl->image);
  3935. get_token(mpl /* <symbolic name> */);
  3936. if (mpl->token == T_INPUT)
  3937. get_token(mpl /* <- */);
  3938. else
  3939. error(mpl, "delimiter <- missing where expected");
  3940. }
  3941. else if (is_reserved(mpl))
  3942. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3943. else
  3944. tab->u.in.set = NULL;
  3945. /* parse field list */
  3946. tab->u.in.fld = last_fld = NULL;
  3947. nflds = 0;
  3948. if (mpl->token == T_LBRACKET)
  3949. get_token(mpl /* [ */);
  3950. else
  3951. error(mpl, "field list missing where expected");
  3952. for (;;)
  3953. { /* create field list entry */
  3954. fld = alloc(TABFLD);
  3955. /* parse field name */
  3956. if (mpl->token == T_NAME)
  3957. ;
  3958. else if (is_reserved(mpl))
  3959. error(mpl,
  3960. "invalid use of reserved keyword %s", mpl->image);
  3961. else
  3962. error(mpl, "field name missing where expected");
  3963. fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3964. strcpy(fld->name, mpl->image);
  3965. get_token(mpl /* <symbolic name> */);
  3966. /* add the entry to the end of the list */
  3967. fld->next = NULL;
  3968. if (last_fld == NULL)
  3969. tab->u.in.fld = fld;
  3970. else
  3971. last_fld->next = fld;
  3972. last_fld = fld;
  3973. nflds++;
  3974. /* field name has been parsed */
  3975. if (mpl->token == T_COMMA)
  3976. get_token(mpl /* , */);
  3977. else if (mpl->token == T_RBRACKET)
  3978. break;
  3979. else
  3980. error(mpl, "syntax error in field list");
  3981. }
  3982. /* check that the set dimen is equal to the number of fields */
  3983. if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
  3984. error(mpl, "there must be %d field%s rather than %d",
  3985. tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
  3986. nflds);
  3987. get_token(mpl /* ] */);
  3988. /* parse optional input list */
  3989. tab->u.in.list = last_in = NULL;
  3990. while (mpl->token == T_COMMA)
  3991. { get_token(mpl /* , */);
  3992. /* create input list entry */
  3993. in = alloc(TABIN);
  3994. /* parse parameter name */
  3995. if (mpl->token == T_NAME)
  3996. ;
  3997. else if (is_reserved(mpl))
  3998. error(mpl,
  3999. "invalid use of reserved keyword %s", mpl->image);
  4000. else
  4001. error(mpl, "parameter name missing where expected");
  4002. node = avl_find_node(mpl->tree, mpl->image);
  4003. if (node == NULL)
  4004. error(mpl, "%s not defined", mpl->image);
  4005. if (avl_get_node_type(node) != A_PARAMETER)
  4006. error(mpl, "%s not a parameter", mpl->image);
  4007. in->par = (PARAMETER *)avl_get_node_link(node);
  4008. if (in->par->dim != nflds)
  4009. error(mpl, "%s must have %d subscript%s rather than %d",
  4010. mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
  4011. if (in->par->assign != NULL)
  4012. error(mpl, "%s needs no data", mpl->image);
  4013. get_token(mpl /* <symbolic name> */);
  4014. /* parse optional field name */
  4015. if (mpl->token == T_TILDE)
  4016. { get_token(mpl /* ~ */);
  4017. /* parse field name */
  4018. if (mpl->token == T_NAME)
  4019. ;
  4020. else if (is_reserved(mpl))
  4021. error(mpl,
  4022. "invalid use of reserved keyword %s", mpl->image);
  4023. else
  4024. error(mpl, "field name missing where expected");
  4025. xassert(strlen(mpl->image) < sizeof(name));
  4026. strcpy(name, mpl->image);
  4027. get_token(mpl /* <symbolic name> */);
  4028. }
  4029. else
  4030. { /* field name is the same as the parameter name */
  4031. xassert(strlen(in->par->name) < sizeof(name));
  4032. strcpy(name, in->par->name);
  4033. }
  4034. /* assign field name */
  4035. in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
  4036. strcpy(in->name, name);
  4037. /* add the entry to the end of the list */
  4038. in->next = NULL;
  4039. if (last_in == NULL)
  4040. tab->u.in.list = in;
  4041. else
  4042. last_in->next = in;
  4043. last_in = in;
  4044. }
  4045. goto end_of_table;
  4046. output_table:
  4047. /* parse output list */
  4048. tab->u.out.list = last_out = NULL;
  4049. for (;;)
  4050. { /* create output list entry */
  4051. out = alloc(TABOUT);
  4052. /* parse expression */
  4053. if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
  4054. error(mpl, "expression missing where expected");
  4055. if (mpl->token == T_NAME)
  4056. { xassert(strlen(mpl->image) < sizeof(name));
  4057. strcpy(name, mpl->image);
  4058. }
  4059. else
  4060. name[0] = '\0';
  4061. out->code = expression_5(mpl);
  4062. /* parse optional field name */
  4063. if (mpl->token == T_TILDE)
  4064. { get_token(mpl /* ~ */);
  4065. /* parse field name */
  4066. if (mpl->token == T_NAME)
  4067. ;
  4068. else if (is_reserved(mpl))
  4069. error(mpl,
  4070. "invalid use of reserved keyword %s", mpl->image);
  4071. else
  4072. error(mpl, "field name missing where expected");
  4073. xassert(strlen(mpl->image) < sizeof(name));
  4074. strcpy(name, mpl->image);
  4075. get_token(mpl /* <symbolic name> */);
  4076. }
  4077. /* assign field name */
  4078. if (name[0] == '\0')
  4079. error(mpl, "field name required");
  4080. out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
  4081. strcpy(out->name, name);
  4082. /* add the entry to the end of the list */
  4083. out->next = NULL;
  4084. if (last_out == NULL)
  4085. tab->u.out.list = out;
  4086. else
  4087. last_out->next = out;
  4088. last_out = out;
  4089. /* output item has been parsed */
  4090. if (mpl->token == T_COMMA)
  4091. get_token(mpl /* , */);
  4092. else if (mpl->token == T_SEMICOLON)
  4093. break;
  4094. else
  4095. error(mpl, "syntax error in output list");
  4096. }
  4097. /* close the domain scope */
  4098. close_scope(mpl,tab->u.out.domain);
  4099. end_of_table:
  4100. /* the table statement must end with semicolon */
  4101. if (mpl->token != T_SEMICOLON)
  4102. error(mpl, "syntax error in table statement");
  4103. get_token(mpl /* ; */);
  4104. return tab;
  4105. }
  4106. #endif
  4107. /*----------------------------------------------------------------------
  4108. -- solve_statement - parse solve statement.
  4109. --
  4110. -- This routine parses solve statement using the syntax:
  4111. --
  4112. -- <solve statement> ::= solve ;
  4113. --
  4114. -- The solve statement can be used at most once. */
  4115. void *solve_statement(MPL *mpl)
  4116. { xassert(is_keyword(mpl, "solve"));
  4117. if (mpl->flag_s)
  4118. error(mpl, "at most one solve statement allowed");
  4119. mpl->flag_s = 1;
  4120. get_token(mpl /* solve */);
  4121. /* semicolon must follow solve statement */
  4122. if (mpl->token != T_SEMICOLON)
  4123. error(mpl, "syntax error in solve statement");
  4124. get_token(mpl /* ; */);
  4125. return NULL;
  4126. }
  4127. /*----------------------------------------------------------------------
  4128. -- check_statement - parse check statement.
  4129. --
  4130. -- This routine parses check statement using the syntax:
  4131. --
  4132. -- <check statement> ::= check <domain> : <expression 13> ;
  4133. -- <domain> ::= <empty>
  4134. -- <domain> ::= <indexing expression>
  4135. --
  4136. -- If <domain> is omitted, colon following it may also be omitted. */
  4137. CHECK *check_statement(MPL *mpl)
  4138. { CHECK *chk;
  4139. xassert(is_keyword(mpl, "check"));
  4140. /* create check descriptor */
  4141. chk = alloc(CHECK);
  4142. chk->domain = NULL;
  4143. chk->code = NULL;
  4144. get_token(mpl /* check */);
  4145. /* parse optional indexing expression */
  4146. if (mpl->token == T_LBRACE)
  4147. { chk->domain = indexing_expression(mpl);
  4148. #if 0
  4149. if (mpl->token != T_COLON)
  4150. error(mpl, "colon missing where expected");
  4151. #endif
  4152. }
  4153. /* skip optional colon */
  4154. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4155. /* parse logical expression */
  4156. chk->code = expression_13(mpl);
  4157. if (chk->code->type != A_LOGICAL)
  4158. error(mpl, "expression has invalid type");
  4159. xassert(chk->code->dim == 0);
  4160. /* close the domain scope */
  4161. if (chk->domain != NULL) close_scope(mpl, chk->domain);
  4162. /* the check statement has been completely parsed */
  4163. if (mpl->token != T_SEMICOLON)
  4164. error(mpl, "syntax error in check statement");
  4165. get_token(mpl /* ; */);
  4166. return chk;
  4167. }
  4168. #if 1 /* 15/V-2010 */
  4169. /*----------------------------------------------------------------------
  4170. -- display_statement - parse display statement.
  4171. --
  4172. -- This routine parses display statement using the syntax:
  4173. --
  4174. -- <display statement> ::= display <domain> : <display list> ;
  4175. -- <display statement> ::= display <domain> <display list> ;
  4176. -- <domain> ::= <empty>
  4177. -- <domain> ::= <indexing expression>
  4178. -- <display list> ::= <display entry>
  4179. -- <display list> ::= <display list> , <display entry>
  4180. -- <display entry> ::= <dummy index>
  4181. -- <display entry> ::= <set name>
  4182. -- <display entry> ::= <set name> [ <subscript list> ]
  4183. -- <display entry> ::= <parameter name>
  4184. -- <display entry> ::= <parameter name> [ <subscript list> ]
  4185. -- <display entry> ::= <variable name>
  4186. -- <display entry> ::= <variable name> [ <subscript list> ]
  4187. -- <display entry> ::= <constraint name>
  4188. -- <display entry> ::= <constraint name> [ <subscript list> ]
  4189. -- <display entry> ::= <expression 13> */
  4190. DISPLAY *display_statement(MPL *mpl)
  4191. { DISPLAY *dpy;
  4192. DISPLAY1 *entry, *last_entry;
  4193. xassert(is_keyword(mpl, "display"));
  4194. /* create display descriptor */
  4195. dpy = alloc(DISPLAY);
  4196. dpy->domain = NULL;
  4197. dpy->list = last_entry = NULL;
  4198. get_token(mpl /* display */);
  4199. /* parse optional indexing expression */
  4200. if (mpl->token == T_LBRACE)
  4201. dpy->domain = indexing_expression(mpl);
  4202. /* skip optional colon */
  4203. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4204. /* parse display list */
  4205. for (;;)
  4206. { /* create new display entry */
  4207. entry = alloc(DISPLAY1);
  4208. entry->type = 0;
  4209. entry->next = NULL;
  4210. /* and append it to the display list */
  4211. if (dpy->list == NULL)
  4212. dpy->list = entry;
  4213. else
  4214. last_entry->next = entry;
  4215. last_entry = entry;
  4216. /* parse display entry */
  4217. if (mpl->token == T_NAME)
  4218. { AVLNODE *node;
  4219. int next_token;
  4220. get_token(mpl /* <symbolic name> */);
  4221. next_token = mpl->token;
  4222. unget_token(mpl);
  4223. if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
  4224. { /* symbolic name begins expression */
  4225. goto expr;
  4226. }
  4227. /* display entry is dummy index or model object */
  4228. node = avl_find_node(mpl->tree, mpl->image);
  4229. if (node == NULL)
  4230. error(mpl, "%s not defined", mpl->image);
  4231. entry->type = avl_get_node_type(node);
  4232. switch (avl_get_node_type(node))
  4233. { case A_INDEX:
  4234. entry->u.slot =
  4235. (DOMAIN_SLOT *)avl_get_node_link(node);
  4236. break;
  4237. case A_SET:
  4238. entry->u.set = (SET *)avl_get_node_link(node);
  4239. break;
  4240. case A_PARAMETER:
  4241. entry->u.par = (PARAMETER *)avl_get_node_link(node);
  4242. break;
  4243. case A_VARIABLE:
  4244. entry->u.var = (VARIABLE *)avl_get_node_link(node);
  4245. if (!mpl->flag_s)
  4246. error(mpl, "invalid reference to variable %s above"
  4247. " solve statement", entry->u.var->name);
  4248. break;
  4249. case A_CONSTRAINT:
  4250. entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
  4251. if (!mpl->flag_s)
  4252. error(mpl, "invalid reference to %s %s above solve"
  4253. " statement",
  4254. entry->u.con->type == A_CONSTRAINT ?
  4255. "constraint" : "objective", entry->u.con->name);
  4256. break;
  4257. default:
  4258. xassert(node != node);
  4259. }
  4260. get_token(mpl /* <symbolic name> */);
  4261. }
  4262. else
  4263. expr: { /* display entry is expression */
  4264. entry->type = A_EXPRESSION;
  4265. entry->u.code = expression_13(mpl);
  4266. }
  4267. /* check a token that follows the entry parsed */
  4268. if (mpl->token == T_COMMA)
  4269. get_token(mpl /* , */);
  4270. else
  4271. break;
  4272. }
  4273. /* close the domain scope */
  4274. if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
  4275. /* the display statement has been completely parsed */
  4276. if (mpl->token != T_SEMICOLON)
  4277. error(mpl, "syntax error in display statement");
  4278. get_token(mpl /* ; */);
  4279. return dpy;
  4280. }
  4281. #endif
  4282. /*----------------------------------------------------------------------
  4283. -- printf_statement - parse printf statement.
  4284. --
  4285. -- This routine parses print statement using the syntax:
  4286. --
  4287. -- <printf statement> ::= <printf clause> ;
  4288. -- <printf statement> ::= <printf clause> > <file name> ;
  4289. -- <printf statement> ::= <printf clause> >> <file name> ;
  4290. -- <printf clause> ::= printf <domain> : <format> <printf list>
  4291. -- <printf clause> ::= printf <domain> <format> <printf list>
  4292. -- <domain> ::= <empty>
  4293. -- <domain> ::= <indexing expression>
  4294. -- <format> ::= <expression 5>
  4295. -- <printf list> ::= <empty>
  4296. -- <printf list> ::= <printf list> , <printf entry>
  4297. -- <printf entry> ::= <expression 9>
  4298. -- <file name> ::= <expression 5> */
  4299. PRINTF *printf_statement(MPL *mpl)
  4300. { PRINTF *prt;
  4301. PRINTF1 *entry, *last_entry;
  4302. xassert(is_keyword(mpl, "printf"));
  4303. /* create printf descriptor */
  4304. prt = alloc(PRINTF);
  4305. prt->domain = NULL;
  4306. prt->fmt = NULL;
  4307. prt->list = last_entry = NULL;
  4308. get_token(mpl /* printf */);
  4309. /* parse optional indexing expression */
  4310. if (mpl->token == T_LBRACE)
  4311. { prt->domain = indexing_expression(mpl);
  4312. #if 0
  4313. if (mpl->token != T_COLON)
  4314. error(mpl, "colon missing where expected");
  4315. #endif
  4316. }
  4317. /* skip optional colon */
  4318. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4319. /* parse expression for format string */
  4320. prt->fmt = expression_5(mpl);
  4321. /* convert it to symbolic type, if necessary */
  4322. if (prt->fmt->type == A_NUMERIC)
  4323. prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
  4324. /* check that now the expression is of symbolic type */
  4325. if (prt->fmt->type != A_SYMBOLIC)
  4326. error(mpl, "format expression has invalid type");
  4327. /* parse printf list */
  4328. while (mpl->token == T_COMMA)
  4329. { get_token(mpl /* , */);
  4330. /* create new printf entry */
  4331. entry = alloc(PRINTF1);
  4332. entry->code = NULL;
  4333. entry->next = NULL;
  4334. /* and append it to the printf list */
  4335. if (prt->list == NULL)
  4336. prt->list = entry;
  4337. else
  4338. last_entry->next = entry;
  4339. last_entry = entry;
  4340. /* parse printf entry */
  4341. entry->code = expression_9(mpl);
  4342. if (!(entry->code->type == A_NUMERIC ||
  4343. entry->code->type == A_SYMBOLIC ||
  4344. entry->code->type == A_LOGICAL))
  4345. error(mpl, "only numeric, symbolic, or logical expression a"
  4346. "llowed");
  4347. }
  4348. /* close the domain scope */
  4349. if (prt->domain != NULL) close_scope(mpl, prt->domain);
  4350. #if 1 /* 14/VII-2006 */
  4351. /* parse optional redirection */
  4352. prt->fname = NULL, prt->app = 0;
  4353. if (mpl->token == T_GT || mpl->token == T_APPEND)
  4354. { prt->app = (mpl->token == T_APPEND);
  4355. get_token(mpl /* > or >> */);
  4356. /* parse expression for file name string */
  4357. prt->fname = expression_5(mpl);
  4358. /* convert it to symbolic type, if necessary */
  4359. if (prt->fname->type == A_NUMERIC)
  4360. prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
  4361. A_SYMBOLIC, 0);
  4362. /* check that now the expression is of symbolic type */
  4363. if (prt->fname->type != A_SYMBOLIC)
  4364. error(mpl, "file name expression has invalid type");
  4365. }
  4366. #endif
  4367. /* the printf statement has been completely parsed */
  4368. if (mpl->token != T_SEMICOLON)
  4369. error(mpl, "syntax error in printf statement");
  4370. get_token(mpl /* ; */);
  4371. return prt;
  4372. }
  4373. /*----------------------------------------------------------------------
  4374. -- for_statement - parse for statement.
  4375. --
  4376. -- This routine parses for statement using the syntax:
  4377. --
  4378. -- <for statement> ::= for <domain> <statement>
  4379. -- <for statement> ::= for <domain> { <statement list> }
  4380. -- <domain> ::= <indexing expression>
  4381. -- <statement list> ::= <empty>
  4382. -- <statement list> ::= <statement list> <statement>
  4383. -- <statement> ::= <check statement>
  4384. -- <statement> ::= <display statement>
  4385. -- <statement> ::= <printf statement>
  4386. -- <statement> ::= <for statement> */
  4387. FOR *for_statement(MPL *mpl)
  4388. { FOR *fur;
  4389. STATEMENT *stmt, *last_stmt;
  4390. xassert(is_keyword(mpl, "for"));
  4391. /* create for descriptor */
  4392. fur = alloc(FOR);
  4393. fur->domain = NULL;
  4394. fur->list = last_stmt = NULL;
  4395. get_token(mpl /* for */);
  4396. /* parse indexing expression */
  4397. if (mpl->token != T_LBRACE)
  4398. error(mpl, "indexing expression missing where expected");
  4399. fur->domain = indexing_expression(mpl);
  4400. /* skip optional colon */
  4401. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4402. /* parse for statement body */
  4403. if (mpl->token != T_LBRACE)
  4404. { /* parse simple statement */
  4405. fur->list = simple_statement(mpl, 1);
  4406. }
  4407. else
  4408. { /* parse compound statement */
  4409. get_token(mpl /* { */);
  4410. while (mpl->token != T_RBRACE)
  4411. { /* parse statement */
  4412. stmt = simple_statement(mpl, 1);
  4413. /* and append it to the end of the statement list */
  4414. if (last_stmt == NULL)
  4415. fur->list = stmt;
  4416. else
  4417. last_stmt->next = stmt;
  4418. last_stmt = stmt;
  4419. }
  4420. get_token(mpl /* } */);
  4421. }
  4422. /* close the domain scope */
  4423. xassert(fur->domain != NULL);
  4424. close_scope(mpl, fur->domain);
  4425. /* the for statement has been completely parsed */
  4426. return fur;
  4427. }
  4428. /*----------------------------------------------------------------------
  4429. -- end_statement - parse end statement.
  4430. --
  4431. -- This routine parses end statement using the syntax:
  4432. --
  4433. -- <end statement> ::= end ; <eof> */
  4434. void end_statement(MPL *mpl)
  4435. { if (!mpl->flag_d && is_keyword(mpl, "end") ||
  4436. mpl->flag_d && is_literal(mpl, "end"))
  4437. { get_token(mpl /* end */);
  4438. if (mpl->token == T_SEMICOLON)
  4439. get_token(mpl /* ; */);
  4440. else
  4441. warning(mpl, "no semicolon following end statement; missing"
  4442. " semicolon inserted");
  4443. }
  4444. else
  4445. warning(mpl, "unexpected end of file; missing end statement in"
  4446. "serted");
  4447. if (mpl->token != T_EOF)
  4448. warning(mpl, "some text detected beyond end statement; text ig"
  4449. "nored");
  4450. return;
  4451. }
  4452. /*----------------------------------------------------------------------
  4453. -- simple_statement - parse simple statement.
  4454. --
  4455. -- This routine parses simple statement using the syntax:
  4456. --
  4457. -- <statement> ::= <set statement>
  4458. -- <statement> ::= <parameter statement>
  4459. -- <statement> ::= <variable statement>
  4460. -- <statement> ::= <constraint statement>
  4461. -- <statement> ::= <objective statement>
  4462. -- <statement> ::= <solve statement>
  4463. -- <statement> ::= <check statement>
  4464. -- <statement> ::= <display statement>
  4465. -- <statement> ::= <printf statement>
  4466. -- <statement> ::= <for statement>
  4467. --
  4468. -- If the flag spec is set, some statements cannot be used. */
  4469. STATEMENT *simple_statement(MPL *mpl, int spec)
  4470. { STATEMENT *stmt;
  4471. stmt = alloc(STATEMENT);
  4472. stmt->line = mpl->line;
  4473. stmt->next = NULL;
  4474. if (is_keyword(mpl, "set"))
  4475. { if (spec)
  4476. error(mpl, "set statement not allowed here");
  4477. stmt->type = A_SET;
  4478. stmt->u.set = set_statement(mpl);
  4479. }
  4480. else if (is_keyword(mpl, "param"))
  4481. { if (spec)
  4482. error(mpl, "parameter statement not allowed here");
  4483. stmt->type = A_PARAMETER;
  4484. stmt->u.par = parameter_statement(mpl);
  4485. }
  4486. else if (is_keyword(mpl, "var"))
  4487. { if (spec)
  4488. error(mpl, "variable statement not allowed here");
  4489. stmt->type = A_VARIABLE;
  4490. stmt->u.var = variable_statement(mpl);
  4491. }
  4492. else if (is_keyword(mpl, "subject") ||
  4493. is_keyword(mpl, "subj") ||
  4494. mpl->token == T_SPTP)
  4495. { if (spec)
  4496. error(mpl, "constraint statement not allowed here");
  4497. stmt->type = A_CONSTRAINT;
  4498. stmt->u.con = constraint_statement(mpl);
  4499. }
  4500. else if (is_keyword(mpl, "minimize") ||
  4501. is_keyword(mpl, "maximize"))
  4502. { if (spec)
  4503. error(mpl, "objective statement not allowed here");
  4504. stmt->type = A_CONSTRAINT;
  4505. stmt->u.con = objective_statement(mpl);
  4506. }
  4507. #if 1 /* 11/II-2008 */
  4508. else if (is_keyword(mpl, "table"))
  4509. { if (spec)
  4510. error(mpl, "table statement not allowed here");
  4511. stmt->type = A_TABLE;
  4512. stmt->u.tab = table_statement(mpl);
  4513. }
  4514. #endif
  4515. else if (is_keyword(mpl, "solve"))
  4516. { if (spec)
  4517. error(mpl, "solve statement not allowed here");
  4518. stmt->type = A_SOLVE;
  4519. stmt->u.slv = solve_statement(mpl);
  4520. }
  4521. else if (is_keyword(mpl, "check"))
  4522. { stmt->type = A_CHECK;
  4523. stmt->u.chk = check_statement(mpl);
  4524. }
  4525. else if (is_keyword(mpl, "display"))
  4526. { stmt->type = A_DISPLAY;
  4527. stmt->u.dpy = display_statement(mpl);
  4528. }
  4529. else if (is_keyword(mpl, "printf"))
  4530. { stmt->type = A_PRINTF;
  4531. stmt->u.prt = printf_statement(mpl);
  4532. }
  4533. else if (is_keyword(mpl, "for"))
  4534. { stmt->type = A_FOR;
  4535. stmt->u.fur = for_statement(mpl);
  4536. }
  4537. else if (mpl->token == T_NAME)
  4538. { if (spec)
  4539. error(mpl, "constraint statement not allowed here");
  4540. stmt->type = A_CONSTRAINT;
  4541. stmt->u.con = constraint_statement(mpl);
  4542. }
  4543. else if (is_reserved(mpl))
  4544. error(mpl, "invalid use of reserved keyword %s", mpl->image);
  4545. else
  4546. error(mpl, "syntax error in model section");
  4547. return stmt;
  4548. }
  4549. /*----------------------------------------------------------------------
  4550. -- model_section - parse model section.
  4551. --
  4552. -- This routine parses model section using the syntax:
  4553. --
  4554. -- <model section> ::= <empty>
  4555. -- <model section> ::= <model section> <statement>
  4556. --
  4557. -- Parsing model section is terminated by either the keyword 'data', or
  4558. -- the keyword 'end', or the end of file. */
  4559. void model_section(MPL *mpl)
  4560. { STATEMENT *stmt, *last_stmt;
  4561. xassert(mpl->model == NULL);
  4562. last_stmt = NULL;
  4563. while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
  4564. is_keyword(mpl, "end")))
  4565. { /* parse statement */
  4566. stmt = simple_statement(mpl, 0);
  4567. /* and append it to the end of the statement list */
  4568. if (last_stmt == NULL)
  4569. mpl->model = stmt;
  4570. else
  4571. last_stmt->next = stmt;
  4572. last_stmt = stmt;
  4573. }
  4574. return;
  4575. }
  4576. /* eof */