evalue_read_from_file: don't modify var_list argument
[barvinok.git] / evalue_read.c
blob89e506069bbfaf71bab9e6aaad67eed9e704975f
1 #include <barvinok/util.h>
2 #include "evalue_read.h"
4 #define ALLOC(type) (type*)malloc(sizeof(type))
5 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
7 enum token_type { TOKEN_UNKNOWN = 256, TOKEN_VALUE, TOKEN_IDENT, TOKEN_GE,
8 TOKEN_NE, TOKEN_UNION, TOKEN_VARS };
10 struct token {
11 enum token_type type;
13 int line;
14 int col;
16 union {
17 Value v;
18 char *s;
19 } u;
22 static struct token *token_new(int line, int col)
24 struct token *tok = ALLOC(struct token);
25 tok->line = line;
26 tok->col = col;
27 return tok;
30 void token_free(struct token *tok)
32 if (tok->type == TOKEN_VALUE)
33 value_clear(tok->u.v);
34 else if (tok->type == TOKEN_IDENT)
35 free(tok->u.s);
36 free(tok);
39 struct stream {
40 FILE *file;
41 int line;
42 int col;
43 int eof;
45 char *buffer;
46 size_t size;
47 size_t len;
48 int c;
50 struct token *tokens[5];
51 int n_token;
54 static struct stream* stream_new(FILE *file)
56 int i;
57 struct stream *s = ALLOC(struct stream);
58 s->file = file;
59 s->size = 256;
60 s->buffer = (char*)malloc(s->size);
61 s->len = 0;
62 s->line = 1;
63 s->col = 0;
64 s->eof = 0;
65 s->c = -1;
66 for (i = 0; i < 5; ++i)
67 s->tokens[i] = NULL;
68 s->n_token = 0;
69 return s;
72 static void stream_free(struct stream *s)
74 free(s->buffer);
75 assert(s->n_token == 0);
76 free(s);
79 static int stream_getc(struct stream *s)
81 int c;
82 if (s->eof)
83 return -1;
84 c = fgetc(s->file);
85 if (c == -1)
86 s->eof = 1;
87 if (s->c != -1) {
88 if (s->c == '\n') {
89 s->line++;
90 s->col = 0;
91 } else
92 s->col++;
94 s->c = c;
95 return c;
98 static void stream_ungetc(struct stream *s, int c)
100 ungetc(c, s->file);
101 s->c = -1;
104 static void stream_push_char(struct stream *s, int c)
106 if (s->len >= s->size) {
107 s->size = (3*s->size)/2;
108 s->buffer = (char*)realloc(s->buffer, s->size);
110 s->buffer[s->len++] = c;
113 static struct token *stream_push_token(struct stream *s, struct token *tok)
115 assert(s->n_token < 5);
116 s->tokens[s->n_token++] = tok;
119 static struct token *stream_next_token(struct stream *s)
121 int c;
122 struct token *tok;
123 int line, col;
125 if (s->n_token)
126 return s->tokens[--s->n_token];
128 s->len = 0;
130 /* skip spaces */
131 while ((c = stream_getc(s)) != -1 && isspace(c))
132 /* nothing */
135 line = s->line;
136 col = s->col;
138 if (c == -1)
139 return NULL;
140 if (c == '(' ||
141 c == ')' ||
142 c == '+' ||
143 c == '/' ||
144 c == '*' ||
145 c == '^' ||
146 c == '=' ||
147 c == ',' ||
148 c == '_' ||
149 c == '[' ||
150 c == ']' ||
151 c == '{' ||
152 c == '}') {
153 tok = token_new(line, col);
154 tok->type = (enum token_type)c;
155 return tok;
157 if (c == '-' || isdigit(c)) {
158 tok = token_new(line, col);
159 tok->type = TOKEN_VALUE;
160 value_init(tok->u.v);
161 stream_push_char(s, c);
162 while ((c = stream_getc(s)) != -1 && isdigit(c))
163 stream_push_char(s, c);
164 if (c != -1)
165 stream_ungetc(s, c);
166 if (s->len == 1 && s->buffer[0] == '-')
167 value_set_si(tok->u.v, -1);
168 else {
169 stream_push_char(s, '\0');
170 mpz_set_str(tok->u.v, s->buffer, 0);
172 return tok;
174 if (c == '#' || isalpha(c)) {
175 tok = token_new(line, col);
176 stream_push_char(s, c);
177 while ((c = stream_getc(s)) != -1 && isalnum(c))
178 stream_push_char(s, c);
179 if (c != -1)
180 stream_ungetc(s, c);
181 stream_push_char(s, '\0');
182 if (!strcmp(s->buffer, "#variables")) {
183 tok->type = TOKEN_VARS;
184 } else if (s->buffer[0] == '#') {
185 tok->type = TOKEN_UNKNOWN;
186 } else if (!strcmp(s->buffer, "UNION")) {
187 tok->type = TOKEN_UNION;
188 } else {
189 tok->type = TOKEN_IDENT;
190 tok->u.s = strdup(s->buffer);
192 return tok;
194 if (c == '>') {
195 if ((c = stream_getc(s)) == '=') {
196 tok = token_new(line, col);
197 tok->type = TOKEN_GE;
198 return tok;
200 if (c != -1)
201 stream_ungetc(s, c);
203 if (c == '!') {
204 if ((c = stream_getc(s)) == '=') {
205 tok = token_new(line, col);
206 tok->type = TOKEN_NE;
207 return tok;
209 if (c != -1)
210 stream_ungetc(s, c);
213 tok = token_new(line, col);
214 tok->type = TOKEN_UNKNOWN;
215 return tok;
218 void stream_error(struct stream *s, struct token *tok, char *msg)
220 int line = tok ? tok->line : s->line;
221 int col = tok ? tok->col : s->col;
222 fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
223 if (tok) {
224 if (tok->type < 256)
225 fprintf(stderr, "got '%c'\n", tok->type);
229 struct parameter {
230 char *name;
231 int pos;
232 struct parameter *next;
235 struct parameter *parameter_new(char *name, int pos, struct parameter *next)
237 struct parameter *p = ALLOC(struct parameter);
238 p->name = strdup(name);
239 p->pos = pos;
240 p->next = next;
241 return p;
244 static int parameter_pos(struct parameter **p, const char *s, int len)
246 int pos = *p ? (*p)->pos+1 : 0;
247 struct parameter *q;
249 if (len == -1)
250 len = strlen(s);
251 for (q = *p; q; q = q->next) {
252 if (strncmp(q->name, s, len) == 0)
253 break;
255 if (q)
256 pos = q->pos;
257 else
258 *p = parameter_new(s, pos, *p);
259 return pos;
262 static int optional_power(struct stream *s)
264 int pow;
265 struct token *tok;
266 tok = stream_next_token(s);
267 if (!tok)
268 return 1;
269 if (tok->type != '^') {
270 stream_push_token(s, tok);
271 return 1;
273 token_free(tok);
274 tok = stream_next_token(s);
275 if (!tok || tok->type != TOKEN_VALUE) {
276 stream_error(s, tok, "expecting exponent");
277 if (tok)
278 stream_push_token(s, tok);
279 return 1;
281 pow = VALUE_TO_INT(tok->u.v);
282 token_free(tok);
283 return pow;
286 static evalue *evalue_read_factor(struct stream *s, struct parameter **p);
287 static evalue *evalue_read_term(struct stream *s, struct parameter **p);
289 static evalue *create_fract_like(struct stream *s, evalue *arg, enode_type type,
290 struct parameter **p)
292 evalue *e;
293 int pow;
294 pow = optional_power(s);
296 e = ALLOC(evalue);
297 value_init(e->d);
298 e->x.p = new_enode(type, pow+2, -1);
299 value_clear(e->x.p->arr[0].d);
300 e->x.p->arr[0] = *arg;
301 free(arg);
302 evalue_set_si(&e->x.p->arr[1+pow], 1, 1);
303 while (--pow >= 0)
304 evalue_set_si(&e->x.p->arr[1+pow], 0, 1);
306 return e;
309 static evalue *create_relation(evalue *arg, int ne)
311 evalue *e;
313 e = ALLOC(evalue);
314 value_init(e->d);
315 e->x.p = new_enode(relation, 2+ne, 0);
316 value_clear(e->x.p->arr[0].d);
317 e->x.p->arr[0] = *arg;
318 free(arg);
319 if (ne)
320 evalue_set_si(&e->x.p->arr[1], 0, 1);
321 evalue_set_si(&e->x.p->arr[1+ne], 1, 1);
323 return e;
326 static evalue *read_fract(struct stream *s, struct token *tok, struct parameter **p)
328 evalue *arg;
330 tok = stream_next_token(s);
331 assert(tok);
332 assert(tok->type == '{');
334 token_free(tok);
335 arg = evalue_read_term(s, p);
336 tok = stream_next_token(s);
337 if (!tok || tok->type != '}') {
338 stream_error(s, tok, "expecting \"}\"");
339 if (tok)
340 stream_push_token(s, tok);
341 } else
342 token_free(tok);
344 return create_fract_like(s, arg, fractional, p);
347 static evalue *read_periodic(struct stream *s, struct parameter **p)
349 evalue **list;
350 int len;
351 int n;
352 evalue *e = NULL;
354 struct token *tok;
355 tok = stream_next_token(s);
356 assert(tok && tok->type == '[');
357 token_free(tok);
359 len = 100;
360 list = (evalue **)malloc(len * sizeof(evalue *));
361 n = 0;
363 for (;;) {
364 evalue *e = evalue_read_term(s, p);
365 if (!e) {
366 stream_error(s, NULL, "missing argument or list element");
367 goto out;
369 if (n >= len) {
370 len = (3*len)/2;
371 list = (evalue **)realloc(list, len * sizeof(evalue *));
373 list[n++] = e;
375 tok = stream_next_token(s);
376 if (!tok) {
377 stream_error(s, NULL, "unexpected EOF");
378 goto out;
380 if (tok->type != ',')
381 break;
382 token_free(tok);
385 if (n == 1 && (tok->type == '=' || tok->type == TOKEN_NE)) {
386 int ne = tok->type == TOKEN_NE;
387 token_free(tok);
388 tok = stream_next_token(s);
389 if (!tok || tok->type != TOKEN_VALUE) {
390 stream_error(s, tok, "expecting \"0\"");
391 if (tok)
392 stream_push_token(s, tok);
393 goto out;
395 token_free(tok);
396 tok = stream_next_token(s);
397 if (!tok || tok->type != ']') {
398 stream_error(s, tok, "expecting \"]\"");
399 if (tok)
400 stream_push_token(s, tok);
401 goto out;
403 token_free(tok);
404 e = create_relation(list[0], ne);
405 n = 0;
406 goto out;
409 if (tok->type != ']') {
410 stream_error(s, tok, "expecting \"]\"");
411 stream_push_token(s, tok);
412 goto out;
415 token_free(tok);
417 tok = stream_next_token(s);
418 if (tok->type == '_') {
419 int pos;
420 token_free(tok);
421 tok = stream_next_token(s);
422 if (!tok || tok->type != TOKEN_IDENT) {
423 stream_error(s, tok, "expecting identifier");
424 if (tok)
425 stream_push_token(s, tok);
426 goto out;
428 e = ALLOC(evalue);
429 value_init(e->d);
430 pos = parameter_pos(p, tok->u.s, -1);
431 token_free(tok);
432 e->x.p = new_enode(periodic, n, pos+1);
433 while (--n >= 0) {
434 value_clear(e->x.p->arr[n].d);
435 e->x.p->arr[n] = *list[n];
436 free(list[n]);
438 } else if (n == 1) {
439 stream_push_token(s, tok);
440 e = create_fract_like(s, list[0], flooring, p);
441 n = 0;
442 } else {
443 stream_error(s, tok, "unexpected token");
444 stream_push_token(s, tok);
447 out:
448 while (--n >= 0) {
449 free_evalue_refs(list[n]);
450 free(list[n]);
452 free(list);
453 return e;
456 static evalue *evalue_read_factor(struct stream *s, struct parameter **p)
458 struct token *tok;
459 evalue *e = NULL;
461 tok = stream_next_token(s);
462 if (!tok)
463 return NULL;
465 if (tok->type == '(') {
466 token_free(tok);
467 e = evalue_read_term(s, p);
468 tok = stream_next_token(s);
469 if (!tok || tok->type != ')') {
470 stream_error(s, tok, "expecting \")\"");
471 if (tok)
472 stream_push_token(s, tok);
473 } else
474 token_free(tok);
475 } else if (tok->type == TOKEN_VALUE) {
476 e = ALLOC(evalue);
477 value_init(e->d);
478 value_set_si(e->d, 1);
479 value_init(e->x.n);
480 value_assign(e->x.n, tok->u.v);
481 token_free(tok);
482 tok = stream_next_token(s);
483 if (tok && tok->type == '/') {
484 token_free(tok);
485 tok = stream_next_token(s);
486 if (!tok || tok->type != TOKEN_VALUE) {
487 stream_error(s, tok, "expecting denominator");
488 if (tok)
489 stream_push_token(s, tok);
490 return NULL;
492 value_assign(e->d, tok->u.v);
493 token_free(tok);
494 } else if (tok)
495 stream_push_token(s, tok);
496 } else if (tok->type == TOKEN_IDENT) {
497 int pos = parameter_pos(p, tok->u.s, -1);
498 int pow = optional_power(s);
499 token_free(tok);
500 e = ALLOC(evalue);
501 value_init(e->d);
502 e->x.p = new_enode(polynomial, pow+1, pos+1);
503 evalue_set_si(&e->x.p->arr[pow], 1, 1);
504 while (--pow >= 0)
505 evalue_set_si(&e->x.p->arr[pow], 0, 1);
506 } else if (tok->type == '[') {
507 stream_push_token(s, tok);
508 e = read_periodic(s, p);
509 } else if (tok->type == '{') {
510 stream_push_token(s, tok);
511 e = read_fract(s, tok, p);
514 tok = stream_next_token(s);
515 if (tok && tok->type == '*') {
516 evalue *e2;
517 token_free(tok);
518 e2 = evalue_read_factor(s, p);
519 if (!e2) {
520 stream_error(s, NULL, "unexpected EOF");
521 return NULL;
523 emul(e2, e);
524 free_evalue_refs(e2);
525 free(e2);
526 } else if (tok)
527 stream_push_token(s, tok);
529 return e;
532 static evalue *evalue_read_term(struct stream *s, struct parameter **p)
534 struct token *tok;
535 evalue *e = NULL;
537 e = evalue_read_factor(s, p);
538 if (!e)
539 return NULL;
541 tok = stream_next_token(s);
542 if (!tok)
543 return e;
545 if (tok->type == '+') {
546 evalue *e2;
547 token_free(tok);
548 e2 = evalue_read_term(s, p);
549 if (!e2) {
550 stream_error(s, NULL, "unexpected EOF");
551 return NULL;
553 eadd(e2, e);
554 free_evalue_refs(e2);
555 free(e2);
556 } else
557 stream_push_token(s, tok);
559 return e;
562 struct constraint {
563 int type;
564 Vector *v;
565 struct constraint *next;
566 struct constraint *union_next;
569 static struct constraint *constraint_new()
571 struct constraint *c = ALLOC(struct constraint);
572 c->type = -1;
573 c->v = Vector_Alloc(16);
574 c->next = NULL;
575 c->union_next = NULL;
576 return c;
579 static void constraint_free(struct constraint *c)
581 while (c) {
582 struct constraint *next = c->next ? c->next : c->union_next;
583 Vector_Free(c->v);
584 free(c);
585 c = next;
589 static void constraint_extend(struct constraint *c, int pos)
591 Vector *v;
592 if (pos < c->v->Size)
593 return;
595 v = Vector_Alloc((3*c->v->Size)/2);
596 Vector_Copy(c->v->p, v->p, c->v->Size);
597 Vector_Free(c->v);
598 c->v = v;
601 static int evalue_read_constraint(struct stream *s, struct parameter **p,
602 struct constraint **constraints,
603 struct constraint *union_next)
605 struct token *tok;
606 struct constraint *c = NULL;
608 while ((tok = stream_next_token(s))) {
609 struct token *tok2;
610 int pos;
611 if (tok->type == '+')
612 token_free(tok);
613 else if (tok->type == TOKEN_IDENT) {
614 if (!c)
615 c = constraint_new();
616 pos = parameter_pos(p, tok->u.s, -1);
617 constraint_extend(c, 1+pos);
618 value_set_si(c->v->p[1+pos], 1);
619 token_free(tok);
620 } else if (tok->type == TOKEN_VALUE) {
621 if (!c)
622 c = constraint_new();
623 tok2 = stream_next_token(s);
624 if (tok2 && tok2->type == TOKEN_IDENT) {
625 pos = parameter_pos(p, tok2->u.s, -1);
626 constraint_extend(c, 1+pos);
627 value_assign(c->v->p[1+pos], tok->u.v);
628 token_free(tok);
629 token_free(tok2);
630 } else {
631 if (tok2)
632 stream_push_token(s, tok2);
633 value_assign(c->v->p[0], tok->u.v);
634 token_free(tok);
636 } else if (tok->type == TOKEN_GE || tok->type == '=') {
637 int type = tok->type == TOKEN_GE;
638 token_free(tok);
639 tok = stream_next_token(s);
640 if (!tok || tok->type != TOKEN_VALUE || value_notzero_p(tok->u.v)) {
641 stream_error(s, tok, "expecting \"0\"");
642 if (tok)
643 stream_push_token(s, tok);
644 *constraints = NULL;
645 } else {
646 c->type = type;
647 c->next = *constraints;
648 c->union_next = union_next;
649 *constraints = c;
650 token_free(tok);
652 break;
653 } else {
654 if (!c)
655 stream_push_token(s, tok);
656 else {
657 stream_error(s, tok, "unexpected token");
658 *constraints = NULL;
660 return 0;
663 return tok != NULL;
666 static struct constraint *evalue_read_domain(struct stream *s, struct parameter **p,
667 unsigned MaxRays)
669 struct constraint *constraints = NULL;
670 struct constraint *union_next = NULL;
671 struct token *tok;
672 int line;
674 tok = stream_next_token(s);
675 if (!tok)
676 return NULL;
677 stream_push_token(s, tok);
679 line = tok->line;
680 while (evalue_read_constraint(s, p, &constraints, union_next)) {
681 tok = stream_next_token(s);
682 if (tok) {
683 if (tok->type == TOKEN_UNION) {
684 token_free(tok);
685 tok = stream_next_token(s);
686 if (!tok) {
687 stream_error(s, NULL, "unexpected EOF");
688 return constraints;
690 stream_push_token(s, tok);
691 union_next = constraints;
692 constraints = NULL;
693 } else {
694 union_next = NULL;
695 stream_push_token(s, tok);
696 /* empty line separates domain from evalue */
697 if (tok->line > line+1)
698 break;
700 line = tok->line;
703 return constraints;
706 struct section {
707 struct constraint *constraints;
708 evalue *e;
709 struct section *next;
712 static char **extract_parameters(struct parameter *p, unsigned *nparam)
714 int i;
715 char **params;
717 *nparam = p ? p->pos+1 : 0;
718 params = ALLOCN(char *, *nparam);
719 for (i = 0; i < *nparam; ++i) {
720 struct parameter *next = p->next;
721 params[p->pos] = p->name;
722 free(p);
723 p = next;
725 return params;
728 static Polyhedron *constraints2domain(struct constraint *constraints,
729 unsigned nparam, unsigned MaxRays)
731 Polyhedron *D;
732 Matrix *M;
733 int n;
734 struct constraint *c;
735 struct constraint *union_next = NULL;
737 for (n = 0, c = constraints; c; ++n, c = c->next)
739 M = Matrix_Alloc(n, 1+nparam+1);
740 while (--n >= 0) {
741 struct constraint *next = constraints->next;
742 union_next = constraints->union_next;
743 Vector_Copy(constraints->v->p+1, M->p[n]+1, nparam);
744 if (constraints->type)
745 value_set_si(M->p[n][0], 1);
746 value_assign(M->p[n][1+nparam], constraints->v->p[0]);
747 constraints->next = NULL;
748 constraints->union_next = NULL;
749 constraint_free(constraints);
750 constraints = next;
752 D = Constraints2Polyhedron(M, MaxRays);
753 Matrix_Free(M);
755 if (union_next)
756 D = DomainConcat(D, constraints2domain(union_next, nparam, MaxRays));
757 return D;
760 static evalue *evalue_read_partition(struct stream *s, struct parameter *p,
761 char ***ppp,
762 unsigned *nparam, unsigned MaxRays)
764 struct section *part = NULL;
765 struct constraint *constraints;
766 evalue *e = NULL;
767 int m = 0;
769 while ((constraints = evalue_read_domain(s, &p, MaxRays))) {
770 evalue *e = evalue_read_term(s, &p);
771 if (!e) {
772 stream_error(s, NULL, "missing evalue");
773 break;
775 struct section *sect = ALLOC(struct section);
776 sect->constraints = constraints;
777 sect->e = e;
778 sect->next = part;
779 part = sect;
780 ++m;
783 if (part) {
784 Polyhedron *D;
785 int j;
787 *ppp = extract_parameters(p, nparam);
788 e = ALLOC(evalue);
789 value_init(e->d);
790 e->x.p = new_enode(partition, 2*m, *nparam);
792 for (j = 0; j < m; ++j) {
793 int n;
794 struct section *next = part->next;
795 constraints = part->constraints;
796 D = constraints2domain(part->constraints, *nparam, MaxRays);
797 EVALUE_SET_DOMAIN(e->x.p->arr[2*j], D);
798 value_clear(e->x.p->arr[2*j+1].d);
799 e->x.p->arr[2*j+1] = *part->e;
800 free(part->e);
801 free(part);
802 part = next;
805 return e;
808 static evalue *evalue_read(struct stream *s, const char *var_list, char ***ppp,
809 unsigned *nvar, unsigned *nparam, unsigned MaxRays)
811 struct token *tok;
812 evalue *e;
813 struct parameter *p = NULL;
814 char *next;
815 int nv;
817 if (var_list) {
818 while ((next = strchr(var_list, ','))) {
819 if (next > var_list)
820 parameter_pos(&p, var_list, next-var_list);
821 var_list = next+1;
823 if (strlen(var_list) > 0)
824 parameter_pos(&p, var_list, -1);
825 nv = p ? p->pos+1 : 0;
826 } else
827 nv = -1;
829 if (!(tok = stream_next_token(s)))
830 return NULL;
832 if (tok->type == TOKEN_VARS) {
833 token_free(tok);
834 for (;;) {
835 tok = stream_next_token(s);
836 if (!tok || tok->type != TOKEN_IDENT) {
837 stream_error(s, tok, "expecting identifier");
838 break;
840 if (nv == -1)
841 parameter_pos(&p, tok->u.s, -1);
842 token_free(tok);
843 tok = stream_next_token(s);
844 if (!tok || tok->type != ',')
845 break;
846 token_free(tok);
848 if (!tok)
849 return NULL;
850 if (nv = -1)
851 nv = p ? p->pos+1 : 0;
854 if (tok->type == '(') {
855 stream_push_token(s, tok);
856 e = evalue_read_term(s, &p);
857 *ppp = extract_parameters(p, nparam);
858 } else if (tok->type == TOKEN_VALUE) {
859 struct token *tok2 = stream_next_token(s);
860 if (tok2)
861 stream_push_token(s, tok2);
862 stream_push_token(s, tok);
863 if (tok2 && (tok2->type == TOKEN_IDENT || tok2->type == TOKEN_GE))
864 e = evalue_read_partition(s, p, ppp, nparam, MaxRays);
865 else {
866 e = evalue_read_term(s, &p);
867 *ppp = extract_parameters(p, nparam);
869 } else if (tok->type == TOKEN_IDENT) {
870 stream_push_token(s, tok);
871 e = evalue_read_partition(s, p, ppp, nparam, MaxRays);
872 } else {
873 stream_error(s, tok, "unexpected token");
874 *nparam = nv == -1 ? 0 : nv;
875 e = NULL;
877 if (nv == -1)
878 *nvar = *nparam;
879 else
880 *nvar = nv;
881 *nparam -= *nvar;
882 return e;
885 evalue *evalue_read_from_file(FILE *in, const char *var_list, char ***ppp,
886 unsigned *nvar, unsigned *nparam, unsigned MaxRays)
888 evalue *e;
889 struct stream *s = stream_new(in);
890 e = evalue_read(s, var_list, ppp, nvar, nparam, MaxRays);
891 stream_free(s);
892 return e;