1 %{/* nlmheader.y - parse NLM header specification keywords.
2 Copyright (C) 1993 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Written by Ian Lance Taylor <ian@cygnus.com>.
22 This bison file parses the commands recognized by the NetWare NLM
23 linker, except for lists of object files. It stores the
24 information in global variables.
26 This implementation is based on the description in the NetWare Tool
27 Maker Specification manual, edition 1.0. */
35 #include "nlm/common.h"
36 #include "nlm/internal.h"
39 /* Information is stored in the structures pointed to by these
42 Nlm_Internal_Fixed_Header *fixed_hdr;
43 Nlm_Internal_Variable_Header *var_hdr;
44 Nlm_Internal_Version_Header *version_hdr;
45 Nlm_Internal_Copyright_Header *copyright_hdr;
46 Nlm_Internal_Extended_Header *extended_hdr;
48 /* Procedure named by CHECK. */
49 char *check_procedure;
50 /* File named by CUSTOM. */
52 /* Whether to generate debugging information (DEBUG). */
54 /* Procedure named by EXIT. */
56 /* Exported symbols (EXPORT). */
57 struct string_list *export_symbols;
58 /* Map file name (MAP, FULLMAP). */
60 /* Whether a full map has been requested (FULLMAP). */
62 /* File named by HELP. */
64 /* Imported symbols (IMPORT). */
65 struct string_list *import_symbols;
66 /* File named by MESSAGES. */
68 /* Autoload module list (MODULE). */
69 struct string_list *modules;
70 /* File named by SHARELIB. */
72 /* Start procedure name (START). */
73 char *start_procedure;
76 /* RPC description file (XDCDATA). */
79 /* The number of serious errors that have occurred. */
82 /* The current symbol prefix when reading a list of import or export
84 static char *symbol_prefix;
86 /* Parser error message handler. */
87 #define yyerror(msg) nlmheader_error (msg);
89 /* Local functions. */
90 static int yylex PARAMS ((void));
91 static void nlmlex_file_push PARAMS ((const char *));
92 static boolean nlmlex_file_open PARAMS ((const char *));
93 static int nlmlex_buf_init PARAMS ((void));
94 static char nlmlex_buf_add PARAMS ((int));
95 static long nlmlex_get_number PARAMS ((const char *));
96 static void nlmheader_identify PARAMS ((void));
97 static void nlmheader_warn PARAMS ((const char *, int));
98 static void nlmheader_error PARAMS ((const char *));
99 static struct string_list * string_list_cons PARAMS ((char *,
100 struct string_list *));
101 static struct string_list * string_list_append PARAMS ((struct string_list *,
102 struct string_list *));
103 static struct string_list * string_list_append1 PARAMS ((struct string_list *,
105 static char *xstrdup PARAMS ((const char *));
112 struct string_list *list;
115 /* The reserved words. */
117 %token CHECK CODESTART COPYRIGHT CUSTOM DATE DEBUG DESCRIPTION EXIT
118 %token EXPORT FLAG_ON FLAG_OFF FULLMAP HELP IMPORT INPUT MAP MESSAGES
119 %token MODULE MULTIPLE OS_DOMAIN OUTPUT PSEUDOPREEMPTION REENTRANT
120 %token SCREENNAME SHARELIB STACK STACKSIZE START SYNCHRONIZE
121 %token THREADNAME TYPE VERBOSE VERSION XDCDATA
125 %token <string> STRING
126 %token <string> QUOTED_STRING
128 /* Typed non-terminals. */
129 %type <list> symbol_list_opt symbol_list module_list
130 %type <string> symbol
134 /* Keywords must start in the leftmost column of the file. Arguments
135 may appear anywhere else. The lexer uses this to determine what
136 token to return, so we don't have to worry about it here. */
138 /* The entire file is just a list of commands. */
144 /* A possibly empty list of commands. */
151 /* A single command. There is where most of the work takes place. */
156 check_procedure = $2;
160 nlmheader_warn ("CODESTART is not implemented; sorry", -1);
163 | COPYRIGHT QUOTED_STRING
167 strncpy (copyright_hdr->stamp, "CoPyRiGhT=", 10);
169 if (len >= NLM_MAX_COPYRIGHT_MESSAGE_LENGTH)
171 nlmheader_warn ("copyright string is too long",
172 NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1);
173 len = NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1;
175 copyright_hdr->copyrightMessageLength = len;
176 strncpy (copyright_hdr->copyrightMessage, $2, len);
177 copyright_hdr->copyrightMessage[len] = '\0';
184 | DATE STRING STRING STRING
186 /* We don't set the version stamp here, because we use the
187 version stamp to detect whether the required VERSION
188 keyword was given. */
189 version_hdr->month = nlmlex_get_number ($2);
190 version_hdr->day = nlmlex_get_number ($3);
191 version_hdr->year = nlmlex_get_number ($4);
200 | DESCRIPTION QUOTED_STRING
205 if (len > NLM_MAX_DESCRIPTION_LENGTH)
207 nlmheader_warn ("description string is too long",
208 NLM_MAX_DESCRIPTION_LENGTH);
209 len = NLM_MAX_DESCRIPTION_LENGTH;
211 var_hdr->descriptionLength = len;
212 strncpy (var_hdr->descriptionText, $2, len);
213 var_hdr->descriptionText[len] = '\0';
222 symbol_prefix = NULL;
226 export_symbols = string_list_append (export_symbols, $3);
230 fixed_hdr->flags |= nlmlex_get_number ($2);
235 fixed_hdr->flags &=~ nlmlex_get_number ($2);
249 symbol_prefix = NULL;
253 import_symbols = string_list_append (import_symbols, $3);
257 nlmheader_warn ("INPUT not supported", -1);
270 modules = string_list_append (modules, $2);
274 fixed_hdr->flags |= 0x2;
278 fixed_hdr->flags |= 0x10;
282 nlmheader_warn ("OUTPUT not supported", -1);
287 fixed_hdr->flags |= 0x8;
291 fixed_hdr->flags |= 0x1;
293 | SCREENNAME QUOTED_STRING
298 if (len >= NLM_MAX_SCREEN_NAME_LENGTH)
300 nlmheader_warn ("screen name is too long",
301 NLM_MAX_SCREEN_NAME_LENGTH);
302 len = NLM_MAX_SCREEN_NAME_LENGTH;
304 var_hdr->screenNameLength = len;
305 strncpy (var_hdr->screenName, $2, len);
306 var_hdr->screenName[NLM_MAX_SCREEN_NAME_LENGTH] = '\0';
315 var_hdr->stackSize = nlmlex_get_number ($2);
320 var_hdr->stackSize = nlmlex_get_number ($2);
325 start_procedure = $2;
329 fixed_hdr->flags |= 0x4;
331 | THREADNAME QUOTED_STRING
336 if (len >= NLM_MAX_THREAD_NAME_LENGTH)
338 nlmheader_warn ("thread name is too long",
339 NLM_MAX_THREAD_NAME_LENGTH);
340 len = NLM_MAX_THREAD_NAME_LENGTH;
342 var_hdr->threadNameLength = len;
343 strncpy (var_hdr->threadName, $2, len);
344 var_hdr->screenName[NLM_MAX_THREAD_NAME_LENGTH] = '\0';
349 fixed_hdr->moduleType = nlmlex_get_number ($2);
356 | VERSION STRING STRING STRING
360 strncpy (version_hdr->stamp, "VeRsIoN#", 8);
361 version_hdr->majorVersion = nlmlex_get_number ($2);
362 val = nlmlex_get_number ($3);
363 if (val < 0 || val > 99)
364 nlmheader_warn ("illegal minor version number (must be between 0 and 99)",
367 version_hdr->minorVersion = val;
368 val = nlmlex_get_number ($4);
369 if (val < 1 || val > 26)
370 nlmheader_warn ("illegal revision number (must be between 1 and 26)",
373 version_hdr->revision = val;
378 | VERSION STRING STRING
382 strncpy (version_hdr->stamp, "VeRsIoN#", 8);
383 version_hdr->majorVersion = nlmlex_get_number ($2);
384 val = nlmlex_get_number ($3);
385 if (val < 0 || val > 99)
386 nlmheader_warn ("illegal minor version number (must be between 0 and 99)",
389 version_hdr->minorVersion = val;
390 version_hdr->revision = 0;
400 /* A possibly empty list of symbols. */
413 /* A list of symbols in an import or export list. Prefixes may appear
414 in parentheses. We need to use left recursion here to avoid
415 building up a large import list on the parser stack. */
420 $$ = string_list_cons ($1, NULL);
428 $$ = string_list_append1 ($1, $2);
430 | symbol_list symbol_prefix
436 /* A prefix for subsequent symbols. */
441 if (symbol_prefix != NULL)
442 free (symbol_prefix);
447 /* A single symbol. */
452 if (symbol_prefix == NULL)
456 $$ = xmalloc (strlen (symbol_prefix) + strlen ($1) + 2);
457 sprintf ($$, "%s@%s", symbol_prefix, $1);
463 /* A list of modules. */
472 $$ = string_list_cons ($1, $2);
478 /* If strerror is just a macro, we want to use the one from libiberty
479 since it will handle undefined values. */
481 extern char *strerror ();
483 /* The lexer is simple, too simple for flex. Keywords are only
484 recognized at the start of lines. Everything else must be an
485 argument. A comma is treated as whitespace. */
487 /* The states the lexer can be in. */
491 /* At the beginning of a line. */
493 /* In the middle of a line. */
497 /* We need to keep a stack of files to handle file inclusion. */
501 /* The file to read from. */
503 /* The name of the file. */
505 /* The current line number. */
507 /* The current state. */
508 enum lex_state state;
509 /* The next file on the stack. */
513 /* The current input file. */
515 static struct input current;
517 /* The character which introduces comments. */
518 #define COMMENT_CHAR '#'
520 /* Start the lexer going on the main input file. */
527 return nlmlex_file_open (name);
530 /* Start the lexer going on a subsidiary input file. */
533 nlmlex_file_push (name)
538 push = (struct input *) xmalloc (sizeof (struct input));
540 if (nlmlex_file_open (name))
549 /* Start lexing from a file. */
552 nlmlex_file_open (name)
555 current.file = fopen (name, "r");
556 if (current.file == NULL)
558 fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno));
562 current.name = xstrdup (name);
564 current.state = BEGINNING_OF_LINE;
568 /* Table used to turn keywords into tokens. */
570 struct keyword_tokens_struct
576 struct keyword_tokens_struct keyword_tokens[] =
579 { "CODESTART", CODESTART },
580 { "COPYRIGHT", COPYRIGHT },
581 { "CUSTOM", CUSTOM },
584 { "DESCRIPTION", DESCRIPTION },
586 { "EXPORT", EXPORT },
587 { "FLAG_ON", FLAG_ON },
588 { "FLAG_OFF", FLAG_OFF },
589 { "FULLMAP", FULLMAP },
591 { "IMPORT", IMPORT },
594 { "MESSAGES", MESSAGES },
595 { "MODULE", MODULE },
596 { "MULTIPLE", MULTIPLE },
597 { "OS_DOMAIN", OS_DOMAIN },
598 { "OUTPUT", OUTPUT },
599 { "PSEUDOPREEMPTION", PSEUDOPREEMPTION },
600 { "REENTRANT", REENTRANT },
601 { "SCREENNAME", SCREENNAME },
602 { "SHARELIB", SHARELIB },
604 { "STACKSIZE", STACKSIZE },
606 { "SYNCHRONIZE", SYNCHRONIZE },
607 { "THREADNAME", THREADNAME },
609 { "VERBOSE", VERBOSE },
610 { "VERSION", VERSION },
611 { "XDCDATA", XDCDATA }
614 #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0]))
616 /* The lexer accumulates strings in these variables. */
617 static char *lex_buf;
621 /* Start accumulating strings into the buffer. */
623 ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ()))
629 lex_buf = xmalloc (lex_size + 1);
634 /* Finish a string in the buffer. */
635 #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0'))
637 /* Accumulate a character into the buffer. */
639 ((void) (lex_pos < lex_size \
640 ? lex_buf[lex_pos++] = (c) \
641 : nlmlex_buf_add (c)))
647 if (lex_pos >= lex_size)
650 lex_buf = xrealloc (lex_buf, lex_size + 1);
653 return lex_buf[lex_pos++] = c;
656 /* The lexer proper. This is called by the bison generated parsing
666 c = getc (current.file);
668 /* Commas are treated as whitespace characters. */
669 while (isspace ((unsigned char) c) || c == ',')
671 current.state = IN_LINE;
675 current.state = BEGINNING_OF_LINE;
677 c = getc (current.file);
680 /* At the end of the file we either pop to the previous file or
684 fclose (current.file);
686 if (current.next == NULL)
699 /* A comment character always means to drop everything until the
701 if (c == COMMENT_CHAR)
705 c = getc (current.file);
709 current.state = BEGINNING_OF_LINE;
713 /* An '@' introduces an include file. */
718 c = getc (current.file);
722 while (isspace ((unsigned char) c));
724 while (! isspace ((unsigned char) c) && c != EOF)
727 c = getc (current.file);
731 ungetc (c, current.file);
733 nlmlex_file_push (lex_buf);
737 /* A non-space character at the start of a line must be the start of
739 if (current.state == BEGINNING_OF_LINE)
742 while (isalnum ((unsigned char) c) || c == '_')
744 if (islower ((unsigned char) c))
745 BUF_ADD (toupper ((unsigned char) c));
748 c = getc (current.file);
752 if (c != EOF && ! isspace ((unsigned char) c) && c != ',')
754 nlmheader_identify ();
755 fprintf (stderr, "%s:%d: illegal character in keyword: %c\n",
756 current.name, current.lineno, c);
762 for (i = 0; i < KEYWORD_COUNT; i++)
764 if (lex_buf[0] == keyword_tokens[i].keyword[0]
765 && strcmp (lex_buf, keyword_tokens[i].keyword) == 0)
767 /* Pushing back the final whitespace avoids worrying
769 ungetc (c, current.file);
770 current.state = IN_LINE;
771 return keyword_tokens[i].token;
775 nlmheader_identify ();
776 fprintf (stderr, "%s:%d: unrecognized keyword: %s\n",
777 current.name, current.lineno, lex_buf);
781 /* Treat the rest of this line as a comment. */
782 ungetc (COMMENT_CHAR, current.file);
786 /* Parentheses just represent themselves. */
787 if (c == '(' || c == ')')
790 /* Handle quoted strings. */
791 if (c == '"' || c == '\'')
797 start_lineno = current.lineno;
799 c = getc (current.file);
801 while (c != quote && c != EOF)
806 c = getc (current.file);
812 nlmheader_identify ();
813 fprintf (stderr, "%s:%d: end of file in quoted string\n",
814 current.name, start_lineno);
818 /* FIXME: Possible memory leak. */
819 yylval.string = xstrdup (lex_buf);
820 return QUOTED_STRING;
823 /* Gather a generic argument. */
832 c = getc (current.file);
836 ungetc (c, current.file);
838 /* FIXME: Possible memory leak. */
839 yylval.string = xstrdup (lex_buf);
843 /* Get a number from a string. */
846 nlmlex_get_number (s)
852 ret = strtol (s, &send, 10);
854 nlmheader_warn ("bad number", -1);
858 /* Prefix the nlmconv warnings with a note as to where they come from.
859 We don't use program_name on every warning, because then some
860 versions of the emacs next-error function can't recognize the line
864 nlmheader_identify ()
870 fprintf (stderr, "%s: problems in NLM command language input:\n",
876 /* Issue a warning. */
879 nlmheader_warn (s, imax)
883 nlmheader_identify ();
884 fprintf (stderr, "%s:%d: %s", current.name, current.lineno, s);
886 fprintf (stderr, " (max %d)", imax);
887 fprintf (stderr, "\n");
890 /* Report an error. */
896 nlmheader_warn (s, -1);
900 /* Add a string to a string list. */
902 static struct string_list *
903 string_list_cons (s, l)
905 struct string_list *l;
907 struct string_list *ret;
909 ret = (struct string_list *) xmalloc (sizeof (struct string_list));
915 /* Append a string list to another string list. */
917 static struct string_list *
918 string_list_append (l1, l2)
919 struct string_list *l1;
920 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 (l, s)
934 struct string_list *l;
937 struct string_list *n;
938 register struct string_list **pp;
940 n = (struct string_list *) xmalloc (sizeof (struct string_list));
943 for (pp = &l; *pp != NULL; pp = &(*pp)->next)
949 /* Duplicate a string in memory. */
959 ret = xmalloc (len + 1);