3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 * E-mail: <mao@gnu.org>.
11 * GLPK is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 * License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
23 ***********************************************************************/
29 /**********************************************************************/
30 /* * * PROCESSING DATA SECTION * * */
31 /**********************************************************************/
33 /*----------------------------------------------------------------------
34 -- create_slice - create slice.
36 -- This routine creates a slice, which initially has no components. */
38 SLICE *create_slice(MPL *mpl)
45 /*----------------------------------------------------------------------
46 -- expand_slice - append new component to slice.
48 -- This routine expands slice appending to it either a given symbol or
49 -- null component, which becomes the last component of the slice. */
53 SLICE *slice, /* destroyed */
54 SYMBOL *sym /* destroyed */
57 /* create a new component */
58 tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
61 /* and append it to the component list */
65 { for (temp = slice; temp->next != NULL; temp = temp->next);
71 /*----------------------------------------------------------------------
72 -- slice_dimen - determine dimension of slice.
74 -- This routine returns dimension of slice, which is number of all its
75 -- components including null ones. */
79 SLICE *slice /* not changed */
85 for (temp = slice; temp != NULL; temp = temp->next) dim++;
89 /*----------------------------------------------------------------------
90 -- slice_arity - determine arity of slice.
92 -- This routine returns arity of slice, i.e. number of null components
93 -- (indicated by asterisks) in the slice. */
97 SLICE *slice /* not changed */
103 for (temp = slice; temp != NULL; temp = temp->next)
104 if (temp->sym == NULL) arity++;
108 /*----------------------------------------------------------------------
109 -- fake_slice - create fake slice of all asterisks.
111 -- This routine creates a fake slice of given dimension, which contains
112 -- asterisks in all components. Zero dimension is allowed. */
114 SLICE *fake_slice(MPL *mpl, int dim)
116 slice = create_slice(mpl);
117 while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
121 /*----------------------------------------------------------------------
122 -- delete_slice - delete slice.
124 -- This routine deletes specified slice. */
128 SLICE *slice /* destroyed */
131 while (slice != NULL)
134 if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
135 xassert(sizeof(SLICE) == sizeof(TUPLE));
136 dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
141 /*----------------------------------------------------------------------
142 -- is_number - check if current token is number.
144 -- If the current token is a number, this routine returns non-zero.
145 -- Otherwise zero is returned. */
147 int is_number(MPL *mpl)
149 mpl->token == T_NUMBER;
152 /*----------------------------------------------------------------------
153 -- is_symbol - check if current token is symbol.
155 -- If the current token is suitable to be a symbol, the routine returns
156 -- non-zero. Otherwise zero is returned. */
158 int is_symbol(MPL *mpl)
160 mpl->token == T_NUMBER ||
161 mpl->token == T_SYMBOL ||
162 mpl->token == T_STRING;
165 /*----------------------------------------------------------------------
166 -- is_literal - check if current token is given symbolic literal.
168 -- If the current token is given symbolic literal, this routine returns
169 -- non-zero. Otherwise zero is returned.
171 -- This routine is used on processing the data section in the same way
172 -- as the routine is_keyword on processing the model section. */
174 int is_literal(MPL *mpl, char *literal)
176 is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
179 /*----------------------------------------------------------------------
180 -- read_number - read number.
182 -- This routine reads the current token, which must be a number, and
183 -- returns its numeric value. */
185 double read_number(MPL *mpl)
187 xassert(is_number(mpl));
189 get_token(mpl /* <number> */);
193 /*----------------------------------------------------------------------
194 -- read_symbol - read symbol.
196 -- This routine reads the current token, which must be a symbol, and
197 -- returns its symbolic value. */
199 SYMBOL *read_symbol(MPL *mpl)
201 xassert(is_symbol(mpl));
203 sym = create_symbol_num(mpl, mpl->value);
205 sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
206 get_token(mpl /* <symbol> */);
210 /*----------------------------------------------------------------------
211 -- read_slice - read slice.
213 -- This routine reads slice using the syntax:
215 -- <slice> ::= [ <symbol list> ]
216 -- <slice> ::= ( <symbol list> )
217 -- <symbol list> ::= <symbol or star>
218 -- <symbol list> ::= <symbol list> , <symbol or star>
219 -- <symbol or star> ::= <symbol>
220 -- <symbol or star> ::= *
222 -- The bracketed form of slice is used for members of multi-dimensional
223 -- objects while the parenthesized form is used for elemental sets. */
227 char *name, /* not changed */
232 xassert(name != NULL);
245 error(mpl, "%s cannot be subscripted", name);
246 get_token(mpl /* ( | [ */);
247 /* read slice components */
248 slice = create_slice(mpl);
250 { /* the current token must be a symbol or asterisk */
252 slice = expand_slice(mpl, slice, read_symbol(mpl));
253 else if (mpl->token == T_ASTERISK)
254 { slice = expand_slice(mpl, slice, NULL);
255 get_token(mpl /* * */);
258 error(mpl, "number, symbol, or asterisk missing where expec"
260 /* check a token that follows the symbol */
261 if (mpl->token == T_COMMA)
262 get_token(mpl /* , */);
263 else if (mpl->token == close)
266 error(mpl, "syntax error in slice");
268 /* number of slice components must be the same as the appropriate
270 if (slice_dimen(mpl, slice) != dim)
273 error(mpl, "%s must have %d subscript%s, not %d", name,
274 dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
277 error(mpl, "%s has dimension %d, not %d", name, dim,
278 slice_dimen(mpl, slice));
281 xassert(close != close);
284 get_token(mpl /* ) | ] */);
288 /*----------------------------------------------------------------------
289 -- select_set - select set to saturate it with elemental sets.
291 -- This routine selects set to saturate it with elemental sets provided
292 -- in the data section. */
296 char *name /* not changed */
300 xassert(name != NULL);
301 node = avl_find_node(mpl->tree, name);
302 if (node == NULL || avl_get_node_type(node) != A_SET)
303 error(mpl, "%s not a set", name);
304 set = (SET *)avl_get_node_link(node);
305 if (set->assign != NULL || set->gadget != NULL)
306 error(mpl, "%s needs no data", name);
311 /*----------------------------------------------------------------------
312 -- simple_format - read set data block in simple format.
314 -- This routine reads set data block using the syntax:
316 -- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
318 -- where <symbols> are used to construct a complete n-tuple, which is
319 -- included in elemental set assigned to the set member. Commae between
320 -- symbols are optional and may be omitted anywhere.
322 -- Number of components in the slice must be the same as dimension of
323 -- n-tuples in elemental sets assigned to the set members. To construct
324 -- complete n-tuple the routine replaces null positions in the slice by
325 -- corresponding <symbols>.
327 -- If the slice contains at least one null position, the current token
328 -- must be symbol. Otherwise, the routine reads no symbols to construct
329 -- the n-tuple, so the current token is not checked. */
333 SET *set, /* not changed */
334 MEMBER *memb, /* modified */
335 SLICE *slice /* not changed */
339 SYMBOL *sym, *with = NULL;
340 xassert(set != NULL);
341 xassert(memb != NULL);
342 xassert(slice != NULL);
343 xassert(set->dimen == slice_dimen(mpl, slice));
344 xassert(memb->value.set->dim == set->dimen);
345 if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
346 /* read symbols and construct complete n-tuple */
347 tuple = create_tuple(mpl);
348 for (temp = slice; temp != NULL; temp = temp->next)
349 { if (temp->sym == NULL)
350 { /* substitution is needed; read symbol */
352 { int lack = slice_arity(mpl, temp);
353 /* with cannot be null due to assertion above */
354 xassert(with != NULL);
356 error(mpl, "one item missing in data group beginning "
357 "with %s", format_symbol(mpl, with));
359 error(mpl, "%d items missing in data group beginning "
360 "with %s", lack, format_symbol(mpl, with));
362 sym = read_symbol(mpl);
363 if (with == NULL) with = sym;
366 { /* copy symbol from the slice */
367 sym = copy_symbol(mpl, temp->sym);
369 /* append the symbol to the n-tuple */
370 tuple = expand_tuple(mpl, tuple, sym);
371 /* skip optional comma *between* <symbols> */
372 if (temp->next != NULL && mpl->token == T_COMMA)
373 get_token(mpl /* , */);
375 /* add constructed n-tuple to elemental set */
376 check_then_add(mpl, memb->value.set, tuple);
380 /*----------------------------------------------------------------------
381 -- matrix_format - read set data block in matrix format.
383 -- This routine reads set data block using the syntax:
385 -- <matrix format> ::= <column> <column> ... <column> :=
386 -- <row> +/- +/- ... +/-
387 -- <row> +/- +/- ... +/-
388 -- . . . . . . . . . . .
389 -- <row> +/- +/- ... +/-
391 -- where <rows> are symbols that denote rows of the matrix, <columns>
392 -- are symbols that denote columns of the matrix, "+" and "-" indicate
393 -- whether corresponding n-tuple needs to be included in the elemental
394 -- set or not, respectively.
396 -- Number of the slice components must be the same as dimension of the
397 -- elemental set. The slice must have two null positions. To construct
398 -- complete n-tuple for particular element of the matrix the routine
399 -- replaces first null position of the slice by the corresponding <row>
400 -- (or <column>, if the flag tr is on) and second null position by the
401 -- corresponding <column> (or by <row>, if the flag tr is on). */
405 SET *set, /* not changed */
406 MEMBER *memb, /* modified */
407 SLICE *slice, /* not changed */
410 { SLICE *list, *col, *temp;
413 xassert(set != NULL);
414 xassert(memb != NULL);
415 xassert(slice != NULL);
416 xassert(set->dimen == slice_dimen(mpl, slice));
417 xassert(memb->value.set->dim == set->dimen);
418 xassert(slice_arity(mpl, slice) == 2);
419 /* read the matrix heading that contains column symbols (there
420 may be no columns at all) */
421 list = create_slice(mpl);
422 while (mpl->token != T_ASSIGN)
423 { /* read column symbol and append it to the column list */
425 error(mpl, "number, symbol, or := missing where expected");
426 list = expand_slice(mpl, list, read_symbol(mpl));
428 get_token(mpl /* := */);
429 /* read zero or more rows that contain matrix data */
430 while (is_symbol(mpl))
431 { /* read row symbol (if the matrix has no columns, row symbols
433 row = read_symbol(mpl);
434 /* read the matrix row accordingly to the column list */
435 for (col = list; col != NULL; col = col->next)
437 /* check indicator */
438 if (is_literal(mpl, "+"))
440 else if (is_literal(mpl, "-"))
441 { get_token(mpl /* - */);
445 { int lack = slice_dimen(mpl, col);
447 error(mpl, "one item missing in data group beginning "
448 "with %s", format_symbol(mpl, row));
450 error(mpl, "%d items missing in data group beginning "
451 "with %s", lack, format_symbol(mpl, row));
453 /* construct complete n-tuple */
454 tuple = create_tuple(mpl);
455 for (temp = slice; temp != NULL; temp = temp->next)
456 { if (temp->sym == NULL)
457 { /* substitution is needed */
460 /* substitute in the first null position */
461 tuple = expand_tuple(mpl, tuple,
462 copy_symbol(mpl, tr ? col->sym : row));
465 /* substitute in the second null position */
466 tuple = expand_tuple(mpl, tuple,
467 copy_symbol(mpl, tr ? row : col->sym));
470 xassert(which != which);
474 { /* copy symbol from the slice */
475 tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
480 /* add constructed n-tuple to elemental set */
481 check_then_add(mpl, memb->value.set, tuple);
482 get_token(mpl /* + */);
484 /* delete the row symbol */
485 delete_symbol(mpl, row);
487 /* delete the column list */
488 delete_slice(mpl, list);
492 /*----------------------------------------------------------------------
493 -- set_data - read set data.
495 -- This routine reads set data using the syntax:
497 -- <set data> ::= set <set name> <assignments> ;
498 -- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
499 -- <set name> ::= <symbolic name>
500 -- <assignments> ::= <empty>
501 -- <assignments> ::= <assignments> , :=
502 -- <assignments> ::= <assignments> , ( <symbol list> )
503 -- <assignments> ::= <assignments> , <simple format>
504 -- <assignments> ::= <assignments> , : <matrix format>
505 -- <assignments> ::= <assignments> , (tr) <matrix format>
506 -- <assignments> ::= <assignments> , (tr) : <matrix format>
508 -- Commae in <assignments> are optional and may be omitted anywhere. */
510 void set_data(MPL *mpl)
516 xassert(is_literal(mpl, "set"));
517 get_token(mpl /* set */);
518 /* symbolic name of set must follows the keyword 'set' */
520 error(mpl, "set name missing where expected");
521 /* select the set to saturate it with data */
522 set = select_set(mpl, mpl->image);
523 get_token(mpl /* <symbolic name> */);
524 /* read optional subscript list, which identifies member of the
526 tuple = create_tuple(mpl);
527 if (mpl->token == T_LBRACKET)
528 { /* subscript list is specified */
530 error(mpl, "%s cannot be subscripted", set->name);
531 get_token(mpl /* [ */);
532 /* read symbols and construct subscript list */
534 { if (!is_symbol(mpl))
535 error(mpl, "number or symbol missing where expected");
536 tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
537 if (mpl->token == T_COMMA)
538 get_token(mpl /* , */);
539 else if (mpl->token == T_RBRACKET)
542 error(mpl, "syntax error in subscript list");
544 if (set->dim != tuple_dimen(mpl, tuple))
545 error(mpl, "%s must have %d subscript%s rather than %d",
546 set->name, set->dim, set->dim == 1 ? "" : "s",
547 tuple_dimen(mpl, tuple));
548 get_token(mpl /* ] */);
551 { /* subscript list is not specified */
553 error(mpl, "%s must be subscripted", set->name);
555 /* there must be no member with the same subscript list */
556 if (find_member(mpl, set->array, tuple) != NULL)
557 error(mpl, "%s%s already defined",
558 set->name, format_tuple(mpl, '[', tuple));
559 /* add new member to the set and assign it empty elemental set */
560 memb = add_member(mpl, set->array, tuple);
561 memb->value.set = create_elemset(mpl, set->dimen);
562 /* create an initial fake slice of all asterisks */
563 slice = fake_slice(mpl, set->dimen);
564 /* read zero or more data assignments */
566 { /* skip optional comma */
567 if (mpl->token == T_COMMA) get_token(mpl /* , */);
568 /* process assignment element */
569 if (mpl->token == T_ASSIGN)
570 { /* assignment ligature is non-significant element */
571 get_token(mpl /* := */);
573 else if (mpl->token == T_LEFT)
574 { /* left parenthesis begins either new slice or "transpose"
577 get_token(mpl /* ( */);
578 is_tr = is_literal(mpl, "tr");
579 unget_token(mpl /* ( */);
580 if (is_tr) goto left;
581 /* delete the current slice and read new one */
582 delete_slice(mpl, slice);
583 slice = read_slice(mpl, set->name, set->dimen);
584 /* each new slice resets the "transpose" indicator */
586 /* if the new slice is 0-ary, formally there is one 0-tuple
587 (in the simple format) that follows it */
588 if (slice_arity(mpl, slice) == 0)
589 simple_format(mpl, set, memb, slice);
591 else if (is_symbol(mpl))
592 { /* number or symbol begins data in the simple format */
593 simple_format(mpl, set, memb, slice);
595 else if (mpl->token == T_COLON)
596 { /* colon begins data in the matrix format */
597 if (slice_arity(mpl, slice) != 2)
598 err1: error(mpl, "slice currently used must specify 2 asterisk"
599 "s, not %d", slice_arity(mpl, slice));
600 get_token(mpl /* : */);
601 /* read elemental set data in the matrix format */
602 matrix_format(mpl, set, memb, slice, tr);
604 else if (mpl->token == T_LEFT)
605 left: { /* left parenthesis begins the "transpose" indicator, which
606 is followed by data in the matrix format */
607 get_token(mpl /* ( */);
608 if (!is_literal(mpl, "tr"))
609 err2: error(mpl, "transpose indicator (tr) incomplete");
610 if (slice_arity(mpl, slice) != 2) goto err1;
611 get_token(mpl /* tr */);
612 if (mpl->token != T_RIGHT) goto err2;
613 get_token(mpl /* ) */);
614 /* in this case the colon is optional */
615 if (mpl->token == T_COLON) get_token(mpl /* : */);
616 /* set the "transpose" indicator */
618 /* read elemental set data in the matrix format */
619 matrix_format(mpl, set, memb, slice, tr);
621 else if (mpl->token == T_SEMICOLON)
622 { /* semicolon terminates the data block */
623 get_token(mpl /* ; */);
627 error(mpl, "syntax error in set data block");
629 /* delete the current slice */
630 delete_slice(mpl, slice);
634 /*----------------------------------------------------------------------
635 -- select_parameter - select parameter to saturate it with data.
637 -- This routine selects parameter to saturate it with data provided in
638 -- the data section. */
640 PARAMETER *select_parameter
642 char *name /* not changed */
646 xassert(name != NULL);
647 node = avl_find_node(mpl->tree, name);
648 if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
649 error(mpl, "%s not a parameter", name);
650 par = (PARAMETER *)avl_get_node_link(node);
651 if (par->assign != NULL)
652 error(mpl, "%s needs no data", name);
654 error(mpl, "%s already provided with data", name);
659 /*----------------------------------------------------------------------
660 -- set_default - set default parameter value.
662 -- This routine sets default value for specified parameter. */
666 PARAMETER *par, /* not changed */
667 SYMBOL *altval /* destroyed */
669 { xassert(par != NULL);
670 xassert(altval != NULL);
671 if (par->option != NULL)
672 error(mpl, "default value for %s already specified in model se"
674 xassert(par->defval == NULL);
675 par->defval = altval;
679 /*----------------------------------------------------------------------
680 -- read_value - read value and assign it to parameter member.
682 -- This routine reads numeric or symbolic value from the input stream
683 -- and assigns to new parameter member specified by its n-tuple, which
684 -- (the member) is created and added to the parameter array. */
688 PARAMETER *par, /* not changed */
689 TUPLE *tuple /* destroyed */
692 xassert(par != NULL);
693 xassert(is_symbol(mpl));
694 /* there must be no member with the same n-tuple */
695 if (find_member(mpl, par->array, tuple) != NULL)
696 error(mpl, "%s%s already defined",
697 par->name, format_tuple(mpl, '[', tuple));
698 /* create new parameter member with given n-tuple */
699 memb = add_member(mpl, par->array, tuple);
700 /* read value and assigns it to the new parameter member */
706 error(mpl, "%s requires numeric data", par->name);
707 memb->value.num = read_number(mpl);
710 memb->value.sym = read_symbol(mpl);
718 /*----------------------------------------------------------------------
719 -- plain_format - read parameter data block in plain format.
721 -- This routine reads parameter data block using the syntax:
723 -- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
725 -- where <symbols> are used to determine a complete subscript list for
726 -- parameter member, <value> is a numeric or symbolic value assigned to
727 -- the parameter member. Commae between data items are optional and may
728 -- be omitted anywhere.
730 -- Number of components in the slice must be the same as dimension of
731 -- the parameter. To construct the complete subscript list the routine
732 -- replaces null positions in the slice by corresponding <symbols>. */
736 PARAMETER *par, /* not changed */
737 SLICE *slice /* not changed */
741 SYMBOL *sym, *with = NULL;
742 xassert(par != NULL);
743 xassert(par->dim == slice_dimen(mpl, slice));
744 xassert(is_symbol(mpl));
745 /* read symbols and construct complete subscript list */
746 tuple = create_tuple(mpl);
747 for (temp = slice; temp != NULL; temp = temp->next)
748 { if (temp->sym == NULL)
749 { /* substitution is needed; read symbol */
751 { int lack = slice_arity(mpl, temp) + 1;
752 xassert(with != NULL);
754 error(mpl, "%d items missing in data group beginning wit"
755 "h %s", lack, format_symbol(mpl, with));
757 sym = read_symbol(mpl);
758 if (with == NULL) with = sym;
761 { /* copy symbol from the slice */
762 sym = copy_symbol(mpl, temp->sym);
764 /* append the symbol to the subscript list */
765 tuple = expand_tuple(mpl, tuple, sym);
766 /* skip optional comma */
767 if (mpl->token == T_COMMA) get_token(mpl /* , */);
769 /* read value and assign it to new parameter member */
771 { xassert(with != NULL);
772 error(mpl, "one item missing in data group beginning with %s",
773 format_symbol(mpl, with));
775 read_value(mpl, par, tuple);
779 /*----------------------------------------------------------------------
780 -- tabular_format - read parameter data block in tabular format.
782 -- This routine reads parameter data block using the syntax:
784 -- <tabular format> ::= <column> <column> ... <column> :=
785 -- <row> <value> <value> ... <value>
786 -- <row> <value> <value> ... <value>
787 -- . . . . . . . . . . .
788 -- <row> <value> <value> ... <value>
790 -- where <rows> are symbols that denote rows of the table, <columns>
791 -- are symbols that denote columns of the table, <values> are numeric
792 -- or symbolic values assigned to the corresponding parameter members.
793 -- If <value> is specified as single point, no value is provided.
795 -- Number of components in the slice must be the same as dimension of
796 -- the parameter. The slice must have two null positions. To construct
797 -- complete subscript list for particular <value> the routine replaces
798 -- the first null position of the slice by the corresponding <row> (or
799 -- <column>, if the flag tr is on) and the second null position by the
800 -- corresponding <column> (or by <row>, if the flag tr is on). */
804 PARAMETER *par, /* not changed */
805 SLICE *slice, /* not changed */
808 { SLICE *list, *col, *temp;
811 xassert(par != NULL);
812 xassert(par->dim == slice_dimen(mpl, slice));
813 xassert(slice_arity(mpl, slice) == 2);
814 /* read the table heading that contains column symbols (the table
815 may have no columns) */
816 list = create_slice(mpl);
817 while (mpl->token != T_ASSIGN)
818 { /* read column symbol and append it to the column list */
820 error(mpl, "number, symbol, or := missing where expected");
821 list = expand_slice(mpl, list, read_symbol(mpl));
823 get_token(mpl /* := */);
824 /* read zero or more rows that contain tabular data */
825 while (is_symbol(mpl))
826 { /* read row symbol (if the table has no columns, these symbols
828 row = read_symbol(mpl);
829 /* read values accordingly to the column list */
830 for (col = list; col != NULL; col = col->next)
832 /* if the token is single point, no value is provided */
833 if (is_literal(mpl, "."))
834 { get_token(mpl /* . */);
837 /* construct complete subscript list */
838 tuple = create_tuple(mpl);
839 for (temp = slice; temp != NULL; temp = temp->next)
840 { if (temp->sym == NULL)
841 { /* substitution is needed */
844 /* substitute in the first null position */
845 tuple = expand_tuple(mpl, tuple,
846 copy_symbol(mpl, tr ? col->sym : row));
849 /* substitute in the second null position */
850 tuple = expand_tuple(mpl, tuple,
851 copy_symbol(mpl, tr ? row : col->sym));
854 xassert(which != which);
858 { /* copy symbol from the slice */
859 tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
864 /* read value and assign it to new parameter member */
866 { int lack = slice_dimen(mpl, col);
868 error(mpl, "one item missing in data group beginning "
869 "with %s", format_symbol(mpl, row));
871 error(mpl, "%d items missing in data group beginning "
872 "with %s", lack, format_symbol(mpl, row));
874 read_value(mpl, par, tuple);
876 /* delete the row symbol */
877 delete_symbol(mpl, row);
879 /* delete the column list */
880 delete_slice(mpl, list);
884 /*----------------------------------------------------------------------
885 -- tabbing_format - read parameter data block in tabbing format.
887 -- This routine reads parameter data block using the syntax:
889 -- <tabbing format> ::= <prefix> <name> , ... , <name> , := ,
890 -- <symbol> , ... , <symbol> , <value> , ... , <value> ,
891 -- <symbol> , ... , <symbol> , <value> , ... , <value> ,
892 -- . . . . . . . . . . . . . . . . .
893 -- <symbol> , ... , <symbol> , <value> , ... , <value>
894 -- <prefix> ::= <empty>
895 -- <prefix> ::= <set name> :
897 -- where <names> are names of parameters (all the parameters must be
898 -- subscripted and have identical dimensions), <symbols> are symbols
899 -- used to define subscripts of parameter members, <values> are numeric
900 -- or symbolic values assigned to the corresponding parameter members.
901 -- Optional <prefix> may specify a simple set, in which case n-tuples
902 -- built of <symbols> for each row of the data table (i.e. subscripts
903 -- of parameter members) are added to the specified set. Commae between
904 -- data items are optional and may be omitted anywhere.
906 -- If the parameter altval is not NULL, it specifies a default value
907 -- provided for all the parameters specified in the data block. */
911 SYMBOL *altval /* not changed */
917 int next_token, j, dim = 0;
918 char *last_name = NULL;
919 /* read the optional <prefix> */
921 { get_token(mpl /* <symbol> */);
922 next_token = mpl->token;
923 unget_token(mpl /* <symbol> */);
924 if (next_token == T_COLON)
925 { /* select the set to saturate it with data */
926 set = select_set(mpl, mpl->image);
927 /* the set must be simple (i.e. not set of sets) */
929 error(mpl, "%s must be a simple set", set->name);
930 /* and must not be defined yet */
931 if (set->array->head != NULL)
932 error(mpl, "%s already defined", set->name);
933 /* add new (the only) member to the set and assign it empty
935 add_member(mpl, set->array, NULL)->value.set =
936 create_elemset(mpl, set->dimen);
937 last_name = set->name, dim = set->dimen;
938 get_token(mpl /* <symbol> */);
939 xassert(mpl->token == T_COLON);
940 get_token(mpl /* : */);
943 /* read the table heading that contains parameter names */
944 list = create_slice(mpl);
945 while (mpl->token != T_ASSIGN)
946 { /* there must be symbolic name of parameter */
948 error(mpl, "parameter name or := missing where expected");
949 /* select the parameter to saturate it with data */
950 par = select_parameter(mpl, mpl->image);
951 /* the parameter must be subscripted */
953 error(mpl, "%s not a subscripted parameter", mpl->image);
954 /* the set (if specified) and all the parameters in the data
955 block must have identical dimension */
956 if (dim != 0 && par->dim != dim)
957 { xassert(last_name != NULL);
958 error(mpl, "%s has dimension %d while %s has dimension %d",
959 last_name, dim, par->name, par->dim);
961 /* set default value for the parameter (if specified) */
963 set_default(mpl, par, copy_symbol(mpl, altval));
964 /* append the parameter to the column list */
965 list = expand_slice(mpl, list, (SYMBOL *)par);
966 last_name = par->name, dim = par->dim;
967 get_token(mpl /* <symbol> */);
968 /* skip optional comma */
969 if (mpl->token == T_COMMA) get_token(mpl /* , */);
971 if (slice_dimen(mpl, list) == 0)
972 error(mpl, "at least one parameter name required");
973 get_token(mpl /* := */);
974 /* skip optional comma */
975 if (mpl->token == T_COMMA) get_token(mpl /* , */);
976 /* read rows that contain tabbing data */
977 while (is_symbol(mpl))
978 { /* read subscript list */
979 tuple = create_tuple(mpl);
980 for (j = 1; j <= dim; j++)
981 { /* read j-th subscript */
983 { int lack = slice_dimen(mpl, list) + dim - j + 1;
984 xassert(tuple != NULL);
986 error(mpl, "%d items missing in data group beginning wit"
987 "h %s", lack, format_symbol(mpl, tuple->sym));
989 /* read and append j-th subscript to the n-tuple */
990 tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
991 /* skip optional comma *between* <symbols> */
992 if (j < dim && mpl->token == T_COMMA)
993 get_token(mpl /* , */);
995 /* if the set is specified, add to it new n-tuple, which is a
996 copy of the subscript list just read */
998 check_then_add(mpl, set->array->head->value.set,
999 copy_tuple(mpl, tuple));
1000 /* skip optional comma between <symbol> and <value> */
1001 if (mpl->token == T_COMMA) get_token(mpl /* , */);
1002 /* read values accordingly to the column list */
1003 for (col = list; col != NULL; col = col->next)
1004 { /* if the token is single point, no value is provided */
1005 if (is_literal(mpl, "."))
1006 { get_token(mpl /* . */);
1009 /* read value and assign it to new parameter member */
1010 if (!is_symbol(mpl))
1011 { int lack = slice_dimen(mpl, col);
1012 xassert(tuple != NULL);
1014 error(mpl, "one item missing in data group beginning "
1015 "with %s", format_symbol(mpl, tuple->sym));
1017 error(mpl, "%d items missing in data group beginning "
1018 "with %s", lack, format_symbol(mpl, tuple->sym));
1020 read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
1022 /* skip optional comma preceding the next value */
1023 if (col->next != NULL && mpl->token == T_COMMA)
1024 get_token(mpl /* , */);
1026 /* delete the original subscript list */
1027 delete_tuple(mpl, tuple);
1028 /* skip optional comma (only if there is next data group) */
1029 if (mpl->token == T_COMMA)
1030 { get_token(mpl /* , */);
1031 if (!is_symbol(mpl)) unget_token(mpl /* , */);
1034 /* delete the column list (it contains parameters, not symbols,
1035 so nullify it before) */
1036 for (col = list; col != NULL; col = col->next) col->sym = NULL;
1037 delete_slice(mpl, list);
1041 /*----------------------------------------------------------------------
1042 -- parameter_data - read parameter data.
1044 -- This routine reads parameter data using the syntax:
1046 -- <parameter data> ::= param <default value> : <tabbing format> ;
1047 -- <parameter data> ::= param <parameter name> <default value>
1049 -- <parameter name> ::= <symbolic name>
1050 -- <default value> ::= <empty>
1051 -- <default value> ::= default <symbol>
1052 -- <assignments> ::= <empty>
1053 -- <assignments> ::= <assignments> , :=
1054 -- <assignments> ::= <assignments> , [ <symbol list> ]
1055 -- <assignments> ::= <assignments> , <plain format>
1056 -- <assignemnts> ::= <assignments> , : <tabular format>
1057 -- <assignments> ::= <assignments> , (tr) <tabular format>
1058 -- <assignments> ::= <assignments> , (tr) : <tabular format>
1060 -- Commae in <assignments> are optional and may be omitted anywhere. */
1062 void parameter_data(MPL *mpl)
1064 SYMBOL *altval = NULL;
1067 xassert(is_literal(mpl, "param"));
1068 get_token(mpl /* param */);
1069 /* read optional default value */
1070 if (is_literal(mpl, "default"))
1071 { get_token(mpl /* default */);
1072 if (!is_symbol(mpl))
1073 error(mpl, "default value missing where expected");
1074 altval = read_symbol(mpl);
1075 /* if the default value follows the keyword 'param', the next
1076 token must be only the colon */
1077 if (mpl->token != T_COLON)
1078 error(mpl, "colon missing where expected");
1080 /* being used after the keyword 'param' or the optional default
1081 value the colon begins data in the tabbing format */
1082 if (mpl->token == T_COLON)
1083 { get_token(mpl /* : */);
1084 /* skip optional comma */
1085 if (mpl->token == T_COMMA) get_token(mpl /* , */);
1086 /* read parameter data in the tabbing format */
1087 tabbing_format(mpl, altval);
1088 /* on reading data in the tabbing format the default value is
1089 always copied, so delete the original symbol */
1090 if (altval != NULL) delete_symbol(mpl, altval);
1091 /* the next token must be only semicolon */
1092 if (mpl->token != T_SEMICOLON)
1093 error(mpl, "symbol, number, or semicolon missing where expe"
1095 get_token(mpl /* ; */);
1098 /* in other cases there must be symbolic name of parameter, which
1099 follows the keyword 'param' */
1100 if (!is_symbol(mpl))
1101 error(mpl, "parameter name missing where expected");
1102 /* select the parameter to saturate it with data */
1103 par = select_parameter(mpl, mpl->image);
1104 get_token(mpl /* <symbol> */);
1105 /* read optional default value */
1106 if (is_literal(mpl, "default"))
1107 { get_token(mpl /* default */);
1108 if (!is_symbol(mpl))
1109 error(mpl, "default value missing where expected");
1110 altval = read_symbol(mpl);
1111 /* set default value for the parameter */
1112 set_default(mpl, par, altval);
1114 /* create initial fake slice of all asterisks */
1115 slice = fake_slice(mpl, par->dim);
1116 /* read zero or more data assignments */
1118 { /* skip optional comma */
1119 if (mpl->token == T_COMMA) get_token(mpl /* , */);
1120 /* process current assignment */
1121 if (mpl->token == T_ASSIGN)
1122 { /* assignment ligature is non-significant element */
1123 get_token(mpl /* := */);
1125 else if (mpl->token == T_LBRACKET)
1126 { /* left bracket begins new slice; delete the current slice
1128 delete_slice(mpl, slice);
1129 slice = read_slice(mpl, par->name, par->dim);
1130 /* each new slice resets the "transpose" indicator */
1133 else if (is_symbol(mpl))
1134 { /* number or symbol begins data in the plain format */
1135 plain_format(mpl, par, slice);
1137 else if (mpl->token == T_COLON)
1138 { /* colon begins data in the tabular format */
1140 err1: error(mpl, "%s not a subscripted parameter",
1142 if (slice_arity(mpl, slice) != 2)
1143 err2: error(mpl, "slice currently used must specify 2 asterisk"
1144 "s, not %d", slice_arity(mpl, slice));
1145 get_token(mpl /* : */);
1146 /* read parameter data in the tabular format */
1147 tabular_format(mpl, par, slice, tr);
1149 else if (mpl->token == T_LEFT)
1150 { /* left parenthesis begins the "transpose" indicator, which
1151 is followed by data in the tabular format */
1152 get_token(mpl /* ( */);
1153 if (!is_literal(mpl, "tr"))
1154 err3: error(mpl, "transpose indicator (tr) incomplete");
1155 if (par->dim == 0) goto err1;
1156 if (slice_arity(mpl, slice) != 2) goto err2;
1157 get_token(mpl /* tr */);
1158 if (mpl->token != T_RIGHT) goto err3;
1159 get_token(mpl /* ) */);
1160 /* in this case the colon is optional */
1161 if (mpl->token == T_COLON) get_token(mpl /* : */);
1162 /* set the "transpose" indicator */
1164 /* read parameter data in the tabular format */
1165 tabular_format(mpl, par, slice, tr);
1167 else if (mpl->token == T_SEMICOLON)
1168 { /* semicolon terminates the data block */
1169 get_token(mpl /* ; */);
1173 error(mpl, "syntax error in parameter data block");
1175 /* delete the current slice */
1176 delete_slice(mpl, slice);
1180 /*----------------------------------------------------------------------
1181 -- data_section - read data section.
1183 -- This routine reads data section using the syntax:
1185 -- <data section> ::= <empty>
1186 -- <data section> ::= <data section> <data block> ;
1187 -- <data block> ::= <set data>
1188 -- <data block> ::= <parameter data>
1190 -- Reading data section is terminated by either the keyword 'end' or
1191 -- the end of file. */
1193 void data_section(MPL *mpl)
1194 { while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
1195 { if (is_literal(mpl, "set"))
1197 else if (is_literal(mpl, "param"))
1198 parameter_data(mpl);
1200 error(mpl, "syntax error in data section");