blob: 999018ea00b2e77083e944e5941c0bdd08d0818b [file] [log] [blame]
Michael J. Spencera55e37f2013-03-01 00:03:36 +00001//===- ReaderWriter/LinkerScript.cpp --------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief Linker script parser.
12///
13//===----------------------------------------------------------------------===//
14
15#include "lld/ReaderWriter/LinkerScript.h"
16
17namespace lld {
18namespace script {
Rui Ueyamac1800be2013-11-05 01:37:40 +000019void Token::dump(raw_ostream &os) const {
Michael J. Spencera55e37f2013-03-01 00:03:36 +000020 switch (_kind) {
Rui Ueyama143672c2013-06-03 18:05:21 +000021#define CASE(name) \
22 case Token::name: \
23 os << #name ": "; \
Michael J. Spencera55e37f2013-03-01 00:03:36 +000024 break;
Rui Ueyama143672c2013-06-03 18:05:21 +000025 CASE(eof)
26 CASE(identifier)
27 CASE(kw_as_needed)
28 CASE(kw_entry)
29 CASE(kw_group)
30 CASE(kw_output_format)
31 CASE(l_paren)
32 CASE(r_paren)
33 CASE(unknown)
34#undef CASE
Michael J. Spencera55e37f2013-03-01 00:03:36 +000035 }
36 os << _range << "\n";
37}
38
39bool Lexer::canStartName(char c) const {
40 switch (c) {
41 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
42 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
43 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
44 case 'V': case 'W': case 'X': case 'Y': case 'Z':
45 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
46 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
47 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
48 case 'v': case 'w': case 'x': case 'y': case 'z':
49 case '_': case '.': case '$': case '/': case '\\':
50 return true;
51 default:
52 return false;
53 }
54}
55
56bool Lexer::canContinueName(char c) const {
57 switch (c) {
58 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
59 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
60 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
61 case 'V': case 'W': case 'X': case 'Y': case 'Z':
62 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
63 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
64 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
65 case 'v': case 'w': case 'x': case 'y': case 'z':
66 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
67 case '7': case '8': case '9':
68 case '_': case '.': case '$': case '/': case '\\': case '~': case '=':
69 case '+': case ',': case '[': case ']': case '*': case '?': case '-':
70 return true;
71 default:
72 return false;
73 }
74}
75
76void Lexer::lex(Token &tok) {
77 skipWhitespace();
78 if (_buffer.empty()) {
79 tok = Token(_buffer, Token::eof);
80 return;
81 }
82 switch (_buffer[0]) {
83 case 0:
84 tok = Token(_buffer.substr(0, 1), Token::eof);
85 _buffer = _buffer.drop_front();
86 return;
87 case '(':
88 tok = Token(_buffer.substr(0, 1), Token::l_paren);
89 _buffer = _buffer.drop_front();
90 return;
91 case ')':
92 tok = Token(_buffer.substr(0, 1), Token::r_paren);
93 _buffer = _buffer.drop_front();
94 return;
95 default:
96 /// keyword or identifer.
97 if (!canStartName(_buffer[0]))
98 break;
99 auto endIter =
100 std::find_if(_buffer.begin() + 1, _buffer.end(), [=](char c) {
101 return !canContinueName(c);
102 });
103 StringRef::size_type end =
104 endIter == _buffer.end() ? StringRef::npos
105 : std::distance(_buffer.begin(), endIter);
106 if (end == StringRef::npos || end == 0)
107 break;
108 StringRef word = _buffer.substr(0, end);
109 Token::Kind kind = llvm::StringSwitch<Token::Kind>(word)
110 .Case("OUTPUT_FORMAT", Token::kw_output_format)
111 .Case("GROUP", Token::kw_group)
112 .Case("AS_NEEDED", Token::kw_as_needed)
Rui Ueyama143672c2013-06-03 18:05:21 +0000113 .Case("ENTRY", Token::kw_entry)
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000114 .Default(Token::identifier);
115 tok = Token(word, kind);
116 _buffer = _buffer.drop_front(end);
117 return;
118 }
119 tok = Token(_buffer.substr(0, 1), Token::unknown);
120 _buffer = _buffer.drop_front();
121}
122
123void Lexer::skipWhitespace() {
124 while (true) {
125 if (_buffer.empty())
126 return;
127 switch (_buffer[0]) {
128 case ' ':
129 case '\r':
130 case '\n':
131 case '\t':
132 _buffer = _buffer.drop_front();
133 break;
134 // Potential comment.
135 case '/':
136 if (_buffer.size() >= 2 && _buffer[1] == '*') {
137 // Skip starting /*
138 _buffer = _buffer.drop_front(2);
139 // If the next char is also a /, it's not the end.
140 if (!_buffer.empty() && _buffer[0] == '/')
141 _buffer = _buffer.drop_front();
142
143 // Scan for /'s. We're done if it is preceeded by a *.
144 while (true) {
145 if (_buffer.empty())
146 break;
147 _buffer = _buffer.drop_front();
148 if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*')
149 break;
150 }
151 } else
152 return;
153 break;
154 default:
155 return;
156 }
157 }
158}
159
160LinkerScript *Parser::parse() {
161 // Get the first token.
162 _lex.lex(_tok);
163 // Parse top level commands.
164 while (true) {
165 switch (_tok._kind) {
166 case Token::eof:
167 return &_script;
168 case Token::kw_output_format: {
169 auto outputFormat = parseOutputFormat();
170 if (!outputFormat)
171 return nullptr;
172 _script._commands.push_back(outputFormat);
173 break;
174 }
175 case Token::kw_group: {
176 auto group = parseGroup();
177 if (!group)
178 return nullptr;
179 _script._commands.push_back(group);
180 break;
181 }
182 case Token::kw_as_needed:
183 // Not allowed at top level.
184 return nullptr;
Rui Ueyama143672c2013-06-03 18:05:21 +0000185 case Token::kw_entry: {
186 Entry *entry = parseEntry();
187 if (!entry)
188 return nullptr;
189 _script._commands.push_back(entry);
190 break;
191 }
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000192 default:
193 // Unexpected.
194 return nullptr;
195 }
196 }
197
198 return nullptr;
199}
200
Rui Ueyama143672c2013-06-03 18:05:21 +0000201// Parse OUTPUT_FORMAT(ident)
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000202OutputFormat *Parser::parseOutputFormat() {
203 assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!");
204 consumeToken();
205 if (!expectAndConsume(Token::l_paren, "expected ("))
206 return nullptr;
207
208 if (_tok._kind != Token::identifier) {
Rui Ueyama143672c2013-06-03 18:05:21 +0000209 error(_tok, "Expected identifier in OUTPUT_FORMAT.");
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000210 return nullptr;
211 }
212
213 auto ret = new (_alloc) OutputFormat(_tok._range);
214 consumeToken();
215
216 if (!expectAndConsume(Token::r_paren, "expected )"))
217 return nullptr;
218
219 return ret;
220}
221
Rui Ueyama143672c2013-06-03 18:05:21 +0000222// Parse GROUP(file ...)
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000223Group *Parser::parseGroup() {
224 assert(_tok._kind == Token::kw_group && "Expected GROUP!");
225 consumeToken();
226 if (!expectAndConsume(Token::l_paren, "expected ("))
227 return nullptr;
228
229 std::vector<Path> paths;
230
231 while (_tok._kind == Token::identifier || _tok._kind == Token::kw_as_needed) {
232 switch (_tok._kind) {
233 case Token::identifier:
234 paths.push_back(Path(_tok._range));
235 consumeToken();
236 break;
237 case Token::kw_as_needed:
238 if (!parseAsNeeded(paths))
239 return nullptr;
240 break;
241 default:
242 llvm_unreachable("Invalid token.");
243 }
244 }
245
246 auto ret = new (_alloc) Group(paths);
247
248 if (!expectAndConsume(Token::r_paren, "expected )"))
249 return nullptr;
250
251 return ret;
252}
253
Rui Ueyama143672c2013-06-03 18:05:21 +0000254// Parse AS_NEEDED(file ...)
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000255bool Parser::parseAsNeeded(std::vector<Path> &paths) {
256 assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!");
257 consumeToken();
258 if (!expectAndConsume(Token::l_paren, "expected ("))
259 return false;
260
261 while (_tok._kind == Token::identifier) {
262 paths.push_back(Path(_tok._range, true));
263 consumeToken();
264 }
265
266 if (!expectAndConsume(Token::r_paren, "expected )"))
267 return false;
268 return true;
269}
Rui Ueyama143672c2013-06-03 18:05:21 +0000270
271// Parse ENTRY(ident)
272Entry *Parser::parseEntry() {
273 assert(_tok._kind == Token::kw_entry && "Expected ENTRY!");
274 consumeToken();
275 if (!expectAndConsume(Token::l_paren, "expected ("))
276 return nullptr;
277 if (_tok._kind != Token::identifier) {
278 error(_tok, "expected identifier in ENTRY");
279 return nullptr;
280 }
281 StringRef entryName(_tok._range);
282 consumeToken();
283 if (!expectAndConsume(Token::r_paren, "expected )"))
284 return nullptr;
285 return new (_alloc) Entry(entryName);
286}
287
Michael J. Spencera55e37f2013-03-01 00:03:36 +0000288} // end namespace script
289} // end namespace lld