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