OSDN Git Service

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