diff options
| author | Ulrich Drepper <[email protected]> | 2005-07-26 05:00:05 +0000 |
|---|---|---|
| committer | Ulrich Drepper <[email protected]> | 2005-07-26 05:00:05 +0000 |
| commit | b08d5a8fb42f4586d756068065186b5af7e48dad (patch) | |
| tree | 9f05f86be7877ed461b4dc05f53b29ea4fc0d2a1 /src/ldlex.l | |
Adjust for monotone.
Diffstat (limited to 'src/ldlex.l')
| -rw-r--r-- | src/ldlex.l | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/src/ldlex.l b/src/ldlex.l new file mode 100644 index 00000000..9e30a865 --- /dev/null +++ b/src/ldlex.l @@ -0,0 +1,349 @@ +%{ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Written by Ulrich Drepper <[email protected]>, 2001. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <ctype.h> +#include <elf.h> +#include <error.h> +#include <inttypes.h> +#include <libintl.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include <system.h> +#include <ld.h> +#include "ldscript.h" + +/* We sure use no threads to read the stream, so use the _unlocked + variants of the functions. */ +#undef getc +#define getc(s) getc_unlocked (s) +#undef ferror +#define ferror(s) ferror_unlocked (s) +#undef fread +#define fread(b, m, n, s) fread_unlocked (b, m, n, s) +#undef fwrite +#define fwrite(b, m, n, s) fwrite_unlocked (b, m, n, s) + +/* ECHO must be redefined since the default implementation ignores + the return value of fwrite_unlocked. */ +#define ECHO do { size_t n__ __attribute__ ((unused)) \ + = fwrite (yytext, yyleng, 1, yyout); } while (0) + +/* Defined in ld.c. */ +extern int ld_scan_version_script; + +#define MAX_PREPDEPTH 20 +static enum prepstate +{ + prep_normal, + skip_if, + skip_to_endif +} prepstate[MAX_PREPDEPTH]; +static int prepdepth; + +static void eat_comment (void); +static void eat_to_eol (bool empty); +static int attrib_convert (int c); +static void push_state (enum prepstate); +static int pop_state (void); +static int handle_ifdef (void); +static void invalid_char (int ch); +%} + +ID [a-zA-Z0-9_.*?]+ +FILENAMECHAR1 [a-zA-Z0-9_/.\\~] +FILENAMECHAR [^][{}[:space:]():;]+ +HEX 0[xX][0-9a-fA-F]+[kKmM]? +OCT 0[0-7]*[kKmM]? +DEC [0-9]+[kKmM]? +WHITE [[:space:]]+ + +%option yylineno +%option never-interactive +%option noyywrap + +%x IGNORE + +%% + if (unlikely (ld_scan_version_script)) + { + ld_scan_version_script = -1; + return kVERSION_SCRIPT; + } + +^"#"ifdef/[[:space:]] { BEGIN (handle_ifdef ()); } +^"#"else/[[:space:]\n] { eat_to_eol (true); + push_state (skip_to_endif); + BEGIN (IGNORE); } +^"#"elifdef/[[:space:]] { eat_to_eol (false); + push_state (skip_to_endif); + BEGIN (IGNORE); } +^"#"endif/[[:space:]\n] { eat_to_eol (true) ; } + +<IGNORE>^"#"ifdef/[[:space:]\n] { eat_to_eol (false); + push_state (skip_to_endif); } +<IGNORE>^"#"else/[[:space:]\n] { eat_to_eol (true); + assert (prepdepth > 0); + if (prepstate[prepdepth - 1] == skip_if) + { + /* Back to normal processing. */ + assert (prepdepth == 1); + BEGIN (pop_state ()); + } + } +<IGNORE>^"#"elifdef/[[:space:]] { assert (prepdepth > 0); + if (prepstate[prepdepth - 1] == skip_if) + { + /* Maybe this symbol is defined. */ + pop_state (); + BEGIN (handle_ifdef ()); + } + } +<IGNORE>^"#"endif/[[:space:]\n] { eat_to_eol (true); + BEGIN (pop_state ()); } +<IGNORE>.|\n { /* nothing */ } + + +"/*" { eat_comment (); } + +ALIGN { return kALIGN; } +AS_NEEDED { return kAS_NEEDED; } +ENTRY { return kENTRY; } +EXCLUDE_FILE { return kEXCLUDE_FILE; } +"global:" { return kGLOBAL; } +GROUP { return kGROUP; } +INPUT { return kINPUT; } +INTERP { return kINTERP; } +KEEP { return kKEEP; } +"local:" { return kLOCAL; } +OUTPUT_FORMAT { return kOUTPUT_FORMAT; } +PAGESIZE { return kPAGESIZE; } +PROVIDE { return kPROVIDE; } +SEARCH_DIR { return kSEARCH_DIR; } +SEGMENT { return kSEGMENT; } +SIZEOF_HEADERS { return kSIZEOF_HEADERS; } +SORT { return kSORT; } +VERSION { return kVERSION; } + +"["([RWX]){0,3}"]" { int cnt = 1 ; + ldlval.num = 0; + while (cnt < yyleng - 1) + ldlval.num |= attrib_convert (yytext[cnt++]); + return kMODE; } + +"{" { return '{'; } +"}" { return '}'; } +"(" { return '('; } +")" { return ')'; } +":" { return ':'; } +";" { return ';'; } +"=" { return '='; } +"+" { ldlval.op = exp_plus; return kADD_OP; } +"-" { ldlval.op = exp_minus; return kADD_OP; } +"*" { return '*'; } +"/" { ldlval.op = exp_div; return kMUL_OP; } +"%" { ldlval.op = exp_mod; return kMUL_OP; } +"&" { return '&'; } +"|" { return '|'; } + +"," { return ','; } + +{HEX}|{OCT}|{DEC} { char *endp; + ldlval.num = strtoumax (yytext, &endp, 0); + if (*endp != '\0') + { + if (tolower (*endp) == 'k') + ldlval.num *= 1024; + else + { + assert (tolower (*endp) == 'm'); + ldlval.num *= 1024 * 1024; + } + } + return kNUM; } + +{ID} { ldlval.str = obstack_strndup (&ld_state.smem, + yytext, yyleng); + return kID; } + +{FILENAMECHAR1}{FILENAMECHAR} { ldlval.str = obstack_strndup (&ld_state.smem, + yytext, yyleng); + return kFILENAME; } + +{WHITE} { /* IGNORE */ } + +. { invalid_char (*yytext); } + +%% + +static void +eat_comment (void) +{ + while (1) + { + int c = input (); + + while (c != '*' && c != EOF) + c = input (); + + if (c == '*') + { + c = input (); + while (c == '*') + c = input (); + if (c == '/') + break; + } + + if (c == EOF) + { + /* XXX Use the setjmp buffer and signal EOF in comment */ + error (0, 0, gettext ("EOF in comment")); + break; + } + } +} + + +static void +eat_to_eol (bool empty) +{ + bool warned = false; + + while (1) + { + int c = input (); + + if (c == EOF) + break; + if (c == '\n') + { + ++yylineno; + break; + } + + if (empty && ! isspace (c) && ! warned) + { + error (0, 0, gettext ("%d: garbage at end of line"), yylineno); + warned = true; + } + } +} + + +static int +attrib_convert (int c) +{ + if (c == 'X') + return PF_X; + if (c == 'W') + return PF_W; + assert (c == 'R'); + return PF_R; +} + + +static void +push_state (enum prepstate state) +{ + if (prepdepth >= MAX_PREPDEPTH) + error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"), + yylineno); + + prepstate[prepdepth++] = state; +} + + +static int +pop_state (void) +{ + if (prepdepth == 0) + error (0, 0, gettext ("%d: unexpected #endif"), yylineno); + else + --prepdepth; + + return prepdepth == 0 ? INITIAL : IGNORE; +} + + +static int +handle_ifdef (void) +{ + char idbuf[50]; + char *id = idbuf; + size_t idlen = 0; + size_t idmax = sizeof (idbuf); + bool ignore_ws = true; + bool defined = false; + int result; + + while (1) + { + int c = input (); + + if (isspace (c) && ignore_ws) + continue; + + if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') + && (idlen == 0 || c < '0' || c > '9')) + { + unput (c); + break; + } + + if (idlen == idmax) + { + char *newp = (char *) alloca (idmax *= 2); + id = memcpy (newp, id, idlen); + } + + id[idlen++] = c; + ignore_ws = false; + } + + /* XXX Compare in a better way. */ + if (idlen == 6 && strncmp (id, "SHARED", 6) == 0) + defined = ld_state.file_type == dso_file_type; + + if (defined) + result = INITIAL; + else + { + push_state (skip_if); + result = IGNORE; + } + + return result; +} + + +static void +invalid_char (int ch) +{ + error (0, 0, (isascii (ch) + ? gettext ("invalid character '%c' at line %d; ignored") + : gettext ("invalid character '\\%o' at line %d; ignored")), + ch, yylineno); +} + + +// Local Variables: +// mode: C +// End: |
