cmListFileLexer.in.l 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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 read_buffer[4];
  33. size_t read_size;
  34. size_t read_position;
  35. char* string_buffer;
  36. char* string_position;
  37. size_t string_left;
  38. yyscan_t scanner;
  39. };
  40. static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
  41. size_t length);
  42. static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
  43. size_t length);
  44. static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
  45. size_t bufferSize);
  46. static void cmListFileLexerInit(cmListFileLexer* lexer);
  47. static void cmListFileLexerDestroy(cmListFileLexer* lexer);
  48. /* Replace the lexer input function. */
  49. #undef YY_INPUT
  50. #define YY_INPUT(buf, result, max_size) \
  51. do { result = cmListFileLexerInput(cmListFileLexer_yyget_extra(yyscanner), buf, max_size); } while (0)
  52. /*--------------------------------------------------------------------------*/
  53. %}
  54. %option prefix="cmListFileLexer_yy"
  55. %option reentrant
  56. %option yylineno
  57. %option noyywrap
  58. %pointer
  59. %x STRING
  60. %x BRACKET
  61. %x BRACKETEND
  62. %x COMMENT
  63. MAKEVAR \$\([A-Za-z0-9_]*\)
  64. UNQUOTED ([^ \t\r\n\(\)#\\\"[=]|\\[^\n])
  65. LEGACY {MAKEVAR}|{UNQUOTED}|\"({MAKEVAR}|{UNQUOTED}|[ \t[=])*\"
  66. %%
  67. <INITIAL,COMMENT>\n {
  68. lexer->token.type = cmListFileLexer_Token_Newline;
  69. cmListFileLexerSetToken(lexer, yytext, yyleng);
  70. ++lexer->line;
  71. lexer->column = 1;
  72. BEGIN(INITIAL);
  73. return 1;
  74. }
  75. #?\[=*\[\n? {
  76. const char* bracket = yytext;
  77. size_t length = yyleng;
  78. lexer->comment = yytext[0] == '#';
  79. if (lexer->comment) {
  80. lexer->token.type = cmListFileLexer_Token_CommentBracket;
  81. bracket += 1;
  82. --length;
  83. } else {
  84. lexer->token.type = cmListFileLexer_Token_ArgumentBracket;
  85. }
  86. cmListFileLexerSetToken(lexer, "", 0);
  87. lexer->bracket = (char*)memchr(bracket + 1, '[', length - 1) - bracket;
  88. if (yytext[yyleng-1] == '\n') {
  89. ++lexer->line;
  90. lexer->column = 1;
  91. } else {
  92. lexer->column += yyleng;
  93. }
  94. BEGIN(BRACKET);
  95. }
  96. # {
  97. lexer->column += yyleng;
  98. BEGIN(COMMENT);
  99. }
  100. <COMMENT>[^\n]* {
  101. if (memchr(yytext, '\0', yyleng) != NULL) {
  102. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  103. }
  104. lexer->column += yyleng;
  105. }
  106. \( {
  107. lexer->token.type = cmListFileLexer_Token_ParenLeft;
  108. cmListFileLexerSetToken(lexer, yytext, yyleng);
  109. lexer->column += yyleng;
  110. return 1;
  111. }
  112. \) {
  113. lexer->token.type = cmListFileLexer_Token_ParenRight;
  114. cmListFileLexerSetToken(lexer, yytext, yyleng);
  115. lexer->column += yyleng;
  116. return 1;
  117. }
  118. [A-Za-z_][A-Za-z0-9_]* {
  119. lexer->token.type = cmListFileLexer_Token_Identifier;
  120. cmListFileLexerSetToken(lexer, yytext, yyleng);
  121. lexer->column += yyleng;
  122. return 1;
  123. }
  124. <BRACKET>\]=* {
  125. /* Handle ]]====]=======]*/
  126. cmListFileLexerAppend(lexer, yytext, yyleng);
  127. lexer->column += yyleng;
  128. if (yyleng == lexer->bracket) {
  129. BEGIN(BRACKETEND);
  130. }
  131. }
  132. <BRACKETEND>\] {
  133. lexer->column += yyleng;
  134. /* Erase the partial bracket from the token. */
  135. lexer->token.length -= lexer->bracket;
  136. BEGIN(INITIAL);
  137. return 1;
  138. }
  139. <BRACKET>([^]\n])+ {
  140. if (memchr(yytext, '\0', yyleng) != NULL) {
  141. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  142. }
  143. cmListFileLexerAppend(lexer, yytext, yyleng);
  144. lexer->column += yyleng;
  145. }
  146. <BRACKET,BRACKETEND>\n {
  147. cmListFileLexerAppend(lexer, yytext, yyleng);
  148. ++lexer->line;
  149. lexer->column = 1;
  150. BEGIN(BRACKET);
  151. }
  152. <BRACKET,BRACKETEND>[^\n] {
  153. if (memchr(yytext, '\0', yyleng) != NULL) {
  154. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  155. }
  156. cmListFileLexerAppend(lexer, yytext, yyleng);
  157. lexer->column += yyleng;
  158. BEGIN(BRACKET);
  159. }
  160. <BRACKET,BRACKETEND><<EOF>> {
  161. lexer->token.type = cmListFileLexer_Token_BadBracket;
  162. BEGIN(INITIAL);
  163. return 1;
  164. }
  165. ({UNQUOTED}|=|\[=*{UNQUOTED})({UNQUOTED}|[[=])* {
  166. if (memchr(yytext, '\0', yyleng) != NULL) {
  167. /* An unquoted argument that contains a null character. */
  168. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  169. } else {
  170. lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
  171. }
  172. cmListFileLexerSetToken(lexer, yytext, yyleng);
  173. lexer->column += yyleng;
  174. return 1;
  175. }
  176. ({MAKEVAR}|{UNQUOTED}|=|\[=*{LEGACY})({LEGACY}|[[=])* {
  177. lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
  178. cmListFileLexerSetToken(lexer, yytext, yyleng);
  179. lexer->column += yyleng;
  180. return 1;
  181. }
  182. \[ {
  183. lexer->token.type = cmListFileLexer_Token_ArgumentUnquoted;
  184. cmListFileLexerSetToken(lexer, yytext, yyleng);
  185. lexer->column += yyleng;
  186. return 1;
  187. }
  188. \" {
  189. lexer->token.type = cmListFileLexer_Token_ArgumentQuoted;
  190. cmListFileLexerSetToken(lexer, "", 0);
  191. lexer->column += yyleng;
  192. BEGIN(STRING);
  193. }
  194. <STRING>([^\\\n\"]|\\[^\n])+ {
  195. if (memchr(yytext, '\0', yyleng) != NULL) {
  196. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  197. }
  198. cmListFileLexerAppend(lexer, yytext, yyleng);
  199. lexer->column += yyleng;
  200. }
  201. <STRING>\\\n {
  202. /* Continuation: text is not part of string */
  203. ++lexer->line;
  204. lexer->column = 1;
  205. }
  206. <STRING>\n {
  207. cmListFileLexerAppend(lexer, yytext, yyleng);
  208. ++lexer->line;
  209. lexer->column = 1;
  210. }
  211. <STRING>\" {
  212. lexer->column += yyleng;
  213. BEGIN(INITIAL);
  214. return 1;
  215. }
  216. <STRING>[^\n] {
  217. if (memchr(yytext, '\0', yyleng) != NULL) {
  218. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  219. }
  220. cmListFileLexerAppend(lexer, yytext, yyleng);
  221. lexer->column += yyleng;
  222. }
  223. <STRING><<EOF>> {
  224. lexer->token.type = cmListFileLexer_Token_BadString;
  225. BEGIN(INITIAL);
  226. return 1;
  227. }
  228. [ \t\r]+ {
  229. lexer->token.type = cmListFileLexer_Token_Space;
  230. cmListFileLexerSetToken(lexer, yytext, yyleng);
  231. lexer->column += yyleng;
  232. return 1;
  233. }
  234. . {
  235. lexer->token.type = cmListFileLexer_Token_BadCharacter;
  236. cmListFileLexerSetToken(lexer, yytext, yyleng);
  237. lexer->column += yyleng;
  238. return 1;
  239. }
  240. <<EOF>> {
  241. lexer->token.type = cmListFileLexer_Token_None;
  242. cmListFileLexerSetToken(lexer, 0, 0);
  243. return 0;
  244. }
  245. %%
  246. /*--------------------------------------------------------------------------*/
  247. static void cmListFileLexerSetToken(cmListFileLexer* lexer, const char* text,
  248. size_t length)
  249. {
  250. /* Set the token line and column number. */
  251. lexer->token.line = lexer->line;
  252. lexer->token.column = lexer->column;
  253. /* Use the same buffer if possible. */
  254. if (lexer->token.text) {
  255. if (text && length < lexer->size) {
  256. memcpy(lexer->token.text, text, length);
  257. lexer->token.length = length;
  258. return;
  259. }
  260. free(lexer->token.text);
  261. lexer->token.text = 0;
  262. lexer->size = 0;
  263. }
  264. /* Need to extend the buffer. */
  265. if (length > 0) {
  266. lexer->token.text = (char*)malloc(length);
  267. memcpy(lexer->token.text, text, length);
  268. lexer->token.length = length;
  269. lexer->size = length;
  270. } else {
  271. lexer->token.length = 0;
  272. }
  273. }
  274. /*--------------------------------------------------------------------------*/
  275. static void cmListFileLexerAppend(cmListFileLexer* lexer, const char* text,
  276. size_t length)
  277. {
  278. char* temp;
  279. size_t newSize;
  280. /* If the appended text will fit in the buffer, do not reallocate. */
  281. newSize = lexer->token.length + length;
  282. if (lexer->token.text && newSize <= lexer->size) {
  283. memcpy(lexer->token.text + lexer->token.length, text, length);
  284. lexer->token.length += length;
  285. return;
  286. }
  287. /* We need to extend the buffer. */
  288. temp = malloc(newSize);
  289. if (lexer->token.text) {
  290. memcpy(temp, lexer->token.text, lexer->token.length);
  291. free(lexer->token.text);
  292. }
  293. memcpy(temp + lexer->token.length, text, length);
  294. lexer->token.text = temp;
  295. lexer->token.length += length;
  296. lexer->size = newSize;
  297. }
  298. /*--------------------------------------------------------------------------*/
  299. static int cmListFileLexerInput(cmListFileLexer* lexer, char* buffer,
  300. size_t bufferSize)
  301. {
  302. if (lexer) {
  303. if (lexer->file) {
  304. /* Convert CRLF -> LF explicitly. The C FILE "t"ext mode
  305. does not convert newlines on all platforms. Move any
  306. trailing CR to the start of the buffer for the next read. */
  307. size_t cr = lexer->cr;
  308. size_t n = 0;
  309. buffer[0] = '\r';
  310. size_t actualBufferSize = bufferSize - cr;
  311. char* p = buffer + cr;
  312. size_t readLeft = lexer->read_size - lexer->read_position;
  313. /* Absorb the bytes that were read during BOM detection, if any. */
  314. if (readLeft > 0) {
  315. size_t actualReadSize =
  316. actualBufferSize >= readLeft ? readLeft : actualBufferSize;
  317. memcpy(p, lexer->read_buffer + lexer->read_position, actualReadSize);
  318. lexer->read_position += actualReadSize;
  319. p += actualReadSize;
  320. n += actualReadSize;
  321. actualBufferSize -= actualReadSize;
  322. }
  323. n += fread(p, 1, actualBufferSize, lexer->file);
  324. if (n) {
  325. char* o = buffer;
  326. const char* i = buffer;
  327. const char* e;
  328. n += cr;
  329. cr = (buffer[n - 1] == '\r') ? 1 : 0;
  330. e = buffer + n - cr;
  331. while (i != e) {
  332. if (i[0] == '\r' && i[1] == '\n') {
  333. ++i;
  334. }
  335. *o++ = *i++;
  336. }
  337. n = o - buffer;
  338. } else {
  339. n = cr;
  340. cr = 0;
  341. }
  342. lexer->cr = cr;
  343. return n;
  344. } else if (lexer->string_left) {
  345. size_t length = lexer->string_left;
  346. if (bufferSize < length) {
  347. length = bufferSize;
  348. }
  349. memcpy(buffer, lexer->string_position, length);
  350. lexer->string_position += length;
  351. lexer->string_left -= length;
  352. return length;
  353. }
  354. }
  355. return 0;
  356. }
  357. /*--------------------------------------------------------------------------*/
  358. static void cmListFileLexerInit(cmListFileLexer* lexer)
  359. {
  360. if (lexer->file || lexer->string_buffer) {
  361. cmListFileLexer_yylex_init(&lexer->scanner);
  362. cmListFileLexer_yyset_extra(lexer, lexer->scanner);
  363. }
  364. }
  365. /*--------------------------------------------------------------------------*/
  366. static void cmListFileLexerDestroy(cmListFileLexer* lexer)
  367. {
  368. cmListFileLexerSetToken(lexer, 0, 0);
  369. if (lexer->file || lexer->string_buffer) {
  370. cmListFileLexer_yylex_destroy(lexer->scanner);
  371. if (lexer->file) {
  372. fclose(lexer->file);
  373. lexer->file = 0;
  374. }
  375. if (lexer->read_size != 0) {
  376. memset(lexer->read_buffer, 0, sizeof(lexer->read_buffer));
  377. lexer->read_size = 0;
  378. lexer->read_position = 0;
  379. }
  380. if (lexer->string_buffer) {
  381. free(lexer->string_buffer);
  382. lexer->string_buffer = 0;
  383. lexer->string_left = 0;
  384. lexer->string_position = 0;
  385. }
  386. }
  387. }
  388. /*--------------------------------------------------------------------------*/
  389. cmListFileLexer* cmListFileLexer_New(void)
  390. {
  391. cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer));
  392. if (!lexer) {
  393. return 0;
  394. }
  395. memset(lexer, 0, sizeof(*lexer));
  396. lexer->line = 1;
  397. lexer->column = 1;
  398. return lexer;
  399. }
  400. /*--------------------------------------------------------------------------*/
  401. void cmListFileLexer_Delete(cmListFileLexer* lexer)
  402. {
  403. cmListFileLexer_SetFileName(lexer, 0, 0);
  404. free(lexer);
  405. }
  406. /*--------------------------------------------------------------------------*/
  407. static cmListFileLexer_BOM cmListFileLexer_ReadBOM(FILE* f,
  408. unsigned char readBuffer[4],
  409. size_t* readSize)
  410. {
  411. /* Read the up to four bytes that might correspond to a BOM. In case these
  412. bytes turn out not to represent a BOM, save them for later consumption in
  413. order to avoid seeking the file (which might not be seekable, e.g., if
  414. it's a pipe). */
  415. unsigned char* b = readBuffer;
  416. size_t n = fread(b, 1, 2, f);
  417. *readSize = n; /* Initialize first and then accumulate */
  418. if (n == 2) {
  419. if (b[0] == 0xEF && b[1] == 0xBB) {
  420. n = fread(b + 2, 1, 1, f);
  421. *readSize += n;
  422. if (n == 1) {
  423. if (b[2] == 0xBF) {
  424. *readSize = 0; /* We consumed the BOM: discard it */
  425. return cmListFileLexer_BOM_UTF8;
  426. }
  427. }
  428. } else if (b[0] == 0xFE && b[1] == 0xFF) {
  429. *readSize = 0; /* We consumed the BOM: discard it */
  430. /* UTF-16 BE */
  431. return cmListFileLexer_BOM_UTF16BE;
  432. } else if (b[0] == 0 && b[1] == 0) {
  433. n = fread(b + 2, 1, 2, f);
  434. *readSize += n;
  435. if (n == 2) {
  436. if (b[2] == 0xFE && b[3] == 0xFF) {
  437. *readSize = 0; /* We consumed the BOM: discard it */
  438. return cmListFileLexer_BOM_UTF32BE;
  439. }
  440. }
  441. } else if (b[0] == 0xFF && b[1] == 0xFE) {
  442. n = fread(b + 2, 1, 2, f);
  443. *readSize += n;
  444. if (n == 2 && b[2] == 0 && b[3] == 0) {
  445. *readSize = 0; /* We consumed the BOM: discard it */
  446. return cmListFileLexer_BOM_UTF32LE;
  447. }
  448. /* In case we were able to subsequently read only a single byte out of two
  449. (i.e., three in total), the file must be corrupt and the BOM cannot
  450. represent a UTF-16-LE BOM since each code unit must consist of two
  451. bytes. This avoids incorrectly detecting an incomplete UTF-32-LE BOM as
  452. UTF-16-LE input. */
  453. if (n % 2 == 0) {
  454. *readSize = n; /* We consumed the read bytes as BOM only partially */
  455. memmove(b, b + 2, n);
  456. return cmListFileLexer_BOM_UTF16LE;
  457. }
  458. }
  459. }
  460. return cmListFileLexer_BOM_None;
  461. }
  462. /*--------------------------------------------------------------------------*/
  463. int cmListFileLexer_SetFileName(cmListFileLexer* lexer, const char* name,
  464. cmListFileLexer_BOM* bom)
  465. {
  466. int result = 1;
  467. cmListFileLexerDestroy(lexer);
  468. if (name) {
  469. #ifdef _WIN32
  470. wchar_t* wname = cmsysEncoding_DupToWide(name);
  471. lexer->file = _wfopen(wname, L"rb");
  472. free(wname);
  473. #else
  474. lexer->file = fopen(name, "rb");
  475. #endif
  476. if (lexer->file) {
  477. if (bom) {
  478. *bom = cmListFileLexer_ReadBOM(
  479. lexer->file, (unsigned char*)lexer->read_buffer, &lexer->read_size);
  480. lexer->read_position = 0;
  481. } else {
  482. memset(lexer->read_buffer, 0, sizeof(lexer->read_buffer));
  483. lexer->read_size = 0;
  484. lexer->read_position = 0;
  485. }
  486. } else {
  487. result = 0;
  488. }
  489. }
  490. cmListFileLexerInit(lexer);
  491. return result;
  492. }
  493. /*--------------------------------------------------------------------------*/
  494. int cmListFileLexer_SetString(cmListFileLexer* lexer, char const* text,
  495. size_t length)
  496. {
  497. int result = 1;
  498. cmListFileLexerDestroy(lexer);
  499. /* text might be not NULL while length is 0. However, on some platforms
  500. malloc(0) will return NULL. To avoid signaling an error to the caller in
  501. such cases, ensure nonzero length. */
  502. size_t read_size = lexer->read_size - lexer->read_position;
  503. size_t string_size = read_size + length;
  504. if (string_size > 0) {
  505. lexer->string_buffer = (char*)malloc(string_size);
  506. if (lexer->string_buffer) {
  507. memcpy(lexer->string_buffer, lexer->read_buffer + lexer->read_position,
  508. read_size);
  509. memcpy(lexer->string_buffer + read_size, text, length);
  510. lexer->read_position += read_size;
  511. lexer->string_position = lexer->string_buffer;
  512. lexer->string_left = length;
  513. } else {
  514. result = 0;
  515. }
  516. }
  517. cmListFileLexerInit(lexer);
  518. return result;
  519. }
  520. /*--------------------------------------------------------------------------*/
  521. cmListFileLexer_Token* cmListFileLexer_Scan(cmListFileLexer* lexer)
  522. {
  523. if (!lexer->file && !lexer->string_buffer) {
  524. return 0;
  525. }
  526. if (cmListFileLexer_yylex(lexer->scanner, lexer)) {
  527. return &lexer->token;
  528. } else {
  529. cmListFileLexer_SetFileName(lexer, 0, 0);
  530. return 0;
  531. }
  532. }
  533. /*--------------------------------------------------------------------------*/
  534. long cmListFileLexer_GetCurrentLine(cmListFileLexer* lexer)
  535. {
  536. return lexer->line;
  537. }
  538. /*--------------------------------------------------------------------------*/
  539. long cmListFileLexer_GetCurrentColumn(cmListFileLexer* lexer)
  540. {
  541. return lexer->column;
  542. }
  543. /*--------------------------------------------------------------------------*/
  544. const char* cmListFileLexer_GetTypeAsString(cmListFileLexer* lexer,
  545. cmListFileLexer_Type type)
  546. {
  547. (void)lexer;
  548. switch (type) {
  549. case cmListFileLexer_Token_None:
  550. return "nothing";
  551. case cmListFileLexer_Token_Space:
  552. return "space";
  553. case cmListFileLexer_Token_Newline:
  554. return "newline";
  555. case cmListFileLexer_Token_Identifier:
  556. return "identifier";
  557. case cmListFileLexer_Token_ParenLeft:
  558. return "left paren";
  559. case cmListFileLexer_Token_ParenRight:
  560. return "right paren";
  561. case cmListFileLexer_Token_ArgumentUnquoted:
  562. return "unquoted argument";
  563. case cmListFileLexer_Token_ArgumentQuoted:
  564. return "quoted argument";
  565. case cmListFileLexer_Token_ArgumentBracket:
  566. return "bracket argument";
  567. case cmListFileLexer_Token_CommentBracket:
  568. return "bracket comment";
  569. case cmListFileLexer_Token_BadCharacter:
  570. return "bad character";
  571. case cmListFileLexer_Token_BadBracket:
  572. return "unterminated bracket";
  573. case cmListFileLexer_Token_BadString:
  574. return "unterminated string";
  575. }
  576. return "unknown token";
  577. }