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