merge from gcc
[external/binutils.git] / ld / deffilep.y
1 %{ /* deffilep.y - parser for .def files */
2
3 /*   Copyright 1995, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
4
5 This file is part of GNU Binutils.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "libiberty.h"
24 #include "bfd.h"
25 #include "sysdep.h"
26 #include "ld.h"
27 #include "ldmisc.h"
28 #include "deffile.h"
29
30 #define TRACE 0
31
32 #define ROUND_UP(a, b) (((a)+((b)-1))&~((b)-1))
33
34 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
35    as well as gratuitiously global symbol names, so we can have multiple
36    yacc generated parsers in ld.  Note that these are only the variables
37    produced by yacc.  If other parser generators (bison, byacc, etc) produce
38    additional global names that conflict at link time, then those parser
39    generators need to be fixed instead of adding those names to this list. */
40
41 #define yymaxdepth def_maxdepth
42 #define yyparse def_parse
43 #define yylex   def_lex
44 #define yyerror def_error
45 #define yylval  def_lval
46 #define yychar  def_char
47 #define yydebug def_debug
48 #define yypact  def_pact        
49 #define yyr1    def_r1                  
50 #define yyr2    def_r2                  
51 #define yydef   def_def         
52 #define yychk   def_chk         
53 #define yypgo   def_pgo         
54 #define yyact   def_act         
55 #define yyexca  def_exca
56 #define yyerrflag def_errflag
57 #define yynerrs def_nerrs
58 #define yyps    def_ps
59 #define yypv    def_pv
60 #define yys     def_s
61 #define yy_yys  def_yys
62 #define yystate def_state
63 #define yytmp   def_tmp
64 #define yyv     def_v
65 #define yy_yyv  def_yyv
66 #define yyval   def_val
67 #define yylloc  def_lloc
68 #define yyreds  def_reds                /* With YYDEBUG defined */
69 #define yytoks  def_toks                /* With YYDEBUG defined */
70 #define yylhs   def_yylhs
71 #define yylen   def_yylen
72 #define yydefred def_yydefred
73 #define yydgoto def_yydgoto
74 #define yysindex def_yysindex
75 #define yyrindex def_yyrindex
76 #define yygindex def_yygindex
77 #define yytable  def_yytable
78 #define yycheck  def_yycheck
79
80 static void def_description PARAMS ((const char *));
81 static void def_exports PARAMS ((const char *, const char *, int, int));
82 static void def_heapsize PARAMS ((int, int));
83 static void def_import
84   PARAMS ((const char *, const char *, const char *, const char *, int));
85 static void def_library PARAMS ((const char *, int));
86 static def_file_module *def_stash_module PARAMS ((def_file *, char *));
87 static void def_name PARAMS ((const char *, int));
88 static void def_section PARAMS ((const char *, int));
89 static void def_section_alt PARAMS ((const char *, const char *));
90 static void def_stacksize PARAMS ((int, int));
91 static void def_version PARAMS ((int, int));
92 static void def_directive PARAMS ((char *));
93 static int def_parse PARAMS ((void));
94 static int def_error PARAMS ((const char *));
95 static void put_buf PARAMS ((char));
96 static int def_getc PARAMS ((void));
97 static int def_ungetc PARAMS ((int));
98 static int def_lex PARAMS ((void));
99
100 static int lex_forced_token = 0;
101 static const char *lex_parse_string = 0;
102 static const char *lex_parse_string_end = 0;
103
104 %}
105
106 %union {
107   char *id;
108   int number;
109 };
110
111 %token NAME, LIBRARY, DESCRIPTION, STACKSIZE, HEAPSIZE, CODE, DATAU, DATAL
112 %token SECTIONS, EXPORTS, IMPORTS, VERSIONK, BASE, CONSTANTU, CONSTANTL
113 %token PRIVATEU, PRIVATEL
114 %token READ WRITE EXECUTE SHARED NONAMEU NONAMEL DIRECTIVE
115 %token <id> ID
116 %token <number> NUMBER
117 %type  <number> opt_base opt_ordinal
118 %type  <number> attr attr_list opt_number exp_opt_list exp_opt
119 %type  <id> opt_name opt_equal_name 
120
121 %%
122
123 start: start command
124         | command
125         ;
126
127 command: 
128                 NAME opt_name opt_base { def_name ($2, $3); }
129         |       LIBRARY opt_name opt_base { def_library ($2, $3); }
130         |       DESCRIPTION ID { def_description ($2);}
131         |       STACKSIZE NUMBER opt_number { def_stacksize ($2, $3);}
132         |       HEAPSIZE NUMBER opt_number { def_heapsize ($2, $3);}
133         |       CODE attr_list { def_section ("CODE", $2);}
134         |       DATAU attr_list  { def_section ("DATA", $2);}
135         |       SECTIONS seclist
136         |       EXPORTS explist 
137         |       IMPORTS implist
138         |       VERSIONK NUMBER { def_version ($2, 0);}
139         |       VERSIONK NUMBER '.' NUMBER { def_version ($2, $4);}
140         |       DIRECTIVE ID { def_directive ($2);}
141         ;
142
143
144 explist:
145                 /* EMPTY */
146         |       expline
147         |       explist expline
148         ;
149
150 expline:
151                 /* The opt_comma is necessary to support both the usual
152                   DEF file syntax as well as .drectve syntax which
153                   mandates <expsym>,<expoptlist>.  */
154                 ID opt_equal_name opt_ordinal opt_comma exp_opt_list
155                         { def_exports ($1, $2, $3, $5); }
156         ;
157 exp_opt_list:
158                 /* The opt_comma is necessary to support both the usual
159                    DEF file syntax as well as .drectve syntax which
160                    allows for comma separated opt list.  */
161                 exp_opt opt_comma exp_opt_list { $$ = $1 | $3; }
162         |       { $$ = 0; }
163         ;
164 exp_opt:
165                 NONAMEU         { $$ = 1; }
166         |       NONAMEL         { $$ = 1; }
167         |       CONSTANTU       { $$ = 2; }
168         |       CONSTANTL       { $$ = 2; }
169         |       DATAU           { $$ = 4; }
170         |       DATAL           { $$ = 4; }
171         |       PRIVATEU        { $$ = 8; }
172         |       PRIVATEL        { $$ = 8; }
173         ;
174 implist:        
175                 implist impline
176         |       impline
177         ;
178
179 impline:
180                ID '=' ID '.' ID '.' ID     { def_import ($1, $3, $5, $7, -1); }
181        |       ID '=' ID '.' ID '.' NUMBER { def_import ($1, $3, $5,  0, $7); }
182        |       ID '=' ID '.' ID            { def_import ($1, $3,  0, $5, -1); }
183        |       ID '=' ID '.' NUMBER        { def_import ($1, $3,  0,  0, $5); }
184        |       ID '.' ID '.' ID            { def_import ( 0, $1, $3, $5, -1); }
185        |       ID '.' ID                   { def_import ( 0, $1,  0, $3, -1); }
186 ;
187
188 seclist:
189                 seclist secline
190         |       secline
191         ;
192
193 secline:
194         ID attr_list { def_section ($1, $2);}
195         | ID ID { def_section_alt ($1, $2);}
196         ;
197
198 attr_list:
199         attr_list opt_comma attr { $$ = $1 | $3; }
200         | attr { $$ = $1; }
201         ;
202
203 opt_comma:
204         ','
205         | 
206         ;
207 opt_number: ',' NUMBER { $$=$2;}
208         |          { $$=-1;}
209         ;
210         
211 attr:
212                 READ    { $$ = 1;}
213         |       WRITE   { $$ = 2;}      
214         |       EXECUTE { $$=4;}
215         |       SHARED  { $$=8;}
216         ;
217
218 opt_name: ID            { $$ = $1; }
219         | ID '.' ID     
220           { 
221             char * name = xmalloc (strlen ($1) + 1 + strlen ($3) + 1);
222             sprintf (name, "%s.%s", $1, $3);
223             $$ = name;
224           }
225         |               { $$ = ""; }
226         ;
227
228 opt_ordinal: 
229           '@' NUMBER     { $$ = $2;}
230         |                { $$ = -1;}
231         ;
232
233 opt_equal_name:
234           '=' ID        { $$ = $2; }
235         |               { $$ =  0; }                     
236         ;
237
238 opt_base: BASE  '=' NUMBER      { $$ = $3;}
239         |       { $$ = 0;}
240         ;
241
242         
243
244 %%
245
246 /*****************************************************************************
247  API
248  *****************************************************************************/
249
250 static FILE *the_file;
251 static const char *def_filename;
252 static int linenumber;
253 static def_file *def;
254 static int saw_newline;
255
256 struct directive
257   {
258     struct directive *next;
259     char *name;
260     int len;
261   };
262
263 static struct directive *directives = 0;
264
265 def_file *
266 def_file_empty ()
267 {
268   def_file *rv = (def_file *) xmalloc (sizeof (def_file));
269   memset (rv, 0, sizeof (def_file));
270   rv->is_dll = -1;
271   rv->base_address = (bfd_vma) (-1);
272   rv->stack_reserve = rv->stack_commit = -1;
273   rv->heap_reserve = rv->heap_commit = -1;
274   rv->version_major = rv->version_minor = -1;
275   return rv;
276 }
277
278 def_file *
279 def_file_parse (filename, add_to)
280      const char *filename;
281      def_file *add_to;
282 {
283   struct directive *d;
284
285   the_file = fopen (filename, "r");
286   def_filename = filename;
287   linenumber = 1;
288   if (!the_file)
289     {
290       perror (filename);
291       return 0;
292     }
293   if (add_to)
294     {
295       def = add_to;
296     }
297   else
298     {
299       def = def_file_empty ();
300     }
301
302   saw_newline = 1;
303   if (def_parse ())
304     {
305       def_file_free (def);
306       fclose (the_file);
307       return 0;
308     }
309
310   fclose (the_file);
311
312   for (d = directives; d; d = d->next)
313     {
314 #if TRACE
315       printf ("Adding directive %08x `%s'\n", d->name, d->name);
316 #endif
317       def_file_add_directive (def, d->name, d->len);
318     }
319
320   return def;
321 }
322
323 void
324 def_file_free (def)
325      def_file *def;
326 {
327   int i;
328   if (!def)
329     return;
330   if (def->name)
331     free (def->name);
332   if (def->description)
333     free (def->description);
334
335   if (def->section_defs)
336     {
337       for (i = 0; i < def->num_section_defs; i++)
338         {
339           if (def->section_defs[i].name)
340             free (def->section_defs[i].name);
341           if (def->section_defs[i].class)
342             free (def->section_defs[i].class);
343         }
344       free (def->section_defs);
345     }
346
347   if (def->exports)
348     {
349       for (i = 0; i < def->num_exports; i++)
350         {
351           if (def->exports[i].internal_name
352               && def->exports[i].internal_name != def->exports[i].name)
353             free (def->exports[i].internal_name);
354           if (def->exports[i].name)
355             free (def->exports[i].name);
356         }
357       free (def->exports);
358     }
359
360   if (def->imports)
361     {
362       for (i = 0; i < def->num_imports; i++)
363         {
364           if (def->imports[i].internal_name
365               && def->imports[i].internal_name != def->imports[i].name)
366             free (def->imports[i].internal_name);
367           if (def->imports[i].name)
368             free (def->imports[i].name);
369         }
370       free (def->imports);
371     }
372
373   while (def->modules)
374     {
375       def_file_module *m = def->modules;
376       def->modules = def->modules->next;
377       free (m);
378     }
379
380   free (def);
381 }
382
383 #ifdef DEF_FILE_PRINT
384 void
385 def_file_print (file, def)
386      FILE *file;
387      def_file *def;
388 {
389   int i;
390   fprintf (file, ">>>> def_file at 0x%08x\n", def);
391   if (def->name)
392     fprintf (file, "  name: %s\n", def->name ? def->name : "(unspecified)");
393   if (def->is_dll != -1)
394     fprintf (file, "  is dll: %s\n", def->is_dll ? "yes" : "no");
395   if (def->base_address != (bfd_vma) (-1))
396     fprintf (file, "  base address: 0x%08x\n", def->base_address);
397   if (def->description)
398     fprintf (file, "  description: `%s'\n", def->description);
399   if (def->stack_reserve != -1)
400     fprintf (file, "  stack reserve: 0x%08x\n", def->stack_reserve);
401   if (def->stack_commit != -1)
402     fprintf (file, "  stack commit: 0x%08x\n", def->stack_commit);
403   if (def->heap_reserve != -1)
404     fprintf (file, "  heap reserve: 0x%08x\n", def->heap_reserve);
405   if (def->heap_commit != -1)
406     fprintf (file, "  heap commit: 0x%08x\n", def->heap_commit);
407
408   if (def->num_section_defs > 0)
409     {
410       fprintf (file, "  section defs:\n");
411       for (i = 0; i < def->num_section_defs; i++)
412         {
413           fprintf (file, "    name: `%s', class: `%s', flags:",
414                    def->section_defs[i].name, def->section_defs[i].class);
415           if (def->section_defs[i].flag_read)
416             fprintf (file, " R");
417           if (def->section_defs[i].flag_write)
418             fprintf (file, " W");
419           if (def->section_defs[i].flag_execute)
420             fprintf (file, " X");
421           if (def->section_defs[i].flag_shared)
422             fprintf (file, " S");
423           fprintf (file, "\n");
424         }
425     }
426
427   if (def->num_exports > 0)
428     {
429       fprintf (file, "  exports:\n");
430       for (i = 0; i < def->num_exports; i++)
431         {
432           fprintf (file, "    name: `%s', int: `%s', ordinal: %d, flags:",
433                    def->exports[i].name, def->exports[i].internal_name,
434                    def->exports[i].ordinal);
435           if (def->exports[i].flag_private)
436             fprintf (file, " P");
437           if (def->exports[i].flag_constant)
438             fprintf (file, " C");
439           if (def->exports[i].flag_noname)
440             fprintf (file, " N");
441           if (def->exports[i].flag_data)
442             fprintf (file, " D");
443           fprintf (file, "\n");
444         }
445     }
446
447   if (def->num_imports > 0)
448     {
449       fprintf (file, "  imports:\n");
450       for (i = 0; i < def->num_imports; i++)
451         {
452           fprintf (file, "    int: %s, from: `%s', name: `%s', ordinal: %d\n",
453                    def->imports[i].internal_name,
454                    def->imports[i].module,
455                    def->imports[i].name,
456                    def->imports[i].ordinal);
457         }
458     }
459   if (def->version_major != -1)
460     fprintf (file, "  version: %d.%d\n", def->version_major, def->version_minor);
461   fprintf (file, "<<<< def_file at 0x%08x\n", def);
462 }
463 #endif
464
465 def_file_export *
466 def_file_add_export (def, external_name, internal_name, ordinal)
467      def_file *def;
468      const char *external_name;
469      const char *internal_name;
470      int ordinal;
471 {
472   def_file_export *e;
473   int max_exports = ROUND_UP(def->num_exports, 32);
474   if (def->num_exports >= max_exports)
475     {
476       max_exports = ROUND_UP(def->num_exports+1, 32);
477       if (def->exports)
478         def->exports = (def_file_export *) xrealloc (def->exports, max_exports * sizeof (def_file_export));
479       else
480         def->exports = (def_file_export *) xmalloc (max_exports * sizeof (def_file_export));
481     }
482   e = def->exports + def->num_exports;
483   memset (e, 0, sizeof (def_file_export));
484   if (internal_name && !external_name)
485     external_name = internal_name;
486   if (external_name && !internal_name)
487     internal_name = external_name;
488   e->name = xstrdup (external_name);
489   e->internal_name = xstrdup (internal_name);
490   e->ordinal = ordinal;
491   def->num_exports++;
492   return e;
493 }
494
495 static def_file_module *
496 def_stash_module (def, name)
497      def_file *def;
498      char *name;
499 {
500   def_file_module *s;
501   for (s=def->modules; s; s=s->next)
502     if (strcmp (s->name, name) == 0)
503       return s;
504   s = (def_file_module *) xmalloc (sizeof (def_file_module) + strlen (name));
505   s->next = def->modules;
506   def->modules = s;
507   s->user_data = 0;
508   strcpy (s->name, name);
509   return s;
510 }
511
512 def_file_import *
513 def_file_add_import (def, name, module, ordinal, internal_name)
514      def_file *def;
515      const char *name;
516      const char *module;
517      int ordinal;
518      const char *internal_name;
519 {
520   def_file_import *i;
521   int max_imports = ROUND_UP(def->num_imports, 16);
522   if (def->num_imports >= max_imports)
523     {
524       max_imports = ROUND_UP(def->num_imports+1, 16);
525       if (def->imports)
526         def->imports = (def_file_import *) xrealloc (def->imports, max_imports * sizeof (def_file_import));
527       else
528         def->imports = (def_file_import *) xmalloc (max_imports * sizeof (def_file_import));
529     }
530   i = def->imports + def->num_imports;
531   memset (i, 0, sizeof (def_file_import));
532   if (name)
533     i->name = xstrdup (name);
534   if (module)
535     i->module = def_stash_module(def, module);
536   i->ordinal = ordinal;
537   if (internal_name)
538     i->internal_name = xstrdup (internal_name);
539   else
540     i->internal_name = i->name;
541   def->num_imports++;
542   return i;
543 }
544
545 struct
546 {
547   char *param;
548   int token;
549 }
550 diropts[] =
551 {
552   { "-heap", HEAPSIZE },
553   { "-stack", STACKSIZE },
554   { "-attr", SECTIONS },
555   { "-export", EXPORTS },
556   { 0, 0 }
557 };
558
559 void
560 def_file_add_directive (my_def, param, len)
561      def_file *my_def;
562      const char *param;
563      int len;
564 {
565   def_file *save_def = def;
566   const char *pend = param + len;
567   const char *tend = param;
568   int i;
569
570   def = my_def;
571
572   while (param < pend)
573     {
574       while (param < pend && isspace (*param))
575         param++;
576       for (tend = param + 1;
577            tend < pend && !(isspace (tend[-1]) && *tend == '-');
578            tend++);
579
580       for (i = 0; diropts[i].param; i++)
581         {
582           int len = strlen (diropts[i].param);
583           if (tend - param >= len
584               && strncmp (param, diropts[i].param, len) == 0
585               && (param[len] == ':' || param[len] == ' '))
586             {
587               lex_parse_string_end = tend;
588               lex_parse_string = param + len + 1;
589               lex_forced_token = diropts[i].token;
590               saw_newline = 0;
591               def_parse ();
592               break;
593             }
594         }
595
596       if (!diropts[i].param)
597         {
598           /* xgettext:c-format */
599           einfo (_("Warning: .drectve `%.*s' unrecognized\n"),
600                  tend - param, param);
601         }
602       lex_parse_string = 0;
603       param = tend;
604     }
605
606   def = save_def;
607 }
608
609 /*****************************************************************************
610  Parser Callbacks
611  *****************************************************************************/
612
613 static void
614 def_name (name, base)
615      const char *name;
616      int base;
617 {
618   if (def->name)
619     free (def->name);
620   def->name = xstrdup (name);
621   def->base_address = base;
622   def->is_dll = 0;
623 }
624
625 static void
626 def_library (name, base)
627      const char *name;
628      int base;
629 {
630   if (def->name)
631     free (def->name);
632   def->name = xstrdup (name);
633   def->base_address = base;
634   def->is_dll = 1;
635 }
636
637 static void
638 def_description (text)
639      const char *text;
640 {
641   int len = def->description ? strlen (def->description) : 0;
642   len += strlen (text) + 1;
643   if (def->description)
644     {
645       def->description = (char *) xrealloc (def->description, len);
646       strcat (def->description, text);
647     }
648   else
649     {
650       def->description = (char *) xmalloc (len);
651       strcpy (def->description, text);
652     }
653 }
654
655 static void
656 def_stacksize (reserve, commit)
657      int reserve;
658      int commit;
659 {
660   def->stack_reserve = reserve;
661   def->stack_commit = commit;
662 }
663
664 static void
665 def_heapsize (reserve, commit)
666      int reserve;
667      int commit;
668 {
669   def->heap_reserve = reserve;
670   def->heap_commit = commit;
671 }
672
673 static void
674 def_section (name, attr)
675      const char *name;
676      int attr;
677 {
678   def_file_section *s;
679   int max_sections = ROUND_UP(def->num_section_defs, 4);
680   if (def->num_section_defs >= max_sections)
681     {
682       max_sections = ROUND_UP(def->num_section_defs+1, 4);
683       if (def->section_defs)
684         def->section_defs = (def_file_section *) xrealloc (def->section_defs, max_sections * sizeof (def_file_import));
685       else
686         def->section_defs = (def_file_section *) xmalloc (max_sections * sizeof (def_file_import));
687     }
688   s = def->section_defs + def->num_section_defs;
689   memset (s, 0, sizeof (def_file_section));
690   s->name = xstrdup (name);
691   if (attr & 1)
692     s->flag_read = 1;
693   if (attr & 2)
694     s->flag_write = 1;
695   if (attr & 4)
696     s->flag_execute = 1;
697   if (attr & 8)
698     s->flag_shared = 1;
699
700   def->num_section_defs++;
701 }
702
703 static void
704 def_section_alt (name, attr)
705      const char *name;
706      const char *attr;
707 {
708   int aval = 0;
709   for (; *attr; attr++)
710     {
711       switch (*attr)
712         {
713         case 'R':
714         case 'r':
715           aval |= 1;
716           break;
717         case 'W':
718         case 'w':
719           aval |= 2;
720           break;
721         case 'X':
722         case 'x':
723           aval |= 4;
724           break;
725         case 'S':
726         case 's':
727           aval |= 8;
728           break;
729         }
730     }
731   def_section (name, aval);
732 }
733
734 static void
735 def_exports (external_name, internal_name, ordinal, flags)
736      const char *external_name;
737      const char *internal_name;
738      int ordinal;
739      int flags;
740 {
741   def_file_export *dfe;
742
743   if (!internal_name && external_name)
744     internal_name = external_name;
745 #if TRACE
746   printf ("def_exports, ext=%s int=%s\n", external_name, internal_name);
747 #endif
748
749   dfe = def_file_add_export (def, external_name, internal_name, ordinal);
750   if (flags & 1)
751     dfe->flag_noname = 1;
752   if (flags & 2)
753     dfe->flag_constant = 1;
754   if (flags & 4)
755     dfe->flag_data = 1;
756   if (flags & 8)
757     dfe->flag_private = 1;
758 }
759
760 static void
761 def_import (internal_name, module, dllext, name, ordinal)
762      const char *internal_name;
763      const char *module;
764      const char *dllext;
765      const char *name;
766      int ordinal;
767 {
768   char *buf = 0;
769
770   if (dllext != NULL)
771     {
772       buf = (char *) xmalloc (strlen (module) + strlen (dllext) + 2);
773       sprintf (buf, "%s.%s", module, dllext);
774       module = buf;
775     }
776
777   def_file_add_import (def, name, module, ordinal, internal_name);
778   if (buf)
779     free (buf);
780 }
781
782 static void
783 def_version (major, minor)
784      int major;
785      int minor;
786 {
787   def->version_major = major;
788   def->version_minor = minor;
789 }
790
791 static void
792 def_directive (str)
793      char *str;
794 {
795   struct directive *d = (struct directive *) xmalloc (sizeof (struct directive));
796   d->next = directives;
797   directives = d;
798   d->name = xstrdup (str);
799   d->len = strlen (str);
800 }
801
802 static int
803 def_error (err)
804      const char *err;
805 {
806   einfo ("%P: %s:%d: %s\n", def_filename, linenumber, err);
807
808   return 0;
809 }
810
811
812 /*****************************************************************************
813  Lexical Scanner
814  *****************************************************************************/
815
816 #undef TRACE
817 #define TRACE 0
818
819 /* Never freed, but always reused as needed, so no real leak */
820 static char *buffer = 0;
821 static int buflen = 0;
822 static int bufptr = 0;
823
824 static void
825 put_buf (c)
826      char c;
827 {
828   if (bufptr == buflen)
829     {
830       buflen += 50;             /* overly reasonable, eh? */
831       if (buffer)
832         buffer = (char *) xrealloc (buffer, buflen + 1);
833       else
834         buffer = (char *) xmalloc (buflen + 1);
835     }
836   buffer[bufptr++] = c;
837   buffer[bufptr] = 0;           /* not optimal, but very convenient */
838 }
839
840 static struct
841 {
842   char *name;
843   int token;
844 }
845 tokens[] =
846 {
847   { "BASE", BASE },
848   { "CODE", CODE },
849   { "CONSTANT", CONSTANTU },
850   { "constant", CONSTANTL },
851   { "DATA", DATAU },
852   { "data", DATAL },
853   { "DESCRIPTION", DESCRIPTION },
854   { "DIRECTIVE", DIRECTIVE },
855   { "EXECUTE", EXECUTE },
856   { "EXPORTS", EXPORTS },
857   { "HEAPSIZE", HEAPSIZE },
858   { "IMPORTS", IMPORTS },
859   { "LIBRARY", LIBRARY },
860   { "NAME", NAME },
861   { "NONAME", NONAMEU },
862   { "noname", NONAMEL },
863   { "PRIVATE", PRIVATEU },
864   { "private", PRIVATEL },
865   { "READ", READ },
866   { "SECTIONS", SECTIONS },
867   { "SEGMENTS", SECTIONS },
868   { "SHARED", SHARED },
869   { "STACKSIZE", STACKSIZE },
870   { "VERSION", VERSIONK },
871   { "WRITE", WRITE },
872   { 0, 0 }
873 };
874
875 static int
876 def_getc ()
877 {
878   int rv;
879   if (lex_parse_string)
880     {
881       if (lex_parse_string >= lex_parse_string_end)
882         rv = EOF;
883       else
884         rv = *lex_parse_string++;
885     }
886   else
887     {
888       rv = fgetc (the_file);
889     }
890   if (rv == '\n')
891     saw_newline = 1;
892   return rv;
893 }
894
895 static int
896 def_ungetc (c)
897      int c;
898 {
899   if (lex_parse_string)
900     {
901       lex_parse_string--;
902       return c;
903     }
904   else
905     return ungetc (c, the_file);
906 }
907
908 static int
909 def_lex ()
910 {
911   int c, i, q;
912
913   if (lex_forced_token)
914     {
915       i = lex_forced_token;
916       lex_forced_token = 0;
917 #if TRACE
918       printf ("lex: forcing token %d\n", i);
919 #endif
920       return i;
921     }
922
923   c = def_getc ();
924
925   /* trim leading whitespace */
926   while (c != EOF && (c == ' ' || c == '\t') && saw_newline)
927     c = def_getc ();
928
929   if (c == EOF)
930     {
931 #if TRACE
932       printf ("lex: EOF\n");
933 #endif
934       return 0;
935     }
936
937   if (saw_newline && c == ';')
938     {
939       do
940         {
941           c = def_getc ();
942         }
943       while (c != EOF && c != '\n');
944       if (c == '\n')
945         return def_lex ();
946       return 0;
947     }
948   /* must be something else */
949   saw_newline = 0;
950
951   if (isdigit (c))
952     {
953       bufptr = 0;
954       while (c != EOF && (isxdigit (c) || (c == 'x')))
955         {
956           put_buf (c);
957           c = def_getc ();
958         }
959       if (c != EOF)
960         def_ungetc (c);
961       yylval.number = strtoul (buffer, 0, 0);
962 #if TRACE
963       printf ("lex: `%s' returns NUMBER %d\n", buffer, yylval.number);
964 #endif
965       return NUMBER;
966     }
967
968   if (isalpha (c) || strchr ("$:-_?", c))
969     {
970       bufptr = 0;
971       while (c != EOF && (isalnum (c) || strchr ("$:-_?/@", c)))
972         {
973           put_buf (c);
974           c = def_getc ();
975         }
976       if (c != EOF)
977         def_ungetc (c);
978       for (i = 0; tokens[i].name; i++)
979         if (strcmp (tokens[i].name, buffer) == 0)
980           {
981 #if TRACE
982             printf ("lex: `%s' is a string token\n", buffer);
983 #endif
984             return tokens[i].token;
985           }
986 #if TRACE
987       printf ("lex: `%s' returns ID\n", buffer);
988 #endif
989       yylval.id = xstrdup (buffer);
990       return ID;
991     }
992
993   if (c == '\'' || c == '"')
994     {
995       q = c;
996       c = def_getc ();
997       bufptr = 0;
998       while (c != EOF && c != q)
999         {
1000           put_buf (c);
1001           c = def_getc ();
1002         }
1003       yylval.id = xstrdup (buffer);
1004 #if TRACE
1005       printf ("lex: `%s' returns ID\n", buffer);
1006 #endif
1007       return ID;
1008     }
1009
1010   if (c == '=' || c == '.' || c == '@' || c == ',')
1011     {
1012 #if TRACE
1013       printf ("lex: `%c' returns itself\n", c);
1014 #endif
1015       return c;
1016     }
1017
1018   if (c == '\n')
1019     {
1020       linenumber++;
1021       saw_newline = 1;
1022     }
1023
1024   /*printf ("lex: 0x%02x ignored\n", c); */
1025   return def_lex ();
1026 }