lemon-project-template-glpk

annotate deps/glpk/src/glpmpl01.c @ 11:4fc6ad2fb8a6

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