24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
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 |
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. |
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 */ |
27 */ |
28 |
28 |
29 #include "object_writer.h" |
|
30 #include "parser.h" |
29 #include "parser.h" |
31 #include "events.h" |
30 #include "events.h" |
32 #include "commands.h" |
31 #include "commands.h" |
33 #include "stringtable.h" |
32 #include "stringtable.h" |
34 #include "variables.h" |
33 #include "variables.h" |
35 #include "containers.h" |
34 #include "containers.h" |
36 #include "lexer.h" |
35 #include "lexer.h" |
37 |
36 #include "data_buffer.h" |
38 #define SCOPE(n) scopestack[g_ScopeCursor - n] |
37 |
39 |
38 #define SCOPE(n) (m_scope_stack[m_scope_cursor - n]) |
40 // TODO: make these static |
|
41 int g_NumStates = 0; |
|
42 int g_NumEvents = 0; |
|
43 parsermode_e g_current_mode = MODE_TOPLEVEL; |
|
44 string g_CurState = ""; |
|
45 bool g_stateSpawnDefined = false; |
|
46 bool g_GotMainLoop = false; |
|
47 int g_ScopeCursor = 0; |
|
48 data_buffer* g_IfExpression = null; |
|
49 bool g_CanElse = false; |
|
50 static string* g_undefined_labels[MAX_MARKS]; // TODO: make a list |
|
51 list<constant_info> g_ConstInfo; |
|
52 |
39 |
53 // ============================================================================ |
40 // ============================================================================ |
54 // |
41 // |
55 botscript_parser::botscript_parser() : |
42 botscript_parser::botscript_parser() : |
56 m_lx (new lexer) {} |
43 m_lx (new lexer) {} |
64 |
51 |
65 // ============================================================================ |
52 // ============================================================================ |
66 // |
53 // |
67 void botscript_parser::check_toplevel() |
54 void botscript_parser::check_toplevel() |
68 { |
55 { |
69 if (g_current_mode != MODE_TOPLEVEL) |
56 if (m_current_mode != MODE_TOPLEVEL) |
70 error ("%1-statements may only be defined at top level!", token_string()); |
57 error ("%1-statements may only be defined at top level!", token_string()); |
71 } |
58 } |
72 |
59 |
73 // ============================================================================ |
60 // ============================================================================ |
74 // |
61 // |
75 void botscript_parser::check_not_toplevel() |
62 void botscript_parser::check_not_toplevel() |
76 { |
63 { |
77 if (g_current_mode == MODE_TOPLEVEL) |
64 if (m_current_mode == MODE_TOPLEVEL) |
78 error ("%1-statements must not be defined at top level!", token_string()); |
65 error ("%1-statements must not be defined at top level!", token_string()); |
79 } |
66 } |
80 |
67 |
81 // ============================================================================ |
68 // ============================================================================ |
82 // Main parser code. Begins read of the script file, checks the syntax of it |
69 // Main parser code. Begins read of the script file, checks the syntax of it |
83 // and writes the data to the object file via Objwriter - which also takes care |
70 // and writes the data to the object file via Objwriter - which also takes care |
84 // of necessary buffering so stuff is written in the correct order. |
71 // of necessary buffering so stuff is written in the correct order. |
85 void botscript_parser::parse_botscript (string file_name, object_writer* w) |
72 void botscript_parser::parse_botscript (string file_name) |
86 { |
73 { |
87 m_writer = w; |
|
88 |
|
89 // Lex and preprocess the file |
74 // Lex and preprocess the file |
90 m_lx->process_file (file_name); |
75 m_lx->process_file (file_name); |
|
76 |
|
77 m_current_mode = MODE_TOPLEVEL; |
|
78 m_num_states = 0; |
|
79 m_num_events = 0; |
|
80 m_scope_cursor = 0; |
|
81 m_state_spawn_defined = false; |
|
82 m_got_main_loop = false; |
|
83 m_if_expression = null; |
|
84 m_can_else = false; |
91 |
85 |
92 // Zero the entire block stack first |
86 // Zero the entire block stack first |
93 // TODO: this shouldn't be necessary |
87 // TODO: this shouldn't be necessary |
94 for (int i = 0; i < MAX_SCOPE; i++) |
88 for (int i = 0; i < MAX_SCOPE; i++) |
95 ZERO (scopestack[i]); |
89 ZERO (m_scope_stack[i]); |
96 |
|
97 for (int i = 0; i < MAX_MARKS; i++) |
|
98 g_undefined_labels[i] = null; |
|
99 |
90 |
100 while (m_lx->get_next()) |
91 while (m_lx->get_next()) |
101 { |
92 { |
102 // Check if else is potentically valid |
93 // Check if else is potentically valid |
103 if (token_is (tk_else) && !g_CanElse) |
94 if (token_is (tk_else) && !m_can_else) |
104 error ("else without preceding if"); |
95 error ("else without preceding if"); |
105 |
96 |
106 if (!token_is (tk_else)) |
97 if (!token_is (tk_else)) |
107 g_CanElse = false; |
98 m_can_else = false; |
108 |
99 |
109 switch (m_lx->get_token()->type) |
100 switch (m_lx->get_token()->type) |
110 { |
101 { |
111 case tk_state: |
102 case tk_state: |
112 parse_state_block(); |
103 parse_state_block(); |
207 // Check if it's a command |
198 // Check if it's a command |
208 command_info* comm = find_command_by_name (token_string()); |
199 command_info* comm = find_command_by_name (token_string()); |
209 |
200 |
210 if (comm) |
201 if (comm) |
211 { |
202 { |
212 m_writer->get_current_buffer()->merge (ParseCommand (comm)); |
203 buffer()->merge_and_destroy (parse_command (comm)); |
213 m_lx->must_get_next (tk_semicolon); |
204 m_lx->must_get_next (tk_semicolon); |
214 continue; |
205 continue; |
215 } |
206 } |
216 |
207 |
217 // If nothing else, parse it as a statement |
208 // If nothing else, parse it as a statement |
218 data_buffer* b = parse_statement(); |
209 data_buffer* b = parse_statement(); |
219 |
210 |
220 if (!b) |
211 if (!b) |
221 error ("unknown token `%1`", token_string()); |
212 error ("unknown token `%1`", token_string()); |
222 |
213 |
223 m_writer->write_buffer (b); |
214 buffer()->merge_and_destroy (b); |
224 m_lx->must_get_next (tk_semicolon); |
215 m_lx->must_get_next (tk_semicolon); |
225 } |
216 } |
226 break; |
217 break; |
227 } |
218 } |
228 } |
219 } |
229 |
220 |
230 // =============================================================================== |
221 // =============================================================================== |
231 // Script file ended. Do some last checks and write the last things to main buffer |
222 // Script file ended. Do some last checks and write the last things to main buffer |
232 if (g_current_mode != MODE_TOPLEVEL) |
223 if (m_current_mode != MODE_TOPLEVEL) |
233 error ("script did not end at top level; a `}` is missing somewhere"); |
224 error ("script did not end at top level; a `}` is missing somewhere"); |
234 |
225 |
235 // stateSpawn must be defined! |
226 // stateSpawn must be defined! |
236 if (!g_stateSpawnDefined) |
227 if (!m_state_spawn_defined) |
237 error ("script must have a state named `stateSpawn`!"); |
228 error ("script must have a state named `stateSpawn`!"); |
238 |
229 |
239 for (int i = 0; i < MAX_MARKS; i++) |
230 // Ensure no goto target is left undefined |
240 if (g_undefined_labels[i]) |
231 if (m_undefined_labels.is_empty() == false) |
241 error ("label `%1` is referenced via `goto` but isn't defined\n", g_undefined_labels[i]); |
232 { |
|
233 string_list names; |
|
234 |
|
235 for (undefined_label& undf : m_undefined_labels) |
|
236 names << undf.name; |
|
237 |
|
238 error ("labels `%1` are referenced via `goto` but are not defined\n", names); |
|
239 } |
242 |
240 |
243 // Dump the last state's onenter and mainloop |
241 // Dump the last state's onenter and mainloop |
244 m_writer->write_member_buffers(); |
242 write_member_buffers(); |
245 |
243 |
246 // String table |
244 // String table |
247 m_writer->write_string_table(); |
245 write_string_table(); |
248 } |
246 } |
249 |
247 |
250 // ============================================================================ |
248 // ============================================================================ |
251 // |
249 // |
252 void botscript_parser::parse_state_block() |
250 void botscript_parser::parse_state_block() |
260 error ("state name must be a single word, got `%1`", statename); |
258 error ("state name must be a single word, got `%1`", statename); |
261 |
259 |
262 // stateSpawn is special - it *must* be defined. If we |
260 // stateSpawn is special - it *must* be defined. If we |
263 // encountered it, then mark down that we have it. |
261 // encountered it, then mark down that we have it. |
264 if (-statename == "statespawn") |
262 if (-statename == "statespawn") |
265 g_stateSpawnDefined = true; |
263 m_state_spawn_defined = true; |
266 |
264 |
267 // Must end in a colon |
265 // Must end in a colon |
268 m_lx->must_get_next (tk_colon); |
266 m_lx->must_get_next (tk_colon); |
269 |
267 |
270 // write the previous state's onenter and |
268 // write the previous state's onenter and |
271 // mainloop buffers to file now |
269 // mainloop buffers to file now |
272 if (g_CurState.is_empty() == false) |
270 if (m_current_state.is_empty() == false) |
273 m_writer->write_member_buffers(); |
271 write_member_buffers(); |
274 |
272 |
275 m_writer->write (dh_state_name); |
273 buffer()->write_dword (dh_state_name); |
276 m_writer->write_string (statename); |
274 buffer()->write_string (statename); |
277 m_writer->write (dh_state_index); |
275 buffer()->write_dword (dh_state_index); |
278 m_writer->write (g_NumStates); |
276 buffer()->write_dword (m_num_states); |
279 |
277 |
280 g_NumStates++; |
278 m_num_states++; |
281 g_CurState = statename; |
279 m_current_state = statename; |
282 g_GotMainLoop = false; |
280 m_got_main_loop = false; |
283 } |
281 } |
284 |
282 |
285 // ============================================================================ |
283 // ============================================================================ |
286 // |
284 // |
287 void botscript_parser::parse_event_block() |
285 void botscript_parser::parse_event_block() |
293 |
291 |
294 if (!e) |
292 if (!e) |
295 error ("bad event, got `%1`\n", token_string()); |
293 error ("bad event, got `%1`\n", token_string()); |
296 |
294 |
297 m_lx->must_get_next (tk_brace_start); |
295 m_lx->must_get_next (tk_brace_start); |
298 g_current_mode = MODE_EVENT; |
296 m_current_mode = MODE_EVENT; |
299 m_writer->write (dh_event); |
297 buffer()->write_dword (dh_event); |
300 m_writer->write (e->number); |
298 buffer()->write_dword (e->number); |
301 g_NumEvents++; |
299 m_num_events++; |
302 } |
300 } |
303 |
301 |
304 // ============================================================================ |
302 // ============================================================================ |
305 // |
303 // |
306 void botscript_parser::parse_mainloop() |
304 void botscript_parser::parse_mainloop() |
307 { |
305 { |
308 check_toplevel(); |
306 check_toplevel(); |
309 m_lx->must_get_next (tk_brace_start); |
307 m_lx->must_get_next (tk_brace_start); |
310 |
308 |
311 // Mode must be set before dataheader is written here! |
309 m_current_mode = MODE_MAINLOOP; |
312 g_current_mode = MODE_MAINLOOP; |
310 m_main_loop_buffer->write_dword (dh_main_loop); |
313 m_writer->write (dh_main_loop); |
|
314 } |
311 } |
315 |
312 |
316 // ============================================================================ |
313 // ============================================================================ |
317 // |
314 // |
318 void botscript_parser::parse_on_enter_exit() |
315 void botscript_parser::parse_on_enter_exit() |
319 { |
316 { |
320 check_toplevel(); |
317 check_toplevel(); |
321 bool onenter = (token_is (tk_onenter)); |
318 bool onenter = (token_is (tk_onenter)); |
322 m_lx->must_get_next (tk_brace_start); |
319 m_lx->must_get_next (tk_brace_start); |
323 |
320 |
324 // Mode must be set before dataheader is written here, |
321 m_current_mode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
325 // because onenter goes to a separate buffer. |
322 buffer()->write_dword (onenter ? dh_on_enter : dh_on_exit); |
326 g_current_mode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
|
327 m_writer->write (onenter ? dh_on_enter : dh_on_exit); |
|
328 } |
323 } |
329 |
324 |
330 // ============================================================================ |
325 // ============================================================================ |
331 // |
326 // |
332 void botscript_parser::parse_variable_declaration() |
327 void botscript_parser::parse_variable_declaration() |
333 { |
328 { |
334 // For now, only globals are supported |
329 // For now, only globals are supported |
335 if (g_current_mode != MODE_TOPLEVEL || g_CurState.is_empty() == false) |
330 if (m_current_mode != MODE_TOPLEVEL || m_current_state.is_empty() == false) |
336 error ("variables must only be global for now"); |
331 error ("variables must only be global for now"); |
337 |
332 |
338 type_e type = (token_is (tk_int)) ? TYPE_INT : |
333 type_e type = (token_is (tk_int)) ? TYPE_INT : |
339 (token_is (tk_str)) ? TYPE_STRING : |
334 (token_is (tk_str)) ? TYPE_STRING : |
340 TYPE_BOOL; |
335 TYPE_BOOL; |
360 // Get the name of the label |
355 // Get the name of the label |
361 m_lx->must_get_next(); |
356 m_lx->must_get_next(); |
362 |
357 |
363 // Find the mark this goto statement points to |
358 // Find the mark this goto statement points to |
364 string target = token_string(); |
359 string target = token_string(); |
365 int m = m_writer->find_byte_mark (target); |
360 byte_mark* mark = buffer()->find_mark_by_name (target); |
366 |
361 |
367 // If not set, define it |
362 // If not set, define it |
368 if (m == MAX_MARKS) |
363 if (!mark) |
369 { |
364 { |
370 m = m_writer->add_mark (target); |
365 undefined_label undf; |
371 g_undefined_labels[m] = new string (target); |
366 undf.name = target; |
|
367 undf.target = buffer()->add_mark (target); |
|
368 m_undefined_labels << undf; |
372 } |
369 } |
373 |
370 |
374 // Add a reference to the mark. |
371 // Add a reference to the mark. |
375 m_writer->write (dh_goto); |
372 buffer()->write_dword (dh_goto); |
376 m_writer->add_reference (m); |
373 buffer()->add_reference (mark); |
377 m_lx->must_get_next (tk_semicolon); |
374 m_lx->must_get_next (tk_semicolon); |
378 } |
375 } |
379 |
376 |
380 // ============================================================================ |
377 // ============================================================================ |
381 // |
378 // |
388 m_lx->must_get_next (tk_paren_start); |
385 m_lx->must_get_next (tk_paren_start); |
389 |
386 |
390 // Read the expression and write it. |
387 // Read the expression and write it. |
391 m_lx->must_get_next(); |
388 m_lx->must_get_next(); |
392 data_buffer* c = parse_expression (TYPE_INT); |
389 data_buffer* c = parse_expression (TYPE_INT); |
393 m_writer->write_buffer (c); |
390 buffer()->merge_and_destroy (c); |
394 |
391 |
395 m_lx->must_get_next (tk_paren_end); |
392 m_lx->must_get_next (tk_paren_end); |
396 m_lx->must_get_next (tk_brace_start); |
393 m_lx->must_get_next (tk_brace_start); |
397 |
394 |
398 // Add a mark - to here temporarily - and add a reference to it. |
395 // Add a mark - to here temporarily - and add a reference to it. |
399 // Upon a closing brace, the mark will be adjusted. |
396 // Upon a closing brace, the mark will be adjusted. |
400 int marknum = m_writer->add_mark (""); |
397 byte_mark* mark = buffer()->add_mark (""); |
401 |
398 |
402 // Use dh_if_not_goto - if the expression is not true, we goto the mark |
399 // Use dh_if_not_goto - if the expression is not true, we goto the mark |
403 // we just defined - and this mark will be at the end of the scope block. |
400 // we just defined - and this mark will be at the end of the scope block. |
404 m_writer->write (dh_if_not_goto); |
401 buffer()->write_dword (dh_if_not_goto); |
405 m_writer->add_reference (marknum); |
402 buffer()->add_reference (mark); |
406 |
403 |
407 // Store it |
404 // Store it |
408 SCOPE (0).mark1 = marknum; |
405 SCOPE (0).mark1 = mark; |
409 SCOPE (0).type = e_if_scope; |
406 SCOPE (0).type = e_if_scope; |
410 } |
407 } |
411 |
408 |
412 // ============================================================================ |
409 // ============================================================================ |
413 // |
410 // |
415 { |
412 { |
416 check_not_toplevel(); |
413 check_not_toplevel(); |
417 m_lx->must_get_next (tk_brace_start); |
414 m_lx->must_get_next (tk_brace_start); |
418 |
415 |
419 // Don't use PushScope as it resets the scope |
416 // Don't use PushScope as it resets the scope |
420 g_ScopeCursor++; |
417 m_scope_cursor++; |
421 |
418 |
422 if (g_ScopeCursor >= MAX_SCOPE) |
419 if (m_scope_cursor >= MAX_SCOPE) |
423 error ("too deep scope"); |
420 error ("too deep scope"); |
424 |
421 |
425 if (SCOPE (0).type != e_if_scope) |
422 if (SCOPE (0).type != e_if_scope) |
426 error ("else without preceding if"); |
423 error ("else without preceding if"); |
427 |
424 |
428 // write down to jump to the end of the else statement |
425 // write down to jump to the end of the else statement |
429 // Otherwise we have fall-throughs |
426 // Otherwise we have fall-throughs |
430 SCOPE (0).mark2 = m_writer->add_mark (""); |
427 SCOPE (0).mark2 = buffer()->add_mark (""); |
431 |
428 |
432 // Instruction to jump to the end after if block is complete |
429 // Instruction to jump to the end after if block is complete |
433 m_writer->write (dh_goto); |
430 buffer()->write_dword (dh_goto); |
434 m_writer->add_reference (SCOPE (0).mark2); |
431 buffer()->add_reference (SCOPE (0).mark2); |
435 |
432 |
436 // Move the ifnot mark here and set type to else |
433 // Move the ifnot mark here and set type to else |
437 m_writer->move_mark (SCOPE (0).mark1); |
434 buffer()->adjust_mark (SCOPE (0).mark1); |
438 SCOPE (0).type = e_else_scope; |
435 SCOPE (0).type = e_else_scope; |
439 } |
436 } |
440 |
437 |
441 // ============================================================================ |
438 // ============================================================================ |
442 // |
439 // |
447 |
444 |
448 // While loops need two marks - one at the start of the loop and one at the |
445 // While loops need two marks - one at the start of the loop and one at the |
449 // end. The condition is checked at the very start of the loop, if it fails, |
446 // end. The condition is checked at the very start of the loop, if it fails, |
450 // we use goto to skip to the end of the loop. At the end, we loop back to |
447 // we use goto to skip to the end of the loop. At the end, we loop back to |
451 // the beginning with a go-to statement. |
448 // the beginning with a go-to statement. |
452 int mark1 = m_writer->add_mark (""); // start |
449 byte_mark* mark1 = buffer()->add_mark (""); // start |
453 int mark2 = m_writer->add_mark (""); // end |
450 byte_mark* mark2 = buffer()->add_mark (""); // end |
454 |
451 |
455 // Condition |
452 // Condition |
456 m_lx->must_get_next (tk_paren_start); |
453 m_lx->must_get_next (tk_paren_start); |
457 m_lx->must_get_next(); |
454 m_lx->must_get_next(); |
458 data_buffer* expr = parse_expression (TYPE_INT); |
455 data_buffer* expr = parse_expression (TYPE_INT); |
459 m_lx->must_get_next (tk_paren_end); |
456 m_lx->must_get_next (tk_paren_end); |
460 m_lx->must_get_next (tk_brace_start); |
457 m_lx->must_get_next (tk_brace_start); |
461 |
458 |
462 // write condition |
459 // write condition |
463 m_writer->write_buffer (expr); |
460 buffer()->merge_and_destroy (expr); |
464 |
461 |
465 // Instruction to go to the end if it fails |
462 // Instruction to go to the end if it fails |
466 m_writer->write (dh_if_not_goto); |
463 buffer()->write_dword (dh_if_not_goto); |
467 m_writer->add_reference (mark2); |
464 buffer()->add_reference (mark2); |
468 |
465 |
469 // Store the needed stuff |
466 // Store the needed stuff |
470 SCOPE (0).mark1 = mark1; |
467 SCOPE (0).mark1 = mark1; |
471 SCOPE (0).mark2 = mark2; |
468 SCOPE (0).mark2 = mark2; |
472 SCOPE (0).type = e_while_scope; |
469 SCOPE (0).type = e_while_scope; |
507 |
504 |
508 m_lx->must_get_next (tk_paren_end); |
505 m_lx->must_get_next (tk_paren_end); |
509 m_lx->must_get_next (tk_brace_start); |
506 m_lx->must_get_next (tk_brace_start); |
510 |
507 |
511 // First, write out the initializer |
508 // First, write out the initializer |
512 m_writer->write_buffer (init); |
509 buffer()->merge_and_destroy (init); |
513 |
510 |
514 // Init two marks |
511 // Init two marks |
515 int mark1 = m_writer->add_mark (""); |
512 byte_mark* mark1 = buffer()->add_mark (""); |
516 int mark2 = m_writer->add_mark (""); |
513 byte_mark* mark2 = buffer()->add_mark (""); |
517 |
514 |
518 // Add the condition |
515 // Add the condition |
519 m_writer->write_buffer (cond); |
516 buffer()->merge_and_destroy (cond); |
520 m_writer->write (dh_if_not_goto); |
517 buffer()->write_dword (dh_if_not_goto); |
521 m_writer->add_reference (mark2); |
518 buffer()->add_reference (mark2); |
522 |
519 |
523 // Store the marks and incrementor |
520 // Store the marks and incrementor |
524 SCOPE (0).mark1 = mark1; |
521 SCOPE (0).mark1 = mark1; |
525 SCOPE (0).mark2 = mark2; |
522 SCOPE (0).mark2 = mark2; |
526 SCOPE (0).buffer1 = incr; |
523 SCOPE (0).buffer1 = incr; |
557 |
554 |
558 check_not_toplevel(); |
555 check_not_toplevel(); |
559 push_scope(); |
556 push_scope(); |
560 m_lx->must_get_next (tk_paren_start); |
557 m_lx->must_get_next (tk_paren_start); |
561 m_lx->must_get_next(); |
558 m_lx->must_get_next(); |
562 m_writer->write_buffer (parse_expression (TYPE_INT)); |
559 buffer()->merge_and_destroy (parse_expression (TYPE_INT)); |
563 m_lx->must_get_next (tk_paren_end); |
560 m_lx->must_get_next (tk_paren_end); |
564 m_lx->must_get_next (tk_brace_start); |
561 m_lx->must_get_next (tk_brace_start); |
565 SCOPE (0).type = e_switch_scope; |
562 SCOPE (0).type = e_switch_scope; |
566 SCOPE (0).mark1 = m_writer->add_mark (""); // end mark |
563 SCOPE (0).mark1 = buffer()->add_mark (""); // end mark |
567 SCOPE (0).buffer1 = null; // default header |
564 SCOPE (0).buffer1 = null; // default header |
568 } |
565 } |
569 |
566 |
570 // ============================================================================ |
567 // ============================================================================ |
571 // |
568 // |
582 |
579 |
583 for (int i = 0; i < MAX_CASE; i++) |
580 for (int i = 0; i < MAX_CASE; i++) |
584 if (SCOPE (0).casenumbers[i] == num) |
581 if (SCOPE (0).casenumbers[i] == num) |
585 error ("multiple case %d labels in one switch", num); |
582 error ("multiple case %d labels in one switch", num); |
586 |
583 |
587 // write down the expression and case-go-to. This builds |
584 // Write down the expression and case-go-to. This builds |
588 // the case tree. The closing event will write the actual |
585 // the case tree. The closing event will write the actual |
589 // blocks and move the marks appropriately. |
586 // blocks and move the marks appropriately. |
590 // AddSwitchCase will add the reference to the mark |
587 // |
|
588 // AddSwitchCase will add the reference to the mark |
591 // for the case block that this heralds, and takes care |
589 // for the case block that this heralds, and takes care |
592 // of buffering setup and stuff like that. |
590 // of buffering setup and stuff like that. |
593 // null the switch buffer for the case-go-to statement, |
591 // |
|
592 // We null the switch buffer for the case-go-to statement as |
594 // we want it all under the switch, not into the case-buffers. |
593 // we want it all under the switch, not into the case-buffers. |
595 m_writer->SwitchBuffer = null; |
594 m_switch_buffer = null; |
596 m_writer->write (dh_case_goto); |
595 buffer()->write_dword (dh_case_goto); |
597 m_writer->write (num); |
596 buffer()->write_dword (num); |
598 add_switch_case (null); |
597 add_switch_case (null); |
599 SCOPE (0).casenumbers[SCOPE (0).casecursor] = num; |
598 SCOPE (0).casenumbers[SCOPE (0).casecursor] = num; |
600 } |
599 } |
601 |
600 |
602 // ============================================================================ |
601 // ============================================================================ |
618 // and is only popped when case succeeds, we have |
617 // and is only popped when case succeeds, we have |
619 // to pop it with dh_drop manually if we end up in |
618 // to pop it with dh_drop manually if we end up in |
620 // a default. |
619 // a default. |
621 data_buffer* b = new data_buffer; |
620 data_buffer* b = new data_buffer; |
622 SCOPE (0).buffer1 = b; |
621 SCOPE (0).buffer1 = b; |
623 b->write (dh_drop); |
622 b->write_dword (dh_drop); |
624 b->write (dh_goto); |
623 b->write_dword (dh_goto); |
625 add_switch_case (b); |
624 add_switch_case (b); |
626 } |
625 } |
627 |
626 |
628 // ============================================================================ |
627 // ============================================================================ |
629 // |
628 // |
630 void botscript_parser::parse_break() |
629 void botscript_parser::parse_break() |
631 { |
630 { |
632 if (!g_ScopeCursor) |
631 if (!m_scope_cursor) |
633 error ("unexpected `break`"); |
632 error ("unexpected `break`"); |
634 |
633 |
635 m_writer->write (dh_goto); |
634 buffer()->write_dword (dh_goto); |
636 |
635 |
637 // switch and if use mark1 for the closing point, |
636 // switch and if use mark1 for the closing point, |
638 // for and while use mark2. |
637 // for and while use mark2. |
639 switch (SCOPE (0).type) |
638 switch (SCOPE (0).type) |
640 { |
639 { |
641 case e_if_scope: |
640 case e_if_scope: |
642 case e_switch_scope: |
641 case e_switch_scope: |
643 { |
642 { |
644 m_writer->add_reference (SCOPE (0).mark1); |
643 buffer()->add_reference (SCOPE (0).mark1); |
645 } break; |
644 } break; |
646 |
645 |
647 case e_for_scope: |
646 case e_for_scope: |
648 case e_while_scope: |
647 case e_while_scope: |
649 { |
648 { |
650 m_writer->add_reference (SCOPE (0).mark2); |
649 buffer()->add_reference (SCOPE (0).mark2); |
651 } break; |
650 } break; |
652 |
651 |
653 default: |
652 default: |
654 { |
653 { |
655 error ("unexpected `break`"); |
654 error ("unexpected `break`"); |
696 // |
695 // |
697 void botscript_parser::parse_block_end() |
696 void botscript_parser::parse_block_end() |
698 { |
697 { |
699 // Closing brace |
698 // Closing brace |
700 // If we're in the block stack, we're descending down from it now |
699 // If we're in the block stack, we're descending down from it now |
701 if (g_ScopeCursor > 0) |
700 if (m_scope_cursor > 0) |
702 { |
701 { |
703 switch (SCOPE (0).type) |
702 switch (SCOPE (0).type) |
704 { |
703 { |
705 case e_if_scope: |
704 case e_if_scope: |
706 // Adjust the closing mark. |
705 // Adjust the closing mark. |
707 m_writer->move_mark (SCOPE (0).mark1); |
706 buffer()->adjust_mark (SCOPE (0).mark1); |
708 |
707 |
709 // We're returning from if, thus else can be next |
708 // We're returning from if, thus else can be next |
710 g_CanElse = true; |
709 m_can_else = true; |
711 break; |
710 break; |
712 |
711 |
713 case e_else_scope: |
712 case e_else_scope: |
714 // else instead uses mark1 for itself (so if expression |
713 // else instead uses mark1 for itself (so if expression |
715 // fails, jump to else), mark2 means end of else |
714 // fails, jump to else), mark2 means end of else |
716 m_writer->move_mark (SCOPE (0).mark2); |
715 buffer()->adjust_mark (SCOPE (0).mark2); |
717 break; |
716 break; |
718 |
717 |
719 case e_for_scope: |
718 case e_for_scope: |
720 // write the incrementor at the end of the loop block |
719 // write the incrementor at the end of the loop block |
721 m_writer->write_buffer (SCOPE (0).buffer1); |
720 buffer()->merge_and_destroy (SCOPE (0).buffer1); |
722 |
721 |
723 // fall-thru |
722 // fall-thru |
724 case e_while_scope: |
723 case e_while_scope: |
725 // write down the instruction to go back to the start of the loop |
724 // write down the instruction to go back to the start of the loop |
726 m_writer->write (dh_goto); |
725 buffer()->write_dword (dh_goto); |
727 m_writer->add_reference (SCOPE (0).mark1); |
726 buffer()->add_reference (SCOPE (0).mark1); |
728 |
727 |
729 // Move the closing mark here since we're at the end of the while loop |
728 // Move the closing mark here since we're at the end of the while loop |
730 m_writer->move_mark (SCOPE (0).mark2); |
729 buffer()->adjust_mark (SCOPE (0).mark2); |
731 break; |
730 break; |
732 |
731 |
733 case e_do_scope: |
732 case e_do_scope: |
734 { |
733 { |
735 m_lx->must_get_next (tk_while); |
734 m_lx->must_get_next (tk_while); |
738 data_buffer* expr = parse_expression (TYPE_INT); |
737 data_buffer* expr = parse_expression (TYPE_INT); |
739 m_lx->must_get_next (tk_paren_end); |
738 m_lx->must_get_next (tk_paren_end); |
740 m_lx->must_get_next (tk_semicolon); |
739 m_lx->must_get_next (tk_semicolon); |
741 |
740 |
742 // If the condition runs true, go back to the start. |
741 // If the condition runs true, go back to the start. |
743 m_writer->write_buffer (expr); |
742 buffer()->merge_and_destroy (expr); |
744 m_writer->write (dh_if_goto); |
743 buffer()->write_dword (dh_if_goto); |
745 m_writer->add_reference (SCOPE (0).mark1); |
744 buffer()->add_reference (SCOPE (0).mark1); |
746 break; |
745 break; |
747 } |
746 } |
748 |
747 |
749 case e_switch_scope: |
748 case e_switch_scope: |
750 { |
749 { |
751 // Switch closes. Move down to the record buffer of |
750 // Switch closes. Move down to the record buffer of |
752 // the lower block. |
751 // the lower block. |
753 if (SCOPE (1).casecursor != -1) |
752 if (SCOPE (1).casecursor != -1) |
754 m_writer->SwitchBuffer = SCOPE (1).casebuffers[SCOPE (1).casecursor]; |
753 m_switch_buffer = SCOPE (1).casebuffers[SCOPE (1).casecursor]; |
755 else |
754 else |
756 m_writer->SwitchBuffer = null; |
755 m_switch_buffer = null; |
757 |
756 |
758 // If there was a default in the switch, write its header down now. |
757 // If there was a default in the switch, write its header down now. |
759 // If not, write instruction to jump to the end of switch after |
758 // If not, write instruction to jump to the end of switch after |
760 // the headers (thus won't fall-through if no case matched) |
759 // the headers (thus won't fall-through if no case matched) |
761 if (SCOPE (0).buffer1) |
760 if (SCOPE (0).buffer1) |
762 m_writer->write_buffer (SCOPE (0).buffer1); |
761 buffer()->merge_and_destroy (SCOPE (0).buffer1); |
763 else |
762 else |
764 { |
763 { |
765 m_writer->write (dh_drop); |
764 buffer()->write_dword (dh_drop); |
766 m_writer->write (dh_goto); |
765 buffer()->write_dword (dh_goto); |
767 m_writer->add_reference (SCOPE (0).mark1); |
766 buffer()->add_reference (SCOPE (0).mark1); |
768 } |
767 } |
769 |
768 |
770 // Go through all of the buffers we |
769 // Go through all of the buffers we |
771 // recorded down and write them. |
770 // recorded down and write them. |
772 for (int u = 0; u < MAX_CASE; u++) |
771 for (int u = 0; u < MAX_CASE; u++) |
773 { |
772 { |
774 if (!SCOPE (0).casebuffers[u]) |
773 if (!SCOPE (0).casebuffers[u]) |
775 continue; |
774 continue; |
776 |
775 |
777 m_writer->move_mark (SCOPE (0).casemarks[u]); |
776 buffer()->adjust_mark (SCOPE (0).casemarks[u]); |
778 m_writer->write_buffer (SCOPE (0).casebuffers[u]); |
777 buffer()->merge_and_destroy (SCOPE (0).casebuffers[u]); |
779 } |
778 } |
780 |
779 |
781 // Move the closing mark here |
780 // Move the closing mark here |
782 m_writer->move_mark (SCOPE (0).mark1); |
781 buffer()->adjust_mark (SCOPE (0).mark1); |
783 break; |
782 break; |
784 } |
783 } |
785 |
784 |
786 case e_unknown_scope: |
785 case e_unknown_scope: |
787 break; |
786 break; |
788 } |
787 } |
789 |
788 |
790 // Descend down the stack |
789 // Descend down the stack |
791 g_ScopeCursor--; |
790 m_scope_cursor--; |
792 return; |
791 return; |
793 } |
792 } |
794 |
793 |
795 int dataheader = (g_current_mode == MODE_EVENT) ? dh_end_event : |
794 int dataheader = (m_current_mode == MODE_EVENT) ? dh_end_event : |
796 (g_current_mode == MODE_MAINLOOP) ? dh_end_main_loop : |
795 (m_current_mode == MODE_MAINLOOP) ? dh_end_main_loop : |
797 (g_current_mode == MODE_ONENTER) ? dh_end_on_enter : |
796 (m_current_mode == MODE_ONENTER) ? dh_end_on_enter : |
798 (g_current_mode == MODE_ONEXIT) ? dh_end_on_exit : -1; |
797 (m_current_mode == MODE_ONEXIT) ? dh_end_on_exit : -1; |
799 |
798 |
800 if (dataheader == -1) |
799 if (dataheader == -1) |
801 error ("unexpected `}`"); |
800 error ("unexpected `}`"); |
802 |
801 |
803 // Data header must be written before mode is changed because |
802 // Data header must be written before mode is changed because |
804 // onenter and mainloop go into special buffers, and we want |
803 // onenter and mainloop go into special buffers, and we want |
805 // the closing data headers into said buffers too. |
804 // the closing data headers into said buffers too. |
806 m_writer->write (dataheader); |
805 buffer()->write_dword (dataheader); |
807 g_current_mode = MODE_TOPLEVEL; |
806 m_current_mode = MODE_TOPLEVEL; |
808 m_lx->get_next (tk_semicolon); |
807 m_lx->get_next (tk_semicolon); |
809 } |
808 } |
810 |
809 |
811 // ============================================================================ |
810 // ============================================================================ |
812 // |
811 // |
844 case TYPE_VOID: |
843 case TYPE_VOID: |
845 break; |
844 break; |
846 } |
845 } |
847 |
846 |
848 info.val = m_lx->get_token()->text; |
847 info.val = m_lx->get_token()->text; |
849 g_ConstInfo << info; |
848 m_constants << info; |
850 |
849 |
851 m_lx->must_get_next (tk_semicolon); |
850 m_lx->must_get_next (tk_semicolon); |
852 } |
851 } |
853 |
852 |
854 // ============================================================================ |
853 // ============================================================================ |
855 // |
854 // |
856 void botscript_parser::parse_label() |
855 void botscript_parser::parse_label() |
857 { |
856 { |
858 check_not_toplevel(); |
857 check_not_toplevel(); |
859 string label_name = token_string(); |
858 string label_name = token_string(); |
|
859 byte_mark* mark = null; |
860 |
860 |
861 // want no conflicts.. |
861 // want no conflicts.. |
862 if (find_command_by_name (label_name)) |
862 if (find_command_by_name (label_name)) |
863 error ("label name `%1` conflicts with command name\n", label_name); |
863 error ("label name `%1` conflicts with command name\n", label_name); |
864 |
864 |
865 if (find_global_variable (label_name)) |
865 if (find_global_variable (label_name)) |
866 error ("label name `%1` conflicts with variable\n", label_name); |
866 error ("label name `%1` conflicts with variable\n", label_name); |
867 |
867 |
868 // See if a mark already exists for this label |
868 // See if a mark already exists for this label |
869 int mark = -1; |
869 for (undefined_label& undf : m_undefined_labels) |
870 |
870 { |
871 for (int i = 0; i < MAX_MARKS; i++) |
871 if (undf.name != label_name) |
872 { |
872 continue; |
873 if (g_undefined_labels[i] && *g_undefined_labels[i] == label_name) |
873 |
874 { |
874 mark = undf.target; |
875 mark = i; |
875 buffer()->adjust_mark (mark); |
876 m_writer->move_mark (i); |
876 |
877 |
877 // No longer undefined |
878 // No longer undefinde |
878 m_undefined_labels.remove (undf); |
879 delete g_undefined_labels[i]; |
879 break; |
880 g_undefined_labels[i] = null; |
|
881 } |
|
882 } |
880 } |
883 |
881 |
884 // Not found in unmarked lists, define it now |
882 // Not found in unmarked lists, define it now |
885 if (mark == -1) |
883 if (mark == null) |
886 m_writer->add_mark (label_name); |
884 buffer()->add_mark (label_name); |
887 |
885 |
888 m_lx->must_get_next (tk_colon); |
886 m_lx->must_get_next (tk_colon); |
889 } |
887 } |
890 |
888 |
891 // ============================================================================= |
889 // ============================================================================= |
992 add_command_definition (comm); |
987 add_command_definition (comm); |
993 } |
988 } |
994 |
989 |
995 // ============================================================================ |
990 // ============================================================================ |
996 // Parses a command call |
991 // Parses a command call |
997 data_buffer* botscript_parser::ParseCommand (command_info* comm) |
992 data_buffer* botscript_parser::parse_command (command_info* comm) |
998 { |
993 { |
999 data_buffer* r = new data_buffer (64); |
994 data_buffer* r = new data_buffer (64); |
1000 |
995 |
1001 if (g_current_mode == MODE_TOPLEVEL) |
996 if (m_current_mode == MODE_TOPLEVEL) |
1002 error ("command call at top level"); |
997 error ("command call at top level"); |
1003 |
998 |
1004 m_lx->must_get_next (tk_paren_start); |
999 m_lx->must_get_next (tk_paren_start); |
1005 m_lx->must_get_next(); |
1000 m_lx->must_get_next(); |
1006 |
1001 |
1171 data_buffer* tb = parse_expr_value (reqtype); |
1166 data_buffer* tb = parse_expr_value (reqtype); |
1172 |
1167 |
1173 // It also is handled differently: there isn't a dataheader for ternary |
1168 // It also is handled differently: there isn't a dataheader for ternary |
1174 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
1169 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
1175 // Behold, big block of writing madness! :P |
1170 // Behold, big block of writing madness! :P |
1176 int mark1 = retbuf->add_mark (""); // start of "else" case |
1171 byte_mark* mark1 = retbuf->add_mark (""); // start of "else" case |
1177 int mark2 = retbuf->add_mark (""); // end of expression |
1172 byte_mark* mark2 = retbuf->add_mark (""); // end of expression |
1178 retbuf->write (dh_if_not_goto); // if the first operand (condition) |
1173 retbuf->write_dword (dh_if_not_goto); // if the first operand (condition) |
1179 retbuf->add_reference (mark1); // didn't eval true, jump into mark1 |
1174 retbuf->add_reference (mark1); // didn't eval true, jump into mark1 |
1180 retbuf->merge (rb); // otherwise, perform second operand (true case) |
1175 retbuf->merge_and_destroy (rb); // otherwise, perform second operand (true case) |
1181 retbuf->write (dh_goto); // afterwards, jump to the end, which is |
1176 retbuf->write_dword (dh_goto); // afterwards, jump to the end, which is |
1182 retbuf->add_reference (mark2); // marked by mark2. |
1177 retbuf->add_reference (mark2); // marked by mark2. |
1183 retbuf->move_mark (mark1); // move mark1 at the end of the true case |
1178 retbuf->adjust_mark (mark1); // move mark1 at the end of the true case |
1184 retbuf->merge (tb); // perform third operand (false case) |
1179 retbuf->merge_and_destroy (tb); // perform third operand (false case) |
1185 retbuf->move_mark (mark2); // move the ending mark2 here |
1180 retbuf->adjust_mark (mark2); // move the ending mark2 here |
1186 } |
1181 } |
1187 else |
1182 else |
1188 { |
1183 { |
1189 // write to buffer |
1184 // write to buffer |
1190 retbuf->merge (rb); |
1185 retbuf->merge_and_destroy (rb); |
1191 retbuf->write (get_data_header_by_operator (null, oper)); |
1186 retbuf->write_dword (get_data_header_by_operator (null, oper)); |
1192 } |
1187 } |
1193 } |
1188 } |
1194 |
1189 |
1195 return retbuf; |
1190 return retbuf; |
1196 } |
1191 } |
1323 error ("strlen only works with const str"); |
1318 error ("strlen only works with const str"); |
1324 |
1319 |
1325 if (reqtype != TYPE_INT) |
1320 if (reqtype != TYPE_INT) |
1326 error ("strlen returns int but %1 is expected\n", GetTypeName (reqtype)); |
1321 error ("strlen returns int but %1 is expected\n", GetTypeName (reqtype)); |
1327 |
1322 |
1328 b->write (dh_push_number); |
1323 b->write_dword (dh_push_number); |
1329 b->write (constant->val.len()); |
1324 b->write_dword (constant->val.len()); |
1330 |
1325 |
1331 m_lx->must_get_next (tk_paren_end); |
1326 m_lx->must_get_next (tk_paren_end); |
1332 } |
1327 } |
1333 else */ |
1328 else */ |
1334 if (token_is (tk_paren_start)) |
1329 if (token_is (tk_paren_start)) |
1335 { |
1330 { |
1336 // Expression |
1331 // Expression |
1337 m_lx->must_get_next(); |
1332 m_lx->must_get_next(); |
1338 data_buffer* c = parse_expression (reqtype); |
1333 data_buffer* c = parse_expression (reqtype); |
1339 b->merge (c); |
1334 b->merge_and_destroy (c); |
1340 m_lx->must_get_next (tk_paren_end); |
1335 m_lx->must_get_next (tk_paren_end); |
1341 } |
1336 } |
1342 else if (command_info* comm = find_command_by_name (token_string())) |
1337 else if (command_info* comm = find_command_by_name (token_string())) |
1343 { |
1338 { |
1344 delete b; |
1339 delete b; |
1345 |
1340 |
1346 // Command |
1341 // Command |
1347 if (reqtype && comm->returnvalue != reqtype) |
1342 if (reqtype && comm->returnvalue != reqtype) |
1348 error ("%1 returns an incompatible data type", comm->name); |
1343 error ("%1 returns an incompatible data type", comm->name); |
1349 |
1344 |
1350 b = ParseCommand (comm); |
1345 b = parse_command (comm); |
1351 } |
1346 } |
1352 else if (constant_info* constant = find_constant (token_string())) |
1347 else if (constant_info* constant = find_constant (token_string())) |
1353 { |
1348 { |
1354 // Type check |
1349 // Type check |
1355 if (reqtype != constant->type) |
1350 if (reqtype != constant->type) |
1395 { |
1390 { |
1396 m_lx->must_be (tk_number); |
1391 m_lx->must_be (tk_number); |
1397 |
1392 |
1398 // All values are written unsigned - thus we need to write the value's |
1393 // All values are written unsigned - thus we need to write the value's |
1399 // absolute value, followed by an unary minus for negatives. |
1394 // absolute value, followed by an unary minus for negatives. |
1400 b->write (dh_push_number); |
1395 b->write_dword (dh_push_number); |
1401 |
1396 |
1402 long v = token_string().to_long(); |
1397 long v = token_string().to_long(); |
1403 b->write (static_cast<word> (abs (v))); |
1398 b->write_dword (static_cast<word> (abs (v))); |
1404 |
1399 |
1405 if (v < 0) |
1400 if (v < 0) |
1406 b->write (dh_unary_minus); |
1401 b->write_dword (dh_unary_minus); |
1407 |
1402 |
1408 break; |
1403 break; |
1409 } |
1404 } |
1410 |
1405 |
1411 case TYPE_STRING: |
1406 case TYPE_STRING: |
1412 // PushToStringTable either returns the string index of the |
1407 // PushToStringTable either returns the string index of the |
1413 // string if it finds it in the table, or writes it to the |
1408 // string if it finds it in the table, or writes it to the |
1414 // table and returns it index if it doesn't find it there. |
1409 // table and returns it index if it doesn't find it there. |
1415 m_lx->must_be (tk_string); |
1410 m_lx->must_be (tk_string); |
1416 b->write_string (token_string()); |
1411 b->write_string_index (token_string()); |
1417 break; |
1412 break; |
1418 } |
1413 } |
1419 } |
1414 } |
1420 |
1415 |
1421 // Negate it now if desired |
1416 // Negate it now if desired |
1422 if (negate) |
1417 if (negate) |
1423 b->write (dh_negate_logical); |
1418 b->write_dword (dh_negate_logical); |
1424 |
1419 |
1425 return b; |
1420 return b; |
1426 } |
1421 } |
1427 |
1422 |
1428 // ============================================================================ |
1423 // ============================================================================ |
1430 // by an assignment operator, followed by an expression value. Expects current |
1425 // by an assignment operator, followed by an expression value. Expects current |
1431 // token to be the name of the variable, and expects the variable to be given. |
1426 // token to be the name of the variable, and expects the variable to be given. |
1432 // |
1427 // |
1433 data_buffer* botscript_parser::parse_assignment (script_variable* var) |
1428 data_buffer* botscript_parser::parse_assignment (script_variable* var) |
1434 { |
1429 { |
1435 bool global = !var->statename.len(); |
|
1436 |
|
1437 // Get an operator |
1430 // Get an operator |
1438 m_lx->must_get_next(); |
1431 m_lx->must_get_next(); |
1439 int oper = parse_operator(); |
1432 int oper = parse_operator(); |
1440 |
1433 |
1441 if (!is_assignment_operator (oper)) |
1434 if (!is_assignment_operator (oper)) |
1442 error ("expected assignment operator"); |
1435 error ("expected assignment operator"); |
1443 |
1436 |
1444 if (g_current_mode == MODE_TOPLEVEL) |
1437 if (m_current_mode == MODE_TOPLEVEL) |
1445 error ("can't alter variables at top level"); |
1438 error ("can't alter variables at top level"); |
1446 |
1439 |
1447 // Parse the right operand |
1440 // Parse the right operand |
1448 m_lx->must_get_next(); |
1441 m_lx->must_get_next(); |
1449 data_buffer* retbuf = new data_buffer; |
1442 data_buffer* retbuf = new data_buffer; |
1452 // <<= and >>= do not have data headers. Solution: expand them. |
1445 // <<= and >>= do not have data headers. Solution: expand them. |
1453 // a <<= b -> a = a << b |
1446 // a <<= b -> a = a << b |
1454 // a >>= b -> a = a >> b |
1447 // a >>= b -> a = a >> b |
1455 if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT) |
1448 if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT) |
1456 { |
1449 { |
1457 retbuf->write (global ? dh_push_global_var : dh_push_local_var); |
1450 retbuf->write_dword (var->is_global() ? dh_push_global_var : dh_push_local_var); |
1458 retbuf->write (var->index); |
1451 retbuf->write_dword (var->index); |
1459 retbuf->merge (expr); |
1452 retbuf->merge_and_destroy (expr); |
1460 retbuf->write ((oper == OPER_ASSIGNLEFTSHIFT) ? dh_left_shift : dh_right_shift); |
1453 retbuf->write_dword ((oper == OPER_ASSIGNLEFTSHIFT) ? dh_left_shift : dh_right_shift); |
1461 retbuf->write (global ? dh_assign_global_var : dh_assign_local_var); |
1454 retbuf->write_dword (var->is_global() ? dh_assign_global_var : dh_assign_local_var); |
1462 retbuf->write (var->index); |
1455 retbuf->write_dword (var->index); |
1463 } |
1456 } |
1464 else |
1457 else |
1465 { |
1458 { |
1466 retbuf->merge (expr); |
1459 retbuf->merge_and_destroy (expr); |
1467 long dh = get_data_header_by_operator (var, oper); |
1460 long dh = get_data_header_by_operator (var, oper); |
1468 retbuf->write (dh); |
1461 retbuf->write_dword (dh); |
1469 retbuf->write (var->index); |
1462 retbuf->write_dword (var->index); |
1470 } |
1463 } |
1471 |
1464 |
1472 return retbuf; |
1465 return retbuf; |
1473 } |
1466 } |
1474 |
1467 |
1475 // ============================================================================ |
1468 // ============================================================================ |
1476 // |
1469 // |
1477 void botscript_parser::push_scope() |
1470 void botscript_parser::push_scope() |
1478 { |
1471 { |
1479 g_ScopeCursor++; |
1472 m_scope_cursor++; |
1480 |
1473 |
1481 if (g_ScopeCursor >= MAX_SCOPE) |
1474 if (m_scope_cursor >= MAX_SCOPE) |
1482 error ("too deep scope"); |
1475 error ("too deep scope"); |
1483 |
1476 |
1484 ScopeInfo* info = &SCOPE (0); |
1477 ScopeInfo* info = &SCOPE (0); |
1485 info->type = e_unknown_scope; |
1478 info->type = e_unknown_scope; |
1486 info->mark1 = 0; |
1479 info->mark1 = null; |
1487 info->mark2 = 0; |
1480 info->mark2 = null; |
1488 info->buffer1 = null; |
1481 info->buffer1 = null; |
1489 info->casecursor = -1; |
1482 info->casecursor = -1; |
1490 |
1483 |
1491 for (int i = 0; i < MAX_CASE; i++) |
1484 for (int i = 0; i < MAX_CASE; i++) |
1492 { |
1485 { |
1493 info->casemarks[i] = MAX_MARKS; |
1486 info->casemarks[i] = null; |
1494 info->casebuffers[i] = null; |
1487 info->casebuffers[i] = null; |
1495 info->casenumbers[i] = -1; |
1488 info->casenumbers[i] = -1; |
1496 } |
1489 } |
1497 } |
1490 } |
1498 |
1491 |
1520 |
1513 |
1521 if (info->casecursor >= MAX_CASE) |
1514 if (info->casecursor >= MAX_CASE) |
1522 error ("too many cases in one switch"); |
1515 error ("too many cases in one switch"); |
1523 |
1516 |
1524 // Init a mark for the case buffer |
1517 // Init a mark for the case buffer |
1525 int m = m_writer->add_mark (""); |
1518 byte_mark* casemark = buffer()->add_mark (""); |
1526 info->casemarks[info->casecursor] = m; |
1519 info->casemarks[info->casecursor] = casemark; |
1527 |
1520 |
1528 // Add a reference to the mark. "case" and "default" both |
1521 // Add a reference to the mark. "case" and "default" both |
1529 // add the necessary bytecode before the reference. |
1522 // add the necessary bytecode before the reference. |
1530 if (b) |
1523 if (b) |
1531 b->add_reference (m); |
1524 b->add_reference (casemark); |
1532 else |
1525 else |
1533 m_writer->add_reference (m); |
1526 buffer()->add_reference (casemark); |
1534 |
1527 |
1535 // Init a buffer for the case block and tell the object |
1528 // Init a buffer for the case block and tell the object |
1536 // writer to record all written data to it. |
1529 // writer to record all written data to it. |
1537 info->casebuffers[info->casecursor] = m_writer->SwitchBuffer = new data_buffer; |
1530 info->casebuffers[info->casecursor] = m_switch_buffer = new data_buffer; |
1538 } |
1531 } |
1539 |
1532 |
1540 // ============================================================================ |
1533 // ============================================================================ |
1541 // |
1534 // |
1542 constant_info* find_constant (const string& tok) |
1535 constant_info* botscript_parser::find_constant (const string& tok) |
1543 { |
1536 { |
1544 for (int i = 0; i < g_ConstInfo.size(); i++) |
1537 for (int i = 0; i < m_constants.size(); i++) |
1545 if (g_ConstInfo[i].name == tok) |
1538 if (m_constants[i].name == tok) |
1546 return &g_ConstInfo[i]; |
1539 return &m_constants[i]; |
1547 |
1540 |
1548 return null; |
1541 return null; |
1549 } |
1542 } |
1550 |
1543 |
1551 // ============================================================================ |
1544 // ============================================================================ |
1567 string botscript_parser::describe_position() const |
1560 string botscript_parser::describe_position() const |
1568 { |
1561 { |
1569 lexer::token* tok = m_lx->get_token(); |
1562 lexer::token* tok = m_lx->get_token(); |
1570 return tok->file + ":" + string (tok->line) + ":" + string (tok->column); |
1563 return tok->file + ":" + string (tok->line) + ":" + string (tok->column); |
1571 } |
1564 } |
|
1565 |
|
1566 // ============================================================================ |
|
1567 // |
|
1568 data_buffer* botscript_parser::buffer() |
|
1569 { |
|
1570 if (m_switch_buffer != null) |
|
1571 return m_switch_buffer; |
|
1572 |
|
1573 if (m_current_mode == MODE_MAINLOOP) |
|
1574 return m_main_loop_buffer; |
|
1575 |
|
1576 if (m_current_mode == MODE_ONENTER) |
|
1577 return m_on_enter_buffer; |
|
1578 |
|
1579 return m_main_buffer; |
|
1580 } |
|
1581 |
|
1582 // ============================================================================ |
|
1583 // |
|
1584 void botscript_parser::write_member_buffers() |
|
1585 { |
|
1586 // If there was no mainloop defined, write a dummy one now. |
|
1587 if (!m_got_main_loop) |
|
1588 { |
|
1589 m_main_loop_buffer->write_dword (dh_main_loop); |
|
1590 m_main_loop_buffer->write_dword (dh_end_main_loop); |
|
1591 } |
|
1592 |
|
1593 // Write the onenter and mainloop buffers, in that order in particular. |
|
1594 for (data_buffer** bufp : list<data_buffer**> ({&m_on_enter_buffer, &m_main_loop_buffer})) |
|
1595 { |
|
1596 buffer()->merge_and_destroy (*bufp); |
|
1597 |
|
1598 // Clear the buffer afterwards for potential next state |
|
1599 *bufp = new data_buffer; |
|
1600 } |
|
1601 |
|
1602 // Next state definitely has no mainloop yet |
|
1603 m_got_main_loop = false; |
|
1604 } |
|
1605 |
|
1606 // ============================================================================ |
|
1607 // |
|
1608 // Write string table |
|
1609 // |
|
1610 void botscript_parser::write_string_table() |
|
1611 { |
|
1612 int stringcount = num_strings_in_table(); |
|
1613 |
|
1614 if (!stringcount) |
|
1615 return; |
|
1616 |
|
1617 // Write header |
|
1618 m_main_buffer->write_dword (dh_string_list); |
|
1619 m_main_buffer->write_dword (stringcount); |
|
1620 |
|
1621 // Write all strings |
|
1622 for (int i = 0; i < stringcount; i++) |
|
1623 m_main_buffer->write_string (get_string_table()[i]); |
|
1624 } |
|
1625 |
|
1626 // ============================================================================ |
|
1627 // |
|
1628 // Write the compiled bytecode to a file |
|
1629 // |
|
1630 void botscript_parser::write_to_file (string outfile) |
|
1631 { |
|
1632 FILE* fp = fopen (outfile, "w"); |
|
1633 CHECK_FILE (fp, outfile, "writing"); |
|
1634 |
|
1635 // First, resolve references |
|
1636 for (int u = 0; u < MAX_MARKS; u++) |
|
1637 { |
|
1638 mark_reference* ref = m_main_buffer->get_refs()[u]; |
|
1639 |
|
1640 if (!ref) |
|
1641 continue; |
|
1642 |
|
1643 // Substitute the placeholder with the mark position |
|
1644 generic_union<word> uni; |
|
1645 uni.as_word = static_cast<word> (ref->target->pos); |
|
1646 |
|
1647 for (int v = 0; v < (int) sizeof (word); v++) |
|
1648 memset (m_main_buffer->get_buffer() + ref->pos + v, uni.as_bytes[v], 1); |
|
1649 |
|
1650 /* |
|
1651 printf ("reference %u at %d resolved to %u at %d\n", |
|
1652 u, ref->pos, ref->num, MainBuffer->marks[ref->num]->pos); |
|
1653 */ |
|
1654 } |
|
1655 |
|
1656 // Then, dump the main buffer to the file |
|
1657 fwrite (m_main_buffer->get_buffer(), 1, m_main_buffer->get_write_size(), fp); |
|
1658 print ("-- %1 byte%s1 written to %2\n", m_main_buffer->get_write_size(), outfile); |
|
1659 fclose (fp); |
|
1660 } |