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