bfd/
[external/binutils.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 '.' ID     
228           { 
229             char *name = xmalloc (strlen ($1) + 1 + strlen ($3) + 1);
230             sprintf (name, "%s.%s", $1, $3);
231             $$ = name;
232           }
233         |               { $$ = ""; }
234         ;
235
236 opt_equalequal_name: EQUAL ID   { $$ = $2; }
237         |                                                       { $$ = 0; }
238         ;
239
240 opt_ordinal: 
241           '@' NUMBER     { $$ = $2;}
242         |                { $$ = -1;}
243         ;
244
245 opt_equal_name:
246           '=' dot_name  { $$ = $2; }
247         |               { $$ =  0; }                     
248         ;
249
250 opt_base: BASE  '=' NUMBER      { $$ = $3;}
251         |       { $$ = -1;}
252         ;
253
254 dot_name: ID            { $$ = $1; }
255         | dot_name '.' ID       
256           { 
257             char *name = xmalloc (strlen ($1) + 1 + strlen ($3) + 1);
258             sprintf (name, "%s.%s", $1, $3);
259             $$ = name;
260           }
261         ;
262
263 anylang_id: ID          { $$ = $1; }
264         | anylang_id '.' opt_digits opt_id
265           {
266             char *id = xmalloc (strlen ($1) + 1 + strlen ($3) + strlen ($4) + 1);
267             sprintf (id, "%s.%s%s", $1, $3, $4);
268             $$ = id;
269           }
270         ;
271
272 opt_digits: DIGITS      { $$ = $1; }
273         |               { $$ = ""; }
274         ;
275
276 opt_id: ID              { $$ = $1; }
277         |               { $$ = ""; }
278         ;
279
280 NUMBER: DIGITS          { $$ = strtoul ($1, 0, 0); }
281
282 %%
283
284 /*****************************************************************************
285  API
286  *****************************************************************************/
287
288 static FILE *the_file;
289 static const char *def_filename;
290 static int linenumber;
291 static def_file *def;
292 static int saw_newline;
293
294 struct directive
295   {
296     struct directive *next;
297     char *name;
298     int len;
299   };
300
301 static struct directive *directives = 0;
302
303 def_file *
304 def_file_empty (void)
305 {
306   def_file *rv = xmalloc (sizeof (def_file));
307   memset (rv, 0, sizeof (def_file));
308   rv->is_dll = -1;
309   rv->base_address = (bfd_vma) -1;
310   rv->stack_reserve = rv->stack_commit = -1;
311   rv->heap_reserve = rv->heap_commit = -1;
312   rv->version_major = rv->version_minor = -1;
313   return rv;
314 }
315
316 def_file *
317 def_file_parse (const char *filename, def_file *add_to)
318 {
319   struct directive *d;
320
321   the_file = fopen (filename, "r");
322   def_filename = filename;
323   linenumber = 1;
324   if (!the_file)
325     {
326       perror (filename);
327       return 0;
328     }
329   if (add_to)
330     {
331       def = add_to;
332     }
333   else
334     {
335       def = def_file_empty ();
336     }
337
338   saw_newline = 1;
339   if (def_parse ())
340     {
341       def_file_free (def);
342       fclose (the_file);
343       return 0;
344     }
345
346   fclose (the_file);
347
348   for (d = directives; d; d = d->next)
349     {
350 #if TRACE
351       printf ("Adding directive %08x `%s'\n", d->name, d->name);
352 #endif
353       def_file_add_directive (def, d->name, d->len);
354     }
355
356   return def;
357 }
358
359 void
360 def_file_free (def_file *def)
361 {
362   int i;
363
364   if (!def)
365     return;
366   if (def->name)
367     free (def->name);
368   if (def->description)
369     free (def->description);
370
371   if (def->section_defs)
372     {
373       for (i = 0; i < def->num_section_defs; i++)
374         {
375           if (def->section_defs[i].name)
376             free (def->section_defs[i].name);
377           if (def->section_defs[i].class)
378             free (def->section_defs[i].class);
379         }
380       free (def->section_defs);
381     }
382
383   if (def->exports)
384     {
385       for (i = 0; i < def->num_exports; i++)
386         {
387           if (def->exports[i].internal_name
388               && def->exports[i].internal_name != def->exports[i].name)
389             free (def->exports[i].internal_name);
390           if (def->exports[i].name)
391             free (def->exports[i].name);
392           if (def->exports[i].its_name)
393             free (def->exports[i].its_name);
394         }
395       free (def->exports);
396     }
397
398   if (def->imports)
399     {
400       for (i = 0; i < def->num_imports; i++)
401         {
402           if (def->imports[i].internal_name
403               && def->imports[i].internal_name != def->imports[i].name)
404             free (def->imports[i].internal_name);
405           if (def->imports[i].name)
406             free (def->imports[i].name);
407           if (def->imports[i].its_name)
408             free (def->imports[i].its_name);
409         }
410       free (def->imports);
411     }
412
413   while (def->modules)
414     {
415       def_file_module *m = def->modules;
416       def->modules = def->modules->next;
417       free (m);
418     }
419
420   while (def->aligncomms)
421     {
422       def_file_aligncomm *c = def->aligncomms;
423       def->aligncomms = def->aligncomms->next;
424       free (c->symbol_name);
425       free (c);
426     }
427
428   free (def);
429 }
430
431 #ifdef DEF_FILE_PRINT
432 void
433 def_file_print (FILE *file, def_file *def)
434 {
435   int i;
436
437   fprintf (file, ">>>> def_file at 0x%08x\n", def);
438   if (def->name)
439     fprintf (file, "  name: %s\n", def->name ? def->name : "(unspecified)");
440   if (def->is_dll != -1)
441     fprintf (file, "  is dll: %s\n", def->is_dll ? "yes" : "no");
442   if (def->base_address != (bfd_vma) -1)
443     fprintf (file, "  base address: 0x%08x\n", def->base_address);
444   if (def->description)
445     fprintf (file, "  description: `%s'\n", def->description);
446   if (def->stack_reserve != -1)
447     fprintf (file, "  stack reserve: 0x%08x\n", def->stack_reserve);
448   if (def->stack_commit != -1)
449     fprintf (file, "  stack commit: 0x%08x\n", def->stack_commit);
450   if (def->heap_reserve != -1)
451     fprintf (file, "  heap reserve: 0x%08x\n", def->heap_reserve);
452   if (def->heap_commit != -1)
453     fprintf (file, "  heap commit: 0x%08x\n", def->heap_commit);
454
455   if (def->num_section_defs > 0)
456     {
457       fprintf (file, "  section defs:\n");
458
459       for (i = 0; i < def->num_section_defs; i++)
460         {
461           fprintf (file, "    name: `%s', class: `%s', flags:",
462                    def->section_defs[i].name, def->section_defs[i].class);
463           if (def->section_defs[i].flag_read)
464             fprintf (file, " R");
465           if (def->section_defs[i].flag_write)
466             fprintf (file, " W");
467           if (def->section_defs[i].flag_execute)
468             fprintf (file, " X");
469           if (def->section_defs[i].flag_shared)
470             fprintf (file, " S");
471           fprintf (file, "\n");
472         }
473     }
474
475   if (def->num_exports > 0)
476     {
477       fprintf (file, "  exports:\n");
478
479       for (i = 0; i < def->num_exports; i++)
480         {
481           fprintf (file, "    name: `%s', int: `%s', ordinal: %d, flags:",
482                    def->exports[i].name, def->exports[i].internal_name,
483                    def->exports[i].ordinal);
484           if (def->exports[i].flag_private)
485             fprintf (file, " P");
486           if (def->exports[i].flag_constant)
487             fprintf (file, " C");
488           if (def->exports[i].flag_noname)
489             fprintf (file, " N");
490           if (def->exports[i].flag_data)
491             fprintf (file, " D");
492           fprintf (file, "\n");
493         }
494     }
495
496   if (def->num_imports > 0)
497     {
498       fprintf (file, "  imports:\n");
499
500       for (i = 0; i < def->num_imports; i++)
501         {
502           fprintf (file, "    int: %s, from: `%s', name: `%s', ordinal: %d\n",
503                    def->imports[i].internal_name,
504                    def->imports[i].module,
505                    def->imports[i].name,
506                    def->imports[i].ordinal);
507         }
508     }
509
510   if (def->version_major != -1)
511     fprintf (file, "  version: %d.%d\n", def->version_major, def->version_minor);
512
513   fprintf (file, "<<<< def_file at 0x%08x\n", def);
514 }
515 #endif
516
517 def_file_export *
518 def_file_add_export (def_file *def,
519                      const char *external_name,
520                      const char *internal_name,
521                      int ordinal,
522                      const char *its_name)
523 {
524   def_file_export *e;
525   int max_exports = ROUND_UP(def->num_exports, 32);
526
527   if (def->num_exports >= max_exports)
528     {
529       max_exports = ROUND_UP(def->num_exports + 1, 32);
530       if (def->exports)
531         def->exports = xrealloc (def->exports,
532                                  max_exports * sizeof (def_file_export));
533       else
534         def->exports = xmalloc (max_exports * sizeof (def_file_export));
535     }
536   e = def->exports + def->num_exports;
537   memset (e, 0, sizeof (def_file_export));
538   if (internal_name && !external_name)
539     external_name = internal_name;
540   if (external_name && !internal_name)
541     internal_name = external_name;
542   e->name = xstrdup (external_name);
543   e->internal_name = xstrdup (internal_name);
544   e->its_name = (its_name ? xstrdup (its_name) : NULL);
545   e->ordinal = ordinal;
546   def->num_exports++;
547   return e;
548 }
549
550 def_file_module *
551 def_get_module (def_file *def, const char *name)
552 {
553   def_file_module *s;
554
555   for (s = def->modules; s; s = s->next)
556     if (strcmp (s->name, name) == 0)
557       return s;
558
559   return NULL;
560 }
561
562 static def_file_module *
563 def_stash_module (def_file *def, const char *name)
564 {
565   def_file_module *s;
566
567   if ((s = def_get_module (def, name)) != NULL)
568       return s;
569   s = xmalloc (sizeof (def_file_module) + strlen (name));
570   s->next = def->modules;
571   def->modules = s;
572   s->user_data = 0;
573   strcpy (s->name, name);
574   return s;
575 }
576
577 def_file_import *
578 def_file_add_import (def_file *def,
579                      const char *name,
580                      const char *module,
581                      int ordinal,
582                      const char *internal_name,
583                      const char *its_name)
584 {
585   def_file_import *i;
586   int max_imports = ROUND_UP (def->num_imports, 16);
587
588   if (def->num_imports >= max_imports)
589     {
590       max_imports = ROUND_UP (def->num_imports+1, 16);
591
592       if (def->imports)
593         def->imports = xrealloc (def->imports,
594                                  max_imports * sizeof (def_file_import));
595       else
596         def->imports = xmalloc (max_imports * sizeof (def_file_import));
597     }
598   i = def->imports + def->num_imports;
599   memset (i, 0, sizeof (def_file_import));
600   if (name)
601     i->name = xstrdup (name);
602   if (module)
603     i->module = def_stash_module (def, module);
604   i->ordinal = ordinal;
605   if (internal_name)
606     i->internal_name = xstrdup (internal_name);
607   else
608     i->internal_name = i->name;
609   i->its_name = (its_name ? xstrdup (its_name) : NULL);
610   def->num_imports++;
611
612   return i;
613 }
614
615 struct
616 {
617   char *param;
618   int token;
619 }
620 diropts[] =
621 {
622   { "-heap", HEAPSIZE },
623   { "-stack", STACKSIZE_K },
624   { "-attr", SECTIONS },
625   { "-export", EXPORTS },
626   { "-aligncomm", ALIGNCOMM },
627   { 0, 0 }
628 };
629
630 void
631 def_file_add_directive (def_file *my_def, const char *param, int len)
632 {
633   def_file *save_def = def;
634   const char *pend = param + len;
635   char * tend = (char *) param;
636   int i;
637
638   def = my_def;
639
640   while (param < pend)
641     {
642       while (param < pend
643              && (ISSPACE (*param) || *param == '\n' || *param == 0))
644         param++;
645
646       if (param == pend)
647         break;
648
649       /* Scan forward until we encounter any of:
650           - the end of the buffer
651           - the start of a new option
652           - a newline seperating options
653           - a NUL seperating options.  */
654       for (tend = (char *) (param + 1);
655            (tend < pend
656             && !(ISSPACE (tend[-1]) && *tend == '-')
657             && *tend != '\n' && *tend != 0);
658            tend++)
659         ;
660
661       for (i = 0; diropts[i].param; i++)
662         {
663           int len = strlen (diropts[i].param);
664
665           if (tend - param >= len
666               && strncmp (param, diropts[i].param, len) == 0
667               && (param[len] == ':' || param[len] == ' '))
668             {
669               lex_parse_string_end = tend;
670               lex_parse_string = param + len + 1;
671               lex_forced_token = diropts[i].token;
672               saw_newline = 0;
673               if (def_parse ())
674                 continue;
675               break;
676             }
677         }
678
679       if (!diropts[i].param)
680         {
681           char saved;
682
683           saved = * tend;
684           * tend = 0;
685           /* xgettext:c-format */
686           einfo (_("Warning: .drectve `%s' unrecognized\n"), param);
687           * tend = saved;
688         }
689
690       lex_parse_string = 0;
691       param = tend;
692     }
693
694   def = save_def;
695 }
696
697 /* Parser Callbacks.  */
698
699 static void
700 def_image_name (const char *name, int base, int is_dll)
701 {
702   /* If a LIBRARY or NAME statement is specified without a name, there is nothing
703      to do here.  We retain the output filename specified on command line.  */
704   if (*name)
705     {
706       const char* image_name = lbasename (name);
707       if (image_name != name)
708         einfo ("%s:%d: Warning: path components stripped from %s, '%s'\n",
709                def_filename, linenumber, is_dll ? "LIBRARY" : "NAME",
710                name);
711       if (def->name)
712         free (def->name);
713       /* Append the default suffix, if none specified.  */ 
714       if (strchr (image_name, '.') == 0)
715         {
716           const char * suffix = is_dll ? ".dll" : ".exe";
717
718           def->name = xmalloc (strlen (image_name) + strlen (suffix) + 1);
719           sprintf (def->name, "%s%s", image_name, suffix);
720         }
721       else
722         def->name = xstrdup (image_name);
723     }
724
725   /* Honor a BASE address statement, even if LIBRARY string is empty.  */
726   def->base_address = base;
727   def->is_dll = is_dll;
728 }
729
730 static void
731 def_description (const char *text)
732 {
733   int len = def->description ? strlen (def->description) : 0;
734
735   len += strlen (text) + 1;
736   if (def->description)
737     {
738       def->description = xrealloc (def->description, len);
739       strcat (def->description, text);
740     }
741   else
742     {
743       def->description = xmalloc (len);
744       strcpy (def->description, text);
745     }
746 }
747
748 static void
749 def_stacksize (int reserve, int commit)
750 {
751   def->stack_reserve = reserve;
752   def->stack_commit = commit;
753 }
754
755 static void
756 def_heapsize (int reserve, int commit)
757 {
758   def->heap_reserve = reserve;
759   def->heap_commit = commit;
760 }
761
762 static void
763 def_section (const char *name, int attr)
764 {
765   def_file_section *s;
766   int max_sections = ROUND_UP (def->num_section_defs, 4);
767
768   if (def->num_section_defs >= max_sections)
769     {
770       max_sections = ROUND_UP (def->num_section_defs+1, 4);
771
772       if (def->section_defs)
773         def->section_defs = xrealloc (def->section_defs,
774                                       max_sections * sizeof (def_file_import));
775       else
776         def->section_defs = xmalloc (max_sections * sizeof (def_file_import));
777     }
778   s = def->section_defs + def->num_section_defs;
779   memset (s, 0, sizeof (def_file_section));
780   s->name = xstrdup (name);
781   if (attr & 1)
782     s->flag_read = 1;
783   if (attr & 2)
784     s->flag_write = 1;
785   if (attr & 4)
786     s->flag_execute = 1;
787   if (attr & 8)
788     s->flag_shared = 1;
789
790   def->num_section_defs++;
791 }
792
793 static void
794 def_section_alt (const char *name, const char *attr)
795 {
796   int aval = 0;
797
798   for (; *attr; attr++)
799     {
800       switch (*attr)
801         {
802         case 'R':
803         case 'r':
804           aval |= 1;
805           break;
806         case 'W':
807         case 'w':
808           aval |= 2;
809           break;
810         case 'X':
811         case 'x':
812           aval |= 4;
813           break;
814         case 'S':
815         case 's':
816           aval |= 8;
817           break;
818         }
819     }
820   def_section (name, aval);
821 }
822
823 static void
824 def_exports (const char *external_name,
825              const char *internal_name,
826              int ordinal,
827              int flags,
828              const char *its_name)
829 {
830   def_file_export *dfe;
831
832   if (!internal_name && external_name)
833     internal_name = external_name;
834 #if TRACE
835   printf ("def_exports, ext=%s int=%s\n", external_name, internal_name);
836 #endif
837
838   dfe = def_file_add_export (def, external_name, internal_name, ordinal,
839                                                          its_name);
840   if (flags & 1)
841     dfe->flag_noname = 1;
842   if (flags & 2)
843     dfe->flag_constant = 1;
844   if (flags & 4)
845     dfe->flag_data = 1;
846   if (flags & 8)
847     dfe->flag_private = 1;
848 }
849
850 static void
851 def_import (const char *internal_name,
852             const char *module,
853             const char *dllext,
854             const char *name,
855             int ordinal,
856             const char *its_name)
857 {
858   char *buf = 0;
859   const char *ext = dllext ? dllext : "dll";    
860    
861   buf = xmalloc (strlen (module) + strlen (ext) + 2);
862   sprintf (buf, "%s.%s", module, ext);
863   module = buf;
864
865   def_file_add_import (def, name, module, ordinal, internal_name, its_name);
866   if (buf)
867     free (buf);
868 }
869
870 static void
871 def_version (int major, int minor)
872 {
873   def->version_major = major;
874   def->version_minor = minor;
875 }
876
877 static void
878 def_directive (char *str)
879 {
880   struct directive *d = xmalloc (sizeof (struct directive));
881
882   d->next = directives;
883   directives = d;
884   d->name = xstrdup (str);
885   d->len = strlen (str);
886 }
887
888 static void
889 def_aligncomm (char *str, int align)
890 {
891   def_file_aligncomm *c = xmalloc (sizeof (def_file_aligncomm));
892
893   c->symbol_name = xstrdup (str);
894   c->alignment = (unsigned int) align;
895
896   c->next = def->aligncomms;
897   def->aligncomms = c;
898 }
899
900 static int
901 def_error (const char *err)
902 {
903   einfo ("%P: %s:%d: %s\n",
904          def_filename ? def_filename : "<unknown-file>", linenumber, err);
905   return 0;
906 }
907
908
909 /* Lexical Scanner.  */
910
911 #undef TRACE
912 #define TRACE 0
913
914 /* Never freed, but always reused as needed, so no real leak.  */
915 static char *buffer = 0;
916 static int buflen = 0;
917 static int bufptr = 0;
918
919 static void
920 put_buf (char c)
921 {
922   if (bufptr == buflen)
923     {
924       buflen += 50;             /* overly reasonable, eh?  */
925       if (buffer)
926         buffer = xrealloc (buffer, buflen + 1);
927       else
928         buffer = xmalloc (buflen + 1);
929     }
930   buffer[bufptr++] = c;
931   buffer[bufptr] = 0;           /* not optimal, but very convenient.  */
932 }
933
934 static struct
935 {
936   char *name;
937   int token;
938 }
939 tokens[] =
940 {
941   { "BASE", BASE },
942   { "CODE", CODE },
943   { "CONSTANT", CONSTANTU },
944   { "constant", CONSTANTL },
945   { "DATA", DATAU },
946   { "data", DATAL },
947   { "DESCRIPTION", DESCRIPTION },
948   { "DIRECTIVE", DIRECTIVE },
949   { "EXECUTE", EXECUTE },
950   { "EXPORTS", EXPORTS },
951   { "HEAPSIZE", HEAPSIZE },
952   { "IMPORTS", IMPORTS },
953   { "LIBRARY", LIBRARY },
954   { "NAME", NAME },
955   { "NONAME", NONAMEU },
956   { "noname", NONAMEL },
957   { "PRIVATE", PRIVATEU },
958   { "private", PRIVATEL },
959   { "READ", READ },
960   { "SECTIONS", SECTIONS },
961   { "SEGMENTS", SECTIONS },
962   { "SHARED", SHARED },
963   { "STACKSIZE", STACKSIZE_K },
964   { "VERSION", VERSIONK },
965   { "WRITE", WRITE },
966   { 0, 0 }
967 };
968
969 static int
970 def_getc (void)
971 {
972   int rv;
973
974   if (lex_parse_string)
975     {
976       if (lex_parse_string >= lex_parse_string_end)
977         rv = EOF;
978       else
979         rv = *lex_parse_string++;
980     }
981   else
982     {
983       rv = fgetc (the_file);
984     }
985   if (rv == '\n')
986     saw_newline = 1;
987   return rv;
988 }
989
990 static int
991 def_ungetc (int c)
992 {
993   if (lex_parse_string)
994     {
995       lex_parse_string--;
996       return c;
997     }
998   else
999     return ungetc (c, the_file);
1000 }
1001
1002 static int
1003 def_lex (void)
1004 {
1005   int c, i, q;
1006
1007   if (lex_forced_token)
1008     {
1009       i = lex_forced_token;
1010       lex_forced_token = 0;
1011 #if TRACE
1012       printf ("lex: forcing token %d\n", i);
1013 #endif
1014       return i;
1015     }
1016
1017   c = def_getc ();
1018
1019   /* Trim leading whitespace.  */
1020   while (c != EOF && (c == ' ' || c == '\t') && saw_newline)
1021     c = def_getc ();
1022
1023   if (c == EOF)
1024     {
1025 #if TRACE
1026       printf ("lex: EOF\n");
1027 #endif
1028       return 0;
1029     }
1030
1031   if (saw_newline && c == ';')
1032     {
1033       do
1034         {
1035           c = def_getc ();
1036         }
1037       while (c != EOF && c != '\n');
1038       if (c == '\n')
1039         return def_lex ();
1040       return 0;
1041     }
1042
1043   /* Must be something else.  */
1044   saw_newline = 0;
1045
1046   if (ISDIGIT (c))
1047     {
1048       bufptr = 0;
1049       while (c != EOF && (ISXDIGIT (c) || (c == 'x')))
1050         {
1051           put_buf (c);
1052           c = def_getc ();
1053         }
1054       if (c != EOF)
1055         def_ungetc (c);
1056       yylval.digits = xstrdup (buffer);
1057 #if TRACE
1058       printf ("lex: `%s' returns DIGITS\n", buffer);
1059 #endif
1060       return DIGITS;
1061     }
1062
1063   if (ISALPHA (c) || strchr ("$:-_?@", c))
1064     {
1065       bufptr = 0;
1066       q = c;
1067       put_buf (c);
1068       c = def_getc ();
1069
1070       if (q == '@')
1071         {
1072           if (ISBLANK (c) ) /* '@' followed by whitespace.  */
1073             return (q);
1074           else if (ISDIGIT (c)) /* '@' followed by digit.  */
1075             {
1076               def_ungetc (c);
1077               return (q);
1078             }
1079 #if TRACE
1080           printf ("lex: @ returns itself\n");
1081 #endif
1082         }
1083
1084       while (c != EOF && (ISALNUM (c) || strchr ("$:-_?/@<>", c)))
1085         {
1086           put_buf (c);
1087           c = def_getc ();
1088         }
1089       if (c != EOF)
1090         def_ungetc (c);
1091       if (ISALPHA (q)) /* Check for tokens.  */
1092         {
1093           for (i = 0; tokens[i].name; i++)
1094             if (strcmp (tokens[i].name, buffer) == 0)
1095               {
1096 #if TRACE
1097                 printf ("lex: `%s' is a string token\n", buffer);
1098 #endif
1099                 return tokens[i].token;
1100               }
1101         }
1102 #if TRACE
1103       printf ("lex: `%s' returns ID\n", buffer);
1104 #endif
1105       yylval.id = xstrdup (buffer);
1106       return ID;
1107     }
1108
1109   if (c == '\'' || c == '"')
1110     {
1111       q = c;
1112       c = def_getc ();
1113       bufptr = 0;
1114
1115       while (c != EOF && c != q)
1116         {
1117           put_buf (c);
1118           c = def_getc ();
1119         }
1120       yylval.id = xstrdup (buffer);
1121 #if TRACE
1122       printf ("lex: `%s' returns ID\n", buffer);
1123 #endif
1124       return ID;
1125     }
1126
1127   if ( c == '=')
1128     {
1129       c = def_getc ();
1130       if (c == '=')
1131         {
1132 #if TRACE
1133           printf ("lex: `==' returns EQUAL\n");
1134 #endif
1135                   return EQUAL;
1136         }
1137       def_ungetc (c);
1138 #if TRACE
1139       printf ("lex: `=' returns itself\n");
1140 #endif
1141       return '=';
1142     }
1143   if (c == '.' || c == ',')
1144     {
1145 #if TRACE
1146       printf ("lex: `%c' returns itself\n", c);
1147 #endif
1148       return c;
1149     }
1150
1151   if (c == '\n')
1152     {
1153       linenumber++;
1154       saw_newline = 1;
1155     }
1156
1157   /*printf ("lex: 0x%02x ignored\n", c); */
1158   return def_lex ();
1159 }