glpmpl02.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. /* glpmpl02.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 Andrew Makhorin, Department for Applied Informatics,
  7. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  8. * 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. #define _GLPSTD_STDIO
  24. #include "glpenv.h"
  25. #include "glpmpl.h"
  26. /**********************************************************************/
  27. /* * * PROCESSING DATA SECTION * * */
  28. /**********************************************************************/
  29. /*----------------------------------------------------------------------
  30. -- create_slice - create slice.
  31. --
  32. -- This routine creates a slice, which initially has no components. */
  33. SLICE *create_slice(MPL *mpl)
  34. { SLICE *slice;
  35. xassert(mpl == mpl);
  36. slice = NULL;
  37. return slice;
  38. }
  39. /*----------------------------------------------------------------------
  40. -- expand_slice - append new component to slice.
  41. --
  42. -- This routine expands slice appending to it either a given symbol or
  43. -- null component, which becomes the last component of the slice. */
  44. SLICE *expand_slice
  45. ( MPL *mpl,
  46. SLICE *slice, /* destroyed */
  47. SYMBOL *sym /* destroyed */
  48. )
  49. { SLICE *tail, *temp;
  50. /* create a new component */
  51. tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
  52. tail->sym = sym;
  53. tail->next = NULL;
  54. /* and append it to the component list */
  55. if (slice == NULL)
  56. slice = tail;
  57. else
  58. { for (temp = slice; temp->next != NULL; temp = temp->next);
  59. temp->next = tail;
  60. }
  61. return slice;
  62. }
  63. /*----------------------------------------------------------------------
  64. -- slice_dimen - determine dimension of slice.
  65. --
  66. -- This routine returns dimension of slice, which is number of all its
  67. -- components including null ones. */
  68. int slice_dimen
  69. ( MPL *mpl,
  70. SLICE *slice /* not changed */
  71. )
  72. { SLICE *temp;
  73. int dim;
  74. xassert(mpl == mpl);
  75. dim = 0;
  76. for (temp = slice; temp != NULL; temp = temp->next) dim++;
  77. return dim;
  78. }
  79. /*----------------------------------------------------------------------
  80. -- slice_arity - determine arity of slice.
  81. --
  82. -- This routine returns arity of slice, i.e. number of null components
  83. -- (indicated by asterisks) in the slice. */
  84. int slice_arity
  85. ( MPL *mpl,
  86. SLICE *slice /* not changed */
  87. )
  88. { SLICE *temp;
  89. int arity;
  90. xassert(mpl == mpl);
  91. arity = 0;
  92. for (temp = slice; temp != NULL; temp = temp->next)
  93. if (temp->sym == NULL) arity++;
  94. return arity;
  95. }
  96. /*----------------------------------------------------------------------
  97. -- fake_slice - create fake slice of all asterisks.
  98. --
  99. -- This routine creates a fake slice of given dimension, which contains
  100. -- asterisks in all components. Zero dimension is allowed. */
  101. SLICE *fake_slice(MPL *mpl, int dim)
  102. { SLICE *slice;
  103. slice = create_slice(mpl);
  104. while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
  105. return slice;
  106. }
  107. /*----------------------------------------------------------------------
  108. -- delete_slice - delete slice.
  109. --
  110. -- This routine deletes specified slice. */
  111. void delete_slice
  112. ( MPL *mpl,
  113. SLICE *slice /* destroyed */
  114. )
  115. { SLICE *temp;
  116. while (slice != NULL)
  117. { temp = slice;
  118. slice = temp->next;
  119. if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
  120. xassert(sizeof(SLICE) == sizeof(TUPLE));
  121. dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
  122. }
  123. return;
  124. }
  125. /*----------------------------------------------------------------------
  126. -- is_number - check if current token is number.
  127. --
  128. -- If the current token is a number, this routine returns non-zero.
  129. -- Otherwise zero is returned. */
  130. int is_number(MPL *mpl)
  131. { return
  132. mpl->token == T_NUMBER;
  133. }
  134. /*----------------------------------------------------------------------
  135. -- is_symbol - check if current token is symbol.
  136. --
  137. -- If the current token is suitable to be a symbol, the routine returns
  138. -- non-zero. Otherwise zero is returned. */
  139. int is_symbol(MPL *mpl)
  140. { return
  141. mpl->token == T_NUMBER ||
  142. mpl->token == T_SYMBOL ||
  143. mpl->token == T_STRING;
  144. }
  145. /*----------------------------------------------------------------------
  146. -- is_literal - check if current token is given symbolic literal.
  147. --
  148. -- If the current token is given symbolic literal, this routine returns
  149. -- non-zero. Otherwise zero is returned.
  150. --
  151. -- This routine is used on processing the data section in the same way
  152. -- as the routine is_keyword on processing the model section. */
  153. int is_literal(MPL *mpl, char *literal)
  154. { return
  155. is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
  156. }
  157. /*----------------------------------------------------------------------
  158. -- read_number - read number.
  159. --
  160. -- This routine reads the current token, which must be a number, and
  161. -- returns its numeric value. */
  162. double read_number(MPL *mpl)
  163. { double num;
  164. xassert(is_number(mpl));
  165. num = mpl->value;
  166. get_token(mpl /* <number> */);
  167. return num;
  168. }
  169. /*----------------------------------------------------------------------
  170. -- read_symbol - read symbol.
  171. --
  172. -- This routine reads the current token, which must be a symbol, and
  173. -- returns its symbolic value. */
  174. SYMBOL *read_symbol(MPL *mpl)
  175. { SYMBOL *sym;
  176. xassert(is_symbol(mpl));
  177. if (is_number(mpl))
  178. sym = create_symbol_num(mpl, mpl->value);
  179. else
  180. sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
  181. get_token(mpl /* <symbol> */);
  182. return sym;
  183. }
  184. /*----------------------------------------------------------------------
  185. -- read_slice - read slice.
  186. --
  187. -- This routine reads slice using the syntax:
  188. --
  189. -- <slice> ::= [ <symbol list> ]
  190. -- <slice> ::= ( <symbol list> )
  191. -- <symbol list> ::= <symbol or star>
  192. -- <symbol list> ::= <symbol list> , <symbol or star>
  193. -- <symbol or star> ::= <symbol>
  194. -- <symbol or star> ::= *
  195. --
  196. -- The bracketed form of slice is used for members of multi-dimensional
  197. -- objects while the parenthesized form is used for elemental sets. */
  198. SLICE *read_slice
  199. ( MPL *mpl,
  200. char *name, /* not changed */
  201. int dim
  202. )
  203. { SLICE *slice;
  204. int close;
  205. xassert(name != NULL);
  206. switch (mpl->token)
  207. { case T_LBRACKET:
  208. close = T_RBRACKET;
  209. break;
  210. case T_LEFT:
  211. xassert(dim > 0);
  212. close = T_RIGHT;
  213. break;
  214. default:
  215. xassert(mpl != mpl);
  216. }
  217. if (dim == 0)
  218. mpl_error(mpl, "%s cannot be subscripted", name);
  219. get_token(mpl /* ( | [ */);
  220. /* read slice components */
  221. slice = create_slice(mpl);
  222. for (;;)
  223. { /* the current token must be a symbol or asterisk */
  224. if (is_symbol(mpl))
  225. slice = expand_slice(mpl, slice, read_symbol(mpl));
  226. else if (mpl->token == T_ASTERISK)
  227. { slice = expand_slice(mpl, slice, NULL);
  228. get_token(mpl /* * */);
  229. }
  230. else
  231. mpl_error(mpl, "number, symbol, or asterisk missing where expec"
  232. "ted");
  233. /* check a token that follows the symbol */
  234. if (mpl->token == T_COMMA)
  235. get_token(mpl /* , */);
  236. else if (mpl->token == close)
  237. break;
  238. else
  239. mpl_error(mpl, "syntax error in slice");
  240. }
  241. /* number of slice components must be the same as the appropriate
  242. dimension */
  243. if (slice_dimen(mpl, slice) != dim)
  244. { switch (close)
  245. { case T_RBRACKET:
  246. mpl_error(mpl, "%s must have %d subscript%s, not %d", name,
  247. dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
  248. break;
  249. case T_RIGHT:
  250. mpl_error(mpl, "%s has dimension %d, not %d", name, dim,
  251. slice_dimen(mpl, slice));
  252. break;
  253. default:
  254. xassert(close != close);
  255. }
  256. }
  257. get_token(mpl /* ) | ] */);
  258. return slice;
  259. }
  260. /*----------------------------------------------------------------------
  261. -- select_set - select set to saturate it with elemental sets.
  262. --
  263. -- This routine selects set to saturate it with elemental sets provided
  264. -- in the data section. */
  265. SET *select_set
  266. ( MPL *mpl,
  267. char *name /* not changed */
  268. )
  269. { SET *set;
  270. AVLNODE *node;
  271. xassert(name != NULL);
  272. node = avl_find_node(mpl->tree, name);
  273. if (node == NULL || avl_get_node_type(node) != A_SET)
  274. mpl_error(mpl, "%s not a set", name);
  275. set = (SET *)avl_get_node_link(node);
  276. if (set->assign != NULL || set->gadget != NULL)
  277. mpl_error(mpl, "%s needs no data", name);
  278. set->data = 1;
  279. return set;
  280. }
  281. /*----------------------------------------------------------------------
  282. -- simple_format - read set data block in simple format.
  283. --
  284. -- This routine reads set data block using the syntax:
  285. --
  286. -- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
  287. --
  288. -- where <symbols> are used to construct a complete n-tuple, which is
  289. -- included in elemental set assigned to the set member. Commae between
  290. -- symbols are optional and may be omitted anywhere.
  291. --
  292. -- Number of components in the slice must be the same as dimension of
  293. -- n-tuples in elemental sets assigned to the set members. To construct
  294. -- complete n-tuple the routine replaces null positions in the slice by
  295. -- corresponding <symbols>.
  296. --
  297. -- If the slice contains at least one null position, the current token
  298. -- must be symbol. Otherwise, the routine reads no symbols to construct
  299. -- the n-tuple, so the current token is not checked. */
  300. void simple_format
  301. ( MPL *mpl,
  302. SET *set, /* not changed */
  303. MEMBER *memb, /* modified */
  304. SLICE *slice /* not changed */
  305. )
  306. { TUPLE *tuple;
  307. SLICE *temp;
  308. SYMBOL *sym, *with = NULL;
  309. xassert(set != NULL);
  310. xassert(memb != NULL);
  311. xassert(slice != NULL);
  312. xassert(set->dimen == slice_dimen(mpl, slice));
  313. xassert(memb->value.set->dim == set->dimen);
  314. if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
  315. /* read symbols and construct complete n-tuple */
  316. tuple = create_tuple(mpl);
  317. for (temp = slice; temp != NULL; temp = temp->next)
  318. { if (temp->sym == NULL)
  319. { /* substitution is needed; read symbol */
  320. if (!is_symbol(mpl))
  321. { int lack = slice_arity(mpl, temp);
  322. /* with cannot be null due to assertion above */
  323. xassert(with != NULL);
  324. if (lack == 1)
  325. mpl_error(mpl, "one item missing in data group beginning "
  326. "with %s", format_symbol(mpl, with));
  327. else
  328. mpl_error(mpl, "%d items missing in data group beginning "
  329. "with %s", lack, format_symbol(mpl, with));
  330. }
  331. sym = read_symbol(mpl);
  332. if (with == NULL) with = sym;
  333. }
  334. else
  335. { /* copy symbol from the slice */
  336. sym = copy_symbol(mpl, temp->sym);
  337. }
  338. /* append the symbol to the n-tuple */
  339. tuple = expand_tuple(mpl, tuple, sym);
  340. /* skip optional comma *between* <symbols> */
  341. if (temp->next != NULL && mpl->token == T_COMMA)
  342. get_token(mpl /* , */);
  343. }
  344. /* add constructed n-tuple to elemental set */
  345. check_then_add(mpl, memb->value.set, tuple);
  346. return;
  347. }
  348. /*----------------------------------------------------------------------
  349. -- matrix_format - read set data block in matrix format.
  350. --
  351. -- This routine reads set data block using the syntax:
  352. --
  353. -- <matrix format> ::= <column> <column> ... <column> :=
  354. -- <row> +/- +/- ... +/-
  355. -- <row> +/- +/- ... +/-
  356. -- . . . . . . . . . . .
  357. -- <row> +/- +/- ... +/-
  358. --
  359. -- where <rows> are symbols that denote rows of the matrix, <columns>
  360. -- are symbols that denote columns of the matrix, "+" and "-" indicate
  361. -- whether corresponding n-tuple needs to be included in the elemental
  362. -- set or not, respectively.
  363. --
  364. -- Number of the slice components must be the same as dimension of the
  365. -- elemental set. The slice must have two null positions. To construct
  366. -- complete n-tuple for particular element of the matrix the routine
  367. -- replaces first null position of the slice by the corresponding <row>
  368. -- (or <column>, if the flag tr is on) and second null position by the
  369. -- corresponding <column> (or by <row>, if the flag tr is on). */
  370. void matrix_format
  371. ( MPL *mpl,
  372. SET *set, /* not changed */
  373. MEMBER *memb, /* modified */
  374. SLICE *slice, /* not changed */
  375. int tr
  376. )
  377. { SLICE *list, *col, *temp;
  378. TUPLE *tuple;
  379. SYMBOL *row;
  380. xassert(set != NULL);
  381. xassert(memb != NULL);
  382. xassert(slice != NULL);
  383. xassert(set->dimen == slice_dimen(mpl, slice));
  384. xassert(memb->value.set->dim == set->dimen);
  385. xassert(slice_arity(mpl, slice) == 2);
  386. /* read the matrix heading that contains column symbols (there
  387. may be no columns at all) */
  388. list = create_slice(mpl);
  389. while (mpl->token != T_ASSIGN)
  390. { /* read column symbol and append it to the column list */
  391. if (!is_symbol(mpl))
  392. mpl_error(mpl, "number, symbol, or := missing where expected");
  393. list = expand_slice(mpl, list, read_symbol(mpl));
  394. }
  395. get_token(mpl /* := */);
  396. /* read zero or more rows that contain matrix data */
  397. while (is_symbol(mpl))
  398. { /* read row symbol (if the matrix has no columns, row symbols
  399. are just ignored) */
  400. row = read_symbol(mpl);
  401. /* read the matrix row accordingly to the column list */
  402. for (col = list; col != NULL; col = col->next)
  403. { int which = 0;
  404. /* check indicator */
  405. if (is_literal(mpl, "+"))
  406. ;
  407. else if (is_literal(mpl, "-"))
  408. { get_token(mpl /* - */);
  409. continue;
  410. }
  411. else
  412. { int lack = slice_dimen(mpl, col);
  413. if (lack == 1)
  414. mpl_error(mpl, "one item missing in data group beginning "
  415. "with %s", format_symbol(mpl, row));
  416. else
  417. mpl_error(mpl, "%d items missing in data group beginning "
  418. "with %s", lack, format_symbol(mpl, row));
  419. }
  420. /* construct complete n-tuple */
  421. tuple = create_tuple(mpl);
  422. for (temp = slice; temp != NULL; temp = temp->next)
  423. { if (temp->sym == NULL)
  424. { /* substitution is needed */
  425. switch (++which)
  426. { case 1:
  427. /* substitute in the first null position */
  428. tuple = expand_tuple(mpl, tuple,
  429. copy_symbol(mpl, tr ? col->sym : row));
  430. break;
  431. case 2:
  432. /* substitute in the second null position */
  433. tuple = expand_tuple(mpl, tuple,
  434. copy_symbol(mpl, tr ? row : col->sym));
  435. break;
  436. default:
  437. xassert(which != which);
  438. }
  439. }
  440. else
  441. { /* copy symbol from the slice */
  442. tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
  443. temp->sym));
  444. }
  445. }
  446. xassert(which == 2);
  447. /* add constructed n-tuple to elemental set */
  448. check_then_add(mpl, memb->value.set, tuple);
  449. get_token(mpl /* + */);
  450. }
  451. /* delete the row symbol */
  452. delete_symbol(mpl, row);
  453. }
  454. /* delete the column list */
  455. delete_slice(mpl, list);
  456. return;
  457. }
  458. /*----------------------------------------------------------------------
  459. -- set_data - read set data.
  460. --
  461. -- This routine reads set data using the syntax:
  462. --
  463. -- <set data> ::= set <set name> <assignments> ;
  464. -- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
  465. -- <set name> ::= <symbolic name>
  466. -- <assignments> ::= <empty>
  467. -- <assignments> ::= <assignments> , :=
  468. -- <assignments> ::= <assignments> , ( <symbol list> )
  469. -- <assignments> ::= <assignments> , <simple format>
  470. -- <assignments> ::= <assignments> , : <matrix format>
  471. -- <assignments> ::= <assignments> , (tr) <matrix format>
  472. -- <assignments> ::= <assignments> , (tr) : <matrix format>
  473. --
  474. -- Commae in <assignments> are optional and may be omitted anywhere. */
  475. void set_data(MPL *mpl)
  476. { SET *set;
  477. TUPLE *tuple;
  478. MEMBER *memb;
  479. SLICE *slice;
  480. int tr = 0;
  481. xassert(is_literal(mpl, "set"));
  482. get_token(mpl /* set */);
  483. /* symbolic name of set must follows the keyword 'set' */
  484. if (!is_symbol(mpl))
  485. mpl_error(mpl, "set name missing where expected");
  486. /* select the set to saturate it with data */
  487. set = select_set(mpl, mpl->image);
  488. get_token(mpl /* <symbolic name> */);
  489. /* read optional subscript list, which identifies member of the
  490. set to be read */
  491. tuple = create_tuple(mpl);
  492. if (mpl->token == T_LBRACKET)
  493. { /* subscript list is specified */
  494. if (set->dim == 0)
  495. mpl_error(mpl, "%s cannot be subscripted", set->name);
  496. get_token(mpl /* [ */);
  497. /* read symbols and construct subscript list */
  498. for (;;)
  499. { if (!is_symbol(mpl))
  500. mpl_error(mpl, "number or symbol missing where expected");
  501. tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
  502. if (mpl->token == T_COMMA)
  503. get_token(mpl /* , */);
  504. else if (mpl->token == T_RBRACKET)
  505. break;
  506. else
  507. mpl_error(mpl, "syntax error in subscript list");
  508. }
  509. if (set->dim != tuple_dimen(mpl, tuple))
  510. mpl_error(mpl, "%s must have %d subscript%s rather than %d",
  511. set->name, set->dim, set->dim == 1 ? "" : "s",
  512. tuple_dimen(mpl, tuple));
  513. get_token(mpl /* ] */);
  514. }
  515. else
  516. { /* subscript list is not specified */
  517. if (set->dim != 0)
  518. mpl_error(mpl, "%s must be subscripted", set->name);
  519. }
  520. /* there must be no member with the same subscript list */
  521. if (find_member(mpl, set->array, tuple) != NULL)
  522. mpl_error(mpl, "%s%s already defined",
  523. set->name, format_tuple(mpl, '[', tuple));
  524. /* add new member to the set and assign it empty elemental set */
  525. memb = add_member(mpl, set->array, tuple);
  526. memb->value.set = create_elemset(mpl, set->dimen);
  527. /* create an initial fake slice of all asterisks */
  528. slice = fake_slice(mpl, set->dimen);
  529. /* read zero or more data assignments */
  530. for (;;)
  531. { /* skip optional comma */
  532. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  533. /* process assignment element */
  534. if (mpl->token == T_ASSIGN)
  535. { /* assignment ligature is non-significant element */
  536. get_token(mpl /* := */);
  537. }
  538. else if (mpl->token == T_LEFT)
  539. { /* left parenthesis begins either new slice or "transpose"
  540. indicator */
  541. int is_tr;
  542. get_token(mpl /* ( */);
  543. is_tr = is_literal(mpl, "tr");
  544. unget_token(mpl /* ( */);
  545. if (is_tr) goto left;
  546. /* delete the current slice and read new one */
  547. delete_slice(mpl, slice);
  548. slice = read_slice(mpl, set->name, set->dimen);
  549. /* each new slice resets the "transpose" indicator */
  550. tr = 0;
  551. /* if the new slice is 0-ary, formally there is one 0-tuple
  552. (in the simple format) that follows it */
  553. if (slice_arity(mpl, slice) == 0)
  554. simple_format(mpl, set, memb, slice);
  555. }
  556. else if (is_symbol(mpl))
  557. { /* number or symbol begins data in the simple format */
  558. simple_format(mpl, set, memb, slice);
  559. }
  560. else if (mpl->token == T_COLON)
  561. { /* colon begins data in the matrix format */
  562. if (slice_arity(mpl, slice) != 2)
  563. err1: mpl_error(mpl, "slice currently used must specify 2 asterisk"
  564. "s, not %d", slice_arity(mpl, slice));
  565. get_token(mpl /* : */);
  566. /* read elemental set data in the matrix format */
  567. matrix_format(mpl, set, memb, slice, tr);
  568. }
  569. else if (mpl->token == T_LEFT)
  570. left: { /* left parenthesis begins the "transpose" indicator, which
  571. is followed by data in the matrix format */
  572. get_token(mpl /* ( */);
  573. if (!is_literal(mpl, "tr"))
  574. err2: mpl_error(mpl, "transpose indicator (tr) incomplete");
  575. if (slice_arity(mpl, slice) != 2) goto err1;
  576. get_token(mpl /* tr */);
  577. if (mpl->token != T_RIGHT) goto err2;
  578. get_token(mpl /* ) */);
  579. /* in this case the colon is optional */
  580. if (mpl->token == T_COLON) get_token(mpl /* : */);
  581. /* set the "transpose" indicator */
  582. tr = 1;
  583. /* read elemental set data in the matrix format */
  584. matrix_format(mpl, set, memb, slice, tr);
  585. }
  586. else if (mpl->token == T_SEMICOLON)
  587. { /* semicolon terminates the data block */
  588. get_token(mpl /* ; */);
  589. break;
  590. }
  591. else
  592. mpl_error(mpl, "syntax error in set data block");
  593. }
  594. /* delete the current slice */
  595. delete_slice(mpl, slice);
  596. return;
  597. }
  598. /*----------------------------------------------------------------------
  599. -- select_parameter - select parameter to saturate it with data.
  600. --
  601. -- This routine selects parameter to saturate it with data provided in
  602. -- the data section. */
  603. PARAMETER *select_parameter
  604. ( MPL *mpl,
  605. char *name /* not changed */
  606. )
  607. { PARAMETER *par;
  608. AVLNODE *node;
  609. xassert(name != NULL);
  610. node = avl_find_node(mpl->tree, name);
  611. if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
  612. mpl_error(mpl, "%s not a parameter", name);
  613. par = (PARAMETER *)avl_get_node_link(node);
  614. if (par->assign != NULL)
  615. mpl_error(mpl, "%s needs no data", name);
  616. if (par->data)
  617. mpl_error(mpl, "%s already provided with data", name);
  618. par->data = 1;
  619. return par;
  620. }
  621. /*----------------------------------------------------------------------
  622. -- set_default - set default parameter value.
  623. --
  624. -- This routine sets default value for specified parameter. */
  625. void set_default
  626. ( MPL *mpl,
  627. PARAMETER *par, /* not changed */
  628. SYMBOL *altval /* destroyed */
  629. )
  630. { xassert(par != NULL);
  631. xassert(altval != NULL);
  632. if (par->option != NULL)
  633. mpl_error(mpl, "default value for %s already specified in model se"
  634. "ction", par->name);
  635. xassert(par->defval == NULL);
  636. par->defval = altval;
  637. return;
  638. }
  639. /*----------------------------------------------------------------------
  640. -- read_value - read value and assign it to parameter member.
  641. --
  642. -- This routine reads numeric or symbolic value from the input stream
  643. -- and assigns to new parameter member specified by its n-tuple, which
  644. -- (the member) is created and added to the parameter array. */
  645. MEMBER *read_value
  646. ( MPL *mpl,
  647. PARAMETER *par, /* not changed */
  648. TUPLE *tuple /* destroyed */
  649. )
  650. { MEMBER *memb;
  651. xassert(par != NULL);
  652. xassert(is_symbol(mpl));
  653. /* there must be no member with the same n-tuple */
  654. if (find_member(mpl, par->array, tuple) != NULL)
  655. mpl_error(mpl, "%s%s already defined",
  656. par->name, format_tuple(mpl, '[', tuple));
  657. /* create new parameter member with given n-tuple */
  658. memb = add_member(mpl, par->array, tuple);
  659. /* read value and assigns it to the new parameter member */
  660. switch (par->type)
  661. { case A_NUMERIC:
  662. case A_INTEGER:
  663. case A_BINARY:
  664. if (!is_number(mpl))
  665. mpl_error(mpl, "%s requires numeric data", par->name);
  666. memb->value.num = read_number(mpl);
  667. break;
  668. case A_SYMBOLIC:
  669. memb->value.sym = read_symbol(mpl);
  670. break;
  671. default:
  672. xassert(par != par);
  673. }
  674. return memb;
  675. }
  676. /*----------------------------------------------------------------------
  677. -- plain_format - read parameter data block in plain format.
  678. --
  679. -- This routine reads parameter data block using the syntax:
  680. --
  681. -- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
  682. --
  683. -- where <symbols> are used to determine a complete subscript list for
  684. -- parameter member, <value> is a numeric or symbolic value assigned to
  685. -- the parameter member. Commae between data items are optional and may
  686. -- be omitted anywhere.
  687. --
  688. -- Number of components in the slice must be the same as dimension of
  689. -- the parameter. To construct the complete subscript list the routine
  690. -- replaces null positions in the slice by corresponding <symbols>. */
  691. void plain_format
  692. ( MPL *mpl,
  693. PARAMETER *par, /* not changed */
  694. SLICE *slice /* not changed */
  695. )
  696. { TUPLE *tuple;
  697. SLICE *temp;
  698. SYMBOL *sym, *with = NULL;
  699. xassert(par != NULL);
  700. xassert(par->dim == slice_dimen(mpl, slice));
  701. xassert(is_symbol(mpl));
  702. /* read symbols and construct complete subscript list */
  703. tuple = create_tuple(mpl);
  704. for (temp = slice; temp != NULL; temp = temp->next)
  705. { if (temp->sym == NULL)
  706. { /* substitution is needed; read symbol */
  707. if (!is_symbol(mpl))
  708. { int lack = slice_arity(mpl, temp) + 1;
  709. xassert(with != NULL);
  710. xassert(lack > 1);
  711. mpl_error(mpl, "%d items missing in data group beginning wit"
  712. "h %s", lack, format_symbol(mpl, with));
  713. }
  714. sym = read_symbol(mpl);
  715. if (with == NULL) with = sym;
  716. }
  717. else
  718. { /* copy symbol from the slice */
  719. sym = copy_symbol(mpl, temp->sym);
  720. }
  721. /* append the symbol to the subscript list */
  722. tuple = expand_tuple(mpl, tuple, sym);
  723. /* skip optional comma */
  724. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  725. }
  726. /* read value and assign it to new parameter member */
  727. if (!is_symbol(mpl))
  728. { xassert(with != NULL);
  729. mpl_error(mpl, "one item missing in data group beginning with %s",
  730. format_symbol(mpl, with));
  731. }
  732. read_value(mpl, par, tuple);
  733. return;
  734. }
  735. /*----------------------------------------------------------------------
  736. -- tabular_format - read parameter data block in tabular format.
  737. --
  738. -- This routine reads parameter data block using the syntax:
  739. --
  740. -- <tabular format> ::= <column> <column> ... <column> :=
  741. -- <row> <value> <value> ... <value>
  742. -- <row> <value> <value> ... <value>
  743. -- . . . . . . . . . . .
  744. -- <row> <value> <value> ... <value>
  745. --
  746. -- where <rows> are symbols that denote rows of the table, <columns>
  747. -- are symbols that denote columns of the table, <values> are numeric
  748. -- or symbolic values assigned to the corresponding parameter members.
  749. -- If <value> is specified as single point, no value is provided.
  750. --
  751. -- Number of components in the slice must be the same as dimension of
  752. -- the parameter. The slice must have two null positions. To construct
  753. -- complete subscript list for particular <value> the routine replaces
  754. -- the first null position of the slice by the corresponding <row> (or
  755. -- <column>, if the flag tr is on) and the second null position by the
  756. -- corresponding <column> (or by <row>, if the flag tr is on). */
  757. void tabular_format
  758. ( MPL *mpl,
  759. PARAMETER *par, /* not changed */
  760. SLICE *slice, /* not changed */
  761. int tr
  762. )
  763. { SLICE *list, *col, *temp;
  764. TUPLE *tuple;
  765. SYMBOL *row;
  766. xassert(par != NULL);
  767. xassert(par->dim == slice_dimen(mpl, slice));
  768. xassert(slice_arity(mpl, slice) == 2);
  769. /* read the table heading that contains column symbols (the table
  770. may have no columns) */
  771. list = create_slice(mpl);
  772. while (mpl->token != T_ASSIGN)
  773. { /* read column symbol and append it to the column list */
  774. if (!is_symbol(mpl))
  775. mpl_error(mpl, "number, symbol, or := missing where expected");
  776. list = expand_slice(mpl, list, read_symbol(mpl));
  777. }
  778. get_token(mpl /* := */);
  779. /* read zero or more rows that contain tabular data */
  780. while (is_symbol(mpl))
  781. { /* read row symbol (if the table has no columns, these symbols
  782. are just ignored) */
  783. row = read_symbol(mpl);
  784. /* read values accordingly to the column list */
  785. for (col = list; col != NULL; col = col->next)
  786. { int which = 0;
  787. /* if the token is single point, no value is provided */
  788. if (is_literal(mpl, "."))
  789. { get_token(mpl /* . */);
  790. continue;
  791. }
  792. /* construct complete subscript list */
  793. tuple = create_tuple(mpl);
  794. for (temp = slice; temp != NULL; temp = temp->next)
  795. { if (temp->sym == NULL)
  796. { /* substitution is needed */
  797. switch (++which)
  798. { case 1:
  799. /* substitute in the first null position */
  800. tuple = expand_tuple(mpl, tuple,
  801. copy_symbol(mpl, tr ? col->sym : row));
  802. break;
  803. case 2:
  804. /* substitute in the second null position */
  805. tuple = expand_tuple(mpl, tuple,
  806. copy_symbol(mpl, tr ? row : col->sym));
  807. break;
  808. default:
  809. xassert(which != which);
  810. }
  811. }
  812. else
  813. { /* copy symbol from the slice */
  814. tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
  815. temp->sym));
  816. }
  817. }
  818. xassert(which == 2);
  819. /* read value and assign it to new parameter member */
  820. if (!is_symbol(mpl))
  821. { int lack = slice_dimen(mpl, col);
  822. if (lack == 1)
  823. mpl_error(mpl, "one item missing in data group beginning "
  824. "with %s", format_symbol(mpl, row));
  825. else
  826. mpl_error(mpl, "%d items missing in data group beginning "
  827. "with %s", lack, format_symbol(mpl, row));
  828. }
  829. read_value(mpl, par, tuple);
  830. }
  831. /* delete the row symbol */
  832. delete_symbol(mpl, row);
  833. }
  834. /* delete the column list */
  835. delete_slice(mpl, list);
  836. return;
  837. }
  838. /*----------------------------------------------------------------------
  839. -- tabbing_format - read parameter data block in tabbing format.
  840. --
  841. -- This routine reads parameter data block using the syntax:
  842. --
  843. -- <tabbing format> ::= <prefix> <name> , ... , <name> , := ,
  844. -- <symbol> , ... , <symbol> , <value> , ... , <value> ,
  845. -- <symbol> , ... , <symbol> , <value> , ... , <value> ,
  846. -- . . . . . . . . . . . . . . . . .
  847. -- <symbol> , ... , <symbol> , <value> , ... , <value>
  848. -- <prefix> ::= <empty>
  849. -- <prefix> ::= <set name> :
  850. --
  851. -- where <names> are names of parameters (all the parameters must be
  852. -- subscripted and have identical dimensions), <symbols> are symbols
  853. -- used to define subscripts of parameter members, <values> are numeric
  854. -- or symbolic values assigned to the corresponding parameter members.
  855. -- Optional <prefix> may specify a simple set, in which case n-tuples
  856. -- built of <symbols> for each row of the data table (i.e. subscripts
  857. -- of parameter members) are added to the specified set. Commae between
  858. -- data items are optional and may be omitted anywhere.
  859. --
  860. -- If the parameter altval is not NULL, it specifies a default value
  861. -- provided for all the parameters specified in the data block. */
  862. void tabbing_format
  863. ( MPL *mpl,
  864. SYMBOL *altval /* not changed */
  865. )
  866. { SET *set = NULL;
  867. PARAMETER *par;
  868. SLICE *list, *col;
  869. TUPLE *tuple;
  870. int next_token, j, dim = 0;
  871. char *last_name = NULL;
  872. /* read the optional <prefix> */
  873. if (is_symbol(mpl))
  874. { get_token(mpl /* <symbol> */);
  875. next_token = mpl->token;
  876. unget_token(mpl /* <symbol> */);
  877. if (next_token == T_COLON)
  878. { /* select the set to saturate it with data */
  879. set = select_set(mpl, mpl->image);
  880. /* the set must be simple (i.e. not set of sets) */
  881. if (set->dim != 0)
  882. mpl_error(mpl, "%s must be a simple set", set->name);
  883. /* and must not be defined yet */
  884. if (set->array->head != NULL)
  885. mpl_error(mpl, "%s already defined", set->name);
  886. /* add new (the only) member to the set and assign it empty
  887. elemental set */
  888. add_member(mpl, set->array, NULL)->value.set =
  889. create_elemset(mpl, set->dimen);
  890. last_name = set->name, dim = set->dimen;
  891. get_token(mpl /* <symbol> */);
  892. xassert(mpl->token == T_COLON);
  893. get_token(mpl /* : */);
  894. }
  895. }
  896. /* read the table heading that contains parameter names */
  897. list = create_slice(mpl);
  898. while (mpl->token != T_ASSIGN)
  899. { /* there must be symbolic name of parameter */
  900. if (!is_symbol(mpl))
  901. mpl_error(mpl, "parameter name or := missing where expected");
  902. /* select the parameter to saturate it with data */
  903. par = select_parameter(mpl, mpl->image);
  904. /* the parameter must be subscripted */
  905. if (par->dim == 0)
  906. mpl_error(mpl, "%s not a subscripted parameter", mpl->image);
  907. /* the set (if specified) and all the parameters in the data
  908. block must have identical dimension */
  909. if (dim != 0 && par->dim != dim)
  910. { xassert(last_name != NULL);
  911. mpl_error(mpl, "%s has dimension %d while %s has dimension %d",
  912. last_name, dim, par->name, par->dim);
  913. }
  914. /* set default value for the parameter (if specified) */
  915. if (altval != NULL)
  916. set_default(mpl, par, copy_symbol(mpl, altval));
  917. /* append the parameter to the column list */
  918. list = expand_slice(mpl, list, (SYMBOL *)par);
  919. last_name = par->name, dim = par->dim;
  920. get_token(mpl /* <symbol> */);
  921. /* skip optional comma */
  922. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  923. }
  924. if (slice_dimen(mpl, list) == 0)
  925. mpl_error(mpl, "at least one parameter name required");
  926. get_token(mpl /* := */);
  927. /* skip optional comma */
  928. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  929. /* read rows that contain tabbing data */
  930. while (is_symbol(mpl))
  931. { /* read subscript list */
  932. tuple = create_tuple(mpl);
  933. for (j = 1; j <= dim; j++)
  934. { /* read j-th subscript */
  935. if (!is_symbol(mpl))
  936. { int lack = slice_dimen(mpl, list) + dim - j + 1;
  937. xassert(tuple != NULL);
  938. xassert(lack > 1);
  939. mpl_error(mpl, "%d items missing in data group beginning wit"
  940. "h %s", lack, format_symbol(mpl, tuple->sym));
  941. }
  942. /* read and append j-th subscript to the n-tuple */
  943. tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
  944. /* skip optional comma *between* <symbols> */
  945. if (j < dim && mpl->token == T_COMMA)
  946. get_token(mpl /* , */);
  947. }
  948. /* if the set is specified, add to it new n-tuple, which is a
  949. copy of the subscript list just read */
  950. if (set != NULL)
  951. check_then_add(mpl, set->array->head->value.set,
  952. copy_tuple(mpl, tuple));
  953. /* skip optional comma between <symbol> and <value> */
  954. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  955. /* read values accordingly to the column list */
  956. for (col = list; col != NULL; col = col->next)
  957. { /* if the token is single point, no value is provided */
  958. if (is_literal(mpl, "."))
  959. { get_token(mpl /* . */);
  960. continue;
  961. }
  962. /* read value and assign it to new parameter member */
  963. if (!is_symbol(mpl))
  964. { int lack = slice_dimen(mpl, col);
  965. xassert(tuple != NULL);
  966. if (lack == 1)
  967. mpl_error(mpl, "one item missing in data group beginning "
  968. "with %s", format_symbol(mpl, tuple->sym));
  969. else
  970. mpl_error(mpl, "%d items missing in data group beginning "
  971. "with %s", lack, format_symbol(mpl, tuple->sym));
  972. }
  973. read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
  974. tuple));
  975. /* skip optional comma preceding the next value */
  976. if (col->next != NULL && mpl->token == T_COMMA)
  977. get_token(mpl /* , */);
  978. }
  979. /* delete the original subscript list */
  980. delete_tuple(mpl, tuple);
  981. /* skip optional comma (only if there is next data group) */
  982. if (mpl->token == T_COMMA)
  983. { get_token(mpl /* , */);
  984. if (!is_symbol(mpl)) unget_token(mpl /* , */);
  985. }
  986. }
  987. /* delete the column list (it contains parameters, not symbols,
  988. so nullify it before) */
  989. for (col = list; col != NULL; col = col->next) col->sym = NULL;
  990. delete_slice(mpl, list);
  991. return;
  992. }
  993. /*----------------------------------------------------------------------
  994. -- parameter_data - read parameter data.
  995. --
  996. -- This routine reads parameter data using the syntax:
  997. --
  998. -- <parameter data> ::= param <default value> : <tabbing format> ;
  999. -- <parameter data> ::= param <parameter name> <default value>
  1000. -- <assignments> ;
  1001. -- <parameter name> ::= <symbolic name>
  1002. -- <default value> ::= <empty>
  1003. -- <default value> ::= default <symbol>
  1004. -- <assignments> ::= <empty>
  1005. -- <assignments> ::= <assignments> , :=
  1006. -- <assignments> ::= <assignments> , [ <symbol list> ]
  1007. -- <assignments> ::= <assignments> , <plain format>
  1008. -- <assignemnts> ::= <assignments> , : <tabular format>
  1009. -- <assignments> ::= <assignments> , (tr) <tabular format>
  1010. -- <assignments> ::= <assignments> , (tr) : <tabular format>
  1011. --
  1012. -- Commae in <assignments> are optional and may be omitted anywhere. */
  1013. void parameter_data(MPL *mpl)
  1014. { PARAMETER *par;
  1015. SYMBOL *altval = NULL;
  1016. SLICE *slice;
  1017. int tr = 0;
  1018. xassert(is_literal(mpl, "param"));
  1019. get_token(mpl /* param */);
  1020. /* read optional default value */
  1021. if (is_literal(mpl, "default"))
  1022. { get_token(mpl /* default */);
  1023. if (!is_symbol(mpl))
  1024. mpl_error(mpl, "default value missing where expected");
  1025. altval = read_symbol(mpl);
  1026. /* if the default value follows the keyword 'param', the next
  1027. token must be only the colon */
  1028. if (mpl->token != T_COLON)
  1029. mpl_error(mpl, "colon missing where expected");
  1030. }
  1031. /* being used after the keyword 'param' or the optional default
  1032. value the colon begins data in the tabbing format */
  1033. if (mpl->token == T_COLON)
  1034. { get_token(mpl /* : */);
  1035. /* skip optional comma */
  1036. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  1037. /* read parameter data in the tabbing format */
  1038. tabbing_format(mpl, altval);
  1039. /* on reading data in the tabbing format the default value is
  1040. always copied, so delete the original symbol */
  1041. if (altval != NULL) delete_symbol(mpl, altval);
  1042. /* the next token must be only semicolon */
  1043. if (mpl->token != T_SEMICOLON)
  1044. mpl_error(mpl, "symbol, number, or semicolon missing where expe"
  1045. "cted");
  1046. get_token(mpl /* ; */);
  1047. goto done;
  1048. }
  1049. /* in other cases there must be symbolic name of parameter, which
  1050. follows the keyword 'param' */
  1051. if (!is_symbol(mpl))
  1052. mpl_error(mpl, "parameter name missing where expected");
  1053. /* select the parameter to saturate it with data */
  1054. par = select_parameter(mpl, mpl->image);
  1055. get_token(mpl /* <symbol> */);
  1056. /* read optional default value */
  1057. if (is_literal(mpl, "default"))
  1058. { get_token(mpl /* default */);
  1059. if (!is_symbol(mpl))
  1060. mpl_error(mpl, "default value missing where expected");
  1061. altval = read_symbol(mpl);
  1062. /* set default value for the parameter */
  1063. set_default(mpl, par, altval);
  1064. }
  1065. /* create initial fake slice of all asterisks */
  1066. slice = fake_slice(mpl, par->dim);
  1067. /* read zero or more data assignments */
  1068. for (;;)
  1069. { /* skip optional comma */
  1070. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  1071. /* process current assignment */
  1072. if (mpl->token == T_ASSIGN)
  1073. { /* assignment ligature is non-significant element */
  1074. get_token(mpl /* := */);
  1075. }
  1076. else if (mpl->token == T_LBRACKET)
  1077. { /* left bracket begins new slice; delete the current slice
  1078. and read new one */
  1079. delete_slice(mpl, slice);
  1080. slice = read_slice(mpl, par->name, par->dim);
  1081. /* each new slice resets the "transpose" indicator */
  1082. tr = 0;
  1083. }
  1084. else if (is_symbol(mpl))
  1085. { /* number or symbol begins data in the plain format */
  1086. plain_format(mpl, par, slice);
  1087. }
  1088. else if (mpl->token == T_COLON)
  1089. { /* colon begins data in the tabular format */
  1090. if (par->dim == 0)
  1091. err1: mpl_error(mpl, "%s not a subscripted parameter",
  1092. par->name);
  1093. if (slice_arity(mpl, slice) != 2)
  1094. err2: mpl_error(mpl, "slice currently used must specify 2 asterisk"
  1095. "s, not %d", slice_arity(mpl, slice));
  1096. get_token(mpl /* : */);
  1097. /* read parameter data in the tabular format */
  1098. tabular_format(mpl, par, slice, tr);
  1099. }
  1100. else if (mpl->token == T_LEFT)
  1101. { /* left parenthesis begins the "transpose" indicator, which
  1102. is followed by data in the tabular format */
  1103. get_token(mpl /* ( */);
  1104. if (!is_literal(mpl, "tr"))
  1105. err3: mpl_error(mpl, "transpose indicator (tr) incomplete");
  1106. if (par->dim == 0) goto err1;
  1107. if (slice_arity(mpl, slice) != 2) goto err2;
  1108. get_token(mpl /* tr */);
  1109. if (mpl->token != T_RIGHT) goto err3;
  1110. get_token(mpl /* ) */);
  1111. /* in this case the colon is optional */
  1112. if (mpl->token == T_COLON) get_token(mpl /* : */);
  1113. /* set the "transpose" indicator */
  1114. tr = 1;
  1115. /* read parameter data in the tabular format */
  1116. tabular_format(mpl, par, slice, tr);
  1117. }
  1118. else if (mpl->token == T_SEMICOLON)
  1119. { /* semicolon terminates the data block */
  1120. get_token(mpl /* ; */);
  1121. break;
  1122. }
  1123. else
  1124. mpl_error(mpl, "syntax error in parameter data block");
  1125. }
  1126. /* delete the current slice */
  1127. delete_slice(mpl, slice);
  1128. done: return;
  1129. }
  1130. /*----------------------------------------------------------------------
  1131. -- data_section - read data section.
  1132. --
  1133. -- This routine reads data section using the syntax:
  1134. --
  1135. -- <data section> ::= <empty>
  1136. -- <data section> ::= <data section> <data block> ;
  1137. -- <data block> ::= <set data>
  1138. -- <data block> ::= <parameter data>
  1139. --
  1140. -- Reading data section is terminated by either the keyword 'end' or
  1141. -- the end of file. */
  1142. void data_section(MPL *mpl)
  1143. { while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
  1144. { if (is_literal(mpl, "set"))
  1145. set_data(mpl);
  1146. else if (is_literal(mpl, "param"))
  1147. parameter_data(mpl);
  1148. else
  1149. mpl_error(mpl, "syntax error in data section");
  1150. }
  1151. return;
  1152. }
  1153. /* eof */