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. */
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 /* List of files from INPUT. */
59 struct string_list *input_files;
60 /* Map file name (MAP, FULLMAP). */
62 /* Whether a full map has been requested (FULLMAP). */
64 /* File named by HELP. */
66 /* Imported symbols (IMPORT). */
67 struct string_list *import_symbols;
68 /* File named by MESSAGES. */
70 /* Autoload module list (MODULE). */
71 struct string_list *modules;
72 /* File named by OUTPUT. */
74 /* File named by SHARELIB. */
76 /* Start procedure name (START). */
77 char *start_procedure;
80 /* RPC description file (XDCDATA). */
83 /* The number of serious errors that have occurred. */
86 /* The current symbol prefix when reading a list of import or export
88 static char *symbol_prefix;
90 /* Parser error message handler. */
91 #define yyerror(msg) nlmheader_error (msg);
93 /* Local functions. */
94 static int yylex PARAMS ((void));
95 static void nlmlex_file_push PARAMS ((const char *));
96 static boolean nlmlex_file_open PARAMS ((const char *));
97 static int nlmlex_buf_init PARAMS ((void));
98 static char nlmlex_buf_add PARAMS ((int));
99 static long nlmlex_get_number PARAMS ((const char *));
100 static void nlmheader_identify PARAMS ((void));
101 static void nlmheader_warn PARAMS ((const char *, int));
102 static void nlmheader_error PARAMS ((const char *));
103 static struct string_list * string_list_cons PARAMS ((char *,
104 struct string_list *));
105 static struct string_list * string_list_append PARAMS ((struct string_list *,
106 struct string_list *));
107 static struct string_list * string_list_append1 PARAMS ((struct string_list *,
109 static char *xstrdup PARAMS ((const char *));
116 struct string_list *list;
119 /* The reserved words. */
121 %token CHECK CODESTART COPYRIGHT CUSTOM DATE DEBUG DESCRIPTION EXIT
122 %token EXPORT FLAG_ON FLAG_OFF FULLMAP HELP IMPORT INPUT MAP MESSAGES
123 %token MODULE MULTIPLE OS_DOMAIN OUTPUT PSEUDOPREEMPTION REENTRANT
124 %token SCREENNAME SHARELIB STACK STACKSIZE START SYNCHRONIZE
125 %token THREADNAME TYPE VERBOSE VERSION XDCDATA
129 %token <string> STRING
130 %token <string> QUOTED_STRING
132 /* Typed non-terminals. */
133 %type <list> symbol_list_opt symbol_list string_list
134 %type <string> symbol
138 /* Keywords must start in the leftmost column of the file. Arguments
139 may appear anywhere else. The lexer uses this to determine what
140 token to return, so we don't have to worry about it here. */
142 /* The entire file is just a list of commands. */
148 /* A possibly empty list of commands. */
155 /* A single command. There is where most of the work takes place. */
160 check_procedure = $2;
164 nlmheader_warn ("CODESTART is not implemented; sorry", -1);
167 | COPYRIGHT QUOTED_STRING
171 strncpy (copyright_hdr->stamp, "CoPyRiGhT=", 10);
173 if (len >= NLM_MAX_COPYRIGHT_MESSAGE_LENGTH)
175 nlmheader_warn ("copyright string is too long",
176 NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1);
177 len = NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1;
179 copyright_hdr->copyrightMessageLength = len;
180 strncpy (copyright_hdr->copyrightMessage, $2, len);
181 copyright_hdr->copyrightMessage[len] = '\0';
188 | DATE STRING STRING STRING
190 /* We don't set the version stamp here, because we use the
191 version stamp to detect whether the required VERSION
192 keyword was given. */
193 version_hdr->month = nlmlex_get_number ($2);
194 version_hdr->day = nlmlex_get_number ($3);
195 version_hdr->year = nlmlex_get_number ($4);
204 | DESCRIPTION QUOTED_STRING
209 if (len > NLM_MAX_DESCRIPTION_LENGTH)
211 nlmheader_warn ("description string is too long",
212 NLM_MAX_DESCRIPTION_LENGTH);
213 len = NLM_MAX_DESCRIPTION_LENGTH;
215 var_hdr->descriptionLength = len;
216 strncpy (var_hdr->descriptionText, $2, len);
217 var_hdr->descriptionText[len] = '\0';
226 symbol_prefix = NULL;
230 export_symbols = string_list_append (export_symbols, $3);
234 fixed_hdr->flags |= nlmlex_get_number ($2);
239 fixed_hdr->flags &=~ nlmlex_get_number ($2);
253 symbol_prefix = NULL;
257 import_symbols = string_list_append (import_symbols, $3);
261 input_files = string_list_append (input_files, $2);
273 modules = string_list_append (modules, $2);
277 fixed_hdr->flags |= 0x2;
281 fixed_hdr->flags |= 0x10;
285 if (output_file == NULL)
288 nlmheader_warn ("ignoring duplicate OUTPUT statement", -1);
292 fixed_hdr->flags |= 0x8;
296 fixed_hdr->flags |= 0x1;
298 | SCREENNAME QUOTED_STRING
303 if (len >= NLM_MAX_SCREEN_NAME_LENGTH)
305 nlmheader_warn ("screen name is too long",
306 NLM_MAX_SCREEN_NAME_LENGTH);
307 len = NLM_MAX_SCREEN_NAME_LENGTH;
309 var_hdr->screenNameLength = len;
310 strncpy (var_hdr->screenName, $2, len);
311 var_hdr->screenName[NLM_MAX_SCREEN_NAME_LENGTH] = '\0';
320 var_hdr->stackSize = nlmlex_get_number ($2);
325 var_hdr->stackSize = nlmlex_get_number ($2);
330 start_procedure = $2;
334 fixed_hdr->flags |= 0x4;
336 | THREADNAME QUOTED_STRING
341 if (len >= NLM_MAX_THREAD_NAME_LENGTH)
343 nlmheader_warn ("thread name is too long",
344 NLM_MAX_THREAD_NAME_LENGTH);
345 len = NLM_MAX_THREAD_NAME_LENGTH;
347 var_hdr->threadNameLength = len;
348 strncpy (var_hdr->threadName, $2, len);
349 var_hdr->screenName[NLM_MAX_THREAD_NAME_LENGTH] = '\0';
354 fixed_hdr->moduleType = nlmlex_get_number ($2);
361 | VERSION STRING STRING STRING
365 strncpy (version_hdr->stamp, "VeRsIoN#", 8);
366 version_hdr->majorVersion = nlmlex_get_number ($2);
367 val = nlmlex_get_number ($3);
368 if (val < 0 || val > 99)
369 nlmheader_warn ("illegal minor version number (must be between 0 and 99)",
372 version_hdr->minorVersion = val;
373 val = nlmlex_get_number ($4);
374 if (val < 1 || val > 26)
375 nlmheader_warn ("illegal revision number (must be between 1 and 26)",
378 version_hdr->revision = val;
383 | VERSION STRING STRING
387 strncpy (version_hdr->stamp, "VeRsIoN#", 8);
388 version_hdr->majorVersion = nlmlex_get_number ($2);
389 val = nlmlex_get_number ($3);
390 if (val < 0 || val > 99)
391 nlmheader_warn ("illegal minor version number (must be between 0 and 99)",
394 version_hdr->minorVersion = val;
395 version_hdr->revision = 0;
405 /* A possibly empty list of symbols. */
418 /* A list of symbols in an import or export list. Prefixes may appear
419 in parentheses. We need to use left recursion here to avoid
420 building up a large import list on the parser stack. */
425 $$ = string_list_cons ($1, NULL);
433 $$ = string_list_append1 ($1, $2);
435 | symbol_list symbol_prefix
441 /* A prefix for subsequent symbols. */
446 if (symbol_prefix != NULL)
447 free (symbol_prefix);
452 /* A single symbol. */
457 if (symbol_prefix == NULL)
461 $$ = xmalloc (strlen (symbol_prefix) + strlen ($1) + 2);
462 sprintf ($$, "%s@%s", symbol_prefix, $1);
468 /* A list of strings. */
477 $$ = string_list_cons ($1, $2);
483 /* If strerror is just a macro, we want to use the one from libiberty
484 since it will handle undefined values. */
486 extern char *strerror ();
488 /* The lexer is simple, too simple for flex. Keywords are only
489 recognized at the start of lines. Everything else must be an
490 argument. A comma is treated as whitespace. */
492 /* The states the lexer can be in. */
496 /* At the beginning of a line. */
498 /* In the middle of a line. */
502 /* We need to keep a stack of files to handle file inclusion. */
506 /* The file to read from. */
508 /* The name of the file. */
510 /* The current line number. */
512 /* The current state. */
513 enum lex_state state;
514 /* The next file on the stack. */
518 /* The current input file. */
520 static struct input current;
522 /* The character which introduces comments. */
523 #define COMMENT_CHAR '#'
525 /* Start the lexer going on the main input file. */
532 return nlmlex_file_open (name);
535 /* Start the lexer going on a subsidiary input file. */
538 nlmlex_file_push (name)
543 push = (struct input *) xmalloc (sizeof (struct input));
545 if (nlmlex_file_open (name))
554 /* Start lexing from a file. */
557 nlmlex_file_open (name)
560 current.file = fopen (name, "r");
561 if (current.file == NULL)
563 fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno));
567 current.name = xstrdup (name);
569 current.state = BEGINNING_OF_LINE;
573 /* Table used to turn keywords into tokens. */
575 struct keyword_tokens_struct
581 struct keyword_tokens_struct keyword_tokens[] =
584 { "CODESTART", CODESTART },
585 { "COPYRIGHT", COPYRIGHT },
586 { "CUSTOM", CUSTOM },
589 { "DESCRIPTION", DESCRIPTION },
591 { "EXPORT", EXPORT },
592 { "FLAG_ON", FLAG_ON },
593 { "FLAG_OFF", FLAG_OFF },
594 { "FULLMAP", FULLMAP },
596 { "IMPORT", IMPORT },
599 { "MESSAGES", MESSAGES },
600 { "MODULE", MODULE },
601 { "MULTIPLE", MULTIPLE },
602 { "OS_DOMAIN", OS_DOMAIN },
603 { "OUTPUT", OUTPUT },
604 { "PSEUDOPREEMPTION", PSEUDOPREEMPTION },
605 { "REENTRANT", REENTRANT },
606 { "SCREENNAME", SCREENNAME },
607 { "SHARELIB", SHARELIB },
609 { "STACKSIZE", STACKSIZE },
611 { "SYNCHRONIZE", SYNCHRONIZE },
612 { "THREADNAME", THREADNAME },
614 { "VERBOSE", VERBOSE },
615 { "VERSION", VERSION },
616 { "XDCDATA", XDCDATA }
619 #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0]))
621 /* The lexer accumulates strings in these variables. */
622 static char *lex_buf;
626 /* Start accumulating strings into the buffer. */
628 ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ()))
634 lex_buf = xmalloc (lex_size + 1);
639 /* Finish a string in the buffer. */
640 #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0'))
642 /* Accumulate a character into the buffer. */
644 ((void) (lex_pos < lex_size \
645 ? lex_buf[lex_pos++] = (c) \
646 : nlmlex_buf_add (c)))
652 if (lex_pos >= lex_size)
655 lex_buf = xrealloc (lex_buf, lex_size + 1);
658 return lex_buf[lex_pos++] = c;
661 /* The lexer proper. This is called by the bison generated parsing
671 c = getc (current.file);
673 /* Commas are treated as whitespace characters. */
674 while (isspace ((unsigned char) c) || c == ',')
676 current.state = IN_LINE;
680 current.state = BEGINNING_OF_LINE;
682 c = getc (current.file);
685 /* At the end of the file we either pop to the previous file or
689 fclose (current.file);
691 if (current.next == NULL)
704 /* A comment character always means to drop everything until the
706 if (c == COMMENT_CHAR)
710 c = getc (current.file);
714 current.state = BEGINNING_OF_LINE;
718 /* An '@' introduces an include file. */
723 c = getc (current.file);
727 while (isspace ((unsigned char) c));
729 while (! isspace ((unsigned char) c) && c != EOF)
732 c = getc (current.file);
736 ungetc (c, current.file);
738 nlmlex_file_push (lex_buf);
742 /* A non-space character at the start of a line must be the start of
744 if (current.state == BEGINNING_OF_LINE)
747 while (isalnum ((unsigned char) c) || c == '_')
749 if (islower ((unsigned char) c))
750 BUF_ADD (toupper ((unsigned char) c));
753 c = getc (current.file);
757 if (c != EOF && ! isspace ((unsigned char) c) && c != ',')
759 nlmheader_identify ();
760 fprintf (stderr, "%s:%d: illegal character in keyword: %c\n",
761 current.name, current.lineno, c);
767 for (i = 0; i < KEYWORD_COUNT; i++)
769 if (lex_buf[0] == keyword_tokens[i].keyword[0]
770 && strcmp (lex_buf, keyword_tokens[i].keyword) == 0)
772 /* Pushing back the final whitespace avoids worrying
774 ungetc (c, current.file);
775 current.state = IN_LINE;
776 return keyword_tokens[i].token;
780 nlmheader_identify ();
781 fprintf (stderr, "%s:%d: unrecognized keyword: %s\n",
782 current.name, current.lineno, lex_buf);
786 /* Treat the rest of this line as a comment. */
787 ungetc (COMMENT_CHAR, current.file);
791 /* Parentheses just represent themselves. */
792 if (c == '(' || c == ')')
795 /* Handle quoted strings. */
796 if (c == '"' || c == '\'')
802 start_lineno = current.lineno;
804 c = getc (current.file);
806 while (c != quote && c != EOF)
811 c = getc (current.file);
817 nlmheader_identify ();
818 fprintf (stderr, "%s:%d: end of file in quoted string\n",
819 current.name, start_lineno);
823 /* FIXME: Possible memory leak. */
824 yylval.string = xstrdup (lex_buf);
825 return QUOTED_STRING;
828 /* Gather a generic argument. */
837 c = getc (current.file);
841 ungetc (c, current.file);
843 /* FIXME: Possible memory leak. */
844 yylval.string = xstrdup (lex_buf);
848 /* Get a number from a string. */
851 nlmlex_get_number (s)
857 ret = strtol (s, &send, 10);
859 nlmheader_warn ("bad number", -1);
863 /* Prefix the nlmconv warnings with a note as to where they come from.
864 We don't use program_name on every warning, because then some
865 versions of the emacs next-error function can't recognize the line
869 nlmheader_identify ()
875 fprintf (stderr, "%s: problems in NLM command language input:\n",
881 /* Issue a warning. */
884 nlmheader_warn (s, 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. */
901 nlmheader_warn (s, -1);
905 /* Add a string to a string list. */
907 static struct string_list *
908 string_list_cons (s, l)
910 struct string_list *l;
912 struct string_list *ret;
914 ret = (struct string_list *) xmalloc (sizeof (struct string_list));
920 /* Append a string list to another string list. */
922 static struct string_list *
923 string_list_append (l1, l2)
924 struct string_list *l1;
925 struct string_list *l2;
927 register struct string_list **pp;
929 for (pp = &l1; *pp != NULL; pp = &(*pp)->next)
935 /* Append a string to a string list. */
937 static struct string_list *
938 string_list_append1 (l, s)
939 struct string_list *l;
942 struct string_list *n;
943 register struct string_list **pp;
945 n = (struct string_list *) xmalloc (sizeof (struct string_list));
948 for (pp = &l; *pp != NULL; pp = &(*pp)->next)
954 /* Duplicate a string in memory. */
964 ret = xmalloc (len + 1);