summaryrefslogtreecommitdiffstats
path: root/src/ldlex.l
diff options
context:
space:
mode:
authorUlrich Drepper <[email protected]>2005-07-26 05:00:05 +0000
committerUlrich Drepper <[email protected]>2005-07-26 05:00:05 +0000
commitb08d5a8fb42f4586d756068065186b5af7e48dad (patch)
tree9f05f86be7877ed461b4dc05f53b29ea4fc0d2a1 /src/ldlex.l
Adjust for monotone.
Diffstat (limited to 'src/ldlex.l')
-rw-r--r--src/ldlex.l349
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: