blob: 382ea4d3d511238aeebb1fedc2711da1788a7f8a [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 {
19void Token::dump(llvm::raw_ostream &os) const {
20 switch (_kind) {
21 case Token::eof:
22 os << "eof: ";
23 break;
24 case Token::identifier:
25 os << "identifier: ";
26 break;
27 case Token::kw_as_needed:
28 os << "kw_as_needed: ";
29 break;
30 case Token::kw_group:
31 os << "kw_group: ";
32 break;
33 case Token::kw_output_format:
34 os << "kw_output_format: ";
35 break;
36 case Token::l_paren:
37 os << "l_paren: ";
38 break;
39 case Token::r_paren:
40 os << "r_paren: ";
41 break;
42 case Token::unknown:
43 os << "unknown: ";
44 break;
45 }
46 os << _range << "\n";
47}
48
49bool Lexer::canStartName(char c) const {
50 switch (c) {
51 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
52 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
53 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
54 case 'V': case 'W': case 'X': case 'Y': case 'Z':
55 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
56 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
57 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
58 case 'v': case 'w': case 'x': case 'y': case 'z':
59 case '_': case '.': case '$': case '/': case '\\':
60 return true;
61 default:
62 return false;
63 }
64}
65
66bool Lexer::canContinueName(char c) const {
67 switch (c) {
68 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
69 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
70 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
71 case 'V': case 'W': case 'X': case 'Y': case 'Z':
72 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
73 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
74 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
75 case 'v': case 'w': case 'x': case 'y': case 'z':
76 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
77 case '7': case '8': case '9':
78 case '_': case '.': case '$': case '/': case '\\': case '~': case '=':
79 case '+': case ',': case '[': case ']': case '*': case '?': case '-':
80 return true;
81 default:
82 return false;
83 }
84}
85
86void Lexer::lex(Token &tok) {
87 skipWhitespace();
88 if (_buffer.empty()) {
89 tok = Token(_buffer, Token::eof);
90 return;
91 }
92 switch (_buffer[0]) {
93 case 0:
94 tok = Token(_buffer.substr(0, 1), Token::eof);
95 _buffer = _buffer.drop_front();
96 return;
97 case '(':
98 tok = Token(_buffer.substr(0, 1), Token::l_paren);
99 _buffer = _buffer.drop_front();
100 return;
101 case ')':
102 tok = Token(_buffer.substr(0, 1), Token::r_paren);
103 _buffer = _buffer.drop_front();
104 return;
105 default:
106 /// keyword or identifer.
107 if (!canStartName(_buffer[0]))
108 break;
109 auto endIter =
110 std::find_if(_buffer.begin() + 1, _buffer.end(), [=](char c) {
111 return !canContinueName(c);
112 });
113 StringRef::size_type end =
114 endIter == _buffer.end() ? StringRef::npos
115 : std::distance(_buffer.begin(), endIter);
116 if (end == StringRef::npos || end == 0)
117 break;
118 StringRef word = _buffer.substr(0, end);
119 Token::Kind kind = llvm::StringSwitch<Token::Kind>(word)
120 .Case("OUTPUT_FORMAT", Token::kw_output_format)
121 .Case("GROUP", Token::kw_group)
122 .Case("AS_NEEDED", Token::kw_as_needed)
123 .Default(Token::identifier);
124 tok = Token(word, kind);
125 _buffer = _buffer.drop_front(end);
126 return;
127 }
128 tok = Token(_buffer.substr(0, 1), Token::unknown);
129 _buffer = _buffer.drop_front();
130}
131
132void Lexer::skipWhitespace() {
133 while (true) {
134 if (_buffer.empty())
135 return;
136 switch (_buffer[0]) {
137 case ' ':
138 case '\r':
139 case '\n':
140 case '\t':
141 _buffer = _buffer.drop_front();
142 break;
143 // Potential comment.
144 case '/':
145 if (_buffer.size() >= 2 && _buffer[1] == '*') {
146 // Skip starting /*
147 _buffer = _buffer.drop_front(2);
148 // If the next char is also a /, it's not the end.
149 if (!_buffer.empty() && _buffer[0] == '/')
150 _buffer = _buffer.drop_front();
151
152 // Scan for /'s. We're done if it is preceeded by a *.
153 while (true) {
154 if (_buffer.empty())
155 break;
156 _buffer = _buffer.drop_front();
157 if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*')
158 break;
159 }
160 } else
161 return;
162 break;
163 default:
164 return;
165 }
166 }
167}
168
169LinkerScript *Parser::parse() {
170 // Get the first token.
171 _lex.lex(_tok);
172 // Parse top level commands.
173 while (true) {
174 switch (_tok._kind) {
175 case Token::eof:
176 return &_script;
177 case Token::kw_output_format: {
178 auto outputFormat = parseOutputFormat();
179 if (!outputFormat)
180 return nullptr;
181 _script._commands.push_back(outputFormat);
182 break;
183 }
184 case Token::kw_group: {
185 auto group = parseGroup();
186 if (!group)
187 return nullptr;
188 _script._commands.push_back(group);
189 break;
190 }
191 case Token::kw_as_needed:
192 // Not allowed at top level.
193 return nullptr;
194 default:
195 // Unexpected.
196 return nullptr;
197 }
198 }
199
200 return nullptr;
201}
202
203OutputFormat *Parser::parseOutputFormat() {
204 assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!");
205 consumeToken();
206 if (!expectAndConsume(Token::l_paren, "expected ("))
207 return nullptr;
208
209 if (_tok._kind != Token::identifier) {
210 error(_tok, "Expected identifer in OUTPUT_FORMAT.");
211 return nullptr;
212 }
213
214 auto ret = new (_alloc) OutputFormat(_tok._range);
215 consumeToken();
216
217 if (!expectAndConsume(Token::r_paren, "expected )"))
218 return nullptr;
219
220 return ret;
221}
222
223Group *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
254bool Parser::parseAsNeeded(std::vector<Path> &paths) {
255 assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!");
256 consumeToken();
257 if (!expectAndConsume(Token::l_paren, "expected ("))
258 return false;
259
260 while (_tok._kind == Token::identifier) {
261 paths.push_back(Path(_tok._range, true));
262 consumeToken();
263 }
264
265 if (!expectAndConsume(Token::r_paren, "expected )"))
266 return false;
267 return true;
268}
269} // end namespace script
270} // end namespace lld