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
81static void def_description (const char *);
82static void def_exports (const char *, const char *, int, int, const char *);
83static void def_heapsize (int, int);
84static void def_import (const char *, const char *, const char *, const char *,
85			int, const char *);
86static void def_image_name (const char *, int, int);
87static void def_section (const char *, int);
88static void def_section_alt (const char *, const char *);
89static void def_stacksize (int, int);
90static void def_version (int, int);
91static void def_directive (char *);
92static void def_aligncomm (char *str, int align);
93static int def_parse (void);
94static int def_error (const char *);
95static int def_lex (void);
96
97static int lex_forced_token = 0;
98static const char *lex_parse_string = 0;
99static 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
124start: start command
125	| command
126	;
127
128command:
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
146explist:
147		/* EMPTY */
148	|	expline
149	|	explist expline
150	;
151
152expline:
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	;
159exp_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	;
166exp_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	;
176implist:
177		implist impline
178	|	impline
179	;
180
181impline:
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
196seclist:
197		seclist secline
198	|	secline
199	;
200
201secline:
202	ID attr_list { def_section ($1, $2);}
203	| ID ID { def_section_alt ($1, $2);}
204	;
205
206attr_list:
207	attr_list opt_comma attr { $$ = $1 | $3; }
208	| attr { $$ = $1; }
209	;
210
211opt_comma:
212	','
213	|
214	;
215opt_number: ',' NUMBER { $$=$2;}
216	|	   { $$=-1;}
217	;
218
219attr:
220		READ	{ $$ = 1;}
221	|	WRITE	{ $$ = 2;}
222	|	EXECUTE	{ $$=4;}
223	|	SHARED	{ $$=8;}
224	;
225
226opt_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
242opt_equalequal_name: EQUAL ID	{ $$ = $2; }
243	|							{ $$ = 0; }
244	;
245
246opt_ordinal:
247	  '@' NUMBER     { $$ = $2;}
248	|                { $$ = -1;}
249	;
250
251opt_equal_name:
252          '=' dot_name	{ $$ = $2; }
253        | 		{ $$ =  0; }
254	;
255
256opt_base: BASE	'=' NUMBER	{ $$ = $3;}
257	|	{ $$ = -1;}
258	;
259
260dot_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
275anylang_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
290opt_digits: DIGITS	{ $$ = $1; }
291	|		{ $$ = ""; }
292	;
293
294opt_id: ID		{ $$ = $1; }
295	|		{ $$ = ""; }
296	;
297
298NUMBER: DIGITS		{ $$ = strtoul ($1, 0, 0); }
299
300%%
301
302/*****************************************************************************
303 API
304 *****************************************************************************/
305
306static FILE *the_file;
307static const char *def_filename;
308static int linenumber;
309static def_file *def;
310static int saw_newline;
311
312struct directive
313  {
314    struct directive *next;
315    char *name;
316    int len;
317  };
318
319static struct directive *directives = 0;
320
321def_file *
322def_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
334def_file *
335def_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
377void
378def_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
452void
453def_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
537def_file_export *
538def_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
570def_file_module *
571def_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
582static def_file_module *
583def_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
597def_file_import *
598def_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
635struct
636{
637  char *param;
638  int token;
639}
640diropts[] =
641{
642  { "-heap", HEAPSIZE },
643  { "-stack", STACKSIZE_K },
644  { "-attr", SECTIONS },
645  { "-export", EXPORTS },
646  { "-aligncomm", ALIGNCOMM },
647  { 0, 0 }
648};
649
650void
651def_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
719static void
720def_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
751static void
752def_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
769static void
770def_stacksize (int reserve, int commit)
771{
772  def->stack_reserve = reserve;
773  def->stack_commit = commit;
774}
775
776static void
777def_heapsize (int reserve, int commit)
778{
779  def->heap_reserve = reserve;
780  def->heap_commit = commit;
781}
782
783static void
784def_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
814static void
815def_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
844static void
845def_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
871static void
872def_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
891static void
892def_version (int major, int minor)
893{
894  def->version_major = major;
895  def->version_minor = minor;
896}
897
898static void
899def_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
909static void
910def_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
921static int
922def_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.  */
936static char *buffer = 0;
937static int buflen = 0;
938static int bufptr = 0;
939
940static void
941put_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
955static struct
956{
957  char *name;
958  int token;
959}
960tokens[] =
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
990static int
991def_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
1011static int
1012def_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
1023static int
1024def_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}
1181