temporarily make isl_val_int_from_isl_int available
[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
327         if (!s->keywords)
328                 return ISL_TOKEN_IDENT;
329
330         name_hash = isl_hash_string(isl_hash_init(), s->buffer);
331         entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,
332                                         s->buffer, 0);
333         if (entry) {
334                 keyword = entry->data;
335                 return keyword->type;
336         }
337
338         return ISL_TOKEN_IDENT;
339 }
340
341 int isl_stream_skip_line(struct isl_stream *s)
342 {
343         int c;
344
345         while ((c = isl_stream_getc(s)) != -1 && c != '\n')
346                 /* nothing */
347                 ;
348
349         return c == -1 ? -1 : 0;
350 }
351
352 static struct isl_token *next_token(struct isl_stream *s, int same_line)
353 {
354         int c;
355         struct isl_token *tok = NULL;
356         int line, col;
357         int old_line = s->line;
358
359         if (s->n_token) {
360                 if (same_line && s->tokens[s->n_token - 1]->on_new_line)
361                         return NULL;
362                 return s->tokens[--s->n_token];
363         }
364
365         if (same_line && s->c == '\n')
366                 return NULL;
367
368         s->len = 0;
369
370         /* skip spaces and comment lines */
371         while ((c = isl_stream_getc(s)) != -1) {
372                 if (c == '#') {
373                         if (isl_stream_skip_line(s) < 0)
374                                 break;
375                         c = '\n';
376                         if (same_line)
377                                 break;
378                 } else if (!isspace(c) || (same_line && c == '\n'))
379                         break;
380         }
381
382         line = s->line;
383         col = s->col;
384
385         if (c == -1 || (same_line && c == '\n'))
386                 return NULL;
387         if (c == '(' ||
388             c == ')' ||
389             c == '+' ||
390             c == '*' ||
391             c == '%' ||
392             c == '?' ||
393             c == '^' ||
394             c == '@' ||
395             c == '$' ||
396             c == ',' ||
397             c == '.' ||
398             c == ';' ||
399             c == '[' ||
400             c == ']' ||
401             c == '{' ||
402             c == '}') {
403                 tok = isl_token_new(s->ctx, line, col, old_line != line);
404                 if (!tok)
405                         return NULL;
406                 tok->type = (enum isl_token_type)c;
407                 return tok;
408         }
409         if (c == '-') {
410                 int c;
411                 if ((c = isl_stream_getc(s)) == '>') {
412                         tok = isl_token_new(s->ctx, line, col, old_line != line);
413                         if (!tok)
414                                 return NULL;
415                         tok->u.s = strdup("->");
416                         tok->type = ISL_TOKEN_TO;
417                         return tok;
418                 }
419                 if (c != -1)
420                         isl_stream_ungetc(s, c);
421                 if (!isdigit(c)) {
422                         tok = isl_token_new(s->ctx, line, col, old_line != line);
423                         if (!tok)
424                                 return NULL;
425                         tok->type = (enum isl_token_type) '-';
426                         return tok;
427                 }
428         }
429         if (c == '-' || isdigit(c)) {
430                 int minus = c == '-';
431                 tok = isl_token_new(s->ctx, line, col, old_line != line);
432                 if (!tok)
433                         return NULL;
434                 tok->type = ISL_TOKEN_VALUE;
435                 isl_int_init(tok->u.v);
436                 if (isl_stream_push_char(s, c))
437                         goto error;
438                 while ((c = isl_stream_getc(s)) != -1 && isdigit(c))
439                         if (isl_stream_push_char(s, c))
440                                 goto error;
441                 if (c != -1)
442                         isl_stream_ungetc(s, c);
443                 isl_stream_push_char(s, '\0');
444                 isl_int_read(tok->u.v, s->buffer);
445                 if (minus && isl_int_is_zero(tok->u.v)) {
446                         tok->col++;
447                         tok->on_new_line = 0;
448                         isl_stream_push_token(s, tok);
449                         tok = isl_token_new(s->ctx, line, col, old_line != line);
450                         if (!tok)
451                                 return NULL;
452                         tok->type = (enum isl_token_type) '-';
453                 }
454                 return tok;
455         }
456         if (isalpha(c) || c == '_') {
457                 tok = isl_token_new(s->ctx, line, col, old_line != line);
458                 if (!tok)
459                         return NULL;
460                 isl_stream_push_char(s, c);
461                 while ((c = isl_stream_getc(s)) != -1 &&
462                                 (isalnum(c) || c == '_'))
463                         isl_stream_push_char(s, c);
464                 if (c != -1)
465                         isl_stream_ungetc(s, c);
466                 while ((c = isl_stream_getc(s)) != -1 && c == '\'')
467                         isl_stream_push_char(s, c);
468                 if (c != -1)
469                         isl_stream_ungetc(s, c);
470                 isl_stream_push_char(s, '\0');
471                 tok->type = check_keywords(s);
472                 if (tok->type != ISL_TOKEN_IDENT)
473                         tok->is_keyword = 1;
474                 tok->u.s = strdup(s->buffer);
475                 if (!tok->u.s)
476                         goto error;
477                 return tok;
478         }
479         if (c == '"') {
480                 tok = isl_token_new(s->ctx, line, col, old_line != line);
481                 if (!tok)
482                         return NULL;
483                 tok->type = ISL_TOKEN_STRING;
484                 tok->u.s = NULL;
485                 while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')
486                         isl_stream_push_char(s, c);
487                 if (c != '"') {
488                         isl_stream_error(s, NULL, "unterminated string");
489                         goto error;
490                 }
491                 isl_stream_push_char(s, '\0');
492                 tok->u.s = strdup(s->buffer);
493                 return tok;
494         }
495         if (c == '=') {
496                 int c;
497                 tok = isl_token_new(s->ctx, line, col, old_line != line);
498                 if (!tok)
499                         return NULL;
500                 if ((c = isl_stream_getc(s)) == '=') {
501                         tok->u.s = strdup("==");
502                         tok->type = ISL_TOKEN_EQ_EQ;
503                         return tok;
504                 }
505                 if (c != -1)
506                         isl_stream_ungetc(s, c);
507                 tok->type = (enum isl_token_type) '=';
508                 return tok;
509         }
510         if (c == ':') {
511                 int c;
512                 tok = isl_token_new(s->ctx, line, col, old_line != line);
513                 if (!tok)
514                         return NULL;
515                 if ((c = isl_stream_getc(s)) == '=') {
516                         tok->u.s = strdup(":=");
517                         tok->type = ISL_TOKEN_DEF;
518                         return tok;
519                 }
520                 if (c != -1)
521                         isl_stream_ungetc(s, c);
522                 tok->type = (enum isl_token_type) ':';
523                 return tok;
524         }
525         if (c == '>') {
526                 int c;
527                 tok = isl_token_new(s->ctx, line, col, old_line != line);
528                 if (!tok)
529                         return NULL;
530                 if ((c = isl_stream_getc(s)) == '=') {
531                         tok->u.s = strdup(">=");
532                         tok->type = ISL_TOKEN_GE;
533                         return tok;
534                 } else if (c == '>') {
535                         if ((c = isl_stream_getc(s)) == '=') {
536                                 tok->u.s = strdup(">>=");
537                                 tok->type = ISL_TOKEN_LEX_GE;
538                                 return tok;
539                         }
540                         tok->u.s = strdup(">>");
541                         tok->type = ISL_TOKEN_LEX_GT;
542                 } else {
543                         tok->u.s = strdup(">");
544                         tok->type = ISL_TOKEN_GT;
545                 }
546                 if (c != -1)
547                         isl_stream_ungetc(s, c);
548                 return tok;
549         }
550         if (c == '<') {
551                 int c;
552                 tok = isl_token_new(s->ctx, line, col, old_line != line);
553                 if (!tok)
554                         return NULL;
555                 if ((c = isl_stream_getc(s)) == '=') {
556                         tok->u.s = strdup("<=");
557                         tok->type = ISL_TOKEN_LE;
558                         return tok;
559                 } else if (c == '<') {
560                         if ((c = isl_stream_getc(s)) == '=') {
561                                 tok->u.s = strdup("<<=");
562                                 tok->type = ISL_TOKEN_LEX_LE;
563                                 return tok;
564                         }
565                         tok->u.s = strdup("<<");
566                         tok->type = ISL_TOKEN_LEX_LT;
567                 } else {
568                         tok->u.s = strdup("<");
569                         tok->type = ISL_TOKEN_LT;
570                 }
571                 if (c != -1)
572                         isl_stream_ungetc(s, c);
573                 return tok;
574         }
575         if (c == '&') {
576                 tok = isl_token_new(s->ctx, line, col, old_line != line);
577                 if (!tok)
578                         return NULL;
579                 tok->type = ISL_TOKEN_AND;
580                 if ((c = isl_stream_getc(s)) != '&' && c != -1) {
581                         tok->u.s = strdup("&");
582                         isl_stream_ungetc(s, c);
583                 } else
584                         tok->u.s = strdup("&&");
585                 return tok;
586         }
587         if (c == '|') {
588                 tok = isl_token_new(s->ctx, line, col, old_line != line);
589                 if (!tok)
590                         return NULL;
591                 tok->type = ISL_TOKEN_OR;
592                 if ((c = isl_stream_getc(s)) != '|' && c != -1) {
593                         tok->u.s = strdup("|");
594                         isl_stream_ungetc(s, c);
595                 } else
596                         tok->u.s = strdup("||");
597                 return tok;
598         }
599         if (c == '/') {
600                 tok = isl_token_new(s->ctx, line, col, old_line != line);
601                 if (!tok)
602                         return NULL;
603                 if ((c = isl_stream_getc(s)) != '\\' && c != -1) {
604                         tok->type = (enum isl_token_type) '/';
605                         isl_stream_ungetc(s, c);
606                 } else {
607                         tok->u.s = strdup("/\\");
608                         tok->type = ISL_TOKEN_AND;
609                 }
610                 return tok;
611         }
612         if (c == '\\') {
613                 tok = isl_token_new(s->ctx, line, col, old_line != line);
614                 if (!tok)
615                         return NULL;
616                 if ((c = isl_stream_getc(s)) != '/' && c != -1) {
617                         tok->type = (enum isl_token_type) '\\';
618                         isl_stream_ungetc(s, c);
619                 } else {
620                         tok->u.s = strdup("\\/");
621                         tok->type = ISL_TOKEN_OR;
622                 }
623                 return tok;
624         }
625         if (c == '!') {
626                 tok = isl_token_new(s->ctx, line, col, old_line != line);
627                 if (!tok)
628                         return NULL;
629                 if ((c = isl_stream_getc(s)) == '=') {
630                         tok->u.s = strdup("!=");
631                         tok->type = ISL_TOKEN_NE;
632                         return tok;
633                 } else {
634                         tok->type = ISL_TOKEN_NOT;
635                         tok->u.s = strdup("!");
636                 }
637                 if (c != -1)
638                         isl_stream_ungetc(s, c);
639                 return tok;
640         }
641
642         tok = isl_token_new(s->ctx, line, col, old_line != line);
643         if (!tok)
644                 return NULL;
645         tok->type = ISL_TOKEN_UNKNOWN;
646         return tok;
647 error:
648         isl_token_free(tok);
649         return NULL;
650 }
651
652 struct isl_token *isl_stream_next_token(struct isl_stream *s)
653 {
654         return next_token(s, 0);
655 }
656
657 struct isl_token *isl_stream_next_token_on_same_line(struct isl_stream *s)
658 {
659         return next_token(s, 1);
660 }
661
662 int isl_stream_eat_if_available(struct isl_stream *s, int type)
663 {
664         struct isl_token *tok;
665
666         tok = isl_stream_next_token(s);
667         if (!tok)
668                 return 0;
669         if (tok->type == type) {
670                 isl_token_free(tok);
671                 return 1;
672         }
673         isl_stream_push_token(s, tok);
674         return 0;
675 }
676
677 int isl_stream_next_token_is(struct isl_stream *s, int type)
678 {
679         struct isl_token *tok;
680         int r;
681
682         tok = isl_stream_next_token(s);
683         if (!tok)
684                 return 0;
685         r = tok->type == type;
686         isl_stream_push_token(s, tok);
687         return r;
688 }
689
690 char *isl_stream_read_ident_if_available(struct isl_stream *s)
691 {
692         struct isl_token *tok;
693
694         tok = isl_stream_next_token(s);
695         if (!tok)
696                 return NULL;
697         if (tok->type == ISL_TOKEN_IDENT) {
698                 char *ident = strdup(tok->u.s);
699                 isl_token_free(tok);
700                 return ident;
701         }
702         isl_stream_push_token(s, tok);
703         return NULL;
704 }
705
706 int isl_stream_eat(struct isl_stream *s, int type)
707 {
708         struct isl_token *tok;
709
710         tok = isl_stream_next_token(s);
711         if (!tok)
712                 return -1;
713         if (tok->type == type) {
714                 isl_token_free(tok);
715                 return 0;
716         }
717         isl_stream_error(s, tok, "expecting other token");
718         isl_stream_push_token(s, tok);
719         return -1;
720 }
721
722 int isl_stream_is_empty(struct isl_stream *s)
723 {
724         struct isl_token *tok;
725
726         tok = isl_stream_next_token(s);
727
728         if (!tok)
729                 return 1;
730
731         isl_stream_push_token(s, tok);
732         return 0;
733 }
734
735 static int free_keyword(void **p, void *user)
736 {
737         struct isl_keyword *keyword = *p;
738
739         free(keyword->name);
740         free(keyword);
741
742         return 0;
743 }
744
745 void isl_stream_flush_tokens(struct isl_stream *s)
746 {
747         int i;
748
749         if (!s)
750                 return;
751         for (i = 0; i < s->n_token; ++i)
752                 isl_token_free(s->tokens[i]);
753         s->n_token = 0;
754 }
755
756 void isl_stream_free(struct isl_stream *s)
757 {
758         if (!s)
759                 return;
760         free(s->buffer);
761         if (s->n_token != 0) {
762                 struct isl_token *tok = isl_stream_next_token(s);
763                 isl_stream_error(s, tok, "unexpected token");
764                 isl_token_free(tok);
765         }
766         if (s->keywords) {
767                 isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);
768                 isl_hash_table_free(s->ctx, s->keywords);
769         }
770         isl_ctx_deref(s->ctx);
771         free(s);
772 }