2 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Use of this software is governed by the GNU LGPLv2.1 license
6 * Written by Sven Verdoolaege, K.U.Leuven, Departement
7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
14 #include <isl_stream_private.h>
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
,
33 struct isl_hash_table_entry
*entry
;
34 struct isl_keyword
*keyword
;
38 s
->keywords
= isl_hash_table_alloc(s
->ctx
, 10);
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
,
49 return ISL_TOKEN_ERROR
;
51 keyword
= entry
->data
;
55 keyword
= isl_calloc_type(s
->ctx
, struct isl_keyword
);
57 return ISL_TOKEN_ERROR
;
58 keyword
->type
= s
->next_type
++;
59 keyword
->name
= strdup(name
);
62 return ISL_TOKEN_ERROR
;
64 entry
->data
= keyword
;
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
);
77 tok
->on_new_line
= on_new_line
;
83 void isl_token_free(struct isl_token
*tok
)
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
);
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
);
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
) {
116 fprintf(stderr
, "got map '");
117 p
= isl_printer_to_file(s
->ctx
, stderr
);
118 p
= isl_printer_print_map(p
, tok
->u
.map
);
120 fprintf(stderr
, "'\n");
121 } else if (tok
->type
== ISL_TOKEN_AFF
) {
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
);
127 fprintf(stderr
, "'\n");
129 fprintf(stderr
, "got token '%s'\n", tok
->u
.s
);
131 fprintf(stderr
, "got token type %d\n", tok
->type
);
135 static struct isl_stream
* isl_stream_new(struct isl_ctx
*ctx
)
138 struct isl_stream
*s
= isl_alloc_type(ctx
, struct isl_stream
);
151 for (i
= 0; i
< 5; ++i
)
156 s
->buffer
= isl_alloc_array(ctx
, char, s
->size
);
165 struct isl_stream
* isl_stream_new_file(struct isl_ctx
*ctx
, FILE *file
)
167 struct isl_stream
*s
= isl_stream_new(ctx
);
174 struct isl_stream
* isl_stream_new_str(struct isl_ctx
*ctx
, const char *str
)
176 struct isl_stream
*s
= isl_stream_new(ctx
);
183 static int stream_getc(struct isl_stream
*s
)
189 return s
->c
= s
->un
[--s
->n_un
];
210 static void isl_stream_ungetc(struct isl_stream
*s
, int c
)
212 isl_assert(s
->ctx
, s
->n_un
< 5, return);
213 s
->un
[s
->n_un
++] = c
;
217 static int isl_stream_getc(struct isl_stream
*s
)
228 isl_stream_ungetc(s
, c
);
233 static int isl_stream_push_char(struct isl_stream
*s
, int c
)
235 if (s
->len
>= s
->size
) {
237 s
->size
= (3*s
->size
)/2;
238 buffer
= isl_realloc_array(s
->ctx
, s
->buffer
, char, s
->size
);
243 s
->buffer
[s
->len
++] = c
;
247 void isl_stream_push_token(struct isl_stream
*s
, struct isl_token
*tok
)
249 isl_assert(s
->ctx
, s
->n_token
< 5, return);
250 s
->tokens
[s
->n_token
++] = tok
;
253 static enum isl_token_type
check_keywords(struct isl_stream
*s
)
255 struct isl_hash_table_entry
*entry
;
256 struct isl_keyword
*keyword
;
259 if (!strcasecmp(s
->buffer
, "exists"))
260 return ISL_TOKEN_EXISTS
;
261 if (!strcasecmp(s
->buffer
, "and"))
262 return ISL_TOKEN_AND
;
263 if (!strcasecmp(s
->buffer
, "or"))
265 if (!strcasecmp(s
->buffer
, "not"))
266 return ISL_TOKEN_NOT
;
267 if (!strcasecmp(s
->buffer
, "infty"))
268 return ISL_TOKEN_INFTY
;
269 if (!strcasecmp(s
->buffer
, "infinity"))
270 return ISL_TOKEN_INFTY
;
271 if (!strcasecmp(s
->buffer
, "NaN"))
272 return ISL_TOKEN_NAN
;
273 if (!strcasecmp(s
->buffer
, "min"))
274 return ISL_TOKEN_MIN
;
275 if (!strcasecmp(s
->buffer
, "max"))
276 return ISL_TOKEN_MAX
;
277 if (!strcasecmp(s
->buffer
, "rat"))
278 return ISL_TOKEN_RAT
;
279 if (!strcasecmp(s
->buffer
, "true"))
280 return ISL_TOKEN_TRUE
;
281 if (!strcasecmp(s
->buffer
, "false"))
282 return ISL_TOKEN_FALSE
;
283 if (!strcasecmp(s
->buffer
, "ceild"))
284 return ISL_TOKEN_CEILD
;
285 if (!strcasecmp(s
->buffer
, "floord"))
286 return ISL_TOKEN_FLOORD
;
287 if (!strcasecmp(s
->buffer
, "mod"))
288 return ISL_TOKEN_MOD
;
291 return ISL_TOKEN_IDENT
;
293 name_hash
= isl_hash_string(isl_hash_init(), s
->buffer
);
294 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
, same_name
,
297 keyword
= entry
->data
;
298 return keyword
->type
;
301 return ISL_TOKEN_IDENT
;
304 int isl_stream_skip_line(struct isl_stream
*s
)
308 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
312 return c
== -1 ? -1 : 0;
315 static struct isl_token
*next_token(struct isl_stream
*s
, int same_line
)
318 struct isl_token
*tok
= NULL
;
320 int old_line
= s
->line
;
323 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
325 return s
->tokens
[--s
->n_token
];
328 if (same_line
&& s
->c
== '\n')
333 /* skip spaces and comment lines */
334 while ((c
= isl_stream_getc(s
)) != -1) {
336 if (isl_stream_skip_line(s
) < 0)
341 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
348 if (c
== -1 || (same_line
&& c
== '\n'))
366 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
369 tok
->type
= (enum isl_token_type
)c
;
374 if ((c
= isl_stream_getc(s
)) == '>') {
375 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
378 tok
->u
.s
= strdup("->");
379 tok
->type
= ISL_TOKEN_TO
;
383 isl_stream_ungetc(s
, c
);
385 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
388 tok
->type
= (enum isl_token_type
) '-';
392 if (c
== '-' || isdigit(c
)) {
393 int minus
= c
== '-';
394 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
397 tok
->type
= ISL_TOKEN_VALUE
;
398 isl_int_init(tok
->u
.v
);
399 if (isl_stream_push_char(s
, c
))
401 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
402 if (isl_stream_push_char(s
, c
))
405 isl_stream_ungetc(s
, c
);
406 isl_stream_push_char(s
, '\0');
407 isl_int_read(tok
->u
.v
, s
->buffer
);
408 if (minus
&& isl_int_is_zero(tok
->u
.v
)) {
410 tok
->on_new_line
= 0;
411 isl_stream_push_token(s
, tok
);
412 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
415 tok
->type
= (enum isl_token_type
) '-';
419 if (isalpha(c
) || c
== '_') {
420 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
423 isl_stream_push_char(s
, c
);
424 while ((c
= isl_stream_getc(s
)) != -1 &&
425 (isalnum(c
) || c
== '_'))
426 isl_stream_push_char(s
, c
);
428 isl_stream_ungetc(s
, c
);
429 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
430 isl_stream_push_char(s
, c
);
432 isl_stream_ungetc(s
, c
);
433 isl_stream_push_char(s
, '\0');
434 tok
->type
= check_keywords(s
);
435 if (tok
->type
!= ISL_TOKEN_IDENT
)
437 tok
->u
.s
= strdup(s
->buffer
);
443 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
446 tok
->type
= ISL_TOKEN_STRING
;
448 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
449 isl_stream_push_char(s
, c
);
451 isl_stream_error(s
, NULL
, "unterminated string");
454 isl_stream_push_char(s
, '\0');
455 tok
->u
.s
= strdup(s
->buffer
);
460 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
463 if ((c
= isl_stream_getc(s
)) == '=') {
464 tok
->u
.s
= strdup("==");
465 tok
->type
= ISL_TOKEN_EQ_EQ
;
469 isl_stream_ungetc(s
, c
);
470 tok
->type
= (enum isl_token_type
) '=';
475 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
478 if ((c
= isl_stream_getc(s
)) == '=') {
479 tok
->u
.s
= strdup(":=");
480 tok
->type
= ISL_TOKEN_DEF
;
484 isl_stream_ungetc(s
, c
);
485 tok
->type
= (enum isl_token_type
) ':';
490 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
493 if ((c
= isl_stream_getc(s
)) == '=') {
494 tok
->u
.s
= strdup(">=");
495 tok
->type
= ISL_TOKEN_GE
;
497 } else if (c
== '>') {
498 if ((c
= isl_stream_getc(s
)) == '=') {
499 tok
->u
.s
= strdup(">>=");
500 tok
->type
= ISL_TOKEN_LEX_GE
;
503 tok
->u
.s
= strdup(">>");
504 tok
->type
= ISL_TOKEN_LEX_GT
;
506 tok
->u
.s
= strdup(">");
507 tok
->type
= ISL_TOKEN_GT
;
510 isl_stream_ungetc(s
, c
);
515 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
518 if ((c
= isl_stream_getc(s
)) == '=') {
519 tok
->u
.s
= strdup("<=");
520 tok
->type
= ISL_TOKEN_LE
;
522 } else if (c
== '<') {
523 if ((c
= isl_stream_getc(s
)) == '=') {
524 tok
->u
.s
= strdup("<<=");
525 tok
->type
= ISL_TOKEN_LEX_LE
;
528 tok
->u
.s
= strdup("<<");
529 tok
->type
= ISL_TOKEN_LEX_LT
;
531 tok
->u
.s
= strdup("<");
532 tok
->type
= ISL_TOKEN_LT
;
535 isl_stream_ungetc(s
, c
);
539 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
542 tok
->type
= ISL_TOKEN_AND
;
543 if ((c
= isl_stream_getc(s
)) != '&' && c
!= -1) {
544 tok
->u
.s
= strdup("&");
545 isl_stream_ungetc(s
, c
);
547 tok
->u
.s
= strdup("&&");
551 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
554 tok
->type
= ISL_TOKEN_OR
;
555 if ((c
= isl_stream_getc(s
)) != '|' && c
!= -1) {
556 tok
->u
.s
= strdup("|");
557 isl_stream_ungetc(s
, c
);
559 tok
->u
.s
= strdup("||");
563 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
566 if ((c
= isl_stream_getc(s
)) != '\\' && c
!= -1) {
567 tok
->type
= (enum isl_token_type
) '/';
568 isl_stream_ungetc(s
, c
);
570 tok
->u
.s
= strdup("/\\");
571 tok
->type
= ISL_TOKEN_AND
;
576 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
579 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
580 tok
->type
= (enum isl_token_type
) '\\';
581 isl_stream_ungetc(s
, c
);
583 tok
->u
.s
= strdup("\\/");
584 tok
->type
= ISL_TOKEN_OR
;
589 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
592 if ((c
= isl_stream_getc(s
)) == '=') {
593 tok
->u
.s
= strdup("!=");
594 tok
->type
= ISL_TOKEN_NE
;
597 tok
->type
= ISL_TOKEN_NOT
;
598 tok
->u
.s
= strdup("!");
601 isl_stream_ungetc(s
, c
);
605 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
608 tok
->type
= ISL_TOKEN_UNKNOWN
;
615 struct isl_token
*isl_stream_next_token(struct isl_stream
*s
)
617 return next_token(s
, 0);
620 struct isl_token
*isl_stream_next_token_on_same_line(struct isl_stream
*s
)
622 return next_token(s
, 1);
625 int isl_stream_eat_if_available(struct isl_stream
*s
, int type
)
627 struct isl_token
*tok
;
629 tok
= isl_stream_next_token(s
);
632 if (tok
->type
== type
) {
636 isl_stream_push_token(s
, tok
);
640 int isl_stream_next_token_is(struct isl_stream
*s
, int type
)
642 struct isl_token
*tok
;
645 tok
= isl_stream_next_token(s
);
648 r
= tok
->type
== type
;
649 isl_stream_push_token(s
, tok
);
653 char *isl_stream_read_ident_if_available(struct isl_stream
*s
)
655 struct isl_token
*tok
;
657 tok
= isl_stream_next_token(s
);
660 if (tok
->type
== ISL_TOKEN_IDENT
) {
661 char *ident
= strdup(tok
->u
.s
);
665 isl_stream_push_token(s
, tok
);
669 int isl_stream_eat(struct isl_stream
*s
, int type
)
671 struct isl_token
*tok
;
673 tok
= isl_stream_next_token(s
);
676 if (tok
->type
== type
) {
680 isl_stream_error(s
, tok
, "expecting other token");
681 isl_stream_push_token(s
, tok
);
685 int isl_stream_is_empty(struct isl_stream
*s
)
687 struct isl_token
*tok
;
689 tok
= isl_stream_next_token(s
);
694 isl_stream_push_token(s
, tok
);
698 static int free_keyword(void **p
, void *user
)
700 struct isl_keyword
*keyword
= *p
;
708 void isl_stream_flush_tokens(struct isl_stream
*s
)
714 for (i
= 0; i
< s
->n_token
; ++i
)
715 isl_token_free(s
->tokens
[i
]);
719 void isl_stream_free(struct isl_stream
*s
)
724 if (s
->n_token
!= 0) {
725 struct isl_token
*tok
= isl_stream_next_token(s
);
726 isl_stream_error(s
, tok
, "unexpected token");
730 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
731 isl_hash_table_free(s
->ctx
, s
->keywords
);
733 isl_ctx_deref(s
->ctx
);