eb15c7bee82a658aec0832e44190d0afb62b1829
[platform/upstream/elfutils.git] / src / ldlex.l
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.  */
62 extern int ld_scan_version_script;
63
64 #define MAX_PREPDEPTH 20
65 static enum prepstate
66 {
67   prep_normal,
68   skip_if,
69   skip_to_endif
70 } prepstate[MAX_PREPDEPTH];
71 static int prepdepth;
72
73 static void eat_comment (void);
74 static void eat_to_eol (bool empty);
75 static int attrib_convert (int c);
76 static void push_state (enum prepstate);
77 static int pop_state (void);
78 static int handle_ifdef (void);
79 static void invalid_char (int ch);
80 %}
81
82 ID              [a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]*
83 FILENAMECHAR1   [a-zA-Z0-9_/.\\~]
84 FILENAMECHAR    [^][{}[:space:]():;]+
85 HEX             0[xX][0-9a-fA-F]+[kKmM]?
86 OCT             0[0-7]*[kKmM]?
87 DEC             [0-9]+[kKmM]?
88 WHITE           [[: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
138 ALIGN                           { return kALIGN; }
139 AS_NEEDED                       { return kAS_NEEDED; }
140 ENTRY                           { return kENTRY; }
141 EXCLUDE_FILE                    { return kEXCLUDE_FILE; }
142 "global:"                       { return kGLOBAL; }
143 GROUP                           { return kGROUP; }
144 INPUT                           { return kINPUT; }
145 INTERP                          { return kINTERP; }
146 KEEP                            { return kKEEP; }
147 "local:"                        { return kLOCAL; }
148 OUTPUT_FORMAT                   { return kOUTPUT_FORMAT; }
149 PAGESIZE                        { return kPAGESIZE; }
150 PROVIDE                         { return kPROVIDE; }
151 SEARCH_DIR                      { return kSEARCH_DIR; }
152 SEGMENT                         { return kSEGMENT; }
153 SIZEOF_HEADERS                  { return kSIZEOF_HEADERS; }
154 SORT                            { return kSORT; }
155 VERSION                         { 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
208 static void
209 eat_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
237 static void
238 eat_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
263 static int
264 attrib_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
275 static void
276 push_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
286 static int
287 pop_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
298 static int
299 handle_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
349 static void
350 invalid_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: