isl_schedule.c: add_inter_constraints: avoid invalid access on error
[isl.git] / isl_stream.c
blob68f6e522495c409339dac6dbdcca2fb500436a63
1 /*
2 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege, K.U.Leuven, Departement
7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8 */
10 #include <ctype.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <isl/ctx.h>
14 #include <isl_stream_private.h>
15 #include <isl/map.h>
16 #include <isl/aff.h>
18 struct isl_keyword {
19 char *name;
20 enum isl_token_type type;
23 static int same_name(const void *entry, const void *val)
25 const struct isl_keyword *keyword = (const struct isl_keyword *)entry;
27 return !strcmp(keyword->name, val);
30 enum isl_token_type isl_stream_register_keyword(struct isl_stream *s,
31 const char *name)
33 struct isl_hash_table_entry *entry;
34 struct isl_keyword *keyword;
35 uint32_t name_hash;
37 if (!s->keywords) {
38 s->keywords = isl_hash_table_alloc(s->ctx, 10);
39 if (!s->keywords)
40 return ISL_TOKEN_ERROR;
41 s->next_type = ISL_TOKEN_LAST;
44 name_hash = isl_hash_string(isl_hash_init(), name);
46 entry = isl_hash_table_find(s->ctx, s->keywords, name_hash,
47 same_name, name, 1);
48 if (!entry)
49 return ISL_TOKEN_ERROR;
50 if (entry->data) {
51 keyword = entry->data;
52 return keyword->type;
55 keyword = isl_calloc_type(s->ctx, struct isl_keyword);
56 if (!keyword)
57 return ISL_TOKEN_ERROR;
58 keyword->type = s->next_type++;
59 keyword->name = strdup(name);
60 if (!keyword->name) {
61 free(keyword);
62 return ISL_TOKEN_ERROR;
64 entry->data = keyword;
66 return keyword->type;
69 struct isl_token *isl_token_new(isl_ctx *ctx,
70 int line, int col, unsigned on_new_line)
72 struct isl_token *tok = isl_alloc_type(ctx, struct isl_token);
73 if (!tok)
74 return NULL;
75 tok->line = line;
76 tok->col = col;
77 tok->on_new_line = on_new_line;
78 tok->is_keyword = 0;
79 tok->u.s = NULL;
80 return tok;
83 void isl_token_free(struct isl_token *tok)
85 if (!tok)
86 return;
87 if (tok->type == ISL_TOKEN_VALUE)
88 isl_int_clear(tok->u.v);
89 else if (tok->type == ISL_TOKEN_MAP)
90 isl_map_free(tok->u.map);
91 else if (tok->type == ISL_TOKEN_AFF)
92 isl_pw_aff_free(tok->u.pwaff);
93 else
94 free(tok->u.s);
95 free(tok);
98 void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg)
100 int line = tok ? tok->line : s->line;
101 int col = tok ? tok->col : s->col;
102 fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
103 if (tok) {
104 if (tok->type < 256)
105 fprintf(stderr, "got '%c'\n", tok->type);
106 else if (tok->type == ISL_TOKEN_IDENT)
107 fprintf(stderr, "got ident '%s'\n", tok->u.s);
108 else if (tok->is_keyword)
109 fprintf(stderr, "got keyword '%s'\n", tok->u.s);
110 else if (tok->type == ISL_TOKEN_VALUE) {
111 fprintf(stderr, "got value '");
112 isl_int_print(stderr, tok->u.v, 0);
113 fprintf(stderr, "'\n");
114 } else if (tok->type == ISL_TOKEN_MAP) {
115 isl_printer *p;
116 fprintf(stderr, "got map '");
117 p = isl_printer_to_file(s->ctx, stderr);
118 p = isl_printer_print_map(p, tok->u.map);
119 isl_printer_free(p);
120 fprintf(stderr, "'\n");
121 } else if (tok->type == ISL_TOKEN_AFF) {
122 isl_printer *p;
123 fprintf(stderr, "got affine expression '");
124 p = isl_printer_to_file(s->ctx, stderr);
125 p = isl_printer_print_pw_aff(p, tok->u.pwaff);
126 isl_printer_free(p);
127 fprintf(stderr, "'\n");
128 } else if (tok->u.s)
129 fprintf(stderr, "got token '%s'\n", tok->u.s);
130 else
131 fprintf(stderr, "got token type %d\n", tok->type);
135 static struct isl_stream* isl_stream_new(struct isl_ctx *ctx)
137 int i;
138 struct isl_stream *s = isl_alloc_type(ctx, struct isl_stream);
139 if (!s)
140 return NULL;
141 s->ctx = ctx;
142 isl_ctx_ref(s->ctx);
143 s->file = NULL;
144 s->str = NULL;
145 s->len = 0;
146 s->line = 1;
147 s->col = 0;
148 s->eof = 0;
149 s->c = -1;
150 s->n_un = 0;
151 for (i = 0; i < 5; ++i)
152 s->tokens[i] = NULL;
153 s->n_token = 0;
154 s->keywords = NULL;
155 s->size = 256;
156 s->buffer = isl_alloc_array(ctx, char, s->size);
157 if (!s->buffer)
158 goto error;
159 return s;
160 error:
161 isl_stream_free(s);
162 return NULL;
165 struct isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file)
167 struct isl_stream *s = isl_stream_new(ctx);
168 if (!s)
169 return NULL;
170 s->file = file;
171 return s;
174 struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str)
176 struct isl_stream *s;
177 if (!str)
178 return NULL;
179 s = isl_stream_new(ctx);
180 if (!s)
181 return NULL;
182 s->str = str;
183 return s;
186 static int stream_getc(struct isl_stream *s)
188 int c;
189 if (s->eof)
190 return -1;
191 if (s->n_un)
192 return s->c = s->un[--s->n_un];
193 if (s->file)
194 c = fgetc(s->file);
195 else {
196 c = *s->str++;
197 if (c == '\0')
198 c = -1;
200 if (c == -1)
201 s->eof = 1;
202 if (!s->eof) {
203 if (s->c == '\n') {
204 s->line++;
205 s->col = 0;
206 } else
207 s->col++;
209 s->c = c;
210 return c;
213 static void isl_stream_ungetc(struct isl_stream *s, int c)
215 isl_assert(s->ctx, s->n_un < 5, return);
216 s->un[s->n_un++] = c;
217 s->c = -1;
220 static int isl_stream_getc(struct isl_stream *s)
222 int c;
224 do {
225 c = stream_getc(s);
226 if (c != '\\')
227 return c;
228 c = stream_getc(s);
229 } while (c == '\n');
231 isl_stream_ungetc(s, c);
233 return '\\';
236 static int isl_stream_push_char(struct isl_stream *s, int c)
238 if (s->len >= s->size) {
239 char *buffer;
240 s->size = (3*s->size)/2;
241 buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size);
242 if (!buffer)
243 return -1;
244 s->buffer = buffer;
246 s->buffer[s->len++] = c;
247 return 0;
250 void isl_stream_push_token(struct isl_stream *s, struct isl_token *tok)
252 isl_assert(s->ctx, s->n_token < 5, return);
253 s->tokens[s->n_token++] = tok;
256 static enum isl_token_type check_keywords(struct isl_stream *s)
258 struct isl_hash_table_entry *entry;
259 struct isl_keyword *keyword;
260 uint32_t name_hash;
262 if (!strcasecmp(s->buffer, "exists"))
263 return ISL_TOKEN_EXISTS;
264 if (!strcasecmp(s->buffer, "and"))
265 return ISL_TOKEN_AND;
266 if (!strcasecmp(s->buffer, "or"))
267 return ISL_TOKEN_OR;
268 if (!strcasecmp(s->buffer, "not"))
269 return ISL_TOKEN_NOT;
270 if (!strcasecmp(s->buffer, "infty"))
271 return ISL_TOKEN_INFTY;
272 if (!strcasecmp(s->buffer, "infinity"))
273 return ISL_TOKEN_INFTY;
274 if (!strcasecmp(s->buffer, "NaN"))
275 return ISL_TOKEN_NAN;
276 if (!strcasecmp(s->buffer, "min"))
277 return ISL_TOKEN_MIN;
278 if (!strcasecmp(s->buffer, "max"))
279 return ISL_TOKEN_MAX;
280 if (!strcasecmp(s->buffer, "rat"))
281 return ISL_TOKEN_RAT;
282 if (!strcasecmp(s->buffer, "true"))
283 return ISL_TOKEN_TRUE;
284 if (!strcasecmp(s->buffer, "false"))
285 return ISL_TOKEN_FALSE;
286 if (!strcasecmp(s->buffer, "ceild"))
287 return ISL_TOKEN_CEILD;
288 if (!strcasecmp(s->buffer, "floord"))
289 return ISL_TOKEN_FLOORD;
290 if (!strcasecmp(s->buffer, "mod"))
291 return ISL_TOKEN_MOD;
293 if (!s->keywords)
294 return ISL_TOKEN_IDENT;
296 name_hash = isl_hash_string(isl_hash_init(), s->buffer);
297 entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,
298 s->buffer, 0);
299 if (entry) {
300 keyword = entry->data;
301 return keyword->type;
304 return ISL_TOKEN_IDENT;
307 int isl_stream_skip_line(struct isl_stream *s)
309 int c;
311 while ((c = isl_stream_getc(s)) != -1 && c != '\n')
312 /* nothing */
315 return c == -1 ? -1 : 0;
318 static struct isl_token *next_token(struct isl_stream *s, int same_line)
320 int c;
321 struct isl_token *tok = NULL;
322 int line, col;
323 int old_line = s->line;
325 if (s->n_token) {
326 if (same_line && s->tokens[s->n_token - 1]->on_new_line)
327 return NULL;
328 return s->tokens[--s->n_token];
331 if (same_line && s->c == '\n')
332 return NULL;
334 s->len = 0;
336 /* skip spaces and comment lines */
337 while ((c = isl_stream_getc(s)) != -1) {
338 if (c == '#') {
339 if (isl_stream_skip_line(s) < 0)
340 break;
341 c = '\n';
342 if (same_line)
343 break;
344 } else if (!isspace(c) || (same_line && c == '\n'))
345 break;
348 line = s->line;
349 col = s->col;
351 if (c == -1 || (same_line && c == '\n'))
352 return NULL;
353 if (c == '(' ||
354 c == ')' ||
355 c == '+' ||
356 c == '*' ||
357 c == '%' ||
358 c == '?' ||
359 c == '^' ||
360 c == '@' ||
361 c == '$' ||
362 c == ',' ||
363 c == '.' ||
364 c == ';' ||
365 c == '[' ||
366 c == ']' ||
367 c == '{' ||
368 c == '}') {
369 tok = isl_token_new(s->ctx, line, col, old_line != line);
370 if (!tok)
371 return NULL;
372 tok->type = (enum isl_token_type)c;
373 return tok;
375 if (c == '-') {
376 int c;
377 if ((c = isl_stream_getc(s)) == '>') {
378 tok = isl_token_new(s->ctx, line, col, old_line != line);
379 if (!tok)
380 return NULL;
381 tok->u.s = strdup("->");
382 tok->type = ISL_TOKEN_TO;
383 return tok;
385 if (c != -1)
386 isl_stream_ungetc(s, c);
387 if (!isdigit(c)) {
388 tok = isl_token_new(s->ctx, line, col, old_line != line);
389 if (!tok)
390 return NULL;
391 tok->type = (enum isl_token_type) '-';
392 return tok;
395 if (c == '-' || isdigit(c)) {
396 int minus = c == '-';
397 tok = isl_token_new(s->ctx, line, col, old_line != line);
398 if (!tok)
399 return NULL;
400 tok->type = ISL_TOKEN_VALUE;
401 isl_int_init(tok->u.v);
402 if (isl_stream_push_char(s, c))
403 goto error;
404 while ((c = isl_stream_getc(s)) != -1 && isdigit(c))
405 if (isl_stream_push_char(s, c))
406 goto error;
407 if (c != -1)
408 isl_stream_ungetc(s, c);
409 isl_stream_push_char(s, '\0');
410 isl_int_read(tok->u.v, s->buffer);
411 if (minus && isl_int_is_zero(tok->u.v)) {
412 tok->col++;
413 tok->on_new_line = 0;
414 isl_stream_push_token(s, tok);
415 tok = isl_token_new(s->ctx, line, col, old_line != line);
416 if (!tok)
417 return NULL;
418 tok->type = (enum isl_token_type) '-';
420 return tok;
422 if (isalpha(c) || c == '_') {
423 tok = isl_token_new(s->ctx, line, col, old_line != line);
424 if (!tok)
425 return NULL;
426 isl_stream_push_char(s, c);
427 while ((c = isl_stream_getc(s)) != -1 &&
428 (isalnum(c) || c == '_'))
429 isl_stream_push_char(s, c);
430 if (c != -1)
431 isl_stream_ungetc(s, c);
432 while ((c = isl_stream_getc(s)) != -1 && c == '\'')
433 isl_stream_push_char(s, c);
434 if (c != -1)
435 isl_stream_ungetc(s, c);
436 isl_stream_push_char(s, '\0');
437 tok->type = check_keywords(s);
438 if (tok->type != ISL_TOKEN_IDENT)
439 tok->is_keyword = 1;
440 tok->u.s = strdup(s->buffer);
441 if (!tok->u.s)
442 goto error;
443 return tok;
445 if (c == '"') {
446 tok = isl_token_new(s->ctx, line, col, old_line != line);
447 if (!tok)
448 return NULL;
449 tok->type = ISL_TOKEN_STRING;
450 tok->u.s = NULL;
451 while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')
452 isl_stream_push_char(s, c);
453 if (c != '"') {
454 isl_stream_error(s, NULL, "unterminated string");
455 goto error;
457 isl_stream_push_char(s, '\0');
458 tok->u.s = strdup(s->buffer);
459 return tok;
461 if (c == '=') {
462 int c;
463 tok = isl_token_new(s->ctx, line, col, old_line != line);
464 if (!tok)
465 return NULL;
466 if ((c = isl_stream_getc(s)) == '=') {
467 tok->u.s = strdup("==");
468 tok->type = ISL_TOKEN_EQ_EQ;
469 return tok;
471 if (c != -1)
472 isl_stream_ungetc(s, c);
473 tok->type = (enum isl_token_type) '=';
474 return tok;
476 if (c == ':') {
477 int c;
478 tok = isl_token_new(s->ctx, line, col, old_line != line);
479 if (!tok)
480 return NULL;
481 if ((c = isl_stream_getc(s)) == '=') {
482 tok->u.s = strdup(":=");
483 tok->type = ISL_TOKEN_DEF;
484 return tok;
486 if (c != -1)
487 isl_stream_ungetc(s, c);
488 tok->type = (enum isl_token_type) ':';
489 return tok;
491 if (c == '>') {
492 int c;
493 tok = isl_token_new(s->ctx, line, col, old_line != line);
494 if (!tok)
495 return NULL;
496 if ((c = isl_stream_getc(s)) == '=') {
497 tok->u.s = strdup(">=");
498 tok->type = ISL_TOKEN_GE;
499 return tok;
500 } else if (c == '>') {
501 if ((c = isl_stream_getc(s)) == '=') {
502 tok->u.s = strdup(">>=");
503 tok->type = ISL_TOKEN_LEX_GE;
504 return tok;
506 tok->u.s = strdup(">>");
507 tok->type = ISL_TOKEN_LEX_GT;
508 } else {
509 tok->u.s = strdup(">");
510 tok->type = ISL_TOKEN_GT;
512 if (c != -1)
513 isl_stream_ungetc(s, c);
514 return tok;
516 if (c == '<') {
517 int c;
518 tok = isl_token_new(s->ctx, line, col, old_line != line);
519 if (!tok)
520 return NULL;
521 if ((c = isl_stream_getc(s)) == '=') {
522 tok->u.s = strdup("<=");
523 tok->type = ISL_TOKEN_LE;
524 return tok;
525 } else if (c == '<') {
526 if ((c = isl_stream_getc(s)) == '=') {
527 tok->u.s = strdup("<<=");
528 tok->type = ISL_TOKEN_LEX_LE;
529 return tok;
531 tok->u.s = strdup("<<");
532 tok->type = ISL_TOKEN_LEX_LT;
533 } else {
534 tok->u.s = strdup("<");
535 tok->type = ISL_TOKEN_LT;
537 if (c != -1)
538 isl_stream_ungetc(s, c);
539 return tok;
541 if (c == '&') {
542 tok = isl_token_new(s->ctx, line, col, old_line != line);
543 if (!tok)
544 return NULL;
545 tok->type = ISL_TOKEN_AND;
546 if ((c = isl_stream_getc(s)) != '&' && c != -1) {
547 tok->u.s = strdup("&");
548 isl_stream_ungetc(s, c);
549 } else
550 tok->u.s = strdup("&&");
551 return tok;
553 if (c == '|') {
554 tok = isl_token_new(s->ctx, line, col, old_line != line);
555 if (!tok)
556 return NULL;
557 tok->type = ISL_TOKEN_OR;
558 if ((c = isl_stream_getc(s)) != '|' && c != -1) {
559 tok->u.s = strdup("|");
560 isl_stream_ungetc(s, c);
561 } else
562 tok->u.s = strdup("||");
563 return tok;
565 if (c == '/') {
566 tok = isl_token_new(s->ctx, line, col, old_line != line);
567 if (!tok)
568 return NULL;
569 if ((c = isl_stream_getc(s)) != '\\' && c != -1) {
570 tok->type = (enum isl_token_type) '/';
571 isl_stream_ungetc(s, c);
572 } else {
573 tok->u.s = strdup("/\\");
574 tok->type = ISL_TOKEN_AND;
576 return tok;
578 if (c == '\\') {
579 tok = isl_token_new(s->ctx, line, col, old_line != line);
580 if (!tok)
581 return NULL;
582 if ((c = isl_stream_getc(s)) != '/' && c != -1) {
583 tok->type = (enum isl_token_type) '\\';
584 isl_stream_ungetc(s, c);
585 } else {
586 tok->u.s = strdup("\\/");
587 tok->type = ISL_TOKEN_OR;
589 return tok;
591 if (c == '!') {
592 tok = isl_token_new(s->ctx, line, col, old_line != line);
593 if (!tok)
594 return NULL;
595 if ((c = isl_stream_getc(s)) == '=') {
596 tok->u.s = strdup("!=");
597 tok->type = ISL_TOKEN_NE;
598 return tok;
599 } else {
600 tok->type = ISL_TOKEN_NOT;
601 tok->u.s = strdup("!");
603 if (c != -1)
604 isl_stream_ungetc(s, c);
605 return tok;
608 tok = isl_token_new(s->ctx, line, col, old_line != line);
609 if (!tok)
610 return NULL;
611 tok->type = ISL_TOKEN_UNKNOWN;
612 return tok;
613 error:
614 isl_token_free(tok);
615 return NULL;
618 struct isl_token *isl_stream_next_token(struct isl_stream *s)
620 return next_token(s, 0);
623 struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s)
625 return next_token(s, 1);
628 int isl_stream_eat_if_available(struct isl_stream *s, int type)
630 struct isl_token *tok;
632 tok = isl_stream_next_token(s);
633 if (!tok)
634 return 0;
635 if (tok->type == type) {
636 isl_token_free(tok);
637 return 1;
639 isl_stream_push_token(s, tok);
640 return 0;
643 int isl_stream_next_token_is(struct isl_stream *s, int type)
645 struct isl_token *tok;
646 int r;
648 tok = isl_stream_next_token(s);
649 if (!tok)
650 return 0;
651 r = tok->type == type;
652 isl_stream_push_token(s, tok);
653 return r;
656 char *isl_stream_read_ident_if_available(struct isl_stream *s)
658 struct isl_token *tok;
660 tok = isl_stream_next_token(s);
661 if (!tok)
662 return NULL;
663 if (tok->type == ISL_TOKEN_IDENT) {
664 char *ident = strdup(tok->u.s);
665 isl_token_free(tok);
666 return ident;
668 isl_stream_push_token(s, tok);
669 return NULL;
672 int isl_stream_eat(struct isl_stream *s, int type)
674 struct isl_token *tok;
676 tok = isl_stream_next_token(s);
677 if (!tok)
678 return -1;
679 if (tok->type == type) {
680 isl_token_free(tok);
681 return 0;
683 isl_stream_error(s, tok, "expecting other token");
684 isl_stream_push_token(s, tok);
685 return -1;
688 int isl_stream_is_empty(struct isl_stream *s)
690 struct isl_token *tok;
692 tok = isl_stream_next_token(s);
694 if (!tok)
695 return 1;
697 isl_stream_push_token(s, tok);
698 return 0;
701 static int free_keyword(void **p, void *user)
703 struct isl_keyword *keyword = *p;
705 free(keyword->name);
706 free(keyword);
708 return 0;
711 void isl_stream_flush_tokens(struct isl_stream *s)
713 int i;
715 if (!s)
716 return;
717 for (i = 0; i < s->n_token; ++i)
718 isl_token_free(s->tokens[i]);
719 s->n_token = 0;
722 void isl_stream_free(struct isl_stream *s)
724 if (!s)
725 return;
726 free(s->buffer);
727 if (s->n_token != 0) {
728 struct isl_token *tok = isl_stream_next_token(s);
729 isl_stream_error(s, tok, "unexpected token");
730 isl_token_free(tok);
732 if (s->keywords) {
733 isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);
734 isl_hash_table_free(s->ctx, s->keywords);
736 isl_ctx_deref(s->ctx);
737 free(s);