brintos

brintos / llvm-project-archived public Read only

0
0
Text · 28.7 KiB · 9fffd45 Raw
1198 lines · c
1/*2 * Copyright 2008-2009 Katholieke Universiteit Leuven3 *4 * Use of this software is governed by the MIT license5 *6 * Written by Sven Verdoolaege, K.U.Leuven, Departement7 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium8 */9 10#include <ctype.h>11#include <string.h>12#include <isl_ctx_private.h>13#include <isl_stream_private.h>14#include <isl/map.h>15#include <isl/aff.h>16#include <isl_val_private.h>17#include <isl_options_private.h>18 19struct isl_keyword {20	char			*name;21	enum isl_token_type	type;22};23 24static isl_bool same_name(const void *entry, const void *val)25{26	const struct isl_keyword *keyword = (const struct isl_keyword *)entry;27 28	return isl_bool_ok(!strcmp(keyword->name, val));29}30 31enum isl_token_type isl_stream_register_keyword(__isl_keep 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 70struct 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/* Return the type of "tok".85 */86int isl_token_get_type(struct isl_token *tok)87{88	return tok ? tok->type : ISL_TOKEN_ERROR;89}90 91/* Given a token of type ISL_TOKEN_VALUE, return the value it represents.92 */93__isl_give isl_val *isl_token_get_val(isl_ctx *ctx, struct isl_token *tok)94{95	if (!tok)96		return NULL;97	if (tok->type != ISL_TOKEN_VALUE)98		isl_die(ctx, isl_error_invalid, "not a value token",99			return NULL);100 101	return isl_val_int_from_isl_int(ctx, tok->u.v);102}103 104/* Does the given token have a string representation?105 */106isl_bool isl_token_has_str(struct isl_token *tok)107{108	if (!tok)109		return isl_bool_error;110	return isl_bool_ok(tok->u.s != NULL);111}112 113/* Given a token with a string representation, return a copy of this string.114 */115__isl_give char *isl_token_get_str(isl_ctx *ctx, struct isl_token *tok)116{117	if (!tok)118		return NULL;119	if (!tok->u.s)120		isl_die(ctx, isl_error_invalid,121			"token does not have a string representation",122			return NULL);123 124	return strdup(tok->u.s);125}126 127void isl_token_free(struct isl_token *tok)128{129	if (!tok)130		return;131	if (tok->type == ISL_TOKEN_VALUE)132		isl_int_clear(tok->u.v);133	else if (tok->type == ISL_TOKEN_MAP)134		isl_map_free(tok->u.map);135	else if (tok->type == ISL_TOKEN_AFF)136		isl_pw_aff_free(tok->u.pwaff);137	else138		free(tok->u.s);139	free(tok);140}141 142void isl_stream_error(__isl_keep isl_stream *s, struct isl_token *tok,143	char *msg)144{145	int line = tok ? tok->line : s->line;146	int col = tok ? tok->col : s->col;147 148	isl_ctx_set_full_error(s->ctx, isl_error_invalid, "syntax error",149				__FILE__, __LINE__);150 151	if (s->ctx->opt->on_error == ISL_ON_ERROR_CONTINUE)152		return;153	fprintf(stderr, "syntax error (%d, %d): %s\n", line, col, msg);154	if (tok) {155		if (tok->type < 256)156			fprintf(stderr, "got '%c'\n", tok->type);157		else if (tok->type == ISL_TOKEN_IDENT)158			fprintf(stderr, "got ident '%s'\n", tok->u.s);159		else if (tok->is_keyword)160			fprintf(stderr, "got keyword '%s'\n", tok->u.s);161		else if (tok->type == ISL_TOKEN_VALUE) {162			fprintf(stderr, "got value '");163			isl_int_print(stderr, tok->u.v, 0);164			fprintf(stderr, "'\n");165		} else if (tok->type == ISL_TOKEN_MAP) {166			isl_printer *p;167			fprintf(stderr, "got map '");168			p = isl_printer_to_file(s->ctx, stderr);169			p = isl_printer_print_map(p, tok->u.map);170			isl_printer_free(p);171			fprintf(stderr, "'\n");172		} else if (tok->type == ISL_TOKEN_AFF) {173			isl_printer *p;174			fprintf(stderr, "got affine expression '");175			p = isl_printer_to_file(s->ctx, stderr);176			p = isl_printer_print_pw_aff(p, tok->u.pwaff);177			isl_printer_free(p);178			fprintf(stderr, "'\n");179		} else if (tok->u.s)180			fprintf(stderr, "got token '%s'\n", tok->u.s);181		else182			fprintf(stderr, "got token type %d\n", tok->type);183	}184	if (s->ctx->opt->on_error == ISL_ON_ERROR_ABORT)185		abort();186}187 188static __isl_give isl_stream* isl_stream_new(struct isl_ctx *ctx)189{190	int i;191	isl_stream *s = isl_calloc_type(ctx, struct isl_stream);192	if (!s)193		return NULL;194	s->ctx = ctx;195	isl_ctx_ref(s->ctx);196	s->file = NULL;197	s->str = NULL;198	s->len = 0;199	s->line = 1;200	s->col = 1;201	s->eof = 0;202	s->last_line = 0;203	s->c = -1;204	s->n_un = 0;205	for (i = 0; i < 5; ++i)206		s->tokens[i] = NULL;207	s->n_token = 0;208	s->keywords = NULL;209	s->size = 256;210	s->buffer = isl_alloc_array(ctx, char, s->size);211	if (!s->buffer)212		goto error;213	return s;214error:215	isl_stream_free(s);216	return NULL;217}218 219__isl_give isl_stream* isl_stream_new_file(struct isl_ctx *ctx, FILE *file)220{221	isl_stream *s = isl_stream_new(ctx);222	if (!s)223		return NULL;224	s->file = file;225	return s;226}227 228__isl_give isl_stream* isl_stream_new_str(struct isl_ctx *ctx, const char *str)229{230	isl_stream *s;231	if (!str)232		return NULL;233	s = isl_stream_new(ctx);234	if (!s)235		return NULL;236	s->str = str;237	return s;238}239 240/* Read a character from the stream and advance s->line and s->col241 * to point to the next character.242 */243static int stream_getc(__isl_keep isl_stream *s)244{245	int c;246	if (s->eof)247		return -1;248	if (s->n_un)249		return s->c = s->un[--s->n_un];250	if (s->file)251		c = fgetc(s->file);252	else {253		c = *s->str++;254		if (c == '\0')255			c = -1;256	}257	if (c == -1)258		s->eof = 1;259	else if (c == '\n') {260		s->line++;261		s->col = 1;262	} else263		s->col++;264	s->c = c;265	return c;266}267 268static void isl_stream_ungetc(__isl_keep isl_stream *s, int c)269{270	isl_assert(s->ctx, s->n_un < 5, return);271	s->un[s->n_un++] = c;272	s->c = -1;273}274 275/* Read a character from the stream, skipping pairs of '\\' and '\n'.276 * Set s->start_line and s->start_col to the line and column277 * of the returned character.278 */279static int isl_stream_getc(__isl_keep isl_stream *s)280{281	int c;282 283	do {284		s->start_line = s->line;285		s->start_col = s->col;286		c = stream_getc(s);287		if (c != '\\')288			return c;289		c = stream_getc(s);290	} while (c == '\n');291 292	isl_stream_ungetc(s, c);293 294	return '\\';295}296 297static int isl_stream_push_char(__isl_keep isl_stream *s, int c)298{299	if (s->len >= s->size) {300		char *buffer;301		s->size = (3*s->size)/2;302		buffer = isl_realloc_array(s->ctx, s->buffer, char, s->size);303		if (!buffer)304			return -1;305		s->buffer = buffer;306	}307	s->buffer[s->len++] = c;308	return 0;309}310 311void isl_stream_push_token(__isl_keep isl_stream *s, struct isl_token *tok)312{313	isl_assert(s->ctx, s->n_token < 5, return);314	s->tokens[s->n_token++] = tok;315}316 317static enum isl_token_type check_keywords(__isl_keep isl_stream *s)318{319	struct isl_hash_table_entry *entry;320	struct isl_keyword *keyword;321	uint32_t name_hash;322 323	if (!strcasecmp(s->buffer, "exists"))324		return ISL_TOKEN_EXISTS;325	if (!strcasecmp(s->buffer, "and"))326		return ISL_TOKEN_AND;327	if (!strcasecmp(s->buffer, "or"))328		return ISL_TOKEN_OR;329	if (!strcasecmp(s->buffer, "implies"))330		return ISL_TOKEN_IMPLIES;331	if (!strcasecmp(s->buffer, "not"))332		return ISL_TOKEN_NOT;333	if (!strcasecmp(s->buffer, "infty"))334		return ISL_TOKEN_INFTY;335	if (!strcasecmp(s->buffer, "infinity"))336		return ISL_TOKEN_INFTY;337	if (!strcasecmp(s->buffer, "NaN"))338		return ISL_TOKEN_NAN;339	if (!strcasecmp(s->buffer, "min"))340		return ISL_TOKEN_MIN;341	if (!strcasecmp(s->buffer, "max"))342		return ISL_TOKEN_MAX;343	if (!strcasecmp(s->buffer, "rat"))344		return ISL_TOKEN_RAT;345	if (!strcasecmp(s->buffer, "true"))346		return ISL_TOKEN_TRUE;347	if (!strcasecmp(s->buffer, "false"))348		return ISL_TOKEN_FALSE;349	if (!strcasecmp(s->buffer, "ceild"))350		return ISL_TOKEN_CEILD;351	if (!strcasecmp(s->buffer, "floord"))352		return ISL_TOKEN_FLOORD;353	if (!strcasecmp(s->buffer, "mod"))354		return ISL_TOKEN_MOD;355	if (!strcasecmp(s->buffer, "ceil"))356		return ISL_TOKEN_CEIL;357	if (!strcasecmp(s->buffer, "floor"))358		return ISL_TOKEN_FLOOR;359 360	if (!s->keywords)361		return ISL_TOKEN_IDENT;362 363	name_hash = isl_hash_string(isl_hash_init(), s->buffer);364	entry = isl_hash_table_find(s->ctx, s->keywords, name_hash, same_name,365					s->buffer, 0);366	if (!entry)367		return ISL_TOKEN_ERROR;368	if (entry != isl_hash_table_entry_none) {369		keyword = entry->data;370		return keyword->type;371	}372 373	return ISL_TOKEN_IDENT;374}375 376int isl_stream_skip_line(__isl_keep isl_stream *s)377{378	int c;379 380	while ((c = isl_stream_getc(s)) != -1 && c != '\n')381		/* nothing */382		;383 384	return c == -1 ? -1 : 0;385}386 387static struct isl_token *next_token(__isl_keep isl_stream *s, int same_line)388{389	int c;390	struct isl_token *tok = NULL;391	int line, col;392	int old_line = s->last_line;393 394	if (s->n_token) {395		if (same_line && s->tokens[s->n_token - 1]->on_new_line)396			return NULL;397		return s->tokens[--s->n_token];398	}399 400	if (same_line && s->c == '\n')401		return NULL;402 403	s->len = 0;404 405	/* skip spaces and comment lines */406	while ((c = isl_stream_getc(s)) != -1) {407		if (c == '#') {408			if (isl_stream_skip_line(s) < 0)409				break;410			c = '\n';411			if (same_line)412				break;413		} else if (!isspace(c) || (same_line && c == '\n'))414			break;415	}416 417	line = s->start_line;418	col = s->start_col;419 420	if (c == -1 || (same_line && c == '\n'))421		return NULL;422	s->last_line = line;423 424	if (c == '(' ||425	    c == ')' ||426	    c == '+' ||427	    c == '*' ||428	    c == '%' ||429	    c == '?' ||430	    c == '^' ||431	    c == '@' ||432	    c == '$' ||433	    c == ',' ||434	    c == '.' ||435	    c == ';' ||436	    c == '[' ||437	    c == ']' ||438	    c == '{' ||439	    c == '}') {440		tok = isl_token_new(s->ctx, line, col, old_line != line);441		if (!tok)442			return NULL;443		tok->type = (enum isl_token_type)c;444		return tok;445	}446	if (c == '-') {447		int c;448		if ((c = isl_stream_getc(s)) == '>') {449			tok = isl_token_new(s->ctx, line, col, old_line != line);450			if (!tok)451				return NULL;452			tok->u.s = strdup("->");453			tok->type = ISL_TOKEN_TO;454			return tok;455		}456		if (c != -1)457			isl_stream_ungetc(s, c);458		tok = isl_token_new(s->ctx, line, col, old_line != line);459		if (!tok)460			return NULL;461		tok->type = (enum isl_token_type) '-';462		return tok;463	}464	if (isdigit(c)) {465		int minus = c == '-';466		tok = isl_token_new(s->ctx, line, col, old_line != line);467		if (!tok)468			return NULL;469		tok->type = ISL_TOKEN_VALUE;470		isl_int_init(tok->u.v);471		if (isl_stream_push_char(s, c))472			goto error;473		while ((c = isl_stream_getc(s)) != -1 && isdigit(c))474			if (isl_stream_push_char(s, c))475				goto error;476		if (c != -1)477			isl_stream_ungetc(s, c);478		isl_stream_push_char(s, '\0');479		isl_int_read(tok->u.v, s->buffer);480		if (minus && isl_int_is_zero(tok->u.v)) {481			tok->col++;482			tok->on_new_line = 0;483			isl_stream_push_token(s, tok);484			tok = isl_token_new(s->ctx, line, col, old_line != line);485			if (!tok)486				return NULL;487			tok->type = (enum isl_token_type) '-';488		}489		return tok;490	}491	if (isalpha(c) || c == '_') {492		tok = isl_token_new(s->ctx, line, col, old_line != line);493		if (!tok)494			return NULL;495		isl_stream_push_char(s, c);496		while ((c = isl_stream_getc(s)) != -1 &&497				(isalnum(c) || c == '_'))498			isl_stream_push_char(s, c);499		if (c != -1)500			isl_stream_ungetc(s, c);501		while ((c = isl_stream_getc(s)) != -1 && c == '\'')502			isl_stream_push_char(s, c);503		if (c != -1)504			isl_stream_ungetc(s, c);505		isl_stream_push_char(s, '\0');506		tok->type = check_keywords(s);507		if (tok->type != ISL_TOKEN_IDENT)508			tok->is_keyword = 1;509		tok->u.s = strdup(s->buffer);510		if (!tok->u.s)511			goto error;512		return tok;513	}514	if (c == '"') {515		tok = isl_token_new(s->ctx, line, col, old_line != line);516		if (!tok)517			return NULL;518		tok->type = ISL_TOKEN_STRING;519		tok->u.s = NULL;520		while ((c = isl_stream_getc(s)) != -1 && c != '"' && c != '\n')521			isl_stream_push_char(s, c);522		if (c != '"') {523			isl_stream_error(s, NULL, "unterminated string");524			goto error;525		}526		isl_stream_push_char(s, '\0');527		tok->u.s = strdup(s->buffer);528		return tok;529	}530	if (c == '=') {531		int c;532		tok = isl_token_new(s->ctx, line, col, old_line != line);533		if (!tok)534			return NULL;535		if ((c = isl_stream_getc(s)) == '=') {536			tok->u.s = strdup("==");537			tok->type = ISL_TOKEN_EQ_EQ;538			return tok;539		}540		if (c != -1)541			isl_stream_ungetc(s, c);542		tok->type = (enum isl_token_type) '=';543		return tok;544	}545	if (c == ':') {546		int c;547		tok = isl_token_new(s->ctx, line, col, old_line != line);548		if (!tok)549			return NULL;550		if ((c = isl_stream_getc(s)) == '=') {551			tok->u.s = strdup(":=");552			tok->type = ISL_TOKEN_DEF;553			return tok;554		}555		if (c != -1)556			isl_stream_ungetc(s, c);557		tok->type = (enum isl_token_type) ':';558		return tok;559	}560	if (c == '>') {561		int c;562		tok = isl_token_new(s->ctx, line, col, old_line != line);563		if (!tok)564			return NULL;565		if ((c = isl_stream_getc(s)) == '=') {566			tok->u.s = strdup(">=");567			tok->type = ISL_TOKEN_GE;568			return tok;569		} else if (c == '>') {570			if ((c = isl_stream_getc(s)) == '=') {571				tok->u.s = strdup(">>=");572				tok->type = ISL_TOKEN_LEX_GE;573				return tok;574			}575			tok->u.s = strdup(">>");576			tok->type = ISL_TOKEN_LEX_GT;577		} else {578			tok->u.s = strdup(">");579			tok->type = ISL_TOKEN_GT;580		}581		if (c != -1)582			isl_stream_ungetc(s, c);583		return tok;584	}585	if (c == '<') {586		int c;587		tok = isl_token_new(s->ctx, line, col, old_line != line);588		if (!tok)589			return NULL;590		if ((c = isl_stream_getc(s)) == '=') {591			tok->u.s = strdup("<=");592			tok->type = ISL_TOKEN_LE;593			return tok;594		} else if (c == '<') {595			if ((c = isl_stream_getc(s)) == '=') {596				tok->u.s = strdup("<<=");597				tok->type = ISL_TOKEN_LEX_LE;598				return tok;599			}600			tok->u.s = strdup("<<");601			tok->type = ISL_TOKEN_LEX_LT;602		} else {603			tok->u.s = strdup("<");604			tok->type = ISL_TOKEN_LT;605		}606		if (c != -1)607			isl_stream_ungetc(s, c);608		return tok;609	}610	if (c == '&') {611		tok = isl_token_new(s->ctx, line, col, old_line != line);612		if (!tok)613			return NULL;614		tok->type = ISL_TOKEN_AND;615		if ((c = isl_stream_getc(s)) != '&' && c != -1) {616			tok->u.s = strdup("&");617			isl_stream_ungetc(s, c);618		} else619			tok->u.s = strdup("&&");620		return tok;621	}622	if (c == '|') {623		tok = isl_token_new(s->ctx, line, col, old_line != line);624		if (!tok)625			return NULL;626		tok->type = ISL_TOKEN_OR;627		if ((c = isl_stream_getc(s)) != '|' && c != -1) {628			tok->u.s = strdup("|");629			isl_stream_ungetc(s, c);630		} else631			tok->u.s = strdup("||");632		return tok;633	}634	if (c == '/') {635		tok = isl_token_new(s->ctx, line, col, old_line != line);636		if (!tok)637			return NULL;638		if ((c = isl_stream_getc(s)) == '\\') {639			tok->u.s = strdup("/\\");640			tok->type = ISL_TOKEN_AND;641			return tok;642		} else if (c == '/') {643			tok->u.s = strdup("//");644			tok->type = ISL_TOKEN_INT_DIV;645			return tok;646		} else {647			tok->type = (enum isl_token_type) '/';648		}649		if (c != -1)650			isl_stream_ungetc(s, c);651		return tok;652	}653	if (c == '\\') {654		tok = isl_token_new(s->ctx, line, col, old_line != line);655		if (!tok)656			return NULL;657		if ((c = isl_stream_getc(s)) != '/' && c != -1) {658			tok->type = (enum isl_token_type) '\\';659			isl_stream_ungetc(s, c);660		} else {661			tok->u.s = strdup("\\/");662			tok->type = ISL_TOKEN_OR;663		}664		return tok;665	}666	if (c == '!') {667		tok = isl_token_new(s->ctx, line, col, old_line != line);668		if (!tok)669			return NULL;670		if ((c = isl_stream_getc(s)) == '=') {671			tok->u.s = strdup("!=");672			tok->type = ISL_TOKEN_NE;673			return tok;674		} else {675			tok->type = ISL_TOKEN_NOT;676			tok->u.s = strdup("!");677		}678		if (c != -1)679			isl_stream_ungetc(s, c);680		return tok;681	}682 683	tok = isl_token_new(s->ctx, line, col, old_line != line);684	if (!tok)685		return NULL;686	tok->type = ISL_TOKEN_UNKNOWN;687	return tok;688error:689	isl_token_free(tok);690	return NULL;691}692 693struct isl_token *isl_stream_next_token(__isl_keep isl_stream *s)694{695	return next_token(s, 0);696}697 698struct isl_token *isl_stream_next_token_on_same_line(__isl_keep isl_stream *s)699{700	return next_token(s, 1);701}702 703int isl_stream_eat_if_available(__isl_keep isl_stream *s, int type)704{705	struct isl_token *tok;706 707	tok = isl_stream_next_token(s);708	if (!tok)709		return 0;710	if (tok->type == type) {711		isl_token_free(tok);712		return 1;713	}714	isl_stream_push_token(s, tok);715	return 0;716}717 718int isl_stream_next_token_is(__isl_keep isl_stream *s, int type)719{720	struct isl_token *tok;721	int r;722 723	tok = isl_stream_next_token(s);724	if (!tok)725		return 0;726	r = tok->type == type;727	isl_stream_push_token(s, tok);728	return r;729}730 731char *isl_stream_read_ident_if_available(__isl_keep isl_stream *s)732{733	struct isl_token *tok;734 735	tok = isl_stream_next_token(s);736	if (!tok)737		return NULL;738	if (tok->type == ISL_TOKEN_IDENT) {739		char *ident = strdup(tok->u.s);740		isl_token_free(tok);741		return ident;742	}743	isl_stream_push_token(s, tok);744	return NULL;745}746 747int isl_stream_eat(__isl_keep isl_stream *s, int type)748{749	struct isl_token *tok;750 751	tok = isl_stream_next_token(s);752	if (!tok) {753		if (s->eof)754			isl_stream_error(s, NULL, "unexpected EOF");755		return -1;756	}757	if (tok->type == type) {758		isl_token_free(tok);759		return 0;760	}761	isl_stream_error(s, tok, "expecting other token");762	isl_token_free(tok);763	return -1;764}765 766int isl_stream_is_empty(__isl_keep isl_stream *s)767{768	struct isl_token *tok;769 770	tok = isl_stream_next_token(s);771 772	if (!tok)773		return 1;774 775	isl_stream_push_token(s, tok);776	return 0;777}778 779static isl_stat free_keyword(void **p, void *user)780{781	struct isl_keyword *keyword = *p;782 783	free(keyword->name);784	free(keyword);785 786	return isl_stat_ok;787}788 789void isl_stream_flush_tokens(__isl_keep isl_stream *s)790{791	int i;792 793	if (!s)794		return;795	for (i = 0; i < s->n_token; ++i)796		isl_token_free(s->tokens[i]);797	s->n_token = 0;798}799 800isl_ctx *isl_stream_get_ctx(__isl_keep isl_stream *s)801{802	return s ? s->ctx : NULL;803}804 805void isl_stream_free(__isl_take isl_stream *s)806{807	if (!s)808		return;809	free(s->buffer);810	if (s->n_token != 0) {811		struct isl_token *tok = isl_stream_next_token(s);812		isl_stream_error(s, tok, "unexpected token");813		isl_token_free(tok);814	}815	if (s->keywords) {816		isl_hash_table_foreach(s->ctx, s->keywords, &free_keyword, NULL);817		isl_hash_table_free(s->ctx, s->keywords);818	}819	free(s->yaml_state);820	free(s->yaml_indent);821	isl_ctx_deref(s->ctx);822	free(s);823}824 825/* Push "state" onto the stack of currently active YAML elements.826 * The caller is responsible for setting the corresponding indentation.827 * Return 0 on success and -1 on failure.828 */829static int push_state(__isl_keep isl_stream *s, enum isl_yaml_state state)830{831	if (s->yaml_size < s->yaml_depth + 1) {832		int *indent;833		enum isl_yaml_state *state;834 835		state = isl_realloc_array(s->ctx, s->yaml_state,836					enum isl_yaml_state, s->yaml_depth + 1);837		if (!state)838			return -1;839		s->yaml_state = state;840 841		indent = isl_realloc_array(s->ctx, s->yaml_indent,842					int, s->yaml_depth + 1);843		if (!indent)844			return -1;845		s->yaml_indent = indent;846 847		s->yaml_size = s->yaml_depth + 1;848	}849 850	s->yaml_state[s->yaml_depth] = state;851	s->yaml_depth++;852 853	return 0;854}855 856/* Remove the innermost active YAML element from the stack.857 * Return isl_stat_ok on success and isl_stat_error on failure.858 */859static isl_stat pop_state(__isl_keep isl_stream *s)860{861	if (!s)862		return isl_stat_error;863	if (s->yaml_depth < 1)864		isl_die(isl_stream_get_ctx(s), isl_error_invalid,865			"not in YAML construct", return isl_stat_error);866 867	s->yaml_depth--;868 869	return isl_stat_ok;870}871 872/* Set the state of the innermost active YAML element to "state".873 * Return 0 on success and -1 on failure.874 */875static int update_state(__isl_keep isl_stream *s, enum isl_yaml_state state)876{877	if (!s)878		return -1;879	if (s->yaml_depth < 1)880		isl_die(isl_stream_get_ctx(s), isl_error_invalid,881			"not in YAML construct", return -1);882 883	s->yaml_state[s->yaml_depth - 1] = state;884 885	return 0;886}887 888/* Return the state of the innermost active YAML element.889 * Return isl_yaml_none if we are not inside any YAML element.890 */891static enum isl_yaml_state current_state(__isl_keep isl_stream *s)892{893	if (!s)894		return isl_yaml_none;895	if (s->yaml_depth < 1)896		return isl_yaml_none;897	return s->yaml_state[s->yaml_depth - 1];898}899 900/* Set the indentation of the innermost active YAML element to "indent".901 * If "indent" is equal to ISL_YAML_INDENT_FLOW, then this means902 * that the current element is in flow format.903 */904static isl_stat set_yaml_indent(__isl_keep isl_stream *s, int indent)905{906	if (s->yaml_depth < 1)907		isl_die(s->ctx, isl_error_internal,908			"not in YAML element", return isl_stat_error);909 910	s->yaml_indent[s->yaml_depth - 1] = indent;911 912	return isl_stat_ok;913}914 915/* Return the indentation of the innermost active YAML element916 * of -1 on error.917 */918static int get_yaml_indent(__isl_keep isl_stream *s)919{920	if (s->yaml_depth < 1)921		isl_die(s->ctx, isl_error_internal,922			"not in YAML element", return -1);923 924	return s->yaml_indent[s->yaml_depth - 1];925}926 927/* Move to the next state at the innermost level.928 * Return isl_bool_true if successful.929 * Return isl_bool_false if we are at the end of the innermost level.930 * Return isl_bool_error on error.931 *932 * If we are in state isl_yaml_mapping_key_start, then we have just933 * started a mapping and we are expecting a key.  If the mapping started934 * with a '{', then we check if the next token is a '}'.  If so,935 * then the mapping is empty and there is no next state at this level.936 * Otherwise, we assume that there is at least one key (the one from937 * which we derived the indentation in isl_stream_yaml_read_start_mapping.938 *939 * If we are in state isl_yaml_mapping_key, then the we expect a colon940 * followed by a value, so there is always a next state unless941 * some error occurs.942 *943 * If we are in state isl_yaml_mapping_val, then there may or may944 * not be a subsequent key in the same mapping.945 * In flow format, the next key is preceded by a comma.946 * In block format, the next key has the same indentation as the first key.947 * If the first token has a smaller indentation, then we have reached948 * the end of the current mapping.949 *950 * If we are in state isl_yaml_sequence_start, then we have just951 * started a sequence.  If the sequence started with a '[',952 * then we check if the next token is a ']'.  If so, then the sequence953 * is empty and there is no next state at this level.954 * Otherwise, we assume that there is at least one element in the sequence955 * (the one from which we derived the indentation in956 * isl_stream_yaml_read_start_sequence.957 *958 * If we are in state isl_yaml_sequence, then there may or may959 * not be a subsequent element in the same sequence.960 * In flow format, the next element is preceded by a comma.961 * In block format, the next element is introduced by a dash with962 * the same indentation as that of the first element.963 * If the first token is not a dash or if it has a smaller indentation,964 * then we have reached the end of the current sequence.965 */966isl_bool isl_stream_yaml_next(__isl_keep isl_stream *s)967{968	struct isl_token *tok;969	enum isl_yaml_state state;970	int indent;971 972	state = current_state(s);973	if (state == isl_yaml_none)974		isl_die(s->ctx, isl_error_invalid,975			"not in YAML element", return isl_bool_error);976	switch (state) {977	case isl_yaml_mapping_key_start:978		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW &&979		    isl_stream_next_token_is(s, '}'))980			return isl_bool_false;981		if (update_state(s, isl_yaml_mapping_key) < 0)982			return isl_bool_error;983		return isl_bool_true;984	case isl_yaml_mapping_key:985		tok = isl_stream_next_token(s);986		if (!tok) {987			if (s->eof)988				isl_stream_error(s, NULL, "unexpected EOF");989			return isl_bool_error;990		}991		if (tok->type == ':') {992			isl_token_free(tok);993			if (update_state(s, isl_yaml_mapping_val) < 0)994				return isl_bool_error;995			return isl_bool_true;996		}997		isl_stream_error(s, tok, "expecting ':'");998		isl_stream_push_token(s, tok);999		return isl_bool_error;1000	case isl_yaml_mapping_val:1001		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {1002			if (!isl_stream_eat_if_available(s, ','))1003				return isl_bool_false;1004			if (update_state(s, isl_yaml_mapping_key) < 0)1005				return isl_bool_error;1006			return isl_bool_true;1007		}1008		tok = isl_stream_next_token(s);1009		if (!tok)1010			return isl_bool_false;1011		indent = tok->col - 1;1012		isl_stream_push_token(s, tok);1013		if (indent < get_yaml_indent(s))1014			return isl_bool_false;1015		if (update_state(s, isl_yaml_mapping_key) < 0)1016			return isl_bool_error;1017		return isl_bool_true;1018	case isl_yaml_sequence_start:1019		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {1020			if (isl_stream_next_token_is(s, ']'))1021				return isl_bool_false;1022			if (update_state(s, isl_yaml_sequence) < 0)1023				return isl_bool_error;1024			return isl_bool_true;1025		}1026		tok = isl_stream_next_token(s);1027		if (!tok) {1028			if (s->eof)1029				isl_stream_error(s, NULL, "unexpected EOF");1030			return isl_bool_error;1031		}1032		if (tok->type == '-') {1033			isl_token_free(tok);1034			if (update_state(s, isl_yaml_sequence) < 0)1035				return isl_bool_error;1036			return isl_bool_true;1037		}1038		isl_stream_error(s, tok, "expecting '-'");1039		isl_stream_push_token(s, tok);1040		return isl_bool_false;1041	case isl_yaml_sequence:1042		if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW)1043			return isl_bool_ok(isl_stream_eat_if_available(s, ','));1044		tok = isl_stream_next_token(s);1045		if (!tok)1046			return isl_bool_false;1047		indent = tok->col - 1;1048		if (indent < get_yaml_indent(s) || tok->type != '-') {1049			isl_stream_push_token(s, tok);1050			return isl_bool_false;1051		}1052		isl_token_free(tok);1053		return isl_bool_true;1054	default:1055		isl_die(s->ctx, isl_error_internal,1056			"unexpected state", return isl_bool_error);1057	}1058}1059 1060/* Start reading a YAML mapping.1061 * Return isl_stat_ok on success and isl_stat_error on error.1062 *1063 * If the first token on the stream is a '{' then we remove this token1064 * from the stream and keep track of the fact that the mapping1065 * is given in flow format.1066 * Otherwise, we assume the first token is the first key of the mapping and1067 * keep track of its indentation, but keep the token on the stream.1068 * In both cases, the next token we expect is the first key of the mapping.1069 */1070isl_stat isl_stream_yaml_read_start_mapping(__isl_keep isl_stream *s)1071{1072	struct isl_token *tok;1073	int indent;1074 1075	if (push_state(s, isl_yaml_mapping_key_start) < 0)1076		return isl_stat_error;1077 1078	tok = isl_stream_next_token(s);1079	if (!tok) {1080		if (s->eof)1081			isl_stream_error(s, NULL, "unexpected EOF");1082		return isl_stat_error;1083	}1084	if (isl_token_get_type(tok) == '{') {1085		isl_token_free(tok);1086		return set_yaml_indent(s, ISL_YAML_INDENT_FLOW);1087	}1088	indent = tok->col - 1;1089	isl_stream_push_token(s, tok);1090 1091	return set_yaml_indent(s, indent);1092}1093 1094/* Finish reading a YAML mapping.1095 * Return isl_stat_ok on success and isl_stat_error on error.1096 *1097 * If the mapping started with a '{', then we expect a '}' to close1098 * the mapping.1099 * Otherwise, we double-check that the next token (if any)1100 * has a smaller indentation than that of the current mapping.1101 */1102isl_stat isl_stream_yaml_read_end_mapping(__isl_keep isl_stream *s)1103{1104	struct isl_token *tok;1105	int indent;1106 1107	if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {1108		if (isl_stream_eat(s, '}') < 0)1109			return isl_stat_error;1110		return pop_state(s);1111	}1112 1113	tok = isl_stream_next_token(s);1114	if (!tok)1115		return pop_state(s);1116 1117	indent = tok->col - 1;1118	isl_stream_push_token(s, tok);1119 1120	if (indent >= get_yaml_indent(s))1121		isl_die(isl_stream_get_ctx(s), isl_error_invalid,1122			"mapping not finished", return isl_stat_error);1123 1124	return pop_state(s);1125}1126 1127/* Start reading a YAML sequence.1128 * Return isl_stat_ok on success and isl_stat_error on error.1129 *1130 * If the first token on the stream is a '[' then we remove this token1131 * from the stream and keep track of the fact that the sequence1132 * is given in flow format.1133 * Otherwise, we assume the first token is the dash that introduces1134 * the first element of the sequence and keep track of its indentation,1135 * but keep the token on the stream.1136 * In both cases, the next token we expect is the first element1137 * of the sequence.1138 */1139isl_stat isl_stream_yaml_read_start_sequence(__isl_keep isl_stream *s)1140{1141	struct isl_token *tok;1142	int indent;1143 1144	if (push_state(s, isl_yaml_sequence_start) < 0)1145		return isl_stat_error;1146 1147	tok = isl_stream_next_token(s);1148	if (!tok) {1149		if (s->eof)1150			isl_stream_error(s, NULL, "unexpected EOF");1151		return isl_stat_error;1152	}1153	if (isl_token_get_type(tok) == '[') {1154		isl_token_free(tok);1155		return set_yaml_indent(s, ISL_YAML_INDENT_FLOW);1156	}1157	indent = tok->col - 1;1158	isl_stream_push_token(s, tok);1159 1160	return set_yaml_indent(s, indent);1161}1162 1163/* Finish reading a YAML sequence.1164 * Return isl_stat_ok on success and isl_stat_error on error.1165 *1166 * If the sequence started with a '[', then we expect a ']' to close1167 * the sequence.1168 * Otherwise, we double-check that the next token (if any)1169 * is not a dash or that it has a smaller indentation than1170 * that of the current sequence.1171 */1172isl_stat isl_stream_yaml_read_end_sequence(__isl_keep isl_stream *s)1173{1174	struct isl_token *tok;1175	int indent;1176	int dash;1177 1178	if (get_yaml_indent(s) == ISL_YAML_INDENT_FLOW) {1179		if (isl_stream_eat(s, ']') < 0)1180			return isl_stat_error;1181		return pop_state(s);1182	}1183 1184	tok = isl_stream_next_token(s);1185	if (!tok)1186		return pop_state(s);1187 1188	indent = tok->col - 1;1189	dash = tok->type == '-';1190	isl_stream_push_token(s, tok);1191 1192	if (indent >= get_yaml_indent(s) && dash)1193		isl_die(isl_stream_get_ctx(s), isl_error_invalid,1194			"sequence not finished", return isl_stat_error);1195 1196	return pop_state(s);1197}1198