isl_input.c: accept_div: accept floor/ceil of rational affine expression
[platform/upstream/isl.git] / isl_stream.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the MIT license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
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>
17 #include <isl_val_private.h>
18
19 struct isl_keyword {
20         char                    *name;
21         enum isl_token_type     type;
22 };
23
24 static int same_name(const void *entry, const void *val)
25 {
26         const struct isl_keyword *keyword = (const struct isl_keyword *)entry;
27
28         return !strcmp(keyword->name, val);
29 }
30
31 enum isl_token_type isl_stream_register_keyword(struct isl_stream *s,
32         const char *name)
33 {
34         struct isl_hash_table_entry *entry;
35         struct isl_keyword *keyword;
36         uint32_t name_hash;
37
38         if (!s->keywords) {
39                 s->keywords = isl_hash_table_alloc(s->ctx, 10);
40                 if (!s->keywords)
41                         return ISL_TOKEN_ERROR;
42                 s->next_type = ISL_TOKEN_LAST;
43         }
44
45         name_hash = isl_hash_string(isl_hash_init(), name);
46
47         entry = isl_hash_table_find(s->ctx, s->keywords, name_hash,
48                                         same_name, name, 1);
49         if (!entry)
50                 return ISL_TOKEN_ERROR;
51         if (entry->data) {
52                 keyword = entry->data;
53                 return keyword->type;
54         }
55
56         keyword = isl_calloc_type(s->ctx, struct isl_keyword);
57         if (!keyword)
58                 return ISL_TOKEN_ERROR;
59         keyword->type = s->next_type++;
60         keyword->name = strdup(name);
61         if (!keyword->name) {
62                 free(keyword);
63                 return ISL_TOKEN_ERROR;
64         }
65         entry->data = keyword;
66
67         return keyword->type;
68 }
69
70 struct isl_token *isl_token_new(isl_ctx *ctx,
71         int line, int col, unsigned on_new_line)
72 {
73         struct isl_token *tok = isl_alloc_type(ctx, struct isl_token);
74         if (!tok)
75                 return NULL;
76         tok->line = line;
77         tok->col = col;
78         tok->on_new_line = on_new_line;
79         tok->is_keyword = 0;
80         tok->u.s = NULL;
81         return tok;
82 }
83
84 /* Return the type of "tok".
85  */
86 int isl_token_get_type(struct isl_token *tok)
87 {
88         return tok ? tok->type : ISL_TOKEN_ERROR;
89 }
90
91 /* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
92  */
93 __isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok)
94 {
95         if (!tok)
96                 return NULL;
97         if (tok->type != ISL_TOKEN_VALUE)
98                 isl_die(ctx, isl_error_invalid, "not a value token",
99                         return NULL);
100
101         return isl_val_int_from_isl_int(ctx, tok->u.v);
102 }
103
104 /* Given a token of type ISL_TOKEN_STRING, return the string it represents.
105  */
106 __isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok)
107 {
108         if (!tok)
109                 return NULL;
110         if (tok->type != ISL_TOKEN_STRING)
111                 isl_die(ctx, isl_error_invalid, "not a string token",
112                         return NULL);
113
114         return strdup(tok->u.s);
115 }
116
117 void isl_token_free(struct isl_token *tok)
118 {
119         if (!tok)
120                 return;
121         if (tok->type == ISL_TOKEN_VALUE)
122                 isl_int_clear(tok->u.v);
123         else if (tok->type == ISL_TOKEN_MAP)
124                 isl_map_free(tok->u.map);
125         else if (tok->type == ISL_TOKEN_AFF)
126                 isl_pw_aff_free(tok->u.pwaff);
127         else
128                 free(tok->u.s);
129         free(tok);
130 }
131
132 void isl_stream_error(struct isl_stream *s, struct isl_token *tok, char *msg)
133 {
134         int line = tok ? tok->line : s->line;
135         int col = tok ? tok->col : s->col;
136         fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);
137         if (tok) {
138                 if (tok->type < 256)
139                         fprintf(stderr, "got '%c'\n", tok->type);
140                 else if (tok->type == ISL_TOKEN_IDENT)
141                         fprintf(stderr, "got ident '%s'\n", tok->u.s);
142                 else if (tok->is_keyword)
143                         fprintf(stderr, "got keyword '%s'\n", tok->u.s);
144                 else if (tok->type == ISL_TOKEN_VALUE) {
145                         fprintf(stderr, "got value '");
146                         isl_int_print(stderr, tok->u.v, 0);
147                         fprintf(stderr, "'\n");
148                 } else if (tok->type == ISL_TOKEN_MAP) {
149                         isl_printer *p;
150                         fprintf(stderr, "got map '");
151                         p = isl_printer_to_file(s->ctx, stderr);
152                         p = isl_printer_print_map(p, tok->u.map);
153                         isl_printer_free(p);
154                         fprintf(stderr, "'\n");
155                 } else if (tok->type == ISL_TOKEN_AFF) {
156                         isl_printer *p;
157                         fprintf(stderr, "got affine expression '");
158                         p = isl_printer_to_file(s->ctx, stderr);
159                         p = isl_printer_print_pw_aff(p, tok->u.pwaff);
160                         isl_printer_free(p);
161                         fprintf(stderr, "'\n");
162                 } else if (tok->u.s)
163                         fprintf(stderr, "got token '%s'\n", tok->u.s);
164                 else
165                         fprintf(stderr, "got token type %d\n", tok->type);
166         }
167 }
168
169 static struct isl_stream* isl_stream_new(struct isl_ctx *ctx)
170 {
171         int i;
172         struct isl_stream *s = isl_alloc_type(ctx, struct isl_stream);
173         if (!s)
174                 return NULL;
175         s->ctx = ctx;
176         isl_ctx_ref(s->ctx);
177         s->file = NULL;
178         s->str = NULL;
179         s->len = 0;
180         s->line = 1;
181         s->col = 0;
182         s->eof = 0;
183         s->c = -1;
184         s->n_un = 0;
185         for (i = 0; i < 5; ++i)
186                 s->tokens[i] = NULL;
187         s->n_token = 0;
188         s->keywords = NULL;
189         s->size = 256;
190         s->buffer = isl_alloc_array(ctx, char, s->size);
191         if (!s->buffer)
192                 goto error;
193         return s;
194 error:
195         isl_stream_free(s);
196         return NULL;
197 }
198
199 struct isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file)
200 {
201         struct isl_stream *s = isl_stream_new(ctx);
202         if (!s)
203                 return NULL;
204         s->file = file;
205         return s;
206 }
207
208 struct isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str)
209 {
210         struct isl_stream *s;
211         if (!str)
212                 return NULL;
213         s = isl_stream_new(ctx);
214         if (!s)
215                 return NULL;
216         s->str = str;
217         return s;
218 }
219
220 static int stream_getc(struct isl_stream *s)
221 {
222         int c;
223         if (s->eof)
224                 return -1;
225         if (s->n_un)
226                 return s->c = s->un[--s->n_un];
227         if (s->file)
228                 c = fgetc(s->file);
229         else {
230                 c = *s->str++;
231                 if (c == '\0')
232                         c = -1;
233         }
234         if (c == -1)
235                 s->eof = 1;
236         if (!s->eof) {
237                 if (s->c == '\n') {
238                         s->line++;
239                         s->col = 0;
240                 } else
241                         s->col++;
242         }
243         s->c = c;
244         return c;
245 }
246
247 static void isl_stream_ungetc(struct isl_stream *s, int c)
248 {
249         isl_assert(s->ctx, s->n_un < 5, return);
250         s->un[s->n_un++] = c;
251         s->c = -1;
252 }
253
254 static int isl_stream_getc(struct isl_stream *s)
255 {
256         int c;
257
258         do {
259                 c = stream_getc(s);
260                 if (c != '\\')
261                         return c;
262                 c = stream_getc(s);
263         } while (c == '\n');
264
265         isl_stream_ungetc(s, c);
266
267         return '\\';
268 }
269
270 static int isl_stream_push_char(struct isl_stream *s, int c)
271 {
272         if (s->len >= s->size) {
273                 char *buffer;
274                 s->size = (3*s->size)/2;
275                 buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size);
276                 if (!buffer)
277                         return -1;
278                 s->buffer = buffer;
279         }
280         s->buffer[s->len++] = c;
281         return 0;
282 }
283
284 void isl_stream_push_token(struct isl_stream *s, struct isl_token *tok)
285 {
286         isl_assert(s->ctx, s->n_token < 5, return);
287         s->tokens[s->n_token++] = tok;
288 }
289
290 static enum isl_token_type check_keywords(struct isl_stream *s)
291 {
292         struct isl_hash_table_entry *entry;
293         struct isl_keyword *keyword;
294         uint32_t name_hash;
295
296         if (!strcasecmp(s->buffer, "exists"))
297                 return ISL_TOKEN_EXISTS;
298         if (!strcasecmp(s->buffer, "and"))
299                 return ISL_TOKEN_AND;
300         if (!strcasecmp(s->buffer, "or"))
301                 return ISL_TOKEN_OR;
302         if (!strcasecmp(s->buffer, "not"))
303                 return ISL_TOKEN_NOT;
304         if (!strcasecmp(s->buffer, "infty"))
305                 return ISL_TOKEN_INFTY;
306         if (!strcasecmp(s->buffer, "infinity"))
307                 return ISL_TOKEN_INFTY;
308         if (!strcasecmp(s->buffer, "NaN"))
309                 return ISL_TOKEN_NAN;
310         if (!strcasecmp(s->buffer, "min"))
311                 return ISL_TOKEN_MIN;
312         if (!strcasecmp(s->buffer, "max"))
313                 return ISL_TOKEN_MAX;
314         if (!strcasecmp(s->buffer, "rat"))
315                 return ISL_TOKEN_RAT;
316         if (!strcasecmp(s->buffer, "true"))
317                 return ISL_TOKEN_TRUE;
318         if (!strcasecmp(s->buffer, "false"))
319                 return ISL_TOKEN_FALSE;
320         if (!strcasecmp(s->buffer, "ceild"))
321                 return ISL_TOKEN_CEILD;
322         if (!strcasecmp(s->buffer, "floord"))
323                 return ISL_TOKEN_FLOORD;
324         if (!strcasecmp(s->buffer, "mod"))
325                 return ISL_TOKEN_MOD;
326         if (!strcasecmp(s->buffer, "ceil"))
327                 return ISL_TOKEN_CEIL;
328         if (!strcasecmp(s->buffer, "floor"))
329                 return ISL_TOKEN_FLOOR;
330
331         if (!s->keywords)
332                 return ISL_TOKEN_IDENT;
333
334         name_hash = isl_hash_string(isl_hash_init(), s->buffer);
335         entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,
336                                         s->buffer, 0);
337         if (entry) {
338                 keyword = entry->data;
339                 return keyword->type;
340         }
341
342         return ISL_TOKEN_IDENT;
343 }
344
345 int isl_stream_skip_line(struct isl_stream *s)
346 {
347         int c;
348
349         while ((c = isl_stream_getc(s)) != -1 && c != '\n')
350                 /* nothing */
351                 ;
352
353         return c == -1 ? -1 : 0;
354 }
355
356 static struct isl_token *next_token(struct isl_stream *s, int same_line)
357 {
358         int c;
359         struct isl_token *tok = NULL;
360         int line, col;
361         int old_line = s->line;
362
363         if (s->n_token) {
364                 if (same_line && s->tokens[s->n_token - 1]->on_new_line)
365                         return NULL;
366                 return s->tokens[--s->n_token];
367         }
368
369         if (same_line && s->c == '\n')
370                 return NULL;
371
372         s->len = 0;
373
374         /* skip spaces and comment lines */
375         while ((c = isl_stream_getc(s)) != -1) {
376                 if (c == '#') {
377                         if (isl_stream_skip_line(s) < 0)
378                                 break;
379                         c = '\n';
380                         if (same_line)
381                                 break;
382                 } else if (!isspace(c) || (same_line && c == '\n'))
383                         break;
384         }
385
386         line = s->line;
387         col = s->col;
388
389         if (c == -1 || (same_line && c == '\n'))
390                 return NULL;
391         if (c == '(' ||
392             c == ')' ||
393             c == '+' ||
394             c == '*' ||
395             c == '%' ||
396             c == '?' ||
397             c == '^' ||
398             c == '@' ||
399             c == '$' ||
400             c == ',' ||
401             c == '.' ||
402             c == ';' ||
403             c == '[' ||
404             c == ']' ||
405             c == '{' ||
406             c == '}') {
407                 tok = isl_token_new(s->ctx, line, col, old_line != line);
408                 if (!tok)
409                         return NULL;
410                 tok->type = (enum isl_token_type)c;
411                 return tok;
412         }
413         if (c == '-') {
414                 int c;
415                 if ((c = isl_stream_getc(s)) == '>') {
416                         tok = isl_token_new(s->ctx, line, col, old_line != line);
417                         if (!tok)
418                                 return NULL;
419                         tok->u.s = strdup("->");
420                         tok->type = ISL_TOKEN_TO;
421                         return tok;
422                 }
423                 if (c != -1)
424                         isl_stream_ungetc(s, c);
425                 if (!isdigit(c)) {
426                         tok = isl_token_new(s->ctx, line, col, old_line != line);
427                         if (!tok)
428                                 return NULL;
429                         tok->type = (enum isl_token_type) '-';
430                         return tok;
431                 }
432         }
433         if (c == '-' || isdigit(c)) {
434                 int minus = c == '-';
435                 tok = isl_token_new(s->ctx, line, col, old_line != line);
436                 if (!tok)
437                         return NULL;
438                 tok->type = ISL_TOKEN_VALUE;
439                 isl_int_init(tok->u.v);
440                 if (isl_stream_push_char(s, c))
441                         goto error;
442                 while ((c = isl_stream_getc(s)) != -1 && isdigit(c))
443                         if (isl_stream_push_char(s, c))
444                                 goto error;
445                 if (c != -1)
446                         isl_stream_ungetc(s, c);
447                 isl_stream_push_char(s, '\0');
448                 isl_int_read(tok->u.v, s->buffer);
449                 if (minus && isl_int_is_zero(tok->u.v)) {
450                         tok->col++;
451                         tok->on_new_line = 0;
452                         isl_stream_push_token(s, tok);
453                         tok = isl_token_new(s->ctx, line, col, old_line != line);
454                         if (!tok)
455                                 return NULL;
456                         tok->type = (enum isl_token_type) '-';
457                 }
458                 return tok;
459         }
460         if (isalpha(c) || c == '_') {
461                 tok = isl_token_new(s->ctx, line, col, old_line != line);
462                 if (!tok)
463                         return NULL;
464                 isl_stream_push_char(s, c);
465                 while ((c = isl_stream_getc(s)) != -1 &&
466                                 (isalnum(c) || c == '_'))
467                         isl_stream_push_char(s, c);
468                 if (c != -1)
469                         isl_stream_ungetc(s, c);
470                 while ((c = isl_stream_getc(s)) != -1 && c == '\'')
471                         isl_stream_push_char(s, c);
472                 if (c != -1)
473                         isl_stream_ungetc(s, c);
474                 isl_stream_push_char(s, '\0');
475                 tok->type = check_keywords(s);
476                 if (tok->type != ISL_TOKEN_IDENT)
477                         tok->is_keyword = 1;
478                 tok->u.s = strdup(s->buffer);
479                 if (!tok->u.s)
480                         goto error;
481                 return tok;
482         }
483         if (c == '"') {
484                 tok = isl_token_new(s->ctx, line, col, old_line != line);
485                 if (!tok)
486                         return NULL;
487                 tok->type = ISL_TOKEN_STRING;
488                 tok->u.s = NULL;
489                 while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')
490                         isl_stream_push_char(s, c);
491                 if (c != '"') {
492                         isl_stream_error(s, NULL, "unterminated string");
493                         goto error;
494                 }
495                 isl_stream_push_char(s, '\0');
496                 tok->u.s = strdup(s->buffer);
497                 return tok;
498         }
499         if (c == '=') {
500                 int c;
501                 tok = isl_token_new(s->ctx, line, col, old_line != line);
502                 if (!tok)
503                         return NULL;
504                 if ((c = isl_stream_getc(s)) == '=') {
505                         tok->u.s = strdup("==");
506                         tok->type = ISL_TOKEN_EQ_EQ;
507                         return tok;
508                 }
509                 if (c != -1)
510                         isl_stream_ungetc(s, c);
511                 tok->type = (enum isl_token_type) '=';
512                 return tok;
513         }
514         if (c == ':') {
515                 int c;
516                 tok = isl_token_new(s->ctx, line, col, old_line != line);
517                 if (!tok)
518                         return NULL;
519                 if ((c = isl_stream_getc(s)) == '=') {
520                         tok->u.s = strdup(":=");
521                         tok->type = ISL_TOKEN_DEF;
522                         return tok;
523                 }
524                 if (c != -1)
525                         isl_stream_ungetc(s, c);
526                 tok->type = (enum isl_token_type) ':';
527                 return tok;
528         }
529         if (c == '>') {
530                 int c;
531                 tok = isl_token_new(s->ctx, line, col, old_line != line);
532                 if (!tok)
533                         return NULL;
534                 if ((c = isl_stream_getc(s)) == '=') {
535                         tok->u.s = strdup(">=");
536                         tok->type = ISL_TOKEN_GE;
537                         return tok;
538                 } else if (c == '>') {
539                         if ((c = isl_stream_getc(s)) == '=') {
540                                 tok->u.s = strdup(">>=");
541                                 tok->type = ISL_TOKEN_LEX_GE;
542                                 return tok;
543                         }
544                         tok->u.s = strdup(">>");
545                         tok->type = ISL_TOKEN_LEX_GT;
546                 } else {
547                         tok->u.s = strdup(">");
548                         tok->type = ISL_TOKEN_GT;
549                 }
550                 if (c != -1)
551                         isl_stream_ungetc(s, c);
552                 return tok;
553         }
554         if (c == '<') {
555                 int c;
556                 tok = isl_token_new(s->ctx, line, col, old_line != line);
557                 if (!tok)
558                         return NULL;
559                 if ((c = isl_stream_getc(s)) == '=') {
560                         tok->u.s = strdup("<=");
561                         tok->type = ISL_TOKEN_LE;
562                         return tok;
563                 } else if (c == '<') {
564                         if ((c = isl_stream_getc(s)) == '=') {
565                                 tok->u.s = strdup("<<=");
566                                 tok->type = ISL_TOKEN_LEX_LE;
567                                 return tok;
568                         }
569                         tok->u.s = strdup("<<");
570                         tok->type = ISL_TOKEN_LEX_LT;
571                 } else {
572                         tok->u.s = strdup("<");
573                         tok->type = ISL_TOKEN_LT;
574                 }
575                 if (c != -1)
576                         isl_stream_ungetc(s, c);
577                 return tok;
578         }
579         if (c == '&') {
580                 tok = isl_token_new(s->ctx, line, col, old_line != line);
581                 if (!tok)
582                         return NULL;
583                 tok->type = ISL_TOKEN_AND;
584                 if ((c = isl_stream_getc(s)) != '&' && c != -1) {
585                         tok->u.s = strdup("&");
586                         isl_stream_ungetc(s, c);
587                 } else
588                         tok->u.s = strdup("&&");
589                 return tok;
590         }
591         if (c == '|') {
592                 tok = isl_token_new(s->ctx, line, col, old_line != line);
593                 if (!tok)
594                         return NULL;
595                 tok->type = ISL_TOKEN_OR;
596                 if ((c = isl_stream_getc(s)) != '|' && c != -1) {
597                         tok->u.s = strdup("|");
598                         isl_stream_ungetc(s, c);
599                 } else
600                         tok->u.s = strdup("||");
601                 return tok;
602         }
603         if (c == '/') {
604                 tok = isl_token_new(s->ctx, line, col, old_line != line);
605                 if (!tok)
606                         return NULL;
607                 if ((c = isl_stream_getc(s)) != '\\' && c != -1) {
608                         tok->type = (enum isl_token_type) '/';
609                         isl_stream_ungetc(s, c);
610                 } else {
611                         tok->u.s = strdup("/\\");
612                         tok->type = ISL_TOKEN_AND;
613                 }
614                 return tok;
615         }
616         if (c == '\\') {
617                 tok = isl_token_new(s->ctx, line, col, old_line != line);
618                 if (!tok)
619                         return NULL;
620                 if ((c = isl_stream_getc(s)) != '/' && c != -1) {
621                         tok->type = (enum isl_token_type) '\\';
622                         isl_stream_ungetc(s, c);
623                 } else {
624                         tok->u.s = strdup("\\/");
625                         tok->type = ISL_TOKEN_OR;
626                 }
627                 return tok;
628         }
629         if (c == '!') {
630                 tok = isl_token_new(s->ctx, line, col, old_line != line);
631                 if (!tok)
632                         return NULL;
633                 if ((c = isl_stream_getc(s)) == '=') {
634                         tok->u.s = strdup("!=");
635                         tok->type = ISL_TOKEN_NE;
636                         return tok;
637                 } else {
638                         tok->type = ISL_TOKEN_NOT;
639                         tok->u.s = strdup("!");
640                 }
641                 if (c != -1)
642                         isl_stream_ungetc(s, c);
643                 return tok;
644         }
645
646         tok = isl_token_new(s->ctx, line, col, old_line != line);
647         if (!tok)
648                 return NULL;
649         tok->type = ISL_TOKEN_UNKNOWN;
650         return tok;
651 error:
652         isl_token_free(tok);
653         return NULL;
654 }
655
656 struct isl_token *isl_stream_next_token(struct isl_stream *s)
657 {
658         return next_token(s, 0);
659 }
660
661 struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s)
662 {
663         return next_token(s, 1);
664 }
665
666 int isl_stream_eat_if_available(struct isl_stream *s, int type)
667 {
668         struct isl_token *tok;
669
670         tok = isl_stream_next_token(s);
671         if (!tok)
672                 return 0;
673         if (tok->type == type) {
674                 isl_token_free(tok);
675                 return 1;
676         }
677         isl_stream_push_token(s, tok);
678         return 0;
679 }
680
681 int isl_stream_next_token_is(struct isl_stream *s, int type)
682 {
683         struct isl_token *tok;
684         int r;
685
686         tok = isl_stream_next_token(s);
687         if (!tok)
688                 return 0;
689         r = tok->type == type;
690         isl_stream_push_token(s, tok);
691         return r;
692 }
693
694 char *isl_stream_read_ident_if_available(struct isl_stream *s)
695 {
696         struct isl_token *tok;
697
698         tok = isl_stream_next_token(s);
699         if (!tok)
700                 return NULL;
701         if (tok->type == ISL_TOKEN_IDENT) {
702                 char *ident = strdup(tok->u.s);
703                 isl_token_free(tok);
704                 return ident;
705         }
706         isl_stream_push_token(s, tok);
707         return NULL;
708 }
709
710 int isl_stream_eat(struct isl_stream *s, int type)
711 {
712         struct isl_token *tok;
713
714         tok = isl_stream_next_token(s);
715         if (!tok)
716                 return -1;
717         if (tok->type == type) {
718                 isl_token_free(tok);
719                 return 0;
720         }
721         isl_stream_error(s, tok, "expecting other token");
722         isl_stream_push_token(s, tok);
723         return -1;
724 }
725
726 int isl_stream_is_empty(struct isl_stream *s)
727 {
728         struct isl_token *tok;
729
730         tok = isl_stream_next_token(s);
731
732         if (!tok)
733                 return 1;
734
735         isl_stream_push_token(s, tok);
736         return 0;
737 }
738
739 static int free_keyword(void **p, void *user)
740 {
741         struct isl_keyword *keyword = *p;
742
743         free(keyword->name);
744         free(keyword);
745
746         return 0;
747 }
748
749 void isl_stream_flush_tokens(struct isl_stream *s)
750 {
751         int i;
752
753         if (!s)
754                 return;
755         for (i = 0; i < s->n_token; ++i)
756                 isl_token_free(s->tokens[i]);
757         s->n_token = 0;
758 }
759
760 void isl_stream_free(struct isl_stream *s)
761 {
762         if (!s)
763                 return;
764         free(s->buffer);
765         if (s->n_token != 0) {
766                 struct isl_token *tok = isl_stream_next_token(s);
767                 isl_stream_error(s, tok, "unexpected token");
768                 isl_token_free(tok);
769         }
770         if (s->keywords) {
771                 isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);
772                 isl_hash_table_free(s->ctx, s->keywords);
773         }
774         isl_ctx_deref(s->ctx);
775         free(s);
776 }