src/glpmpl02.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     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 
    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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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          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             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             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                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                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 
   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          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);
   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 
   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                   error(mpl, "one item missing in data group beginning "
   357                      "with %s", format_symbol(mpl, with));
   358                else
   359                   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 
   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             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                   error(mpl, "one item missing in data group beginning "
   448                      "with %s", format_symbol(mpl, row));
   449                else
   450                   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 
   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          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             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                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                error(mpl, "syntax error in subscript list");
   543          }
   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 /* ] */);
   549       }
   550       else
   551       {  /* subscript list is not specified */
   552          if (set->dim != 0)
   553             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          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:          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:          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             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 
   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          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);
   653       if (par->data)
   654          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 
   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          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 
   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          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                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 
   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                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          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 
   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             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                   error(mpl, "one item missing in data group beginning "
   869                      "with %s", format_symbol(mpl, row));
   870                else
   871                   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 
   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                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
   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             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             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);
   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          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                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                   error(mpl, "one item missing in data group beginning "
  1015                      "with %s", format_symbol(mpl, tuple->sym));
  1016                else
  1017                   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 
  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             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");
  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             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          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);
  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:          error(mpl, "%s not a subscripted parameter",
  1141                   par->name);
  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);
  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:          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             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 
  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             error(mpl, "syntax error in data section");
  1201       }
  1202       return;
  1203 }
  1204 
  1205 /* eof */