src/Lexer.cc

changeset 119
bdf8d46c145f
parent 118
e3361cf7cbf4
child 120
5ea0faefa82a
equal deleted inserted replaced
118:e3361cf7cbf4 119:bdf8d46c145f
1 /*
2 Copyright 2012-2014 Santeri Piippo
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <cstring>
30 #include "Lexer.h"
31
32 static StringList gFileNameStack;
33 static Lexer* gMainLexer = null;
34
35 // =============================================================================
36 //
37 Lexer::Lexer()
38 {
39 assert (gMainLexer == null);
40 gMainLexer = this;
41 }
42
43 // =============================================================================
44 //
45 Lexer::~Lexer()
46 {
47 gMainLexer = null;
48 }
49
50 // =============================================================================
51 //
52 void Lexer::processFile (String fileName)
53 {
54 gFileNameStack << fileName;
55 FILE* fp = fopen (fileName, "r");
56
57 if (fp == null)
58 error ("couldn't open %1 for reading: %2", fileName, strerror (errno));
59
60 LexerScanner sc (fp);
61 checkFileHeader (sc);
62
63 while (sc.getNextToken())
64 {
65 // Preprocessor commands:
66 if (sc.getTokenType() ==TK_Hash)
67 {
68 mustGetFromScanner (sc,TK_Symbol);
69
70 if (sc.getTokenText() == "include")
71 {
72 mustGetFromScanner (sc,TK_String);
73 String fileName = sc.getTokenText();
74
75 if (gFileNameStack.contains (fileName))
76 error ("attempted to #include %1 recursively", sc.getTokenText());
77
78 processFile (fileName);
79 }
80 else
81 error ("unknown preprocessor directive \"#%1\"", sc.getTokenText());
82 }
83 else
84 {
85 TokenInfo tok;
86 tok.file = fileName;
87 tok.line = sc.getLine();
88 tok.column = sc.getColumn();
89 tok.type = sc.getTokenType();
90 tok.text = sc.getTokenText();
91
92 // devf ("Token #%1: %2:%3:%4: %5 (%6)\n", mTokens.size(),
93 // tok.file, tok.line, tok.column, DescribeToken (&tok),
94 // GetTokenTypeString (tok.type));
95
96 m_tokens << tok;
97 }
98 }
99
100 m_tokenPosition = m_tokens.begin() - 1;
101 gFileNameStack.removeOne (fileName);
102 }
103
104 // ============================================================================
105 //
106 static bool IsValidHeader (String header)
107 {
108 if (header.endsWith ("\n"))
109 header.removeFromEnd (1);
110
111 StringList tokens = header.split (" ");
112
113 if (tokens.size() != 2 || tokens[0] != "#!botc" || tokens[1].isEmpty())
114 return false;
115
116 StringList nums = tokens[1].split (".");
117
118 if (nums.size() == 2)
119 nums << "0";
120 elif (nums.size() != 3)
121 return false;
122
123 bool okA, okB, okC;
124 long major = nums[0].toLong (&okA);
125 long minor = nums[1].toLong (&okB);
126 long patch = nums[2].toLong (&okC);
127
128 if (!okA || !okB || !okC)
129 return false;
130
131 if (VERSION_NUMBER < MAKE_VERSION_NUMBER (major, minor, patch))
132 error ("The script file requires " APPNAME " v%1, this is v%2",
133 makeVersionString (major, minor, patch), versionString (false));
134
135 return true;
136 }
137
138 // ============================================================================
139 //
140 void Lexer::checkFileHeader (LexerScanner& sc)
141 {
142 if (!IsValidHeader (sc.readLine()))
143 error ("Not a valid botscript file! File must start with '#!botc <version>'");
144 }
145
146 // =============================================================================
147 //
148 bool Lexer::next (ETokenType req)
149 {
150 Iterator pos = m_tokenPosition;
151
152 if (m_tokens.isEmpty())
153 return false;
154
155 m_tokenPosition++;
156
157 if (isAtEnd() || (req !=TK_Any && tokenType() != req))
158 {
159 m_tokenPosition = pos;
160 return false;
161 }
162
163 return true;
164 }
165
166 // =============================================================================
167 //
168 void Lexer::mustGetNext (ETokenType tok)
169 {
170 if (!next())
171 error ("unexpected EOF");
172
173 if (tok !=TK_Any)
174 tokenMustBe (tok);
175 }
176
177 // =============================================================================
178 // eugh..
179 //
180 void Lexer::mustGetFromScanner (LexerScanner& sc, ETokenType tt)
181 {
182 if (sc.getNextToken() == false)
183 error ("unexpected EOF");
184
185 if (tt != TK_Any && sc.getTokenType() != tt)
186 {
187 // TODO
188 TokenInfo tok;
189 tok.type = sc.getTokenType();
190 tok.text = sc.getTokenText();
191
192 error ("at %1:%2: expected %3, got %4",
193 gFileNameStack.last(),
194 sc.getLine(),
195 describeTokenType (tt),
196 describeToken (&tok));
197 }
198 }
199
200 // =============================================================================
201 //
202 void Lexer::mustGetAnyOf (const List<ETokenType>& toks)
203 {
204 if (!next())
205 error ("unexpected EOF");
206
207 for (ETokenType tok : toks)
208 if (tokenType() == tok)
209 return;
210
211 String toknames;
212
213 for (const ETokenType& tokType : toks)
214 {
215 if (&tokType == &toks.last())
216 toknames += " or ";
217 elif (toknames.isEmpty() == false)
218 toknames += ", ";
219
220 toknames += describeTokenType (tokType);
221 }
222
223 error ("expected %1, got %2", toknames, describeToken (token()));
224 }
225
226 // =============================================================================
227 //
228 int Lexer::getOneSymbol (const StringList& syms)
229 {
230 if (!next())
231 error ("unexpected EOF");
232
233 if (tokenType() ==TK_Symbol)
234 {
235 for (int i = 0; i < syms.size(); ++i)
236 {
237 if (syms[i] == token()->text)
238 return i;
239 }
240 }
241
242 error ("expected one of %1, got %2", syms, describeToken (token()));
243 return -1;
244 }
245
246 // =============================================================================
247 //
248 void Lexer::tokenMustBe (ETokenType tok)
249 {
250 if (tokenType() != tok)
251 error ("expected %1, got %2", describeTokenType (tok),
252 describeToken (token()));
253 }
254
255 // =============================================================================
256 //
257 String Lexer::describeTokenPrivate (ETokenType tokType, Lexer::TokenInfo* tok)
258 {
259 if (tokType <gLastNamedToken)
260 return "\"" + LexerScanner::getTokenString (tokType) + "\"";
261
262 switch (tokType)
263 {
264 case TK_Symbol: return tok ? tok->text : "a symbol";
265 case TK_Number: return tok ? tok->text : "a number";
266 case TK_String: return tok ? ("\"" + tok->text + "\"") : "a string";
267 case TK_Any: return tok ? tok->text : "any token";
268 default: break;
269 }
270
271 return "";
272 }
273
274 // =============================================================================
275 //
276 bool Lexer::peekNext (Lexer::TokenInfo* tk)
277 {
278 Iterator pos = m_tokenPosition;
279 bool r = next();
280
281 if (r && tk != null)
282 *tk = *m_tokenPosition;
283
284 m_tokenPosition = pos;
285 return r;
286 }
287
288 // =============================================================================
289 //
290 bool Lexer::peekNextType (ETokenType req)
291 {
292 Iterator pos = m_tokenPosition;
293 bool result = false;
294
295 if (next() && tokenType() == req)
296 result = true;
297
298 m_tokenPosition = pos;
299 return result;
300 }
301
302 // =============================================================================
303 //
304 Lexer* Lexer::getCurrentLexer()
305 {
306 return gMainLexer;
307 }
308
309 // =============================================================================
310 //
311 String Lexer::peekNextString (int a)
312 {
313 if (m_tokenPosition + a >= m_tokens.end())
314 return "";
315
316 Iterator oldpos = m_tokenPosition;
317 m_tokenPosition += a;
318 String result = token()->text;
319 m_tokenPosition = oldpos;
320 return result;
321 }
322
323 // =============================================================================
324 //
325 String Lexer::describeCurrentPosition()
326 {
327 return token()->file + ":" + token()->line;
328 }
329
330 // =============================================================================
331 //
332 String Lexer::describeTokenPosition()
333 {
334 return format ("%1 / %2", m_tokenPosition - m_tokens.begin(), m_tokens.size());
335 }
336
337 // =============================================================================
338 //
339 void Lexer::mustGetSymbol (const String& a)
340 {
341 mustGetNext (TK_Any);
342 if (token()->text != a)
343 error ("expected \"%1\", got \"%2\"", a, token()->text);
344 }

mercurial