1 /* |
1 #include "main.h" |
2 * botc source code |
|
3 * Copyright (C) 2012 Santeri `Dusk` Piippo |
|
4 * All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright notice, |
|
10 * this list of conditions and the following disclaimer. |
|
11 * 2. Redistributions in binary form must reproduce the above copyright notice, |
|
12 * this list of conditions and the following disclaimer in the documentation |
|
13 * and/or other materials provided with the distribution. |
|
14 * 3. Neither the name of the developer nor the names of its contributors may |
|
15 * be used to endorse or promote products derived from this software without |
|
16 * specific prior written permission. |
|
17 * 4. Redistributions in any form must be accompanied by information on how to |
|
18 * obtain complete source code for the software and any accompanying |
|
19 * software that uses the software. The source code must either be included |
|
20 * in the distribution or be available for no more than the cost of |
|
21 * distribution plus a nominal fee, and must be freely redistributable |
|
22 * under reasonable conditions. For an executable file, complete source |
|
23 * code means the source code for all modules it contains. It does not |
|
24 * include source code for modules or files that typically accompany the |
|
25 * major components of the operating system on which the executable file |
|
26 * runs. |
|
27 * |
|
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
38 * POSSIBILITY OF SUCH DAMAGE. |
|
39 */ |
|
40 |
|
41 #include <stdio.h> |
|
42 #include <stdlib.h> |
|
43 #include "string.h" |
|
44 #include "str.h" |
|
45 #include "common.h" |
|
46 #include "scriptreader.h" |
2 #include "scriptreader.h" |
47 |
3 |
48 #define STORE_POSITION \ |
4 #define STORE_POSITION \ |
49 bool _atnewline = atnewline; \ |
5 bool stored_atnewline = atnewline; \ |
50 unsigned int _curline = curline[fc]; \ |
6 unsigned int stored_curline = curline[fc]; \ |
51 unsigned int _curchar = curchar[fc]; |
7 unsigned int stored_curchar = curchar[fc]; |
52 |
8 |
53 #define RESTORE_POSITION \ |
9 #define RESTORE_POSITION \ |
54 atnewline = _atnewline; \ |
10 atnewline = stored_atnewline; \ |
55 curline[fc] = _curline; \ |
11 curline[fc] = stored_curline; \ |
56 curchar[fc] = _curchar; |
12 curchar[fc] = stored_curchar; |
57 |
13 |
58 // ============================================================================ |
14 // ============================================================================ |
59 ScriptReader::ScriptReader (str path) { |
15 ScriptReader::ScriptReader (string path) { |
60 token = ""; |
16 token = ""; |
61 prevtoken = ""; |
17 prevtoken = ""; |
62 prevpos = 0; |
18 prevpos = 0; |
63 fc = -1; |
19 fc = -1; |
64 |
20 |
65 for (unsigned int u = 0; u < MAX_FILESTACK; u++) |
21 for (unsigned int u = 0; u < MAX_FILESTACK; u++) |
66 fp[u] = NULL; |
22 fp[u] = null; |
67 |
23 |
68 OpenFile (path); |
24 OpenFile (path); |
69 commentmode = 0; |
25 commentmode = 0; |
70 } |
26 } |
71 |
27 |
85 } |
41 } |
86 } |
42 } |
87 |
43 |
88 // ============================================================================ |
44 // ============================================================================ |
89 // Opens a file and pushes its pointer to stack |
45 // Opens a file and pushes its pointer to stack |
90 void ScriptReader::OpenFile (str path) { |
46 void ScriptReader::OpenFile (string path) { |
91 if (fc+1 >= MAX_FILESTACK) |
47 if (fc+1 >= MAX_FILESTACK) |
92 ParserError ("supposed to open file `%s` but file stack is full! do you have recursive `#include` directives?", |
48 ParserError ("supposed to open file `%s` but file stack is full! do you have recursive `#include` directives?", |
93 path.chars()); |
49 path.chars()); |
94 |
50 |
95 // Save the position first. |
51 // Save the position first. |
273 return true; |
229 return true; |
274 } |
230 } |
275 |
231 |
276 // ============================================================================ |
232 // ============================================================================ |
277 // Returns the next token without advancing the cursor. |
233 // Returns the next token without advancing the cursor. |
278 str ScriptReader::PeekNext (int offset) { |
234 string ScriptReader::PeekNext (int offset) { |
279 // Store current information |
235 // Store current information |
280 str storedtoken = token; |
236 string storedtoken = token; |
281 int cpos = ftell (fp[fc]); |
237 int cpos = ftell (fp[fc]); |
282 STORE_POSITION |
238 STORE_POSITION |
283 |
239 |
284 // Advance on the token. |
240 // Advance on the token. |
285 while (offset >= 0) { |
241 while (offset >= 0) { |
286 if (!Next (true)) |
242 if (!Next (true)) |
287 return ""; |
243 return ""; |
288 offset--; |
244 offset--; |
289 } |
245 } |
290 |
246 |
291 str tmp = token; |
247 string tmp = token; |
292 |
248 |
293 // Restore position |
249 // Restore position |
294 fseek (fp[fc], cpos, SEEK_SET); |
250 fseek (fp[fc], cpos, SEEK_SET); |
295 pos[fc]--; |
251 pos[fc]--; |
296 token = storedtoken; |
252 token = storedtoken; |
335 ParserError ("expected `%s`, got `%s` instead", c, token.chars()); |
291 ParserError ("expected `%s`, got `%s` instead", c, token.chars()); |
336 } |
292 } |
337 |
293 |
338 // ============================================================================ |
294 // ============================================================================ |
339 void ScriptReader::ParserError (const char* message, ...) { |
295 void ScriptReader::ParserError (const char* message, ...) { |
340 PERFORM_FORMAT (message, outmessage); |
296 char buf[512]; |
341 ParserMessage ("\nError: ", outmessage); |
297 va_list va; |
|
298 va_start (va, message); |
|
299 sprintf (buf, message, va); |
|
300 va_end (va); |
|
301 ParserMessage ("\nError: ", buf); |
342 exit (1); |
302 exit (1); |
343 } |
303 } |
344 |
304 |
345 // ============================================================================ |
305 // ============================================================================ |
346 void ScriptReader::ParserWarning (const char* message, ...) { |
306 void ScriptReader::ParserWarning (const char* message, ...) { |
347 PERFORM_FORMAT (message, outmessage); |
307 char buf[512]; |
348 ParserMessage ("Warning: ", outmessage); |
308 va_list va; |
349 } |
309 va_start (va, message); |
350 |
310 sprintf (buf, message, va); |
351 // ============================================================================ |
311 va_end (va); |
352 void ScriptReader::ParserMessage (const char* header, char* message) { |
312 ParserMessage ("Warning: ", buf); |
|
313 } |
|
314 |
|
315 // ============================================================================ |
|
316 void ScriptReader::ParserMessage (const char* header, string message) { |
353 if (fc >= 0 && fc < MAX_FILESTACK) |
317 if (fc >= 0 && fc < MAX_FILESTACK) |
354 fprintf (stderr, "%s%s:%u:%u: %s\n", |
318 fprintf (stderr, "%s%s:%u:%u: %s\n", |
355 header, filepath[fc], curline[fc], curchar[fc], message); |
319 header, filepath[fc].c_str(), curline[fc], curchar[fc], message.c_str()); |
356 else |
320 else |
357 fprintf (stderr, "%s%s\n", header, message); |
321 fprintf (stderr, "%s%s\n", header, message.c_str()); |
358 } |
322 } |
359 |
323 |
360 // ============================================================================ |
324 // ============================================================================ |
361 // if gotquote == 1, the current token already holds the quotation mark. |
325 // if gotquote == 1, the current token already holds the quotation mark. |
362 void ScriptReader::MustString (bool gotquote) { |
326 void ScriptReader::MustString (bool gotquote) { |
363 if (gotquote) |
327 if (gotquote) |
364 MustThis ("\""); |
328 MustThis ("\""); |
365 else |
329 else |
366 MustNext ("\""); |
330 MustNext ("\""); |
367 |
331 |
368 str string; |
332 string string; |
369 // Keep reading characters until we find a terminating quote. |
333 // Keep reading characters until we find a terminating quote. |
370 while (1) { |
334 while (1) { |
371 // can't end here! |
335 // can't end here! |
372 if (feof (fp[fc])) |
336 if (feof (fp[fc])) |
373 ParserError ("unterminated string"); |
337 ParserError ("unterminated string"); |
385 // ============================================================================ |
349 // ============================================================================ |
386 void ScriptReader::MustNumber (bool fromthis) { |
350 void ScriptReader::MustNumber (bool fromthis) { |
387 if (!fromthis) |
351 if (!fromthis) |
388 MustNext (); |
352 MustNext (); |
389 |
353 |
390 str num = token; |
354 string num = token; |
391 if (num == "-") { |
355 if (num == "-") { |
392 MustNext (); |
356 MustNext (); |
393 num += token; |
357 num += token; |
394 } |
358 } |
395 |
359 |
396 // "true" and "false" are valid numbers |
360 // "true" and "false" are valid numbers |
397 if (!token.icompare ("true")) |
361 if (-token == "true") |
398 token = "1"; |
362 token = "1"; |
399 else if (!token.icompare ("false")) |
363 else if (-token == "false") |
400 token = "0"; |
364 token = "0"; |
401 else { |
365 else { |
402 if (!token.isnumber()) |
366 bool ok; |
403 ParserError ("expected a number, got `%s`", num.chars()); |
367 int num = token.to_long (&ok); |
404 |
368 |
405 str check; |
369 if (!ok) |
406 check.appendformat ("%d", atoi (num)); |
370 ParserError ("expected a number, got `%s`", token.chars()); |
407 if (token != check) |
371 |
408 ParserWarning ("integer too large: %s -> %s", num.chars(), check.chars()); |
|
409 |
|
410 token = num; |
372 token = num; |
411 } |
373 } |
412 } |
374 } |