nlmheader.y 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. %{/* nlmheader.y - parse NLM header specification keywords.
  2. Copyright (C) 1993-2015 Free Software Foundation, Inc.
  3. This file is part of GNU Binutils.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  15. MA 02110-1301, USA. */
  16. /* Written by Ian Lance Taylor <ian@cygnus.com>.
  17. This bison file parses the commands recognized by the NetWare NLM
  18. linker, except for lists of object files. It stores the
  19. information in global variables.
  20. This implementation is based on the description in the NetWare Tool
  21. Maker Specification manual, edition 1.0. */
  22. #include "sysdep.h"
  23. #include "safe-ctype.h"
  24. #include "bfd.h"
  25. #include "nlm/common.h"
  26. #include "nlm/internal.h"
  27. #include "bucomm.h"
  28. #include "nlmconv.h"
  29. /* Information is stored in the structures pointed to by these
  30. variables. */
  31. Nlm_Internal_Fixed_Header *fixed_hdr;
  32. Nlm_Internal_Variable_Header *var_hdr;
  33. Nlm_Internal_Version_Header *version_hdr;
  34. Nlm_Internal_Copyright_Header *copyright_hdr;
  35. Nlm_Internal_Extended_Header *extended_hdr;
  36. /* Procedure named by CHECK. */
  37. char *check_procedure;
  38. /* File named by CUSTOM. */
  39. char *custom_file;
  40. /* Whether to generate debugging information (DEBUG). */
  41. bfd_boolean debug_info;
  42. /* Procedure named by EXIT. */
  43. char *exit_procedure;
  44. /* Exported symbols (EXPORT). */
  45. struct string_list *export_symbols;
  46. /* List of files from INPUT. */
  47. struct string_list *input_files;
  48. /* Map file name (MAP, FULLMAP). */
  49. char *map_file;
  50. /* Whether a full map has been requested (FULLMAP). */
  51. bfd_boolean full_map;
  52. /* File named by HELP. */
  53. char *help_file;
  54. /* Imported symbols (IMPORT). */
  55. struct string_list *import_symbols;
  56. /* File named by MESSAGES. */
  57. char *message_file;
  58. /* Autoload module list (MODULE). */
  59. struct string_list *modules;
  60. /* File named by OUTPUT. */
  61. char *output_file;
  62. /* File named by SHARELIB. */
  63. char *sharelib_file;
  64. /* Start procedure name (START). */
  65. char *start_procedure;
  66. /* VERBOSE. */
  67. bfd_boolean verbose;
  68. /* RPC description file (XDCDATA). */
  69. char *rpc_file;
  70. /* The number of serious errors that have occurred. */
  71. int parse_errors;
  72. /* The current symbol prefix when reading a list of import or export
  73. symbols. */
  74. static char *symbol_prefix;
  75. /* Parser error message handler. */
  76. #define yyerror(msg) nlmheader_error (msg);
  77. /* Local functions. */
  78. static int yylex (void);
  79. static void nlmlex_file_push (const char *);
  80. static bfd_boolean nlmlex_file_open (const char *);
  81. static int nlmlex_buf_init (void);
  82. static char nlmlex_buf_add (int);
  83. static long nlmlex_get_number (const char *);
  84. static void nlmheader_identify (void);
  85. static void nlmheader_warn (const char *, int);
  86. static void nlmheader_error (const char *);
  87. static struct string_list * string_list_cons (char *, struct string_list *);
  88. static struct string_list * string_list_append (struct string_list *,
  89. struct string_list *);
  90. static struct string_list * string_list_append1 (struct string_list *,
  91. char *);
  92. static char *xstrdup (const char *);
  93. %}
  94. %union
  95. {
  96. char *string;
  97. struct string_list *list;
  98. };
  99. /* The reserved words. */
  100. %token CHECK CODESTART COPYRIGHT CUSTOM DATE DEBUG_K DESCRIPTION EXIT
  101. %token EXPORT FLAG_ON FLAG_OFF FULLMAP HELP IMPORT INPUT MAP MESSAGES
  102. %token MODULE MULTIPLE OS_DOMAIN OUTPUT PSEUDOPREEMPTION REENTRANT
  103. %token SCREENNAME SHARELIB STACK START SYNCHRONIZE
  104. %token THREADNAME TYPE VERBOSE VERSIONK XDCDATA
  105. /* Arguments. */
  106. %token <string> STRING
  107. %token <string> QUOTED_STRING
  108. /* Typed non-terminals. */
  109. %type <list> symbol_list_opt symbol_list string_list
  110. %type <string> symbol
  111. %%
  112. /* Keywords must start in the leftmost column of the file. Arguments
  113. may appear anywhere else. The lexer uses this to determine what
  114. token to return, so we don't have to worry about it here. */
  115. /* The entire file is just a list of commands. */
  116. file:
  117. commands
  118. ;
  119. /* A possibly empty list of commands. */
  120. commands:
  121. /* May be empty. */
  122. | command commands
  123. ;
  124. /* A single command. There is where most of the work takes place. */
  125. command:
  126. CHECK STRING
  127. {
  128. check_procedure = $2;
  129. }
  130. | CODESTART STRING
  131. {
  132. nlmheader_warn (_("CODESTART is not implemented; sorry"), -1);
  133. free ($2);
  134. }
  135. | COPYRIGHT QUOTED_STRING
  136. {
  137. int len;
  138. strncpy (copyright_hdr->stamp, "CoPyRiGhT=", 10);
  139. len = strlen ($2);
  140. if (len >= NLM_MAX_COPYRIGHT_MESSAGE_LENGTH)
  141. {
  142. nlmheader_warn (_("copyright string is too long"),
  143. NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1);
  144. len = NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1;
  145. }
  146. copyright_hdr->copyrightMessageLength = len;
  147. strncpy (copyright_hdr->copyrightMessage, $2, len);
  148. copyright_hdr->copyrightMessage[len] = '\0';
  149. free ($2);
  150. }
  151. | CUSTOM STRING
  152. {
  153. custom_file = $2;
  154. }
  155. | DATE STRING STRING STRING
  156. {
  157. /* We don't set the version stamp here, because we use the
  158. version stamp to detect whether the required VERSION
  159. keyword was given. */
  160. version_hdr->month = nlmlex_get_number ($2);
  161. version_hdr->day = nlmlex_get_number ($3);
  162. version_hdr->year = nlmlex_get_number ($4);
  163. free ($2);
  164. free ($3);
  165. free ($4);
  166. if (version_hdr->month < 1 || version_hdr->month > 12)
  167. nlmheader_warn (_("illegal month"), -1);
  168. if (version_hdr->day < 1 || version_hdr->day > 31)
  169. nlmheader_warn (_("illegal day"), -1);
  170. if (version_hdr->year < 1900 || version_hdr->year > 3000)
  171. nlmheader_warn (_("illegal year"), -1);
  172. }
  173. | DEBUG_K
  174. {
  175. debug_info = TRUE;
  176. }
  177. | DESCRIPTION QUOTED_STRING
  178. {
  179. int len;
  180. len = strlen ($2);
  181. if (len > NLM_MAX_DESCRIPTION_LENGTH)
  182. {
  183. nlmheader_warn (_("description string is too long"),
  184. NLM_MAX_DESCRIPTION_LENGTH);
  185. len = NLM_MAX_DESCRIPTION_LENGTH;
  186. }
  187. var_hdr->descriptionLength = len;
  188. strncpy (var_hdr->descriptionText, $2, len);
  189. var_hdr->descriptionText[len] = '\0';
  190. free ($2);
  191. }
  192. | EXIT STRING
  193. {
  194. exit_procedure = $2;
  195. }
  196. | EXPORT
  197. {
  198. symbol_prefix = NULL;
  199. }
  200. symbol_list_opt
  201. {
  202. export_symbols = string_list_append (export_symbols, $3);
  203. }
  204. | FLAG_ON STRING
  205. {
  206. fixed_hdr->flags |= nlmlex_get_number ($2);
  207. free ($2);
  208. }
  209. | FLAG_OFF STRING
  210. {
  211. fixed_hdr->flags &=~ nlmlex_get_number ($2);
  212. free ($2);
  213. }
  214. | FULLMAP
  215. {
  216. map_file = "";
  217. full_map = TRUE;
  218. }
  219. | FULLMAP STRING
  220. {
  221. map_file = $2;
  222. full_map = TRUE;
  223. }
  224. | HELP STRING
  225. {
  226. help_file = $2;
  227. }
  228. | IMPORT
  229. {
  230. symbol_prefix = NULL;
  231. }
  232. symbol_list_opt
  233. {
  234. import_symbols = string_list_append (import_symbols, $3);
  235. }
  236. | INPUT string_list
  237. {
  238. input_files = string_list_append (input_files, $2);
  239. }
  240. | MAP
  241. {
  242. map_file = "";
  243. }
  244. | MAP STRING
  245. {
  246. map_file = $2;
  247. }
  248. | MESSAGES STRING
  249. {
  250. message_file = $2;
  251. }
  252. | MODULE string_list
  253. {
  254. modules = string_list_append (modules, $2);
  255. }
  256. | MULTIPLE
  257. {
  258. fixed_hdr->flags |= 0x2;
  259. }
  260. | OS_DOMAIN
  261. {
  262. fixed_hdr->flags |= 0x10;
  263. }
  264. | OUTPUT STRING
  265. {
  266. if (output_file == NULL)
  267. output_file = $2;
  268. else
  269. nlmheader_warn (_("ignoring duplicate OUTPUT statement"), -1);
  270. }
  271. | PSEUDOPREEMPTION
  272. {
  273. fixed_hdr->flags |= 0x8;
  274. }
  275. | REENTRANT
  276. {
  277. fixed_hdr->flags |= 0x1;
  278. }
  279. | SCREENNAME QUOTED_STRING
  280. {
  281. int len;
  282. len = strlen ($2);
  283. if (len >= NLM_MAX_SCREEN_NAME_LENGTH)
  284. {
  285. nlmheader_warn (_("screen name is too long"),
  286. NLM_MAX_SCREEN_NAME_LENGTH);
  287. len = NLM_MAX_SCREEN_NAME_LENGTH;
  288. }
  289. var_hdr->screenNameLength = len;
  290. strncpy (var_hdr->screenName, $2, len);
  291. var_hdr->screenName[NLM_MAX_SCREEN_NAME_LENGTH] = '\0';
  292. free ($2);
  293. }
  294. | SHARELIB STRING
  295. {
  296. sharelib_file = $2;
  297. }
  298. | STACK STRING
  299. {
  300. var_hdr->stackSize = nlmlex_get_number ($2);
  301. free ($2);
  302. }
  303. | START STRING
  304. {
  305. start_procedure = $2;
  306. }
  307. | SYNCHRONIZE
  308. {
  309. fixed_hdr->flags |= 0x4;
  310. }
  311. | THREADNAME QUOTED_STRING
  312. {
  313. int len;
  314. len = strlen ($2);
  315. if (len >= NLM_MAX_THREAD_NAME_LENGTH)
  316. {
  317. nlmheader_warn (_("thread name is too long"),
  318. NLM_MAX_THREAD_NAME_LENGTH);
  319. len = NLM_MAX_THREAD_NAME_LENGTH;
  320. }
  321. var_hdr->threadNameLength = len;
  322. strncpy (var_hdr->threadName, $2, len);
  323. var_hdr->threadName[len] = '\0';
  324. free ($2);
  325. }
  326. | TYPE STRING
  327. {
  328. fixed_hdr->moduleType = nlmlex_get_number ($2);
  329. free ($2);
  330. }
  331. | VERBOSE
  332. {
  333. verbose = TRUE;
  334. }
  335. | VERSIONK STRING STRING STRING
  336. {
  337. long val;
  338. strncpy (version_hdr->stamp, "VeRsIoN#", 8);
  339. version_hdr->majorVersion = nlmlex_get_number ($2);
  340. val = nlmlex_get_number ($3);
  341. if (val < 0 || val > 99)
  342. nlmheader_warn (_("illegal minor version number (must be between 0 and 99)"),
  343. -1);
  344. else
  345. version_hdr->minorVersion = val;
  346. val = nlmlex_get_number ($4);
  347. if (val < 0)
  348. nlmheader_warn (_("illegal revision number (must be between 0 and 26)"),
  349. -1);
  350. else if (val > 26)
  351. version_hdr->revision = 0;
  352. else
  353. version_hdr->revision = val;
  354. free ($2);
  355. free ($3);
  356. free ($4);
  357. }
  358. | VERSIONK STRING STRING
  359. {
  360. long val;
  361. strncpy (version_hdr->stamp, "VeRsIoN#", 8);
  362. version_hdr->majorVersion = nlmlex_get_number ($2);
  363. val = nlmlex_get_number ($3);
  364. if (val < 0 || val > 99)
  365. nlmheader_warn (_("illegal minor version number (must be between 0 and 99)"),
  366. -1);
  367. else
  368. version_hdr->minorVersion = val;
  369. version_hdr->revision = 0;
  370. free ($2);
  371. free ($3);
  372. }
  373. | XDCDATA STRING
  374. {
  375. rpc_file = $2;
  376. }
  377. ;
  378. /* A possibly empty list of symbols. */
  379. symbol_list_opt:
  380. /* Empty. */
  381. {
  382. $$ = NULL;
  383. }
  384. | symbol_list
  385. {
  386. $$ = $1;
  387. }
  388. ;
  389. /* A list of symbols in an import or export list. Prefixes may appear
  390. in parentheses. We need to use left recursion here to avoid
  391. building up a large import list on the parser stack. */
  392. symbol_list:
  393. symbol
  394. {
  395. $$ = string_list_cons ($1, NULL);
  396. }
  397. | symbol_prefix
  398. {
  399. $$ = NULL;
  400. }
  401. | symbol_list symbol
  402. {
  403. $$ = string_list_append1 ($1, $2);
  404. }
  405. | symbol_list symbol_prefix
  406. {
  407. $$ = $1;
  408. }
  409. ;
  410. /* A prefix for subsequent symbols. */
  411. symbol_prefix:
  412. '(' STRING ')'
  413. {
  414. if (symbol_prefix != NULL)
  415. free (symbol_prefix);
  416. symbol_prefix = $2;
  417. }
  418. ;
  419. /* A single symbol. */
  420. symbol:
  421. STRING
  422. {
  423. if (symbol_prefix == NULL)
  424. $$ = $1;
  425. else
  426. {
  427. $$ = xmalloc (strlen (symbol_prefix) + strlen ($1) + 2);
  428. sprintf ($$, "%s@%s", symbol_prefix, $1);
  429. free ($1);
  430. }
  431. }
  432. ;
  433. /* A list of strings. */
  434. string_list:
  435. /* May be empty. */
  436. {
  437. $$ = NULL;
  438. }
  439. | STRING string_list
  440. {
  441. $$ = string_list_cons ($1, $2);
  442. }
  443. ;
  444. %%
  445. /* If strerror is just a macro, we want to use the one from libiberty
  446. since it will handle undefined values. */
  447. #undef strerror
  448. extern char *strerror (int);
  449. /* The lexer is simple, too simple for flex. Keywords are only
  450. recognized at the start of lines. Everything else must be an
  451. argument. A comma is treated as whitespace. */
  452. /* The states the lexer can be in. */
  453. enum lex_state
  454. {
  455. /* At the beginning of a line. */
  456. BEGINNING_OF_LINE,
  457. /* In the middle of a line. */
  458. IN_LINE
  459. };
  460. /* We need to keep a stack of files to handle file inclusion. */
  461. struct input
  462. {
  463. /* The file to read from. */
  464. FILE *file;
  465. /* The name of the file. */
  466. char *name;
  467. /* The current line number. */
  468. int lineno;
  469. /* The current state. */
  470. enum lex_state state;
  471. /* The next file on the stack. */
  472. struct input *next;
  473. };
  474. /* The current input file. */
  475. static struct input current;
  476. /* The character which introduces comments. */
  477. #define COMMENT_CHAR '#'
  478. /* Start the lexer going on the main input file. */
  479. bfd_boolean
  480. nlmlex_file (const char *name)
  481. {
  482. current.next = NULL;
  483. return nlmlex_file_open (name);
  484. }
  485. /* Start the lexer going on a subsidiary input file. */
  486. static void
  487. nlmlex_file_push (const char *name)
  488. {
  489. struct input *push;
  490. push = (struct input *) xmalloc (sizeof (struct input));
  491. *push = current;
  492. if (nlmlex_file_open (name))
  493. current.next = push;
  494. else
  495. {
  496. current = *push;
  497. free (push);
  498. }
  499. }
  500. /* Start lexing from a file. */
  501. static bfd_boolean
  502. nlmlex_file_open (const char *name)
  503. {
  504. current.file = fopen (name, "r");
  505. if (current.file == NULL)
  506. {
  507. fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno));
  508. ++parse_errors;
  509. return FALSE;
  510. }
  511. current.name = xstrdup (name);
  512. current.lineno = 1;
  513. current.state = BEGINNING_OF_LINE;
  514. return TRUE;
  515. }
  516. /* Table used to turn keywords into tokens. */
  517. struct keyword_tokens_struct
  518. {
  519. const char *keyword;
  520. int token;
  521. };
  522. static struct keyword_tokens_struct keyword_tokens[] =
  523. {
  524. { "CHECK", CHECK },
  525. { "CODESTART", CODESTART },
  526. { "COPYRIGHT", COPYRIGHT },
  527. { "CUSTOM", CUSTOM },
  528. { "DATE", DATE },
  529. { "DEBUG", DEBUG_K },
  530. { "DESCRIPTION", DESCRIPTION },
  531. { "EXIT", EXIT },
  532. { "EXPORT", EXPORT },
  533. { "FLAG_ON", FLAG_ON },
  534. { "FLAG_OFF", FLAG_OFF },
  535. { "FULLMAP", FULLMAP },
  536. { "HELP", HELP },
  537. { "IMPORT", IMPORT },
  538. { "INPUT", INPUT },
  539. { "MAP", MAP },
  540. { "MESSAGES", MESSAGES },
  541. { "MODULE", MODULE },
  542. { "MULTIPLE", MULTIPLE },
  543. { "OS_DOMAIN", OS_DOMAIN },
  544. { "OUTPUT", OUTPUT },
  545. { "PSEUDOPREEMPTION", PSEUDOPREEMPTION },
  546. { "REENTRANT", REENTRANT },
  547. { "SCREENNAME", SCREENNAME },
  548. { "SHARELIB", SHARELIB },
  549. { "STACK", STACK },
  550. { "STACKSIZE", STACK },
  551. { "START", START },
  552. { "SYNCHRONIZE", SYNCHRONIZE },
  553. { "THREADNAME", THREADNAME },
  554. { "TYPE", TYPE },
  555. { "VERBOSE", VERBOSE },
  556. { "VERSION", VERSIONK },
  557. { "XDCDATA", XDCDATA }
  558. };
  559. #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0]))
  560. /* The lexer accumulates strings in these variables. */
  561. static char *lex_buf;
  562. static int lex_size;
  563. static int lex_pos;
  564. /* Start accumulating strings into the buffer. */
  565. #define BUF_INIT() \
  566. ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ()))
  567. static int
  568. nlmlex_buf_init (void)
  569. {
  570. lex_size = 10;
  571. lex_buf = xmalloc (lex_size + 1);
  572. lex_pos = 0;
  573. return 0;
  574. }
  575. /* Finish a string in the buffer. */
  576. #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0'))
  577. /* Accumulate a character into the buffer. */
  578. #define BUF_ADD(c) \
  579. ((void) (lex_pos < lex_size \
  580. ? lex_buf[lex_pos++] = (c) \
  581. : nlmlex_buf_add (c)))
  582. static char
  583. nlmlex_buf_add (int c)
  584. {
  585. if (lex_pos >= lex_size)
  586. {
  587. lex_size *= 2;
  588. lex_buf = xrealloc (lex_buf, lex_size + 1);
  589. }
  590. return lex_buf[lex_pos++] = c;
  591. }
  592. /* The lexer proper. This is called by the bison generated parsing
  593. code. */
  594. static int
  595. yylex (void)
  596. {
  597. int c;
  598. tail_recurse:
  599. c = getc (current.file);
  600. /* Commas are treated as whitespace characters. */
  601. while (ISSPACE (c) || c == ',')
  602. {
  603. current.state = IN_LINE;
  604. if (c == '\n')
  605. {
  606. ++current.lineno;
  607. current.state = BEGINNING_OF_LINE;
  608. }
  609. c = getc (current.file);
  610. }
  611. /* At the end of the file we either pop to the previous file or
  612. finish up. */
  613. if (c == EOF)
  614. {
  615. fclose (current.file);
  616. free (current.name);
  617. if (current.next == NULL)
  618. return 0;
  619. else
  620. {
  621. struct input *next;
  622. next = current.next;
  623. current = *next;
  624. free (next);
  625. goto tail_recurse;
  626. }
  627. }
  628. /* A comment character always means to drop everything until the
  629. next newline. */
  630. if (c == COMMENT_CHAR)
  631. {
  632. do
  633. {
  634. c = getc (current.file);
  635. }
  636. while (c != '\n');
  637. ++current.lineno;
  638. current.state = BEGINNING_OF_LINE;
  639. goto tail_recurse;
  640. }
  641. /* An '@' introduces an include file. */
  642. if (c == '@')
  643. {
  644. do
  645. {
  646. c = getc (current.file);
  647. if (c == '\n')
  648. ++current.lineno;
  649. }
  650. while (ISSPACE (c));
  651. BUF_INIT ();
  652. while (! ISSPACE (c) && c != EOF)
  653. {
  654. BUF_ADD (c);
  655. c = getc (current.file);
  656. }
  657. BUF_FINISH ();
  658. ungetc (c, current.file);
  659. nlmlex_file_push (lex_buf);
  660. goto tail_recurse;
  661. }
  662. /* A non-space character at the start of a line must be the start of
  663. a keyword. */
  664. if (current.state == BEGINNING_OF_LINE)
  665. {
  666. BUF_INIT ();
  667. while (ISALNUM (c) || c == '_')
  668. {
  669. BUF_ADD (TOUPPER (c));
  670. c = getc (current.file);
  671. }
  672. BUF_FINISH ();
  673. if (c != EOF && ! ISSPACE (c) && c != ',')
  674. {
  675. nlmheader_identify ();
  676. fprintf (stderr, _("%s:%d: illegal character in keyword: %c\n"),
  677. current.name, current.lineno, c);
  678. }
  679. else
  680. {
  681. unsigned int i;
  682. for (i = 0; i < KEYWORD_COUNT; i++)
  683. {
  684. if (lex_buf[0] == keyword_tokens[i].keyword[0]
  685. && strcmp (lex_buf, keyword_tokens[i].keyword) == 0)
  686. {
  687. /* Pushing back the final whitespace avoids worrying
  688. about \n here. */
  689. ungetc (c, current.file);
  690. current.state = IN_LINE;
  691. return keyword_tokens[i].token;
  692. }
  693. }
  694. nlmheader_identify ();
  695. fprintf (stderr, _("%s:%d: unrecognized keyword: %s\n"),
  696. current.name, current.lineno, lex_buf);
  697. }
  698. ++parse_errors;
  699. /* Treat the rest of this line as a comment. */
  700. ungetc (COMMENT_CHAR, current.file);
  701. goto tail_recurse;
  702. }
  703. /* Parentheses just represent themselves. */
  704. if (c == '(' || c == ')')
  705. return c;
  706. /* Handle quoted strings. */
  707. if (c == '"' || c == '\'')
  708. {
  709. int quote;
  710. int start_lineno;
  711. quote = c;
  712. start_lineno = current.lineno;
  713. c = getc (current.file);
  714. BUF_INIT ();
  715. while (c != quote && c != EOF)
  716. {
  717. BUF_ADD (c);
  718. if (c == '\n')
  719. ++current.lineno;
  720. c = getc (current.file);
  721. }
  722. BUF_FINISH ();
  723. if (c == EOF)
  724. {
  725. nlmheader_identify ();
  726. fprintf (stderr, _("%s:%d: end of file in quoted string\n"),
  727. current.name, start_lineno);
  728. ++parse_errors;
  729. }
  730. /* FIXME: Possible memory leak. */
  731. yylval.string = xstrdup (lex_buf);
  732. return QUOTED_STRING;
  733. }
  734. /* Gather a generic argument. */
  735. BUF_INIT ();
  736. while (! ISSPACE (c)
  737. && c != ','
  738. && c != COMMENT_CHAR
  739. && c != '('
  740. && c != ')')
  741. {
  742. BUF_ADD (c);
  743. c = getc (current.file);
  744. }
  745. BUF_FINISH ();
  746. ungetc (c, current.file);
  747. /* FIXME: Possible memory leak. */
  748. yylval.string = xstrdup (lex_buf);
  749. return STRING;
  750. }
  751. /* Get a number from a string. */
  752. static long
  753. nlmlex_get_number (const char *s)
  754. {
  755. long ret;
  756. char *send;
  757. ret = strtol (s, &send, 10);
  758. if (*send != '\0')
  759. nlmheader_warn (_("bad number"), -1);
  760. return ret;
  761. }
  762. /* Prefix the nlmconv warnings with a note as to where they come from.
  763. We don't use program_name on every warning, because then some
  764. versions of the emacs next-error function can't recognize the line
  765. number. */
  766. static void
  767. nlmheader_identify (void)
  768. {
  769. static int done;
  770. if (! done)
  771. {
  772. fprintf (stderr, _("%s: problems in NLM command language input:\n"),
  773. program_name);
  774. done = 1;
  775. }
  776. }
  777. /* Issue a warning. */
  778. static void
  779. nlmheader_warn (const char *s, int imax)
  780. {
  781. nlmheader_identify ();
  782. fprintf (stderr, "%s:%d: %s", current.name, current.lineno, s);
  783. if (imax != -1)
  784. fprintf (stderr, " (max %d)", imax);
  785. fprintf (stderr, "\n");
  786. }
  787. /* Report an error. */
  788. static void
  789. nlmheader_error (const char *s)
  790. {
  791. nlmheader_warn (s, -1);
  792. ++parse_errors;
  793. }
  794. /* Add a string to a string list. */
  795. static struct string_list *
  796. string_list_cons (char *s, struct string_list *l)
  797. {
  798. struct string_list *ret;
  799. ret = (struct string_list *) xmalloc (sizeof (struct string_list));
  800. ret->next = l;
  801. ret->string = s;
  802. return ret;
  803. }
  804. /* Append a string list to another string list. */
  805. static struct string_list *
  806. string_list_append (struct string_list *l1, struct string_list *l2)
  807. {
  808. register struct string_list **pp;
  809. for (pp = &l1; *pp != NULL; pp = &(*pp)->next)
  810. ;
  811. *pp = l2;
  812. return l1;
  813. }
  814. /* Append a string to a string list. */
  815. static struct string_list *
  816. string_list_append1 (struct string_list *l, char *s)
  817. {
  818. struct string_list *n;
  819. register struct string_list **pp;
  820. n = (struct string_list *) xmalloc (sizeof (struct string_list));
  821. n->next = NULL;
  822. n->string = s;
  823. for (pp = &l; *pp != NULL; pp = &(*pp)->next)
  824. ;
  825. *pp = n;
  826. return l;
  827. }
  828. /* Duplicate a string in memory. */
  829. static char *
  830. xstrdup (const char *s)
  831. {
  832. unsigned long len;
  833. char *ret;
  834. len = strlen (s);
  835. ret = xmalloc (len + 1);
  836. strcpy (ret, s);
  837. return ret;
  838. }