2 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege, K.U.Leuven, Departement
7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
14 #include <isl_stream_private.h>
17 #include <isl_val_private.h>
21 enum isl_token_type type
;
24 static int same_name(const void *entry
, const void *val
)
26 const struct isl_keyword
*keyword
= (const struct isl_keyword
*)entry
;
28 return !strcmp(keyword
->name
, val
);
31 enum isl_token_type
isl_stream_register_keyword(struct isl_stream
*s
,
34 struct isl_hash_table_entry
*entry
;
35 struct isl_keyword
*keyword
;
39 s
->keywords
= isl_hash_table_alloc(s
->ctx
, 10);
41 return ISL_TOKEN_ERROR
;
42 s
->next_type
= ISL_TOKEN_LAST
;
45 name_hash
= isl_hash_string(isl_hash_init(), name
);
47 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
,
50 return ISL_TOKEN_ERROR
;
52 keyword
= entry
->data
;
56 keyword
= isl_calloc_type(s
->ctx
, struct isl_keyword
);
58 return ISL_TOKEN_ERROR
;
59 keyword
->type
= s
->next_type
++;
60 keyword
->name
= strdup(name
);
63 return ISL_TOKEN_ERROR
;
65 entry
->data
= keyword
;
70 struct isl_token
*isl_token_new(isl_ctx
*ctx
,
71 int line
, int col
, unsigned on_new_line
)
73 struct isl_token
*tok
= isl_alloc_type(ctx
, struct isl_token
);
78 tok
->on_new_line
= on_new_line
;
84 /* Return the type of "tok".
86 int isl_token_get_type(struct isl_token
*tok
)
88 return tok
? tok
->type
: ISL_TOKEN_ERROR
;
91 /* Given a token of type ISL_TOKEN_VALUE, return the value it represents.
93 __isl_give isl_val
*isl_token_get_val(isl_ctx
*ctx
, struct isl_token
*tok
)
97 if (tok
->type
!= ISL_TOKEN_VALUE
)
98 isl_die(ctx
, isl_error_invalid
, "not a value token",
101 return isl_val_int_from_isl_int(ctx
, tok
->u
.v
);
104 /* Given a token of type ISL_TOKEN_STRING, return the string it represents.
106 __isl_give
char *isl_token_get_str(isl_ctx
*ctx
, struct isl_token
*tok
)
110 if (tok
->type
!= ISL_TOKEN_STRING
)
111 isl_die(ctx
, isl_error_invalid
, "not a string token",
114 return strdup(tok
->u
.s
);
117 void isl_token_free(struct isl_token
*tok
)
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
);
132 void isl_stream_error(struct isl_stream
*s
, struct isl_token
*tok
, char *msg
)
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
);
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
) {
150 fprintf(stderr
, "got map '");
151 p
= isl_printer_to_file(s
->ctx
, stderr
);
152 p
= isl_printer_print_map(p
, tok
->u
.map
);
154 fprintf(stderr
, "'\n");
155 } else if (tok
->type
== ISL_TOKEN_AFF
) {
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
);
161 fprintf(stderr
, "'\n");
163 fprintf(stderr
, "got token '%s'\n", tok
->u
.s
);
165 fprintf(stderr
, "got token type %d\n", tok
->type
);
169 static struct isl_stream
* isl_stream_new(struct isl_ctx
*ctx
)
172 struct isl_stream
*s
= isl_alloc_type(ctx
, struct isl_stream
);
185 for (i
= 0; i
< 5; ++i
)
190 s
->buffer
= isl_alloc_array(ctx
, char, s
->size
);
199 struct isl_stream
* isl_stream_new_file(struct isl_ctx
*ctx
, FILE *file
)
201 struct isl_stream
*s
= isl_stream_new(ctx
);
208 struct isl_stream
* isl_stream_new_str(struct isl_ctx
*ctx
, const char *str
)
210 struct isl_stream
*s
;
213 s
= isl_stream_new(ctx
);
220 static int stream_getc(struct isl_stream
*s
)
226 return s
->c
= s
->un
[--s
->n_un
];
247 static void isl_stream_ungetc(struct isl_stream
*s
, int c
)
249 isl_assert(s
->ctx
, s
->n_un
< 5, return);
250 s
->un
[s
->n_un
++] = c
;
254 static int isl_stream_getc(struct isl_stream
*s
)
265 isl_stream_ungetc(s
, c
);
270 static int isl_stream_push_char(struct isl_stream
*s
, int c
)
272 if (s
->len
>= s
->size
) {
274 s
->size
= (3*s
->size
)/2;
275 buffer
= isl_realloc_array(s
->ctx
, s
->buffer
, char, s
->size
);
280 s
->buffer
[s
->len
++] = c
;
284 void isl_stream_push_token(struct isl_stream
*s
, struct isl_token
*tok
)
286 isl_assert(s
->ctx
, s
->n_token
< 5, return);
287 s
->tokens
[s
->n_token
++] = tok
;
290 static enum isl_token_type
check_keywords(struct isl_stream
*s
)
292 struct isl_hash_table_entry
*entry
;
293 struct isl_keyword
*keyword
;
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"))
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
;
328 return ISL_TOKEN_IDENT
;
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
,
334 keyword
= entry
->data
;
335 return keyword
->type
;
338 return ISL_TOKEN_IDENT
;
341 int isl_stream_skip_line(struct isl_stream
*s
)
345 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
349 return c
== -1 ? -1 : 0;
352 static struct isl_token
*next_token(struct isl_stream
*s
, int same_line
)
355 struct isl_token
*tok
= NULL
;
357 int old_line
= s
->line
;
360 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
362 return s
->tokens
[--s
->n_token
];
365 if (same_line
&& s
->c
== '\n')
370 /* skip spaces and comment lines */
371 while ((c
= isl_stream_getc(s
)) != -1) {
373 if (isl_stream_skip_line(s
) < 0)
378 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
385 if (c
== -1 || (same_line
&& c
== '\n'))
403 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
406 tok
->type
= (enum isl_token_type
)c
;
411 if ((c
= isl_stream_getc(s
)) == '>') {
412 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
415 tok
->u
.s
= strdup("->");
416 tok
->type
= ISL_TOKEN_TO
;
420 isl_stream_ungetc(s
, c
);
422 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
425 tok
->type
= (enum isl_token_type
) '-';
429 if (c
== '-' || isdigit(c
)) {
430 int minus
= c
== '-';
431 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
434 tok
->type
= ISL_TOKEN_VALUE
;
435 isl_int_init(tok
->u
.v
);
436 if (isl_stream_push_char(s
, c
))
438 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
439 if (isl_stream_push_char(s
, c
))
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
)) {
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
);
452 tok
->type
= (enum isl_token_type
) '-';
456 if (isalpha(c
) || c
== '_') {
457 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
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
);
465 isl_stream_ungetc(s
, c
);
466 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
467 isl_stream_push_char(s
, c
);
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
)
474 tok
->u
.s
= strdup(s
->buffer
);
480 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
483 tok
->type
= ISL_TOKEN_STRING
;
485 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
486 isl_stream_push_char(s
, c
);
488 isl_stream_error(s
, NULL
, "unterminated string");
491 isl_stream_push_char(s
, '\0');
492 tok
->u
.s
= strdup(s
->buffer
);
497 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
500 if ((c
= isl_stream_getc(s
)) == '=') {
501 tok
->u
.s
= strdup("==");
502 tok
->type
= ISL_TOKEN_EQ_EQ
;
506 isl_stream_ungetc(s
, c
);
507 tok
->type
= (enum isl_token_type
) '=';
512 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
515 if ((c
= isl_stream_getc(s
)) == '=') {
516 tok
->u
.s
= strdup(":=");
517 tok
->type
= ISL_TOKEN_DEF
;
521 isl_stream_ungetc(s
, c
);
522 tok
->type
= (enum isl_token_type
) ':';
527 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
530 if ((c
= isl_stream_getc(s
)) == '=') {
531 tok
->u
.s
= strdup(">=");
532 tok
->type
= ISL_TOKEN_GE
;
534 } else if (c
== '>') {
535 if ((c
= isl_stream_getc(s
)) == '=') {
536 tok
->u
.s
= strdup(">>=");
537 tok
->type
= ISL_TOKEN_LEX_GE
;
540 tok
->u
.s
= strdup(">>");
541 tok
->type
= ISL_TOKEN_LEX_GT
;
543 tok
->u
.s
= strdup(">");
544 tok
->type
= ISL_TOKEN_GT
;
547 isl_stream_ungetc(s
, c
);
552 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
555 if ((c
= isl_stream_getc(s
)) == '=') {
556 tok
->u
.s
= strdup("<=");
557 tok
->type
= ISL_TOKEN_LE
;
559 } else if (c
== '<') {
560 if ((c
= isl_stream_getc(s
)) == '=') {
561 tok
->u
.s
= strdup("<<=");
562 tok
->type
= ISL_TOKEN_LEX_LE
;
565 tok
->u
.s
= strdup("<<");
566 tok
->type
= ISL_TOKEN_LEX_LT
;
568 tok
->u
.s
= strdup("<");
569 tok
->type
= ISL_TOKEN_LT
;
572 isl_stream_ungetc(s
, c
);
576 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
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
);
584 tok
->u
.s
= strdup("&&");
588 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
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
);
596 tok
->u
.s
= strdup("||");
600 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
603 if ((c
= isl_stream_getc(s
)) != '\\' && c
!= -1) {
604 tok
->type
= (enum isl_token_type
) '/';
605 isl_stream_ungetc(s
, c
);
607 tok
->u
.s
= strdup("/\\");
608 tok
->type
= ISL_TOKEN_AND
;
613 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
616 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
617 tok
->type
= (enum isl_token_type
) '\\';
618 isl_stream_ungetc(s
, c
);
620 tok
->u
.s
= strdup("\\/");
621 tok
->type
= ISL_TOKEN_OR
;
626 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
629 if ((c
= isl_stream_getc(s
)) == '=') {
630 tok
->u
.s
= strdup("!=");
631 tok
->type
= ISL_TOKEN_NE
;
634 tok
->type
= ISL_TOKEN_NOT
;
635 tok
->u
.s
= strdup("!");
638 isl_stream_ungetc(s
, c
);
642 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
645 tok
->type
= ISL_TOKEN_UNKNOWN
;
652 struct isl_token
*isl_stream_next_token(struct isl_stream
*s
)
654 return next_token(s
, 0);
657 struct isl_token
*isl_stream_next_token_on_same_line(struct isl_stream
*s
)
659 return next_token(s
, 1);
662 int isl_stream_eat_if_available(struct isl_stream
*s
, int type
)
664 struct isl_token
*tok
;
666 tok
= isl_stream_next_token(s
);
669 if (tok
->type
== type
) {
673 isl_stream_push_token(s
, tok
);
677 int isl_stream_next_token_is(struct isl_stream
*s
, int type
)
679 struct isl_token
*tok
;
682 tok
= isl_stream_next_token(s
);
685 r
= tok
->type
== type
;
686 isl_stream_push_token(s
, tok
);
690 char *isl_stream_read_ident_if_available(struct isl_stream
*s
)
692 struct isl_token
*tok
;
694 tok
= isl_stream_next_token(s
);
697 if (tok
->type
== ISL_TOKEN_IDENT
) {
698 char *ident
= strdup(tok
->u
.s
);
702 isl_stream_push_token(s
, tok
);
706 int isl_stream_eat(struct isl_stream
*s
, int type
)
708 struct isl_token
*tok
;
710 tok
= isl_stream_next_token(s
);
713 if (tok
->type
== type
) {
717 isl_stream_error(s
, tok
, "expecting other token");
718 isl_stream_push_token(s
, tok
);
722 int isl_stream_is_empty(struct isl_stream
*s
)
724 struct isl_token
*tok
;
726 tok
= isl_stream_next_token(s
);
731 isl_stream_push_token(s
, tok
);
735 static int free_keyword(void **p
, void *user
)
737 struct isl_keyword
*keyword
= *p
;
745 void isl_stream_flush_tokens(struct isl_stream
*s
)
751 for (i
= 0; i
< s
->n_token
; ++i
)
752 isl_token_free(s
->tokens
[i
]);
756 void isl_stream_free(struct isl_stream
*s
)
761 if (s
->n_token
!= 0) {
762 struct isl_token
*tok
= isl_stream_next_token(s
);
763 isl_stream_error(s
, tok
, "unexpected token");
767 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
768 isl_hash_table_free(s
->ctx
, s
->keywords
);
770 isl_ctx_deref(s
->ctx
);