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