1 /*
2 * A utility for building various tables and specializations for the
3 * KJS Frostbyte bytecode
4 *
5 * Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23 #include "parser.h"
24
25 #include <cstdlib>
26 #include <wtf/ASCIICType.h>
27
28 /**
29 This is a fairly straightforward affair. It's written in a
30 recursive descent style, but the language is actually regular.
31
32 The error recovert is even simpler: we just exit. That's it.
33 */
34
Parser(istream * stream)35 Parser::Parser(istream *stream): tokenLoaded(false), lexer(new Lexer(stream))
36 {}
37
~Parser()38 Parser::~Parser()
39 {
40 delete lexer;
41 }
42
matchIdentifier()43 string Parser::matchIdentifier()
44 {
45 Lexer::Token tok = getNext();
46 if (tok.type == Lexer::Ident) {
47 return tok.value;
48 }
49 issueError("Expected identifier, got:" + tok.toString(lexer));
50 return "";
51 }
52
matchCode(std::string * strOut,int * lineOut)53 void Parser::matchCode(std::string *strOut, int *lineOut)
54 {
55 Lexer::Token tok = getNext();
56 if (tok.type == Lexer::Code) {
57 *lineOut = tok.lineNum;
58 *strOut = tok.value;
59 return;
60 }
61 issueError("Expected code, got:" + tok.toString(lexer));
62 }
63
matchNumber()64 int Parser::matchNumber()
65 {
66 Lexer::Token tok = getNext();
67 if (tok.type == Lexer::Number) {
68 return std::atol(tok.value.c_str());
69 }
70 issueError("Expected number, got:" + tok.toString(lexer));
71 return 0;
72 }
73
match(Lexer::TokenType t)74 void Parser::match(Lexer::TokenType t)
75 {
76 Lexer::Token tok = getNext();
77 if (tok.type != t) {
78 issueError("Expected " + Lexer::Token(t).toString(lexer) + " got:" + tok.toString(lexer));
79 }
80 }
81
check(Lexer::TokenType t)82 bool Parser::check(Lexer::TokenType t)
83 {
84 if (peekNext().type == t) {
85 getNext(); // tasty!
86 return true;
87 } else {
88 return false;
89 }
90 }
91
matchFlags(const Flag * permittedFlags)92 unsigned Parser::matchFlags(const Flag *permittedFlags)
93 {
94 unsigned flagsVal = 0;
95 if (check(Lexer::LBracket)) {
96 while (true) {
97 std::string flag;
98
99 // We permit keywords to double as flags.
100 if (peekNext().isKeyword()) {
101 flag = getNext().toString(lexer);
102 } else {
103 flag = matchIdentifier();
104 }
105
106 // Lookup the name.
107 bool found = false;
108 for (int pos = 0; permittedFlags[pos].name; ++pos) {
109 if (flag == std::string(permittedFlags[pos].name)) {
110 found = true;
111 flagsVal |= permittedFlags[pos].value;
112 }
113 }
114
115 if (!found) {
116 issueError("invalid flag:" + flag);
117 }
118
119 // Done or more?
120 if (check(Lexer::RBracket)) {
121 return flagsVal;
122 } else {
123 match(Lexer::Comma);
124 }
125 }
126 }
127 return 0;
128 }
129
issueError(const string & msg)130 void Parser::issueError(const string &msg)
131 {
132 std::cerr << "Parse error:" << msg << " at about line:" << lexer->lineNumber() << "\n";
133 std::exit(-1);
134 }
135
peekNext()136 Lexer::Token Parser::peekNext()
137 {
138 if (!tokenLoaded) {
139 nextToken = lexer->nextToken();
140 tokenLoaded = true;
141 }
142
143 return nextToken;
144 }
145
getNext()146 Lexer::Token Parser::getNext()
147 {
148 if (tokenLoaded) {
149 tokenLoaded = false;
150 return nextToken;
151 }
152
153 return lexer->nextToken();
154 }
155
parse()156 void Parser::parse()
157 {
158 Lexer::Token tok = peekNext();
159
160 // The types are first..
161 while (tok.type == Lexer::Type) {
162 parseType();
163 tok = peekNext();
164 }
165
166 // Now we may have conversions or operations
167 while (tok.type == Lexer::Conversion || tok.type == Lexer::Operation) {
168 if (tok.type == Lexer::Conversion) {
169 parseConversion();
170 } else {
171 parseOperation();
172 }
173 tok = peekNext();
174 }
175
176 match(Lexer::EndOfFile);
177 }
178
parseType()179 void Parser::parseType()
180 {
181 //type identifier: nativeName *? [immediate?, register?, ?align8]?;
182 match(Lexer::Type);
183
184 string name = matchIdentifier();
185 match(Lexer::Colon);
186 string nativeName = matchIdentifier();
187
188 if (nativeName == "const") {
189 nativeName += " " + matchIdentifier(); // krazy:exclude=doublequote_chars
190 }
191
192 while (check(Lexer::Scope)) {
193 nativeName += "::" + matchIdentifier();
194 }
195
196 if (check(Lexer::Star)) {
197 nativeName += "*"; // krazy:exclude=doublequote_chars
198 }
199
200 const Flag typeFlags[] = {
201 {"immediate", Type_HaveImm},
202 {"register", Type_HaveReg},
203 {"align8", Type_Align8},
204 {nullptr, 0}
205 };
206
207 unsigned flags = matchFlags(typeFlags);
208 match(Lexer::SemiColon);
209
210 handleType(name, nativeName, flags);
211 }
212
parseConversion()213 void Parser::parseConversion()
214 {
215 // conversion from => to { clauses .. }
216 // clause := tile costs number; || impl [checked?, mayThrow?]? code; || register ident costs number;
217 match(Lexer::Conversion);
218 string from = matchIdentifier();
219 match(Lexer::Arrow);
220 string to = matchIdentifier();
221
222 match(Lexer::LBrace);
223
224 // impl clause info..
225 const Flag conversionFlags[] = {
226 {"checked", Conv_Checked},
227 {"mayThrow", Conv_MayThrow},
228 {nullptr, 0}
229 };
230
231 unsigned flags = 0;
232 string code;
233 int codeLine = 0;
234
235 // tile clause info
236 int tileCost = 0;
237
238 // register clause info
239 string registerIdent;
240 int registerCost = 0;
241
242 while (!check(Lexer::RBrace)) {
243 if (check(Lexer::Impl)) {
244 // impl [[code]]
245 flags = matchFlags(conversionFlags);
246 matchCode(&code, &codeLine);
247 } else if (check(Lexer::Tile)) {
248 // tile costs number;
249 match(Lexer::Costs);
250 tileCost = matchNumber();
251 match(Lexer::SemiColon);
252 } else if (check(Lexer::Register)) {
253 //register costs number;
254 flags |= Conv_HaveReg;
255 match(Lexer::Costs);
256 registerCost = matchNumber();
257 match(Lexer::SemiColon);
258 } else {
259 issueError("Invalid start of a clause within conversion block:" + peekNext().toString(lexer));
260 }
261 }
262
263 handleConversion(code, codeLine, flags, from, to, tileCost, registerCost);
264 }
265
parseOperation()266 void Parser::parseOperation()
267 {
268 // operation identifier { ... }, where ... is a list of impl or tile statements.
269 match(Lexer::Operation);
270
271 const Flag opFlags[] = {
272 {"endsBB", Op_EndsBB},
273 {"hint", Op_Hint},
274 {nullptr, 0}
275 };
276
277 std::string name = matchIdentifier();
278 unsigned flags = matchFlags(opFlags);
279
280 handleOperation(name, flags);
281
282 match(Lexer::LBrace);
283 Lexer::Token tok = peekNext();
284 while (tok.type == Lexer::Tile || tok.type == Lexer::Impl) {
285 if (tok.type == Lexer::Tile) {
286 parseTile();
287 } else {
288 parseImpl();
289 }
290 tok = peekNext();
291 }
292 match(Lexer::RBrace);
293 }
294
parseImpl()295 void Parser::parseImpl()
296 {
297 match(Lexer::Impl);
298 // impl identifier identifier? ( paramList? ) code
299 // paramList := ident ident
300 // paramList := ident ident , paramList
301
302 string ret = matchIdentifier();
303
304 string fn;
305 if (peekNext().type == Lexer::Ident) {
306 fn = matchIdentifier();
307 }
308 match(Lexer::LParen);
309
310 const Flag paramFlags[] = {
311 {"noimm", Param_NoImm},
312 {"noreg", Param_NoReg},
313 {"exact", Param_Exact},
314 {nullptr, 0}
315 };
316
317 // Parse parameter types and names, if any..
318 vector<Parameter> params;
319 while (peekNext().type != Lexer::RParen) {
320 Parameter param;
321 param.typeName = matchIdentifier();
322 param.flags = matchFlags(paramFlags);
323 param.name = matchIdentifier();
324
325 params.push_back(param);
326
327 if (!check(Lexer::Comma)) {
328 break;
329 }
330
331 // Make sure we have an ident next, and not an rparen..
332 if (peekNext().type != Lexer::Ident) {
333 issueError("Parameter signature in impl doesn't start with an identifier!");
334 }
335 }
336 match(Lexer::RParen);
337
338 int cost = 0;
339 if (peekNext().type == Lexer::Costs) {
340 getNext();
341 cost = matchNumber();
342 }
343
344 int codeLine;
345 string code;
346 matchCode(&code, &codeLine);
347
348 handleImpl(fn, code, codeLine, cost, ret, params);
349 }
350
parseTile()351 void Parser::parseTile()
352 {
353 // tile signature as identifier;
354 match(Lexer::Tile);
355
356 StringList paramSigs;
357 match(Lexer::LParen);
358 while (peekNext().type != Lexer::RParen) {
359 paramSigs.push_back(matchIdentifier());
360 if (peekNext().type != Lexer::Comma) {
361 break;
362 }
363 getNext(); // Eat the comma..
364 // Make sure we have an ident next, and not an rparen..
365 if (peekNext().type != Lexer::Ident) {
366 issueError("Parameter signature in tile doesn't start with an identifier!");
367 }
368 }
369
370 match(Lexer::RParen);
371
372 match(Lexer::As);
373 string fn = matchIdentifier();
374 handleTile(fn, paramSigs);
375 match(Lexer::SemiColon);
376 }
377
378