1%{
2/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
3   This file is part of Red Hat elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
5
6   Red Hat elfutils is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 2 of the License.
9
10   Red Hat elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License along
16   with Red Hat elfutils; if not, write to the Free Software Foundation,
17   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19   Red Hat elfutils is an included package of the Open Invention Network.
20   An included package of the Open Invention Network is a package for which
21   Open Invention Network licensees cross-license their patents.  No patent
22   license is granted, either expressly or impliedly, by designation as an
23   included package.  Should you wish to participate in the Open Invention
24   Network licensing program, please visit www.openinventionnetwork.com
25   <http://www.openinventionnetwork.com>.  */
26
27#ifdef HAVE_CONFIG_H
28# include <config.h>
29#endif
30
31#include <assert.h>
32#include <ctype.h>
33#include <elf.h>
34#include <error.h>
35#include <inttypes.h>
36#include <libintl.h>
37#include <stdbool.h>
38#include <stdio.h>
39#include <string.h>
40
41#include <system.h>
42#include <ld.h>
43#include "ldscript.h"
44
45/* We sure use no threads to read the stream, so use the _unlocked
46   variants of the functions.  */
47#undef getc
48#define getc(s) getc_unlocked (s)
49#undef ferror
50#define ferror(s) ferror_unlocked (s)
51#undef fread
52#define fread(b, m, n, s) fread_unlocked (b, m, n, s)
53#undef fwrite
54#define fwrite(b, m, n, s) fwrite_unlocked (b, m, n, s)
55
56/* ECHO must be redefined since the default implementation ignores
57   the return value of fwrite_unlocked.  */
58#define ECHO do { size_t n__ __attribute__ ((unused)) \
59			   = fwrite (yytext, yyleng, 1, yyout); } while (0)
60
61/* Defined in ld.c.  */
62extern int ld_scan_version_script;
63
64#define MAX_PREPDEPTH 20
65static enum prepstate
66{
67  prep_normal,
68  skip_if,
69  skip_to_endif
70} prepstate[MAX_PREPDEPTH];
71static int prepdepth;
72
73static void eat_comment (void);
74static void eat_to_eol (bool empty);
75static int attrib_convert (int c);
76static void push_state (enum prepstate);
77static int pop_state (void);
78static int handle_ifdef (void);
79static void invalid_char (int ch);
80%}
81
82ID		[a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]*
83FILENAMECHAR1	[a-zA-Z0-9_/.\\~]
84FILENAMECHAR	[^][{}[:space:]():;]+
85HEX		0[xX][0-9a-fA-F]+[kKmM]?
86OCT		0[0-7]*[kKmM]?
87DEC		[0-9]+[kKmM]?
88WHITE		[[:space:]]+
89
90%option yylineno
91%option never-interactive
92%option noyywrap
93
94%x IGNORE
95
96%%
97				if (unlikely (ld_scan_version_script))
98				  {
99				    ld_scan_version_script = -1;
100				    return kVERSION_SCRIPT;
101				  }
102
103^"#"ifdef/[[:space:]]		{ BEGIN (handle_ifdef ()); }
104^"#"else/[[:space:]\n]		{ eat_to_eol (true);
105				  push_state (skip_to_endif);
106				  BEGIN (IGNORE); }
107^"#"elifdef/[[:space:]]		{ eat_to_eol (false);
108				  push_state (skip_to_endif);
109				  BEGIN (IGNORE); }
110^"#"endif/[[:space:]\n]		{ eat_to_eol (true) ; }
111
112<IGNORE>^"#"ifdef/[[:space:]\n] { eat_to_eol (false);
113				  push_state (skip_to_endif); }
114<IGNORE>^"#"else/[[:space:]\n]	{ eat_to_eol (true);
115				  assert (prepdepth > 0);
116				  if (prepstate[prepdepth - 1] == skip_if)
117				    {
118				      /* Back to normal processing.  */
119				      assert (prepdepth == 1);
120				      BEGIN (pop_state ());
121				    }
122				}
123<IGNORE>^"#"elifdef/[[:space:]]	{ assert (prepdepth > 0);
124				  if (prepstate[prepdepth - 1] == skip_if)
125				    {
126				      /* Maybe this symbol is defined.  */
127				      pop_state ();
128				      BEGIN (handle_ifdef ());
129				    }
130				}
131<IGNORE>^"#"endif/[[:space:]\n] { eat_to_eol (true);
132				  BEGIN (pop_state ()); }
133<IGNORE>.|\n			{ /* nothing */ }
134
135
136"/*"				{ eat_comment (); }
137
138ALIGN				{ return kALIGN; }
139AS_NEEDED			{ return kAS_NEEDED; }
140ENTRY				{ return kENTRY; }
141EXCLUDE_FILE			{ return kEXCLUDE_FILE; }
142"global:"			{ return kGLOBAL; }
143GROUP				{ return kGROUP; }
144INPUT				{ return kINPUT; }
145INTERP				{ return kINTERP; }
146KEEP				{ return kKEEP; }
147"local:"			{ return kLOCAL; }
148OUTPUT_FORMAT			{ return kOUTPUT_FORMAT; }
149PAGESIZE			{ return kPAGESIZE; }
150PROVIDE				{ return kPROVIDE; }
151SEARCH_DIR			{ return kSEARCH_DIR; }
152SEGMENT				{ return kSEGMENT; }
153SIZEOF_HEADERS			{ return kSIZEOF_HEADERS; }
154SORT				{ return kSORT; }
155VERSION				{ return kVERSION; }
156
157"["([RWX]){0,3}"]"		{ int cnt = 1 ;
158				  ldlval.num = 0;
159				  while (cnt < yyleng - 1)
160				    ldlval.num |= attrib_convert (yytext[cnt++]);
161				  return kMODE; }
162
163"{"				{ return '{'; }
164"}"				{ return '}'; }
165"("				{ return '('; }
166")"				{ return ')'; }
167":"				{ return ':'; }
168";"				{ return ';'; }
169"="				{ return '='; }
170"+"				{ ldlval.op = exp_plus; return kADD_OP; }
171"-"				{ ldlval.op = exp_minus; return kADD_OP; }
172"*"				{ return '*'; }
173"/"				{ ldlval.op = exp_div; return kMUL_OP; }
174"%"				{ ldlval.op = exp_mod; return kMUL_OP; }
175"&"				{ return '&'; }
176"|"				{ return '|'; }
177
178","				{ return ','; }
179
180{HEX}|{OCT}|{DEC}		{ char *endp;
181				  ldlval.num = strtoumax (yytext, &endp, 0);
182				  if (*endp != '\0')
183				    {
184				      if (tolower (*endp) == 'k')
185					ldlval.num *= 1024;
186				      else
187					{
188					  assert (tolower (*endp) == 'm');
189					  ldlval.num *= 1024 * 1024;
190					}
191				    }
192				  return kNUM; }
193
194{ID}				{ ldlval.str = obstack_strndup (&ld_state.smem,
195								yytext, yyleng);
196				  return kID; }
197
198{FILENAMECHAR1}{FILENAMECHAR}	{ ldlval.str = obstack_strndup (&ld_state.smem,
199								yytext, yyleng);
200				  return kFILENAME; }
201
202{WHITE}				{ /* IGNORE */ }
203
204.				{ invalid_char (*yytext); }
205
206%%
207
208static void
209eat_comment (void)
210{
211  while (1)
212    {
213      int c = input ();
214
215      while (c != '*' && c != EOF)
216	c = input ();
217
218      if (c == '*')
219	{
220	  c = input ();
221	  while (c == '*')
222	    c = input ();
223	  if (c == '/')
224	    break;
225	}
226
227      if (c == EOF)
228	{
229	  /* XXX Use the setjmp buffer and signal EOF in comment */
230	  error (0, 0, gettext ("EOF in comment"));
231	  break;
232	}
233    }
234}
235
236
237static void
238eat_to_eol (bool empty)
239{
240  bool warned = false;
241
242  while (1)
243    {
244      int c = input ();
245
246      if (c == EOF)
247	break;
248      if (c == '\n')
249	{
250	  ++yylineno;
251	  break;
252	}
253
254      if (empty && ! isspace (c) && ! warned)
255	{
256	  error (0, 0, gettext ("%d: garbage at end of line"), yylineno);
257	  warned = true;
258	}
259    }
260}
261
262
263static int
264attrib_convert (int c)
265{
266  if (c == 'X')
267    return PF_X;
268  if (c == 'W')
269    return PF_W;
270  assert (c == 'R');
271  return PF_R;
272}
273
274
275static void
276push_state (enum prepstate state)
277{
278  if (prepdepth >= MAX_PREPDEPTH)
279    error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"),
280	   yylineno);
281
282  prepstate[prepdepth++] = state;
283}
284
285
286static int
287pop_state (void)
288{
289  if (prepdepth == 0)
290    error (0, 0, gettext ("%d: unexpected #endif"), yylineno);
291  else
292    --prepdepth;
293
294  return prepdepth == 0 ? INITIAL : IGNORE;
295}
296
297
298static int
299handle_ifdef (void)
300{
301  char idbuf[50];
302  char *id = idbuf;
303  size_t idlen = 0;
304  size_t idmax = sizeof (idbuf);
305  bool ignore_ws = true;
306  bool defined = false;
307  int result;
308
309  while (1)
310    {
311      int c = input ();
312
313      if (isspace (c) && ignore_ws)
314	continue;
315
316      if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')
317	  && (idlen == 0 || c < '0' || c > '9'))
318	{
319	  unput (c);
320	  break;
321	}
322
323      if (idlen == idmax)
324	{
325	  char *newp = (char *) alloca (idmax *= 2);
326	  id = memcpy (newp, id, idlen);
327	}
328
329      id[idlen++] = c;
330      ignore_ws = false;
331    }
332
333  /* XXX Compare in a better way.  */
334  if (idlen == 6 && strncmp (id, "SHARED", 6) == 0)
335    defined = ld_state.file_type == dso_file_type;
336
337  if (defined)
338    result = INITIAL;
339  else
340    {
341      push_state (skip_if);
342      result = IGNORE;
343    }
344
345  return result;
346}
347
348
349static void
350invalid_char (int ch)
351{
352  error (0, 0, (isascii (ch)
353		? gettext ("invalid character '%c' at line %d; ignored")
354		: gettext ("invalid character '\\%o' at line %d; ignored")),
355	 ch, yylineno);
356}
357
358
359// Local Variables:
360// mode: C
361// End:
362