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