isl_stream.c 28 KB

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