1 /* glpmpl02.c */
2 
3 /***********************************************************************
4 *  This code is part of GLPK (GNU Linear Programming Kit).
5 *
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>.
10 *
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.
15 *
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.
20 *
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 ***********************************************************************/
24 
25 #define _GLPSTD_STDIO
26 #include "glpenv.h"
27 #include "glpmpl.h"
28 
29 /**********************************************************************/
30 /* * *                  PROCESSING DATA SECTION                   * * */
31 /**********************************************************************/
32 
33 /*----------------------------------------------------------------------
34 -- create_slice - create slice.
35 --
36 -- This routine creates a slice, which initially has no components. */
37 
create_slice(MPL * mpl)38 SLICE *create_slice(MPL *mpl)
39 {     SLICE *slice;
40       xassert(mpl == mpl);
41       slice = NULL;
42       return slice;
43 }
44 
45 /*----------------------------------------------------------------------
46 -- expand_slice - append new component to slice.
47 --
48 -- This routine expands slice appending to it either a given symbol or
49 -- null component, which becomes the last component of the slice. */
50 
expand_slice(MPL * mpl,SLICE * slice,SYMBOL * sym)51 SLICE *expand_slice
52 (     MPL *mpl,
53       SLICE *slice,           /* destroyed */
54       SYMBOL *sym             /* destroyed */
55 )
56 {     SLICE *tail, *temp;
57       /* create a new component */
58       tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
59       tail->sym = sym;
60       tail->next = NULL;
61       /* and append it to the component list */
62       if (slice == NULL)
63          slice = tail;
64       else
65       {  for (temp = slice; temp->next != NULL; temp = temp->next);
66          temp->next = tail;
67       }
68       return slice;
69 }
70 
71 /*----------------------------------------------------------------------
72 -- slice_dimen - determine dimension of slice.
73 --
74 -- This routine returns dimension of slice, which is number of all its
75 -- components including null ones. */
76 
slice_dimen(MPL * mpl,SLICE * slice)77 int slice_dimen
78 (     MPL *mpl,
79       SLICE *slice            /* not changed */
80 )
81 {     SLICE *temp;
82       int dim;
83       xassert(mpl == mpl);
84       dim = 0;
85       for (temp = slice; temp != NULL; temp = temp->next) dim++;
86       return dim;
87 }
88 
89 /*----------------------------------------------------------------------
90 -- slice_arity - determine arity of slice.
91 --
92 -- This routine returns arity of slice, i.e. number of null components
93 -- (indicated by asterisks) in the slice. */
94 
slice_arity(MPL * mpl,SLICE * slice)95 int slice_arity
96 (     MPL *mpl,
97       SLICE *slice            /* not changed */
98 )
99 {     SLICE *temp;
100       int arity;
101       xassert(mpl == mpl);
102       arity = 0;
103       for (temp = slice; temp != NULL; temp = temp->next)
104          if (temp->sym == NULL) arity++;
105       return arity;
106 }
107 
108 /*----------------------------------------------------------------------
109 -- fake_slice - create fake slice of all asterisks.
110 --
111 -- This routine creates a fake slice of given dimension, which contains
112 -- asterisks in all components. Zero dimension is allowed. */
113 
fake_slice(MPL * mpl,int dim)114 SLICE *fake_slice(MPL *mpl, int dim)
115 {     SLICE *slice;
116       slice = create_slice(mpl);
117       while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
118       return slice;
119 }
120 
121 /*----------------------------------------------------------------------
122 -- delete_slice - delete slice.
123 --
124 -- This routine deletes specified slice. */
125 
delete_slice(MPL * mpl,SLICE * slice)126 void delete_slice
127 (     MPL *mpl,
128       SLICE *slice            /* destroyed */
129 )
130 {     SLICE *temp;
131       while (slice != NULL)
132       {  temp = slice;
133          slice = temp->next;
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));
137       }
138       return;
139 }
140 
141 /*----------------------------------------------------------------------
142 -- is_number - check if current token is number.
143 --
144 -- If the current token is a number, this routine returns non-zero.
145 -- Otherwise zero is returned. */
146 
is_number(MPL * mpl)147 int is_number(MPL *mpl)
148 {     return
149          mpl->token == T_NUMBER;
150 }
151 
152 /*----------------------------------------------------------------------
153 -- is_symbol - check if current token is symbol.
154 --
155 -- If the current token is suitable to be a symbol, the routine returns
156 -- non-zero. Otherwise zero is returned. */
157 
is_symbol(MPL * mpl)158 int is_symbol(MPL *mpl)
159 {     return
160          mpl->token == T_NUMBER ||
161          mpl->token == T_SYMBOL ||
162          mpl->token == T_STRING;
163 }
164 
165 /*----------------------------------------------------------------------
166 -- is_literal - check if current token is given symbolic literal.
167 --
168 -- If the current token is given symbolic literal, this routine returns
169 -- non-zero. Otherwise zero is returned.
170 --
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. */
173 
is_literal(MPL * mpl,char * literal)174 int is_literal(MPL *mpl, char *literal)
175 {     return
176          is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
177 }
178 
179 /*----------------------------------------------------------------------
180 -- read_number - read number.
181 --
182 -- This routine reads the current token, which must be a number, and
183 -- returns its numeric value. */
184 
read_number(MPL * mpl)185 double read_number(MPL *mpl)
186 {     double num;
187       xassert(is_number(mpl));
188       num = mpl->value;
189       get_token(mpl /* <number> */);
190       return num;
191 }
192 
193 /*----------------------------------------------------------------------
194 -- read_symbol - read symbol.
195 --
196 -- This routine reads the current token, which must be a symbol, and
197 -- returns its symbolic value. */
198 
read_symbol(MPL * mpl)199 SYMBOL *read_symbol(MPL *mpl)
200 {     SYMBOL *sym;
201       xassert(is_symbol(mpl));
202       if (is_number(mpl))
203          sym = create_symbol_num(mpl, mpl->value);
204       else
205          sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
206       get_token(mpl /* <symbol> */);
207       return sym;
208 }
209 
210 /*----------------------------------------------------------------------
211 -- read_slice - read slice.
212 --
213 -- This routine reads slice using the syntax:
214 --
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> ::= *
221 --
222 -- The bracketed form of slice is used for members of multi-dimensional
223 -- objects while the parenthesized form is used for elemental sets. */
224 
read_slice(MPL * mpl,char * name,int dim)225 SLICE *read_slice
226 (     MPL *mpl,
227       char *name,             /* not changed */
228       int dim
229 )
230 {     SLICE *slice;
231       int close;
232       xassert(name != NULL);
233       switch (mpl->token)
234       {  case T_LBRACKET:
235             close = T_RBRACKET;
236             break;
237          case T_LEFT:
238             xassert(dim > 0);
239             close = T_RIGHT;
240             break;
241          default:
242             xassert(mpl != mpl);
243       }
244       if (dim == 0)
245          mpl_error(mpl, "%s cannot be subscripted", name);
246       get_token(mpl /* ( | [ */);
247       /* read slice components */
248       slice = create_slice(mpl);
249       for (;;)
250       {  /* the current token must be a symbol or asterisk */
251          if (is_symbol(mpl))
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 /* * */);
256          }
257          else
258             mpl_error(mpl, "number, symbol, or asterisk missing where expec"
259                "ted");
260          /* check a token that follows the symbol */
261          if (mpl->token == T_COMMA)
262             get_token(mpl /* , */);
263          else if (mpl->token == close)
264             break;
265          else
266             mpl_error(mpl, "syntax error in slice");
267       }
268       /* number of slice components must be the same as the appropriate
269          dimension */
270       if (slice_dimen(mpl, slice) != dim)
271       {  switch (close)
272          {  case T_RBRACKET:
273                mpl_error(mpl, "%s must have %d subscript%s, not %d", name,
274                   dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
275                break;
276             case T_RIGHT:
277                mpl_error(mpl, "%s has dimension %d, not %d", name, dim,
278                   slice_dimen(mpl, slice));
279                break;
280             default:
281                xassert(close != close);
282          }
283       }
284       get_token(mpl /* ) | ] */);
285       return slice;
286 }
287 
288 /*----------------------------------------------------------------------
289 -- select_set - select set to saturate it with elemental sets.
290 --
291 -- This routine selects set to saturate it with elemental sets provided
292 -- in the data section. */
293 
select_set(MPL * mpl,char * name)294 SET *select_set
295 (     MPL *mpl,
296       char *name              /* not changed */
297 )
298 {     SET *set;
299       AVLNODE *node;
300       xassert(name != NULL);
301       node = avl_find_node(mpl->tree, name);
302       if (node == NULL || avl_get_node_type(node) != A_SET)
303          mpl_error(mpl, "%s not a set", name);
304       set = (SET *)avl_get_node_link(node);
305       if (set->assign != NULL || set->gadget != NULL)
306          mpl_error(mpl, "%s needs no data", name);
307       set->data = 1;
308       return set;
309 }
310 
311 /*----------------------------------------------------------------------
312 -- simple_format - read set data block in simple format.
313 --
314 -- This routine reads set data block using the syntax:
315 --
316 -- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
317 --
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.
321 --
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>.
326 --
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. */
330 
simple_format(MPL * mpl,SET * set,MEMBER * memb,SLICE * slice)331 void simple_format
332 (     MPL *mpl,
333       SET *set,               /* not changed */
334       MEMBER *memb,           /* modified */
335       SLICE *slice            /* not changed */
336 )
337 {     TUPLE *tuple;
338       SLICE *temp;
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 */
351             if (!is_symbol(mpl))
352             {  int lack = slice_arity(mpl, temp);
353                /* with cannot be null due to assertion above */
354                xassert(with != NULL);
355                if (lack == 1)
356                   mpl_error(mpl, "one item missing in data group beginning "
357                      "with %s", format_symbol(mpl, with));
358                else
359                   mpl_error(mpl, "%d items missing in data group beginning "
360                      "with %s", lack, format_symbol(mpl, with));
361             }
362             sym = read_symbol(mpl);
363             if (with == NULL) with = sym;
364          }
365          else
366          {  /* copy symbol from the slice */
367             sym = copy_symbol(mpl, temp->sym);
368          }
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 /* , */);
374       }
375       /* add constructed n-tuple to elemental set */
376       check_then_add(mpl, memb->value.set, tuple);
377       return;
378 }
379 
380 /*----------------------------------------------------------------------
381 -- matrix_format - read set data block in matrix format.
382 --
383 -- This routine reads set data block using the syntax:
384 --
385 -- <matrix format> ::= <column> <column> ... <column> :=
386 --               <row>   +/-      +/-    ...   +/-
387 --               <row>   +/-      +/-    ...   +/-
388 --                 .  .  .  .  .  .  .  .  .  .  .
389 --               <row>   +/-      +/-    ...   +/-
390 --
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.
395 --
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). */
402 
matrix_format(MPL * mpl,SET * set,MEMBER * memb,SLICE * slice,int tr)403 void matrix_format
404 (     MPL *mpl,
405       SET *set,               /* not changed */
406       MEMBER *memb,           /* modified */
407       SLICE *slice,           /* not changed */
408       int tr
409 )
410 {     SLICE *list, *col, *temp;
411       TUPLE *tuple;
412       SYMBOL *row;
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 */
424          if (!is_symbol(mpl))
425             mpl_error(mpl, "number, symbol, or := missing where expected");
426          list = expand_slice(mpl, list, read_symbol(mpl));
427       }
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
432             are just ignored) */
433          row = read_symbol(mpl);
434          /* read the matrix row accordingly to the column list */
435          for (col = list; col != NULL; col = col->next)
436          {  int which = 0;
437             /* check indicator */
438             if (is_literal(mpl, "+"))
439                ;
440             else if (is_literal(mpl, "-"))
441             {  get_token(mpl /* - */);
442                continue;
443             }
444             else
445             {  int lack = slice_dimen(mpl, col);
446                if (lack == 1)
447                   mpl_error(mpl, "one item missing in data group beginning "
448                      "with %s", format_symbol(mpl, row));
449                else
450                   mpl_error(mpl, "%d items missing in data group beginning "
451                      "with %s", lack, format_symbol(mpl, row));
452             }
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 */
458                   switch (++which)
459                   {  case 1:
460                         /* substitute in the first null position */
461                         tuple = expand_tuple(mpl, tuple,
462                            copy_symbol(mpl, tr ? col->sym : row));
463                         break;
464                      case 2:
465                         /* substitute in the second null position */
466                         tuple = expand_tuple(mpl, tuple,
467                            copy_symbol(mpl, tr ? row : col->sym));
468                         break;
469                      default:
470                         xassert(which != which);
471                   }
472                }
473                else
474                {  /* copy symbol from the slice */
475                   tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
476                      temp->sym));
477                }
478             }
479             xassert(which == 2);
480             /* add constructed n-tuple to elemental set */
481             check_then_add(mpl, memb->value.set, tuple);
482             get_token(mpl /* + */);
483          }
484          /* delete the row symbol */
485          delete_symbol(mpl, row);
486       }
487       /* delete the column list */
488       delete_slice(mpl, list);
489       return;
490 }
491 
492 /*----------------------------------------------------------------------
493 -- set_data - read set data.
494 --
495 -- This routine reads set data using the syntax:
496 --
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>
507 --
508 -- Commae in <assignments> are optional and may be omitted anywhere. */
509 
set_data(MPL * mpl)510 void set_data(MPL *mpl)
511 {     SET *set;
512       TUPLE *tuple;
513       MEMBER *memb;
514       SLICE *slice;
515       int tr = 0;
516       xassert(is_literal(mpl, "set"));
517       get_token(mpl /* set */);
518       /* symbolic name of set must follows the keyword 'set' */
519       if (!is_symbol(mpl))
520          mpl_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
525          set to be read */
526       tuple = create_tuple(mpl);
527       if (mpl->token == T_LBRACKET)
528       {  /* subscript list is specified */
529          if (set->dim == 0)
530             mpl_error(mpl, "%s cannot be subscripted", set->name);
531          get_token(mpl /* [ */);
532          /* read symbols and construct subscript list */
533          for (;;)
534          {  if (!is_symbol(mpl))
535                mpl_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)
540                break;
541             else
542                mpl_error(mpl, "syntax error in subscript list");
543          }
544          if (set->dim != tuple_dimen(mpl, tuple))
545             mpl_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 /* ] */);
549       }
550       else
551       {  /* subscript list is not specified */
552          if (set->dim != 0)
553             mpl_error(mpl, "%s must be subscripted", set->name);
554       }
555       /* there must be no member with the same subscript list */
556       if (find_member(mpl, set->array, tuple) != NULL)
557          mpl_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 */
565       for (;;)
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 /* := */);
572          }
573          else if (mpl->token == T_LEFT)
574          {  /* left parenthesis begins either new slice or "transpose"
575                indicator */
576             int is_tr;
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 */
585             tr = 0;
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);
590          }
591          else if (is_symbol(mpl))
592          {  /* number or symbol begins data in the simple format */
593             simple_format(mpl, set, memb, slice);
594          }
595          else if (mpl->token == T_COLON)
596          {  /* colon begins data in the matrix format */
597             if (slice_arity(mpl, slice) != 2)
598 err1:          mpl_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);
603          }
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:          mpl_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 */
617             tr = 1;
618             /* read elemental set data in the matrix format */
619             matrix_format(mpl, set, memb, slice, tr);
620          }
621          else if (mpl->token == T_SEMICOLON)
622          {  /* semicolon terminates the data block */
623             get_token(mpl /* ; */);
624             break;
625          }
626          else
627             mpl_error(mpl, "syntax error in set data block");
628       }
629       /* delete the current slice */
630       delete_slice(mpl, slice);
631       return;
632 }
633 
634 /*----------------------------------------------------------------------
635 -- select_parameter - select parameter to saturate it with data.
636 --
637 -- This routine selects parameter to saturate it with data provided in
638 -- the data section. */
639 
select_parameter(MPL * mpl,char * name)640 PARAMETER *select_parameter
641 (     MPL *mpl,
642       char *name              /* not changed */
643 )
644 {     PARAMETER *par;
645       AVLNODE *node;
646       xassert(name != NULL);
647       node = avl_find_node(mpl->tree, name);
648       if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
649          mpl_error(mpl, "%s not a parameter", name);
650       par = (PARAMETER *)avl_get_node_link(node);
651       if (par->assign != NULL)
652          mpl_error(mpl, "%s needs no data", name);
653       if (par->data)
654          mpl_error(mpl, "%s already provided with data", name);
655       par->data = 1;
656       return par;
657 }
658 
659 /*----------------------------------------------------------------------
660 -- set_default - set default parameter value.
661 --
662 -- This routine sets default value for specified parameter. */
663 
set_default(MPL * mpl,PARAMETER * par,SYMBOL * altval)664 void set_default
665 (     MPL *mpl,
666       PARAMETER *par,         /* not changed */
667       SYMBOL *altval          /* destroyed */
668 )
669 {     xassert(par != NULL);
670       xassert(altval != NULL);
671       if (par->option != NULL)
672          mpl_error(mpl, "default value for %s already specified in model se"
673             "ction", par->name);
674       xassert(par->defval == NULL);
675       par->defval = altval;
676       return;
677 }
678 
679 /*----------------------------------------------------------------------
680 -- read_value - read value and assign it to parameter member.
681 --
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. */
685 
read_value(MPL * mpl,PARAMETER * par,TUPLE * tuple)686 MEMBER *read_value
687 (     MPL *mpl,
688       PARAMETER *par,         /* not changed */
689       TUPLE *tuple            /* destroyed */
690 )
691 {     MEMBER *memb;
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          mpl_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 */
701       switch (par->type)
702       {  case A_NUMERIC:
703          case A_INTEGER:
704          case A_BINARY:
705             if (!is_number(mpl))
706                mpl_error(mpl, "%s requires numeric data", par->name);
707             memb->value.num = read_number(mpl);
708             break;
709          case A_SYMBOLIC:
710             memb->value.sym = read_symbol(mpl);
711             break;
712          default:
713             xassert(par != par);
714       }
715       return memb;
716 }
717 
718 /*----------------------------------------------------------------------
719 -- plain_format - read parameter data block in plain format.
720 --
721 -- This routine reads parameter data block using the syntax:
722 --
723 -- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
724 --
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.
729 --
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>. */
733 
plain_format(MPL * mpl,PARAMETER * par,SLICE * slice)734 void plain_format
735 (     MPL *mpl,
736       PARAMETER *par,         /* not changed */
737       SLICE *slice            /* not changed */
738 )
739 {     TUPLE *tuple;
740       SLICE *temp;
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 */
750             if (!is_symbol(mpl))
751             {  int lack = slice_arity(mpl, temp) + 1;
752                xassert(with != NULL);
753                xassert(lack > 1);
754                mpl_error(mpl, "%d items missing in data group beginning wit"
755                   "h %s", lack, format_symbol(mpl, with));
756             }
757             sym = read_symbol(mpl);
758             if (with == NULL) with = sym;
759          }
760          else
761          {  /* copy symbol from the slice */
762             sym = copy_symbol(mpl, temp->sym);
763          }
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 /* , */);
768       }
769       /* read value and assign it to new parameter member */
770       if (!is_symbol(mpl))
771       {  xassert(with != NULL);
772          mpl_error(mpl, "one item missing in data group beginning with %s",
773             format_symbol(mpl, with));
774       }
775       read_value(mpl, par, tuple);
776       return;
777 }
778 
779 /*----------------------------------------------------------------------
780 -- tabular_format - read parameter data block in tabular format.
781 --
782 -- This routine reads parameter data block using the syntax:
783 --
784 -- <tabular format> ::= <column> <column> ... <column> :=
785 --                <row> <value>  <value>  ... <value>
786 --                <row> <value>  <value>  ... <value>
787 --                  .  .  .  .  .  .  .  .  .  .  .
788 --                <row> <value>  <value>  ... <value>
789 --
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.
794 --
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). */
801 
tabular_format(MPL * mpl,PARAMETER * par,SLICE * slice,int tr)802 void tabular_format
803 (     MPL *mpl,
804       PARAMETER *par,         /* not changed */
805       SLICE *slice,           /* not changed */
806       int tr
807 )
808 {     SLICE *list, *col, *temp;
809       TUPLE *tuple;
810       SYMBOL *row;
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 */
819          if (!is_symbol(mpl))
820             mpl_error(mpl, "number, symbol, or := missing where expected");
821          list = expand_slice(mpl, list, read_symbol(mpl));
822       }
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
827             are just ignored) */
828          row = read_symbol(mpl);
829          /* read values accordingly to the column list */
830          for (col = list; col != NULL; col = col->next)
831          {  int which = 0;
832             /* if the token is single point, no value is provided */
833             if (is_literal(mpl, "."))
834             {  get_token(mpl /* . */);
835                continue;
836             }
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 */
842                   switch (++which)
843                   {  case 1:
844                         /* substitute in the first null position */
845                         tuple = expand_tuple(mpl, tuple,
846                            copy_symbol(mpl, tr ? col->sym : row));
847                         break;
848                      case 2:
849                         /* substitute in the second null position */
850                         tuple = expand_tuple(mpl, tuple,
851                            copy_symbol(mpl, tr ? row : col->sym));
852                         break;
853                      default:
854                         xassert(which != which);
855                   }
856                }
857                else
858                {  /* copy symbol from the slice */
859                   tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
860                      temp->sym));
861                }
862             }
863             xassert(which == 2);
864             /* read value and assign it to new parameter member */
865             if (!is_symbol(mpl))
866             {  int lack = slice_dimen(mpl, col);
867                if (lack == 1)
868                   mpl_error(mpl, "one item missing in data group beginning "
869                      "with %s", format_symbol(mpl, row));
870                else
871                   mpl_error(mpl, "%d items missing in data group beginning "
872                      "with %s", lack, format_symbol(mpl, row));
873             }
874             read_value(mpl, par, tuple);
875          }
876          /* delete the row symbol */
877          delete_symbol(mpl, row);
878       }
879       /* delete the column list */
880       delete_slice(mpl, list);
881       return;
882 }
883 
884 /*----------------------------------------------------------------------
885 -- tabbing_format - read parameter data block in tabbing format.
886 --
887 -- This routine reads parameter data block using the syntax:
888 --
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> :
896 --
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.
905 --
906 -- If the parameter altval is not NULL, it specifies a default value
907 -- provided for all the parameters specified in the data block.  */
908 
tabbing_format(MPL * mpl,SYMBOL * altval)909 void tabbing_format
910 (     MPL *mpl,
911       SYMBOL *altval          /* not changed */
912 )
913 {     SET *set = NULL;
914       PARAMETER *par;
915       SLICE *list, *col;
916       TUPLE *tuple;
917       int next_token, j, dim = 0;
918       char *last_name = NULL;
919       /* read the optional <prefix> */
920       if (is_symbol(mpl))
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) */
928             if (set->dim != 0)
929                mpl_error(mpl, "%s must be a simple set", set->name);
930             /* and must not be defined yet */
931             if (set->array->head != NULL)
932                mpl_error(mpl, "%s already defined", set->name);
933             /* add new (the only) member to the set and assign it empty
934                elemental set */
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 /* : */);
941          }
942       }
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 */
947          if (!is_symbol(mpl))
948             mpl_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 */
952          if (par->dim == 0)
953             mpl_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             mpl_error(mpl, "%s has dimension %d while %s has dimension %d",
959                last_name, dim, par->name, par->dim);
960          }
961          /* set default value for the parameter (if specified) */
962          if (altval != NULL)
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 /* , */);
970       }
971       if (slice_dimen(mpl, list) == 0)
972          mpl_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 */
982             if (!is_symbol(mpl))
983             {  int lack = slice_dimen(mpl, list) + dim - j + 1;
984                xassert(tuple != NULL);
985                xassert(lack > 1);
986                mpl_error(mpl, "%d items missing in data group beginning wit"
987                   "h %s", lack, format_symbol(mpl, tuple->sym));
988             }
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 /* , */);
994          }
995          /* if the set is specified, add to it new n-tuple, which is a
996             copy of the subscript list just read */
997          if (set != NULL)
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 /* . */);
1007                continue;
1008             }
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);
1013                if (lack == 1)
1014                   mpl_error(mpl, "one item missing in data group beginning "
1015                      "with %s", format_symbol(mpl, tuple->sym));
1016                else
1017                   mpl_error(mpl, "%d items missing in data group beginning "
1018                      "with %s", lack, format_symbol(mpl, tuple->sym));
1019             }
1020             read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
1021                tuple));
1022             /* skip optional comma preceding the next value */
1023             if (col->next != NULL && mpl->token == T_COMMA)
1024                get_token(mpl /* , */);
1025          }
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 /* , */);
1032          }
1033       }
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);
1038       return;
1039 }
1040 
1041 /*----------------------------------------------------------------------
1042 -- parameter_data - read parameter data.
1043 --
1044 -- This routine reads parameter data using the syntax:
1045 --
1046 -- <parameter data> ::= param <default value> : <tabbing format> ;
1047 -- <parameter data> ::= param <parameter name> <default value>
1048 --                      <assignments> ;
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>
1059 --
1060 -- Commae in <assignments> are optional and may be omitted anywhere. */
1061 
parameter_data(MPL * mpl)1062 void parameter_data(MPL *mpl)
1063 {     PARAMETER *par;
1064       SYMBOL *altval = NULL;
1065       SLICE *slice;
1066       int tr = 0;
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             mpl_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             mpl_error(mpl, "colon missing where expected");
1079       }
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             mpl_error(mpl, "symbol, number, or semicolon missing where expe"
1094                "cted");
1095          get_token(mpl /* ; */);
1096          goto done;
1097       }
1098       /* in other cases there must be symbolic name of parameter, which
1099          follows the keyword 'param' */
1100       if (!is_symbol(mpl))
1101          mpl_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             mpl_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);
1113       }
1114       /* create initial fake slice of all asterisks */
1115       slice = fake_slice(mpl, par->dim);
1116       /* read zero or more data assignments */
1117       for (;;)
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 /* := */);
1124          }
1125          else if (mpl->token == T_LBRACKET)
1126          {  /* left bracket begins new slice; delete the current slice
1127                and read new one */
1128             delete_slice(mpl, slice);
1129             slice = read_slice(mpl, par->name, par->dim);
1130             /* each new slice resets the "transpose" indicator */
1131             tr = 0;
1132          }
1133          else if (is_symbol(mpl))
1134          {  /* number or symbol begins data in the plain format */
1135             plain_format(mpl, par, slice);
1136          }
1137          else if (mpl->token == T_COLON)
1138          {  /* colon begins data in the tabular format */
1139             if (par->dim == 0)
1140 err1:          mpl_error(mpl, "%s not a subscripted parameter",
1141                   par->name);
1142             if (slice_arity(mpl, slice) != 2)
1143 err2:          mpl_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);
1148          }
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:          mpl_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 */
1163             tr = 1;
1164             /* read parameter data in the tabular format */
1165             tabular_format(mpl, par, slice, tr);
1166          }
1167          else if (mpl->token == T_SEMICOLON)
1168          {  /* semicolon terminates the data block */
1169             get_token(mpl /* ; */);
1170             break;
1171          }
1172          else
1173             mpl_error(mpl, "syntax error in parameter data block");
1174       }
1175       /* delete the current slice */
1176       delete_slice(mpl, slice);
1177 done: return;
1178 }
1179 
1180 /*----------------------------------------------------------------------
1181 -- data_section - read data section.
1182 --
1183 -- This routine reads data section using the syntax:
1184 --
1185 -- <data section> ::= <empty>
1186 -- <data section> ::= <data section> <data block> ;
1187 -- <data block> ::= <set data>
1188 -- <data block> ::= <parameter data>
1189 --
1190 -- Reading data section is terminated by either the keyword 'end' or
1191 -- the end of file. */
1192 
data_section(MPL * mpl)1193 void data_section(MPL *mpl)
1194 {     while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
1195       {  if (is_literal(mpl, "set"))
1196             set_data(mpl);
1197          else if (is_literal(mpl, "param"))
1198             parameter_data(mpl);
1199          else
1200             mpl_error(mpl, "syntax error in data section");
1201       }
1202       return;
1203 }
1204 
1205 /* eof */
1206