1 %{/* nlmheader.y - parse NLM header specification keywords.
2 Copyright (C) 1993-2015 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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.
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.
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. */
21 /* Written by Ian Lance Taylor <ian@cygnus.com>.
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.
27 This implementation is based on the description in the NetWare Tool
28 Maker Specification manual, edition 1.0. */
31 #include "safe-ctype.h"
33 #include "nlm/common.h"
34 #include "nlm/internal.h"
38 /* Information is stored in the structures pointed to by these
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;
47 /* Procedure named by CHECK. */
48 char *check_procedure;
49 /* File named by CUSTOM. */
51 /* Whether to generate debugging information (DEBUG). */
52 bfd_boolean debug_info;
53 /* Procedure named by EXIT. */
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). */
61 /* Whether a full map has been requested (FULLMAP). */
63 /* File named by HELP. */
65 /* Imported symbols (IMPORT). */
66 struct string_list *import_symbols;
67 /* File named by MESSAGES. */
69 /* Autoload module list (MODULE). */
70 struct string_list *modules;
71 /* File named by OUTPUT. */
73 /* File named by SHARELIB. */
75 /* Start procedure name (START). */
76 char *start_procedure;
79 /* RPC description file (XDCDATA). */
82 /* The number of serious errors that have occurred. */
85 /* The current symbol prefix when reading a list of import or export
87 static char *symbol_prefix;
89 /* Parser error message handler. */
90 #define yyerror(msg) nlmheader_error (msg);
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 *,
107 static char *xstrdup (const char *);
114 struct string_list *list;
117 /* The reserved words. */
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
127 %token <string> STRING
128 %token <string> QUOTED_STRING
130 /* Typed non-terminals. */
131 %type <list> symbol_list_opt symbol_list string_list
132 %type <string> symbol
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. */
140 /* The entire file is just a list of commands. */
146 /* A possibly empty list of commands. */
153 /* A single command. There is where most of the work takes place. */
158 check_procedure = $2;
162 nlmheader_warn (_("CODESTART is not implemented; sorry"), -1);
165 | COPYRIGHT QUOTED_STRING
169 strncpy (copyright_hdr->stamp, "CoPyRiGhT=", 10);
171 if (len >= NLM_MAX_COPYRIGHT_MESSAGE_LENGTH)
173 nlmheader_warn (_("copyright string is too long"),
174 NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1);
175 len = NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1;
177 copyright_hdr->copyrightMessageLength = len;
178 strncpy (copyright_hdr->copyrightMessage, $2, len);
179 copyright_hdr->copyrightMessage[len] = '\0';
186 | DATE STRING STRING STRING
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);
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);
208 | DESCRIPTION QUOTED_STRING
213 if (len > NLM_MAX_DESCRIPTION_LENGTH)
215 nlmheader_warn (_("description string is too long"),
216 NLM_MAX_DESCRIPTION_LENGTH);
217 len = NLM_MAX_DESCRIPTION_LENGTH;
219 var_hdr->descriptionLength = len;
220 strncpy (var_hdr->descriptionText, $2, len);
221 var_hdr->descriptionText[len] = '\0';
230 symbol_prefix = NULL;
234 export_symbols = string_list_append (export_symbols, $3);
238 fixed_hdr->flags |= nlmlex_get_number ($2);
243 fixed_hdr->flags &=~ nlmlex_get_number ($2);
262 symbol_prefix = NULL;
266 import_symbols = string_list_append (import_symbols, $3);
270 input_files = string_list_append (input_files, $2);
286 modules = string_list_append (modules, $2);
290 fixed_hdr->flags |= 0x2;
294 fixed_hdr->flags |= 0x10;
298 if (output_file == NULL)
301 nlmheader_warn (_("ignoring duplicate OUTPUT statement"), -1);
305 fixed_hdr->flags |= 0x8;
309 fixed_hdr->flags |= 0x1;
311 | SCREENNAME QUOTED_STRING
316 if (len >= NLM_MAX_SCREEN_NAME_LENGTH)
318 nlmheader_warn (_("screen name is too long"),
319 NLM_MAX_SCREEN_NAME_LENGTH);
320 len = NLM_MAX_SCREEN_NAME_LENGTH;
322 var_hdr->screenNameLength = len;
323 strncpy (var_hdr->screenName, $2, len);
324 var_hdr->screenName[NLM_MAX_SCREEN_NAME_LENGTH] = '\0';
333 var_hdr->stackSize = nlmlex_get_number ($2);
338 start_procedure = $2;
342 fixed_hdr->flags |= 0x4;
344 | THREADNAME QUOTED_STRING
349 if (len >= NLM_MAX_THREAD_NAME_LENGTH)
351 nlmheader_warn (_("thread name is too long"),
352 NLM_MAX_THREAD_NAME_LENGTH);
353 len = NLM_MAX_THREAD_NAME_LENGTH;
355 var_hdr->threadNameLength = len;
356 strncpy (var_hdr->threadName, $2, len);
357 var_hdr->threadName[len] = '\0';
362 fixed_hdr->moduleType = nlmlex_get_number ($2);
369 | VERSIONK STRING STRING STRING
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)"),
380 version_hdr->minorVersion = val;
381 val = nlmlex_get_number ($4);
383 nlmheader_warn (_("illegal revision number (must be between 0 and 26)"),
386 version_hdr->revision = 0;
388 version_hdr->revision = val;
393 | VERSIONK STRING STRING
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)"),
404 version_hdr->minorVersion = val;
405 version_hdr->revision = 0;
415 /* A possibly empty list of symbols. */
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. */
435 $$ = string_list_cons ($1, NULL);
443 $$ = string_list_append1 ($1, $2);
445 | symbol_list symbol_prefix
451 /* A prefix for subsequent symbols. */
456 if (symbol_prefix != NULL)
457 free (symbol_prefix);
462 /* A single symbol. */
467 if (symbol_prefix == NULL)
471 $$ = xmalloc (strlen (symbol_prefix) + strlen ($1) + 2);
472 sprintf ($$, "%s@%s", symbol_prefix, $1);
478 /* A list of strings. */
487 $$ = string_list_cons ($1, $2);
493 /* If strerror is just a macro, we want to use the one from libiberty
494 since it will handle undefined values. */
496 extern char *strerror (int);
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. */
502 /* The states the lexer can be in. */
506 /* At the beginning of a line. */
508 /* In the middle of a line. */
512 /* We need to keep a stack of files to handle file inclusion. */
516 /* The file to read from. */
518 /* The name of the file. */
520 /* The current line number. */
522 /* The current state. */
523 enum lex_state state;
524 /* The next file on the stack. */
528 /* The current input file. */
530 static struct input current;
532 /* The character which introduces comments. */
533 #define COMMENT_CHAR '#'
535 /* Start the lexer going on the main input file. */
538 nlmlex_file (const char *name)
541 return nlmlex_file_open (name);
544 /* Start the lexer going on a subsidiary input file. */
547 nlmlex_file_push (const char *name)
551 push = (struct input *) xmalloc (sizeof (struct input));
553 if (nlmlex_file_open (name))
562 /* Start lexing from a file. */
565 nlmlex_file_open (const char *name)
567 current.file = fopen (name, "r");
568 if (current.file == NULL)
570 fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno));
574 current.name = xstrdup (name);
576 current.state = BEGINNING_OF_LINE;
580 /* Table used to turn keywords into tokens. */
582 struct keyword_tokens_struct
588 static struct keyword_tokens_struct keyword_tokens[] =
591 { "CODESTART", CODESTART },
592 { "COPYRIGHT", COPYRIGHT },
593 { "CUSTOM", CUSTOM },
595 { "DEBUG", DEBUG_K },
596 { "DESCRIPTION", DESCRIPTION },
598 { "EXPORT", EXPORT },
599 { "FLAG_ON", FLAG_ON },
600 { "FLAG_OFF", FLAG_OFF },
601 { "FULLMAP", FULLMAP },
603 { "IMPORT", IMPORT },
606 { "MESSAGES", MESSAGES },
607 { "MODULE", MODULE },
608 { "MULTIPLE", MULTIPLE },
609 { "OS_DOMAIN", OS_DOMAIN },
610 { "OUTPUT", OUTPUT },
611 { "PSEUDOPREEMPTION", PSEUDOPREEMPTION },
612 { "REENTRANT", REENTRANT },
613 { "SCREENNAME", SCREENNAME },
614 { "SHARELIB", SHARELIB },
616 { "STACKSIZE", STACK },
618 { "SYNCHRONIZE", SYNCHRONIZE },
619 { "THREADNAME", THREADNAME },
621 { "VERBOSE", VERBOSE },
622 { "VERSION", VERSIONK },
623 { "XDCDATA", XDCDATA }
626 #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0]))
628 /* The lexer accumulates strings in these variables. */
629 static char *lex_buf;
633 /* Start accumulating strings into the buffer. */
635 ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ()))
638 nlmlex_buf_init (void)
641 lex_buf = xmalloc (lex_size + 1);
646 /* Finish a string in the buffer. */
647 #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0'))
649 /* Accumulate a character into the buffer. */
651 ((void) (lex_pos < lex_size \
652 ? lex_buf[lex_pos++] = (c) \
653 : nlmlex_buf_add (c)))
656 nlmlex_buf_add (int c)
658 if (lex_pos >= lex_size)
661 lex_buf = xrealloc (lex_buf, lex_size + 1);
664 return lex_buf[lex_pos++] = c;
667 /* The lexer proper. This is called by the bison generated parsing
677 c = getc (current.file);
679 /* Commas are treated as whitespace characters. */
680 while (ISSPACE (c) || c == ',')
682 current.state = IN_LINE;
686 current.state = BEGINNING_OF_LINE;
688 c = getc (current.file);
691 /* At the end of the file we either pop to the previous file or
695 fclose (current.file);
697 if (current.next == NULL)
710 /* A comment character always means to drop everything until the
712 if (c == COMMENT_CHAR)
716 c = getc (current.file);
720 current.state = BEGINNING_OF_LINE;
724 /* An '@' introduces an include file. */
729 c = getc (current.file);
735 while (! ISSPACE (c) && c != EOF)
738 c = getc (current.file);
742 ungetc (c, current.file);
744 nlmlex_file_push (lex_buf);
748 /* A non-space character at the start of a line must be the start of
750 if (current.state == BEGINNING_OF_LINE)
753 while (ISALNUM (c) || c == '_')
755 BUF_ADD (TOUPPER (c));
756 c = getc (current.file);
760 if (c != EOF && ! ISSPACE (c) && c != ',')
762 nlmheader_identify ();
763 fprintf (stderr, _("%s:%d: illegal character in keyword: %c\n"),
764 current.name, current.lineno, c);
770 for (i = 0; i < KEYWORD_COUNT; i++)
772 if (lex_buf[0] == keyword_tokens[i].keyword[0]
773 && strcmp (lex_buf, keyword_tokens[i].keyword) == 0)
775 /* Pushing back the final whitespace avoids worrying
777 ungetc (c, current.file);
778 current.state = IN_LINE;
779 return keyword_tokens[i].token;
783 nlmheader_identify ();
784 fprintf (stderr, _("%s:%d: unrecognized keyword: %s\n"),
785 current.name, current.lineno, lex_buf);
789 /* Treat the rest of this line as a comment. */
790 ungetc (COMMENT_CHAR, current.file);
794 /* Parentheses just represent themselves. */
795 if (c == '(' || c == ')')
798 /* Handle quoted strings. */
799 if (c == '"' || c == '\'')
805 start_lineno = current.lineno;
807 c = getc (current.file);
809 while (c != quote && c != EOF)
814 c = getc (current.file);
820 nlmheader_identify ();
821 fprintf (stderr, _("%s:%d: end of file in quoted string\n"),
822 current.name, start_lineno);
826 /* FIXME: Possible memory leak. */
827 yylval.string = xstrdup (lex_buf);
828 return QUOTED_STRING;
831 /* Gather a generic argument. */
840 c = getc (current.file);
844 ungetc (c, current.file);
846 /* FIXME: Possible memory leak. */
847 yylval.string = xstrdup (lex_buf);
851 /* Get a number from a string. */
854 nlmlex_get_number (const char *s)
859 ret = strtol (s, &send, 10);
861 nlmheader_warn (_("bad number"), -1);
865 /* Prefix the nlmconv warnings with a note as to where they come from.
866 We don't use program_name on every warning, because then some
867 versions of the emacs next-error function can't recognize the line
871 nlmheader_identify (void)
877 fprintf (stderr, _("%s: problems in NLM command language input:\n"),
883 /* Issue a warning. */
886 nlmheader_warn (const char *s, int imax)
888 nlmheader_identify ();
889 fprintf (stderr, "%s:%d: %s", current.name, current.lineno, s);
891 fprintf (stderr, " (max %d)", imax);
892 fprintf (stderr, "\n");
895 /* Report an error. */
898 nlmheader_error (const char *s)
900 nlmheader_warn (s, -1);
904 /* Add a string to a string list. */
906 static struct string_list *
907 string_list_cons (char *s, struct string_list *l)
909 struct string_list *ret;
911 ret = (struct string_list *) xmalloc (sizeof (struct string_list));
917 /* Append a string list to another string list. */
919 static struct string_list *
920 string_list_append (struct string_list *l1, struct string_list *l2)
922 register struct string_list **pp;
924 for (pp = &l1; *pp != NULL; pp = &(*pp)->next)
930 /* Append a string to a string list. */
932 static struct string_list *
933 string_list_append1 (struct string_list *l, char *s)
935 struct string_list *n;
936 register struct string_list **pp;
938 n = (struct string_list *) xmalloc (sizeof (struct string_list));
941 for (pp = &l; *pp != NULL; pp = &(*pp)->next)
947 /* Duplicate a string in memory. */
950 xstrdup (const char *s)
956 ret = xmalloc (len + 1);