src/glpmpl01.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

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