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.h>
18 enum isl_token_type type
;
21 static int same_name(const void *entry
, const void *val
)
23 const struct isl_keyword
*keyword
= (const struct isl_keyword
*)entry
;
25 return !strcmp(keyword
->name
, val
);
28 enum isl_token_type
isl_stream_register_keyword(struct isl_stream
*s
,
31 struct isl_hash_table_entry
*entry
;
32 struct isl_keyword
*keyword
;
36 s
->keywords
= isl_hash_table_alloc(s
->ctx
, 10);
38 return ISL_TOKEN_ERROR
;
39 s
->next_type
= ISL_TOKEN_LAST
;
42 name_hash
= isl_hash_string(isl_hash_init(), name
);
44 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
,
47 return ISL_TOKEN_ERROR
;
49 keyword
= entry
->data
;
53 keyword
= isl_calloc_type(s
->ctx
, struct isl_keyword
);
55 return ISL_TOKEN_ERROR
;
56 keyword
->type
= s
->next_type
++;
57 keyword
->name
= strdup(name
);
60 return ISL_TOKEN_ERROR
;
62 entry
->data
= keyword
;
67 static struct isl_token
*isl_token_new(struct isl_ctx
*ctx
,
68 int line
, int col
, unsigned on_new_line
)
70 struct isl_token
*tok
= isl_alloc_type(ctx
, struct isl_token
);
75 tok
->on_new_line
= on_new_line
;
81 void isl_token_free(struct isl_token
*tok
)
85 if (tok
->type
== ISL_TOKEN_VALUE
)
86 isl_int_clear(tok
->u
.v
);
92 void isl_stream_error(struct isl_stream
*s
, struct isl_token
*tok
, char *msg
)
94 int line
= tok
? tok
->line
: s
->line
;
95 int col
= tok
? tok
->col
: s
->col
;
96 fprintf(stderr
, "syntax error (%d, %d): %s\n", line
, col
, msg
);
99 fprintf(stderr
, "got '%c'\n", tok
->type
);
100 else if (tok
->type
== ISL_TOKEN_IDENT
)
101 fprintf(stderr
, "got ident '%s'\n", tok
->u
.s
);
102 else if (tok
->is_keyword
)
103 fprintf(stderr
, "got keyword '%s'\n", tok
->u
.s
);
104 else if (tok
->type
== ISL_TOKEN_VALUE
) {
105 fprintf(stderr
, "got value '");
106 isl_int_print(stderr
, tok
->u
.v
, 0);
107 fprintf(stderr
, "'\n");
109 fprintf(stderr
, "got token '%s'\n", tok
->u
.s
);
111 fprintf(stderr
, "got token type %d\n", tok
->type
);
115 static struct isl_stream
* isl_stream_new(struct isl_ctx
*ctx
)
118 struct isl_stream
*s
= isl_alloc_type(ctx
, struct isl_stream
);
131 for (i
= 0; i
< 5; ++i
)
136 s
->buffer
= isl_alloc_array(ctx
, char, s
->size
);
145 struct isl_stream
* isl_stream_new_file(struct isl_ctx
*ctx
, FILE *file
)
147 struct isl_stream
*s
= isl_stream_new(ctx
);
154 struct isl_stream
* isl_stream_new_str(struct isl_ctx
*ctx
, const char *str
)
156 struct isl_stream
*s
= isl_stream_new(ctx
);
163 static int stream_getc(struct isl_stream
*s
)
169 return s
->c
= s
->un
[--s
->n_un
];
190 static void isl_stream_ungetc(struct isl_stream
*s
, int c
)
192 isl_assert(s
->ctx
, s
->n_un
< 5, return);
193 s
->un
[s
->n_un
++] = c
;
197 static int isl_stream_getc(struct isl_stream
*s
)
208 isl_stream_ungetc(s
, c
);
213 static int isl_stream_push_char(struct isl_stream
*s
, int c
)
215 if (s
->len
>= s
->size
) {
217 s
->size
= (3*s
->size
)/2;
218 buffer
= isl_realloc_array(s
->ctx
, s
->buffer
, char, s
->size
);
223 s
->buffer
[s
->len
++] = c
;
227 void isl_stream_push_token(struct isl_stream
*s
, struct isl_token
*tok
)
229 isl_assert(s
->ctx
, s
->n_token
< 5, return);
230 s
->tokens
[s
->n_token
++] = tok
;
233 static enum isl_token_type
check_keywords(struct isl_stream
*s
)
235 struct isl_hash_table_entry
*entry
;
236 struct isl_keyword
*keyword
;
239 if (!strcasecmp(s
->buffer
, "exists"))
240 return ISL_TOKEN_EXISTS
;
241 if (!strcasecmp(s
->buffer
, "and"))
242 return ISL_TOKEN_AND
;
243 if (!strcasecmp(s
->buffer
, "or"))
245 if (!strcasecmp(s
->buffer
, "not"))
246 return ISL_TOKEN_NOT
;
247 if (!strcasecmp(s
->buffer
, "infty"))
248 return ISL_TOKEN_INFTY
;
249 if (!strcasecmp(s
->buffer
, "infinity"))
250 return ISL_TOKEN_INFTY
;
251 if (!strcasecmp(s
->buffer
, "NaN"))
252 return ISL_TOKEN_NAN
;
253 if (!strcasecmp(s
->buffer
, "min"))
254 return ISL_TOKEN_MIN
;
255 if (!strcasecmp(s
->buffer
, "max"))
256 return ISL_TOKEN_MAX
;
257 if (!strcasecmp(s
->buffer
, "rat"))
258 return ISL_TOKEN_RAT
;
259 if (!strcasecmp(s
->buffer
, "true"))
260 return ISL_TOKEN_TRUE
;
261 if (!strcasecmp(s
->buffer
, "false"))
262 return ISL_TOKEN_FALSE
;
263 if (!strcasecmp(s
->buffer
, "ceild"))
264 return ISL_TOKEN_CEILD
;
265 if (!strcasecmp(s
->buffer
, "floord"))
266 return ISL_TOKEN_FLOORD
;
269 return ISL_TOKEN_IDENT
;
271 name_hash
= isl_hash_string(isl_hash_init(), s
->buffer
);
272 entry
= isl_hash_table_find(s
->ctx
, s
->keywords
, name_hash
, same_name
,
275 keyword
= entry
->data
;
276 return keyword
->type
;
279 return ISL_TOKEN_IDENT
;
282 int isl_stream_skip_line(struct isl_stream
*s
)
286 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '\n')
290 return c
== -1 ? -1 : 0;
293 static struct isl_token
*next_token(struct isl_stream
*s
, int same_line
)
296 struct isl_token
*tok
= NULL
;
298 int old_line
= s
->line
;
301 if (same_line
&& s
->tokens
[s
->n_token
- 1]->on_new_line
)
303 return s
->tokens
[--s
->n_token
];
306 if (same_line
&& s
->c
== '\n')
311 /* skip spaces and comment lines */
312 while ((c
= isl_stream_getc(s
)) != -1) {
314 if (isl_stream_skip_line(s
) < 0)
319 } else if (!isspace(c
) || (same_line
&& c
== '\n'))
326 if (c
== -1 || (same_line
&& c
== '\n'))
344 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
347 tok
->type
= (enum isl_token_type
)c
;
352 if ((c
= isl_stream_getc(s
)) == '>') {
353 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
356 tok
->u
.s
= strdup("->");
357 tok
->type
= ISL_TOKEN_TO
;
361 isl_stream_ungetc(s
, c
);
363 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
366 tok
->type
= (enum isl_token_type
) '-';
370 if (c
== '-' || isdigit(c
)) {
371 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
374 tok
->type
= ISL_TOKEN_VALUE
;
375 isl_int_init(tok
->u
.v
);
376 if (isl_stream_push_char(s
, c
))
378 while ((c
= isl_stream_getc(s
)) != -1 && isdigit(c
))
379 if (isl_stream_push_char(s
, c
))
382 isl_stream_ungetc(s
, c
);
383 isl_stream_push_char(s
, '\0');
384 isl_int_read(tok
->u
.v
, s
->buffer
);
387 if (isalpha(c
) || c
== '_') {
388 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
391 isl_stream_push_char(s
, c
);
392 while ((c
= isl_stream_getc(s
)) != -1 &&
393 (isalnum(c
) || c
== '_'))
394 isl_stream_push_char(s
, c
);
396 isl_stream_ungetc(s
, c
);
397 while ((c
= isl_stream_getc(s
)) != -1 && c
== '\'')
398 isl_stream_push_char(s
, c
);
400 isl_stream_ungetc(s
, c
);
401 isl_stream_push_char(s
, '\0');
402 tok
->type
= check_keywords(s
);
403 if (tok
->type
!= ISL_TOKEN_IDENT
)
405 tok
->u
.s
= strdup(s
->buffer
);
411 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
414 tok
->type
= ISL_TOKEN_STRING
;
416 while ((c
= isl_stream_getc(s
)) != -1 && c
!= '"' && c
!= '\n')
417 isl_stream_push_char(s
, c
);
419 isl_stream_error(s
, NULL
, "unterminated string");
422 isl_stream_push_char(s
, '\0');
423 tok
->u
.s
= strdup(s
->buffer
);
428 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
431 if ((c
= isl_stream_getc(s
)) == '=') {
432 tok
->u
.s
= strdup(":=");
433 tok
->type
= ISL_TOKEN_DEF
;
437 isl_stream_ungetc(s
, c
);
438 tok
->type
= (enum isl_token_type
) ':';
443 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
446 if ((c
= isl_stream_getc(s
)) == '=') {
447 tok
->u
.s
= strdup(">=");
448 tok
->type
= ISL_TOKEN_GE
;
450 } else if (c
== '>') {
451 if ((c
= isl_stream_getc(s
)) == '=') {
452 tok
->u
.s
= strdup(">>=");
453 tok
->type
= ISL_TOKEN_LEX_GE
;
456 tok
->u
.s
= strdup(">>");
457 tok
->type
= ISL_TOKEN_LEX_GT
;
459 tok
->u
.s
= strdup(">");
460 tok
->type
= ISL_TOKEN_GT
;
463 isl_stream_ungetc(s
, c
);
468 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
471 if ((c
= isl_stream_getc(s
)) == '=') {
472 tok
->u
.s
= strdup("<=");
473 tok
->type
= ISL_TOKEN_LE
;
475 } else if (c
== '<') {
476 if ((c
= isl_stream_getc(s
)) == '=') {
477 tok
->u
.s
= strdup("<<=");
478 tok
->type
= ISL_TOKEN_LEX_LE
;
481 tok
->u
.s
= strdup("<<");
482 tok
->type
= ISL_TOKEN_LEX_LT
;
484 tok
->u
.s
= strdup("<");
485 tok
->type
= ISL_TOKEN_LT
;
488 isl_stream_ungetc(s
, c
);
492 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
495 tok
->type
= ISL_TOKEN_AND
;
496 if ((c
= isl_stream_getc(s
)) != '&' && c
!= -1) {
497 tok
->u
.s
= strdup("&");
498 isl_stream_ungetc(s
, c
);
500 tok
->u
.s
= strdup("&&");
504 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
507 tok
->type
= ISL_TOKEN_OR
;
508 if ((c
= isl_stream_getc(s
)) != '|' && c
!= -1) {
509 tok
->u
.s
= strdup("|");
510 isl_stream_ungetc(s
, c
);
512 tok
->u
.s
= strdup("||");
516 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
519 if ((c
= isl_stream_getc(s
)) != '\\' && c
!= -1) {
520 tok
->type
= (enum isl_token_type
) '/';
521 isl_stream_ungetc(s
, c
);
523 tok
->u
.s
= strdup("/\\");
524 tok
->type
= ISL_TOKEN_AND
;
529 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
532 if ((c
= isl_stream_getc(s
)) != '/' && c
!= -1) {
533 tok
->type
= (enum isl_token_type
) '\\';
534 isl_stream_ungetc(s
, c
);
536 tok
->u
.s
= strdup("\\/");
537 tok
->type
= ISL_TOKEN_OR
;
542 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
545 tok
->type
= ISL_TOKEN_NOT
;
546 tok
->u
.s
= strdup("!");
550 tok
= isl_token_new(s
->ctx
, line
, col
, old_line
!= line
);
553 tok
->type
= ISL_TOKEN_UNKNOWN
;
560 struct isl_token
*isl_stream_next_token(struct isl_stream
*s
)
562 return next_token(s
, 0);
565 struct isl_token
*isl_stream_next_token_on_same_line(struct isl_stream
*s
)
567 return next_token(s
, 1);
570 int isl_stream_eat_if_available(struct isl_stream
*s
, int type
)
572 struct isl_token
*tok
;
574 tok
= isl_stream_next_token(s
);
577 if (tok
->type
== type
) {
581 isl_stream_push_token(s
, tok
);
585 int isl_stream_next_token_is(struct isl_stream
*s
, int type
)
587 struct isl_token
*tok
;
590 tok
= isl_stream_next_token(s
);
593 r
= tok
->type
== type
;
594 isl_stream_push_token(s
, tok
);
598 char *isl_stream_read_ident_if_available(struct isl_stream
*s
)
600 struct isl_token
*tok
;
602 tok
= isl_stream_next_token(s
);
605 if (tok
->type
== ISL_TOKEN_IDENT
) {
606 char *ident
= strdup(tok
->u
.s
);
610 isl_stream_push_token(s
, tok
);
614 int isl_stream_eat(struct isl_stream
*s
, int type
)
616 struct isl_token
*tok
;
618 tok
= isl_stream_next_token(s
);
621 if (tok
->type
== type
) {
625 isl_stream_error(s
, tok
, "expecting other token");
626 isl_stream_push_token(s
, tok
);
630 int isl_stream_is_empty(struct isl_stream
*s
)
632 struct isl_token
*tok
;
634 tok
= isl_stream_next_token(s
);
639 isl_stream_push_token(s
, tok
);
643 static int free_keyword(void **p
, void *user
)
645 struct isl_keyword
*keyword
= *p
;
653 void isl_stream_flush_tokens(struct isl_stream
*s
)
659 for (i
= 0; i
< s
->n_token
; ++i
)
660 isl_token_free(s
->tokens
[i
]);
664 void isl_stream_free(struct isl_stream
*s
)
669 if (s
->n_token
!= 0) {
670 struct isl_token
*tok
= isl_stream_next_token(s
);
671 isl_stream_error(s
, tok
, "unexpected token");
675 isl_hash_table_foreach(s
->ctx
, s
->keywords
, &free_keyword
, NULL
);
676 isl_hash_table_free(s
->ctx
, s
->keywords
);
678 isl_ctx_deref(s
->ctx
);