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
, "implies"))
303 return ISL_TOKEN_IMPLIES
;
304 if (!strcasecmp(s
->buffer
, "not"))
305 return ISL_TOKEN_NOT
;
306 if (!strcasecmp(s
->buffer
, "infty"))
307 return ISL_TOKEN_INFTY
;
308 if (!strcasecmp(s
->buffer
, "infinity"))
309 return ISL_TOKEN_INFTY
;
310 if (!strcasecmp(s
->buffer
, "NaN"))
311 return ISL_TOKEN_NAN
;
312 if (!strcasecmp(s
->buffer
, "min"))
313 return ISL_TOKEN_MIN
;
314 if (!strcasecmp(s
->buffer
, "max"))
315 return ISL_TOKEN_MAX
;
316 if (!strcasecmp(s
->buffer
, "rat"))
317 return ISL_TOKEN_RAT
;
318 if (!strcasecmp(s
->buffer
, "true"))
319 return ISL_TOKEN_TRUE
;
320 if (!strcasecmp(s
->buffer
, "false"))
321 return ISL_TOKEN_FALSE
;
322 if (!strcasecmp(s
->buffer
, "ceild"))
323 return ISL_TOKEN_CEILD
;
324 if (!strcasecmp(s
->buffer
, "floord"))
325 return ISL_TOKEN_FLOORD
;
326 if (!strcasecmp(s
->buffer
, "mod"))
327 return ISL_TOKEN_MOD
;
328 if (!strcasecmp(s
->buffer
, "ceil"))
329 return ISL_TOKEN_CEIL
;
330 if (!strcasecmp(s
->buffer
, "floor"))
331 return ISL_TOKEN_FLOOR
;
334 return ISL_TOKEN_IDENT
;
336 name_hash
= isl_hash_string(isl_hash_init(), s
->buffer
);
337 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
, same_name
,
340 keyword
= entry
->data
;
341 return keyword
->type
;
344 return ISL_TOKEN_IDENT
;
347 int isl_stream_skip_line(struct isl_stream
*s
)
351 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
355 return c
== -1 ? -1 : 0;
358 static struct isl_token
*next_token(struct isl_stream
*s
, int same_line
)
361 struct isl_token
*tok
= NULL
;
363 int old_line
= s
->line
;
366 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
368 return s
->tokens
[--s
->n_token
];
371 if (same_line
&& s
->c
== '\n')
376 /* skip spaces and comment lines */
377 while ((c
= isl_stream_getc(s
)) != -1) {
379 if (isl_stream_skip_line(s
) < 0)
384 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
391 if (c
== -1 || (same_line
&& c
== '\n'))
409 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
412 tok
->type
= (enum isl_token_type
)c
;
417 if ((c
= isl_stream_getc(s
)) == '>') {
418 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
421 tok
->u
.s
= strdup("->");
422 tok
->type
= ISL_TOKEN_TO
;
426 isl_stream_ungetc(s
, c
);
428 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
431 tok
->type
= (enum isl_token_type
) '-';
435 if (c
== '-' || isdigit(c
)) {
436 int minus
= c
== '-';
437 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
440 tok
->type
= ISL_TOKEN_VALUE
;
441 isl_int_init(tok
->u
.v
);
442 if (isl_stream_push_char(s
, c
))
444 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
445 if (isl_stream_push_char(s
, c
))
448 isl_stream_ungetc(s
, c
);
449 isl_stream_push_char(s
, '\0');
450 isl_int_read(tok
->u
.v
, s
->buffer
);
451 if (minus
&& isl_int_is_zero(tok
->u
.v
)) {
453 tok
->on_new_line
= 0;
454 isl_stream_push_token(s
, tok
);
455 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
458 tok
->type
= (enum isl_token_type
) '-';
462 if (isalpha(c
) || c
== '_') {
463 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
466 isl_stream_push_char(s
, c
);
467 while ((c
= isl_stream_getc(s
)) != -1 &&
468 (isalnum(c
) || c
== '_'))
469 isl_stream_push_char(s
, c
);
471 isl_stream_ungetc(s
, c
);
472 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
473 isl_stream_push_char(s
, c
);
475 isl_stream_ungetc(s
, c
);
476 isl_stream_push_char(s
, '\0');
477 tok
->type
= check_keywords(s
);
478 if (tok
->type
!= ISL_TOKEN_IDENT
)
480 tok
->u
.s
= strdup(s
->buffer
);
486 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
489 tok
->type
= ISL_TOKEN_STRING
;
491 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
492 isl_stream_push_char(s
, c
);
494 isl_stream_error(s
, NULL
, "unterminated string");
497 isl_stream_push_char(s
, '\0');
498 tok
->u
.s
= strdup(s
->buffer
);
503 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
506 if ((c
= isl_stream_getc(s
)) == '=') {
507 tok
->u
.s
= strdup("==");
508 tok
->type
= ISL_TOKEN_EQ_EQ
;
512 isl_stream_ungetc(s
, c
);
513 tok
->type
= (enum isl_token_type
) '=';
518 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
521 if ((c
= isl_stream_getc(s
)) == '=') {
522 tok
->u
.s
= strdup(":=");
523 tok
->type
= ISL_TOKEN_DEF
;
527 isl_stream_ungetc(s
, c
);
528 tok
->type
= (enum isl_token_type
) ':';
533 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
536 if ((c
= isl_stream_getc(s
)) == '=') {
537 tok
->u
.s
= strdup(">=");
538 tok
->type
= ISL_TOKEN_GE
;
540 } else if (c
== '>') {
541 if ((c
= isl_stream_getc(s
)) == '=') {
542 tok
->u
.s
= strdup(">>=");
543 tok
->type
= ISL_TOKEN_LEX_GE
;
546 tok
->u
.s
= strdup(">>");
547 tok
->type
= ISL_TOKEN_LEX_GT
;
549 tok
->u
.s
= strdup(">");
550 tok
->type
= ISL_TOKEN_GT
;
553 isl_stream_ungetc(s
, c
);
558 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
561 if ((c
= isl_stream_getc(s
)) == '=') {
562 tok
->u
.s
= strdup("<=");
563 tok
->type
= ISL_TOKEN_LE
;
565 } else if (c
== '<') {
566 if ((c
= isl_stream_getc(s
)) == '=') {
567 tok
->u
.s
= strdup("<<=");
568 tok
->type
= ISL_TOKEN_LEX_LE
;
571 tok
->u
.s
= strdup("<<");
572 tok
->type
= ISL_TOKEN_LEX_LT
;
574 tok
->u
.s
= strdup("<");
575 tok
->type
= ISL_TOKEN_LT
;
578 isl_stream_ungetc(s
, c
);
582 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
585 tok
->type
= ISL_TOKEN_AND
;
586 if ((c
= isl_stream_getc(s
)) != '&' && c
!= -1) {
587 tok
->u
.s
= strdup("&");
588 isl_stream_ungetc(s
, c
);
590 tok
->u
.s
= strdup("&&");
594 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
597 tok
->type
= ISL_TOKEN_OR
;
598 if ((c
= isl_stream_getc(s
)) != '|' && c
!= -1) {
599 tok
->u
.s
= strdup("|");
600 isl_stream_ungetc(s
, c
);
602 tok
->u
.s
= strdup("||");
606 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
609 if ((c
= isl_stream_getc(s
)) != '\\' && c
!= -1) {
610 tok
->type
= (enum isl_token_type
) '/';
611 isl_stream_ungetc(s
, c
);
613 tok
->u
.s
= strdup("/\\");
614 tok
->type
= ISL_TOKEN_AND
;
619 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
622 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
623 tok
->type
= (enum isl_token_type
) '\\';
624 isl_stream_ungetc(s
, c
);
626 tok
->u
.s
= strdup("\\/");
627 tok
->type
= ISL_TOKEN_OR
;
632 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
635 if ((c
= isl_stream_getc(s
)) == '=') {
636 tok
->u
.s
= strdup("!=");
637 tok
->type
= ISL_TOKEN_NE
;
640 tok
->type
= ISL_TOKEN_NOT
;
641 tok
->u
.s
= strdup("!");
644 isl_stream_ungetc(s
, c
);
648 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
651 tok
->type
= ISL_TOKEN_UNKNOWN
;
658 struct isl_token
*isl_stream_next_token(struct isl_stream
*s
)
660 return next_token(s
, 0);
663 struct isl_token
*isl_stream_next_token_on_same_line(struct isl_stream
*s
)
665 return next_token(s
, 1);
668 int isl_stream_eat_if_available(struct isl_stream
*s
, int type
)
670 struct isl_token
*tok
;
672 tok
= isl_stream_next_token(s
);
675 if (tok
->type
== type
) {
679 isl_stream_push_token(s
, tok
);
683 int isl_stream_next_token_is(struct isl_stream
*s
, int type
)
685 struct isl_token
*tok
;
688 tok
= isl_stream_next_token(s
);
691 r
= tok
->type
== type
;
692 isl_stream_push_token(s
, tok
);
696 char *isl_stream_read_ident_if_available(struct isl_stream
*s
)
698 struct isl_token
*tok
;
700 tok
= isl_stream_next_token(s
);
703 if (tok
->type
== ISL_TOKEN_IDENT
) {
704 char *ident
= strdup(tok
->u
.s
);
708 isl_stream_push_token(s
, tok
);
712 int isl_stream_eat(struct isl_stream
*s
, int type
)
714 struct isl_token
*tok
;
716 tok
= isl_stream_next_token(s
);
719 if (tok
->type
== type
) {
723 isl_stream_error(s
, tok
, "expecting other token");
724 isl_stream_push_token(s
, tok
);
728 int isl_stream_is_empty(struct isl_stream
*s
)
730 struct isl_token
*tok
;
732 tok
= isl_stream_next_token(s
);
737 isl_stream_push_token(s
, tok
);
741 static int free_keyword(void **p
, void *user
)
743 struct isl_keyword
*keyword
= *p
;
751 void isl_stream_flush_tokens(struct isl_stream
*s
)
757 for (i
= 0; i
< s
->n_token
; ++i
)
758 isl_token_free(s
->tokens
[i
]);
762 void isl_stream_free(struct isl_stream
*s
)
767 if (s
->n_token
!= 0) {
768 struct isl_token
*tok
= isl_stream_next_token(s
);
769 isl_stream_error(s
, tok
, "unexpected token");
773 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
774 isl_hash_table_free(s
->ctx
, s
->keywords
);
776 isl_ctx_deref(s
->ctx
);