Imported Upstream version 0.155
[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 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.  */
54 extern int ld_scan_version_script;
55
56 #define MAX_PREPDEPTH 20
57 static enum prepstate
58 {
59   prep_normal,
60   skip_if,
61   skip_to_endif
62 } prepstate[MAX_PREPDEPTH];
63 static int prepdepth;
64
65 static void eat_comment (void);
66 static void eat_to_eol (bool empty);
67 static int attrib_convert (int c);
68 static void push_state (enum prepstate);
69 static int pop_state (void);
70 static int handle_ifdef (void);
71 static void invalid_char (int ch);
72 %}
73
74 ID              [a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]*
75 FILENAMECHAR1   [a-zA-Z0-9_/.\\~]
76 FILENAMECHAR    [^][{}[:space:]():;]+
77 HEX             0[xX][0-9a-fA-F]+[kKmM]?
78 OCT             0[0-7]*[kKmM]?
79 DEC             [0-9]+[kKmM]?
80 WHITE           [[: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
130 ALIGN                           { return kALIGN; }
131 AS_NEEDED                       { return kAS_NEEDED; }
132 ENTRY                           { return kENTRY; }
133 EXCLUDE_FILE                    { return kEXCLUDE_FILE; }
134 "global:"                       { return kGLOBAL; }
135 GROUP                           { return kGROUP; }
136 INPUT                           { return kINPUT; }
137 INTERP                          { return kINTERP; }
138 KEEP                            { return kKEEP; }
139 "local:"                        { return kLOCAL; }
140 OUTPUT_FORMAT                   { return kOUTPUT_FORMAT; }
141 PAGESIZE                        { return kPAGESIZE; }
142 PROVIDE                         { return kPROVIDE; }
143 SEARCH_DIR                      { return kSEARCH_DIR; }
144 SEGMENT                         { return kSEGMENT; }
145 SIZEOF_HEADERS                  { return kSIZEOF_HEADERS; }
146 SORT                            { return kSORT; }
147 VERSION                         { return kVERSION; }
148
149 "["([RWX]){0,3}"]"              { 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
200 static void
201 eat_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
229 static void
230 eat_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
255 static int
256 attrib_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
267 static void
268 push_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
278 static int
279 pop_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
290 static int
291 handle_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
341 static void
342 invalid_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: