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