cmListFileLexer.in.l 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. %{
  2. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  3. file LICENSE.rst or https://cmake.org/licensing for details. */
  4. /*
  5. This file must be translated to C and modified to build everywhere.
  6. Run flex >= 2.6 like this:
  7. flex --nounistd -DFLEXINT_H --noline -ocmListFileLexer.c cmListFileLexer.in.l
  8. Modify cmListFileLexer.c:
  9. - remove trailing whitespace: sed -i 's/\s*$//' cmListFileLexer.c
  10. - remove blank lines at end of file: sed -i '${/^$/d;}' cmListFileLexer.c
  11. - #include "cmStandardLexer.h" at the top: sed -i '1i#include "cmStandardLexer.h"' cmListFileLexer.c
  12. */
  13. /* IWYU pragma: no_forward_declare yyguts_t */
  14. #ifdef _WIN32
  15. #include "cmsys/Encoding.h"
  16. #endif
  17. /* Setup the proper cmListFileLexer_yylex declaration. */
  18. #define YY_EXTRA_TYPE cmListFileLexer*
  19. #define YY_DECL int cmListFileLexer_yylex (yyscan_t yyscanner, cmListFileLexer* lexer)
  20. #include "cmListFileLexer.h"
  21. /*--------------------------------------------------------------------------*/
  22. struct cmListFileLexer_s
  23. {
  24. cmListFileLexer_Token token;
  25. int bracket;
  26. int comment;
  27. int line;
  28. int column;
  29. size_t size;
  30. FILE* file;
  31. size_t cr;
  32. char* string_buffer;
  33. char* string_position;
  34. size_t string_left;
  35. yyscan_t scanner;
  36. };
  37. static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
  38. size_t length);
  39. static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
  40. size_t length);
  41. static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
  42. size_t bufferSize);
  43. static void cmListFileLexerInit(cmListFileLexer* lexer);
  44. static void cmListFileLexerDestroy(cmListFileLexer* lexer);
  45. /* Replace the lexer input function. */
  46. #undef YY_INPUT
  47. #define YY_INPUT(buf, result, max_size) \
  48. do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0)
  49. /*--------------------------------------------------------------------------*/
  50. %}
  51. %option prefix="cmListFileLexer_yy"
  52. %option reentrant
  53. %option yylineno
  54. %option noyywrap
  55. %pointer
  56. %x STRING
  57. %x BRACKET
  58. %x BRACKETEND
  59. %x COMMENT
  60. MAKEVAR \$\([A-Za-z0-9_]*\)
  61. UNQUOTED ([^ \0\t\r\n\(\)#\\\"[=]|\\[^\0\n])
  62. LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\"
  63. %%
  64. <INITIAL,COMMENT>\n {
  65. lexer->token.type = cmListFileLexer_Token_Newline;
  66. cmListFileLexerSetToken(lexer, yytext, yyleng);
  67. ++lexer->line;
  68. lexer->column = 1;
  69. BEGIN(INITIAL);
  70. return 1;
  71. }
  72. #?\[=*\[\n? {
  73. const char* bracket = yytext;
  74. size_t length = yyleng;
  75. lexer->comment = yytext[0] == '#';
  76. if (lexer->comment) {
  77. lexer->token.type = cmListFileLexer_Token_CommentBracket;
  78. bracket += 1;
  79. --length;
  80. } else {
  81. lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
  82. }
  83. cmListFileLexerSetToken(lexer, "", 0);
  84. lexer->bracket = (char*)memchr(bracket + 1, '[', length - 1) - bracket;
  85. if (yytext[yyleng-1] == '\n') {
  86. ++lexer->line;
  87. lexer->column = 1;
  88. } else {
  89. lexer->column += yyleng;
  90. }
  91. BEGIN(BRACKET);
  92. }
  93. # {
  94. lexer->column += yyleng;
  95. BEGIN(COMMENT);
  96. }
  97. <COMMENT>[^\0\n]* {
  98. lexer->column += yyleng;
  99. }
  100. \( {
  101. lexer->token.type = cmListFileLexer_Token_ParenLeft;
  102. cmListFileLexerSetToken(lexer, yytext, yyleng);
  103. lexer->column += yyleng;
  104. return 1;
  105. }
  106. \) {
  107. lexer->token.type = cmListFileLexer_Token_ParenRight;
  108. cmListFileLexerSetToken(lexer, yytext, yyleng);
  109. lexer->column += yyleng;
  110. return 1;
  111. }
  112. [A-Za-z_][A-Za-z0-9_]* {
  113. lexer->token.type = cmListFileLexer_Token_Identifier;
  114. cmListFileLexerSetToken(lexer, yytext, yyleng);
  115. lexer->column += yyleng;
  116. return 1;
  117. }
  118. <BRACKET>\]=* {
  119. /* Handle ]]====]=======]*/
  120. cmListFileLexerAppend(lexer, yytext, yyleng);
  121. lexer->column += yyleng;
  122. if (yyleng == lexer->bracket) {
  123. BEGIN(BRACKETEND);
  124. }
  125. }
  126. <BRACKETEND>\] {
  127. lexer->column += yyleng;
  128. /* Erase the partial bracket from the token. */
  129. lexer->token.length -= lexer->bracket;
  130. BEGIN(INITIAL);
  131. return 1;
  132. }
  133. <BRACKET>([^]\0\n])+ {
  134. cmListFileLexerAppend(lexer, yytext, yyleng);
  135. lexer->column += yyleng;
  136. }
  137. <BRACKET,BRACKETEND>\n {
  138. cmListFileLexerAppend(lexer, yytext, yyleng);
  139. ++lexer->line;
  140. lexer->column = 1;
  141. BEGIN(BRACKET);
  142. }
  143. <BRACKET,BRACKETEND>[^\0\n] {
  144. cmListFileLexerAppend(lexer, yytext, yyleng);
  145. lexer->column += yyleng;
  146. BEGIN(BRACKET);
  147. }
  148. <BRACKET,BRACKETEND><<EOF>> {
  149. lexer->token.type = cmListFileLexer_Token_BadBracket;
  150. BEGIN(INITIAL);
  151. return 1;
  152. }
  153. ({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* {
  154. lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
  155. cmListFileLexerSetToken(lexer, yytext, yyleng);
  156. lexer->column += yyleng;
  157. return 1;
  158. }
  159. ({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* {
  160. lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
  161. cmListFileLexerSetToken(lexer, yytext, yyleng);
  162. lexer->column += yyleng;
  163. return 1;
  164. }
  165. \[ {
  166. lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
  167. cmListFileLexerSetToken(lexer, yytext, yyleng);
  168. lexer->column += yyleng;
  169. return 1;
  170. }
  171. \" {
  172. lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
  173. cmListFileLexerSetToken(lexer, "", 0);
  174. lexer->column += yyleng;
  175. BEGIN(STRING);
  176. }
  177. <STRING>([^\\\0\n\"]|\\[^\0\n])+ {
  178. cmListFileLexerAppend(lexer, yytext, yyleng);
  179. lexer->column += yyleng;
  180. }
  181. <STRING>\\\n {
  182. /* Continuation: text is not part of string */
  183. ++lexer->line;
  184. lexer->column = 1;
  185. }
  186. <STRING>\n {
  187. cmListFileLexerAppend(lexer, yytext, yyleng);
  188. ++lexer->line;
  189. lexer->column = 1;
  190. }
  191. <STRING>\" {
  192. lexer->column += yyleng;
  193. BEGIN(INITIAL);
  194. return 1;
  195. }
  196. <STRING>[^\0\n] {
  197. cmListFileLexerAppend(lexer, yytext, yyleng);
  198. lexer->column += yyleng;
  199. }
  200. <STRING><<EOF>> {
  201. lexer->token.type = cmListFileLexer_Token_BadString;
  202. BEGIN(INITIAL);
  203. return 1;
  204. }
  205. [ \t\r]+ {
  206. lexer->token.type = cmListFileLexer_Token_Space;
  207. cmListFileLexerSetToken(lexer, yytext, yyleng);
  208. lexer->column += yyleng;
  209. return 1;
  210. }
  211. . {
  212. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  213. cmListFileLexerSetToken(lexer, yytext, yyleng);
  214. lexer->column += yyleng;
  215. return 1;
  216. }
  217. <<EOF>> {
  218. lexer->token.type = cmListFileLexer_Token_None;
  219. cmListFileLexerSetToken(lexer, 0, 0);
  220. return 0;
  221. }
  222. %%
  223. /*--------------------------------------------------------------------------*/
  224. static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
  225. size_t length)
  226. {
  227. /* Set the token line and column number. */
  228. lexer->token.line = lexer->line;
  229. lexer->token.column = lexer->column;
  230. /* Use the same buffer if possible. */
  231. if (lexer->token.text) {
  232. if (text && length < lexer->size) {
  233. memcpy(lexer->token.text, text, length);
  234. lexer->token.length = length;
  235. return;
  236. }
  237. free(lexer->token.text);
  238. lexer->token.text = 0;
  239. lexer->size = 0;
  240. }
  241. /* Need to extend the buffer. */
  242. if (length > 0) {
  243. lexer->token.text = (char*)malloc(length);
  244. memcpy(lexer->token.text, text, length);
  245. lexer->token.length = length;
  246. lexer->size = length;
  247. } else {
  248. lexer->token.length = 0;
  249. }
  250. }
  251. /*--------------------------------------------------------------------------*/
  252. static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
  253. size_t length)
  254. {
  255. char* temp;
  256. size_t newSize;
  257. /* If the appended text will fit in the buffer, do not reallocate. */
  258. newSize = lexer->token.length + length;
  259. if (lexer->token.text && newSize <= lexer->size) {
  260. memcpy(lexer->token.text + lexer->token.length, text, length);
  261. lexer->token.length += length;
  262. return;
  263. }
  264. /* We need to extend the buffer. */
  265. temp = malloc(newSize);
  266. if (lexer->token.text) {
  267. memcpy(temp, lexer->token.text, lexer->token.length);
  268. free(lexer->token.text);
  269. }
  270. memcpy(temp + lexer->token.length, text, length);
  271. lexer->token.text = temp;
  272. lexer->token.length += length;
  273. lexer->size = newSize;
  274. }
  275. /*--------------------------------------------------------------------------*/
  276. static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
  277. size_t bufferSize)
  278. {
  279. if (lexer) {
  280. if (lexer->file) {
  281. /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
  282. does not convert newlines on all platforms. Move any
  283. trailing CR to the start of the buffer for the next read. */
  284. size_t cr = lexer->cr;
  285. size_t n;
  286. buffer[0] = '\r';
  287. n = fread(buffer + cr, 1, bufferSize - cr, lexer->file);
  288. if (n) {
  289. char* o = buffer;
  290. const char* i = buffer;
  291. const char* e;
  292. n += cr;
  293. cr = (buffer[n - 1] == '\r') ? 1 : 0;
  294. e = buffer + n - cr;
  295. while (i != e) {
  296. if (i[0] == '\r' && i[1] == '\n') {
  297. ++i;
  298. }
  299. *o++ = *i++;
  300. }
  301. n = o - buffer;
  302. } else {
  303. n = cr;
  304. cr = 0;
  305. }
  306. lexer->cr = cr;
  307. return n;
  308. } else if (lexer->string_left) {
  309. size_t length = lexer->string_left;
  310. if (bufferSize < length) {
  311. length = bufferSize;
  312. }
  313. memcpy(buffer, lexer->string_position, length);
  314. lexer->string_position += length;
  315. lexer->string_left -= length;
  316. return length;
  317. }
  318. }
  319. return 0;
  320. }
  321. /*--------------------------------------------------------------------------*/
  322. static void cmListFileLexerInit(cmListFileLexer* lexer)
  323. {
  324. if (lexer->file || lexer->string_buffer) {
  325. cmListFileLexer_yylex_init(&lexer->scanner);
  326. cmListFileLexer_yyset_extra(lexer, lexer->scanner);
  327. }
  328. }
  329. /*--------------------------------------------------------------------------*/
  330. static void cmListFileLexerDestroy(cmListFileLexer* lexer)
  331. {
  332. cmListFileLexerSetToken(lexer, 0, 0);
  333. if (lexer->file || lexer->string_buffer) {
  334. cmListFileLexer_yylex_destroy(lexer->scanner);
  335. if (lexer->file) {
  336. fclose(lexer->file);
  337. lexer->file = 0;
  338. }
  339. if (lexer->string_buffer) {
  340. free(lexer->string_buffer);
  341. lexer->string_buffer = 0;
  342. lexer->string_left = 0;
  343. lexer->string_position = 0;
  344. }
  345. }
  346. }
  347. /*--------------------------------------------------------------------------*/
  348. cmListFileLexer* cmListFileLexer_New(void)
  349. {
  350. cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
  351. if (!lexer) {
  352. return 0;
  353. }
  354. memset(lexer, 0, sizeof(*lexer));
  355. lexer->line = 1;
  356. lexer->column = 1;
  357. return lexer;
  358. }
  359. /*--------------------------------------------------------------------------*/
  360. void cmListFileLexer_Delete(cmListFileLexer* lexer)
  361. {
  362. cmListFileLexer_SetFileName(lexer, 0, 0);
  363. free(lexer);
  364. }
  365. /*--------------------------------------------------------------------------*/
  366. static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f)
  367. {
  368. unsigned char b[2];
  369. if (fread(b, 1, 2, f) == 2) {
  370. if (b[0] == 0xEF && b[1] == 0xBB) {
  371. if (fread(b, 1, 1, f) == 1 && b[0] == 0xBF) {
  372. return cmListFileLexer_BOM_UTF8;
  373. }
  374. } else if (b[0] == 0xFE && b[1] == 0xFF) {
  375. /* UTF-16 BE */
  376. return cmListFileLexer_BOM_UTF16BE;
  377. } else if (b[0] == 0 && b[1] == 0) {
  378. if (fread(b, 1, 2, f) == 2 && b[0] == 0xFE && b[1] == 0xFF) {
  379. return cmListFileLexer_BOM_UTF32BE;
  380. }
  381. } else if (b[0] == 0xFF && b[1] == 0xFE) {
  382. fpos_t p;
  383. fgetpos(f, &p);
  384. if (fread(b, 1, 2, f) == 2 && b[0] == 0 && b[1] == 0) {
  385. return cmListFileLexer_BOM_UTF32LE;
  386. }
  387. if (fsetpos(f, &p) != 0) {
  388. return cmListFileLexer_BOM_Broken;
  389. }
  390. return cmListFileLexer_BOM_UTF16LE;
  391. }
  392. }
  393. if (fseek(f, 0, SEEK_SET) != 0) {
  394. return cmListFileLexer_BOM_Broken;
  395. }
  396. return cmListFileLexer_BOM_None;
  397. }
  398. /*--------------------------------------------------------------------------*/
  399. int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
  400. cmListFileLexer_BOM* bom)
  401. {
  402. int result = 1;
  403. cmListFileLexerDestroy(lexer);
  404. if (name) {
  405. #ifdef _WIN32
  406. wchar_t* wname = cmsysEncoding_DupToWide(name);
  407. lexer->file = _wfopen(wname, L"rb");
  408. free(wname);
  409. #else
  410. lexer->file = fopen(name, "rb");
  411. #endif
  412. if (lexer->file) {
  413. if (bom) {
  414. *bom = cmListFileLexer_ReadBOM(lexer->file);
  415. }
  416. } else {
  417. result = 0;
  418. }
  419. }
  420. cmListFileLexerInit(lexer);
  421. return result;
  422. }
  423. /*--------------------------------------------------------------------------*/
  424. int cmListFileLexer_SetString(cmListFileLexer* lexer, char const* text,
  425. size_t length)
  426. {
  427. int result = 1;
  428. cmListFileLexerDestroy(lexer);
  429. /* text might be not NULL while length is 0. However, on some platforms
  430. malloc(0) will return NULL. To avoid signaling an error to the caller in
  431. such cases, ensure nonzero length. */
  432. if (length > 0) {
  433. lexer->string_buffer = (char*)malloc(length);
  434. if (lexer->string_buffer) {
  435. memcpy(lexer->string_buffer, text, length);
  436. lexer->string_position = lexer->string_buffer;
  437. lexer->string_left = length;
  438. } else {
  439. result = 0;
  440. }
  441. }
  442. cmListFileLexerInit(lexer);
  443. return result;
  444. }
  445. /*--------------------------------------------------------------------------*/
  446. cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
  447. {
  448. if (!lexer->file && !lexer->string_buffer) {
  449. return 0;
  450. }
  451. if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
  452. return &lexer->token;
  453. } else {
  454. cmListFileLexer_SetFileName(lexer, 0, 0);
  455. return 0;
  456. }
  457. }
  458. /*--------------------------------------------------------------------------*/
  459. long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
  460. {
  461. return lexer->line;
  462. }
  463. /*--------------------------------------------------------------------------*/
  464. long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
  465. {
  466. return lexer->column;
  467. }
  468. /*--------------------------------------------------------------------------*/
  469. const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
  470. cmListFileLexer_Type type)
  471. {
  472. (void)lexer;
  473. switch (type) {
  474. case cmListFileLexer_Token_None:
  475. return "nothing";
  476. case cmListFileLexer_Token_Space:
  477. return "space";
  478. case cmListFileLexer_Token_Newline:
  479. return "newline";
  480. case cmListFileLexer_Token_Identifier:
  481. return "identifier";
  482. case cmListFileLexer_Token_ParenLeft:
  483. return "left paren";
  484. case cmListFileLexer_Token_ParenRight:
  485. return "right paren";
  486. case cmListFileLexer_Token_ArgumentUnquoted:
  487. return "unquoted argument";
  488. case cmListFileLexer_Token_ArgumentQuoted:
  489. return "quoted argument";
  490. case cmListFileLexer_Token_ArgumentBracket:
  491. return "bracket argument";
  492. case cmListFileLexer_Token_CommentBracket:
  493. return "bracket comment";
  494. case cmListFileLexer_Token_BadCharacter:
  495. return "bad character";
  496. case cmListFileLexer_Token_BadBracket:
  497. return "unterminated bracket";
  498. case cmListFileLexer_Token_BadString:
  499. return "unterminated string";
  500. }
  501. return "unknown token";
  502. }