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