src/parser.cxx

changeset 75
bf8c57437231
parent 74
007fbadfa7f9
child 76
c8058716070a
equal deleted inserted replaced
74:007fbadfa7f9 75:bf8c57437231
1 /*
2 Copyright (c) 2013-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 are met:
7
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 * 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
15 * Neither the name of the <organization> nor the
16 names of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "object_writer.h"
32 #include "parser.h"
33 #include "events.h"
34 #include "commands.h"
35 #include "stringtable.h"
36 #include "variables.h"
37 #include "containers.h"
38 #include "lexer.h"
39
40 #define TOKEN (string (m_lx->get_token()->string))
41 #define SCOPE(n) scopestack[g_ScopeCursor - n]
42
43 // TODO: make these static
44 int g_NumStates = 0;
45 int g_NumEvents = 0;
46 parsermode_e g_CurMode = MODE_TOPLEVEL;
47 string g_CurState = "";
48 bool g_stateSpawnDefined = false;
49 bool g_GotMainLoop = false;
50 int g_ScopeCursor = 0;
51 data_buffer* g_IfExpression = null;
52 bool g_CanElse = false;
53 string* g_UndefinedLabels[MAX_MARKS];
54 list<constant_info> g_ConstInfo;
55
56 static botscript_parser* g_current_parser = null;
57
58 // ============================================================================
59 //
60 botscript_parser::botscript_parser() :
61 m_lx (new lexer) {}
62
63 // ============================================================================
64 //
65 botscript_parser::~botscript_parser()
66 {
67 delete m_lx;
68 }
69
70 // ============================================================================
71 //
72 void botscript_parser::check_toplevel()
73 {
74 if (g_CurMode != MODE_TOPLEVEL)
75 error ("%1-statements may only be defined at top level!", TOKEN.chars());
76 }
77
78 // ============================================================================
79 //
80 void botscript_parser::check_not_toplevel()
81 {
82 if (g_CurMode == MODE_TOPLEVEL)
83 error ("%1-statements must not be defined at top level!", TOKEN.chars());
84 }
85
86 // ============================================================================
87 // Main parser code. Begins read of the script file, checks the syntax of it
88 // and writes the data to the object file via Objwriter - which also takes care
89 // of necessary buffering so stuff is written in the correct order.
90 void botscript_parser::parse_botscript (string file_name, object_writer* w)
91 {
92 // Lex and preprocess the file
93 m_lx->process_file (file_name);
94
95 // Zero the entire block stack first
96 for (int i = 0; i < MAX_SCOPE; i++)
97 ZERO (scopestack[i]);
98
99 for (int i = 0; i < MAX_MARKS; i++)
100 g_UndefinedLabels[i] = null;
101
102 while (m_lx->get_next())
103 {
104 // Check if else is potentically valid
105 if (TOKEN == "else" && !g_CanElse)
106 error ("else without preceding if");
107
108 if (TOKEN != "else")
109 g_CanElse = false;
110
111 switch (m_lx->get_token())
112 {
113 case tk_state:
114 {
115 check_toplevel();
116 m_lx->must_get_next (tk_string);
117
118 // State name must be a word.
119 if (TOKEN.first (" ") != -1)
120 error ("state name must be a single word, got `%1`", TOKEN);
121
122 string statename = TOKEN;
123
124 // stateSpawn is special - it *must* be defined. If we
125 // encountered it, then mark down that we have it.
126 if (-TOKEN == "statespawn")
127 g_stateSpawnDefined = true;
128
129 // Must end in a colon
130 m_lx->must_get_next (tk_colon);
131
132 // write the previous state's onenter and
133 // mainloop buffers to file now
134 if (g_CurState.is_empty() == false)
135 w->write_member_buffers();
136
137 w->write (dh_state_name);
138 w->write_string (statename);
139 w->write (dh_state_index);
140 w->write (g_NumStates);
141
142 g_NumStates++;
143 g_CurState = TOKEN;
144 g_GotMainLoop = false;
145 }
146 break;
147
148 // ============================================================
149 //
150 case tk_event:
151 {
152 check_toplevel();
153
154 // Event definition
155 m_lx->must_get_next (tk_string);
156
157 event_info* e = find_event_by_name (token_string());
158
159 if (!e)
160 error ("bad event, got `%1`\n", token_string());
161
162 m_lx->must_get_next (tk_brace_start);
163 g_CurMode = MODE_EVENT;
164 w->write (dh_event);
165 w->write (e->number);
166 g_NumEvents++;
167 continue;
168 } break;
169
170 // ============================================================
171 //
172 case tk_mainloop:
173 {
174 check_toplevel();
175 m_lx->must_get_next (tk_brace_start);
176
177 // Mode must be set before dataheader is written here!
178 g_CurMode = MODE_MAINLOOP;
179 w->write (dh_main_loop);
180 }
181 break;
182
183 // ============================================================
184 //
185 case tk_onenter:
186 case tk_onexit:
187 {
188 check_toplevel();
189 bool onenter = (m_lx->get_token() == "onenter");
190 m_lx->must_get_next (tk_brace_start);
191
192 // Mode must be set before dataheader is written here,
193 // because onenter goes to a separate buffer.
194 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT;
195 w->write (onenter ? dh_on_enter : dh_on_exit);
196 }
197 break;
198
199 // ============================================================
200 //
201 case tk_int:
202 case tk_str:
203 case tk_void:
204 {
205 // For now, only globals are supported
206 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len())
207 error ("variables must only be global for now");
208
209 type_e type = (token_is (tk_int)) ? TYPE_INT :
210 (token_is (tk_str)) ? TYPE_STRING :
211 TYPE_BOOL;
212
213 m_lx->must_get_next();
214
215 // Var name must not be a number
216 if (TOKEN.is_numeric())
217 error ("variable name must not be a number");
218
219 string varname = TOKEN;
220 script_variable* var = declare_global_variable (this, type, varname);
221 m_lx->must_get_next (tk_semicolon);
222 }
223 break;
224
225 // ============================================================
226 //
227 case tk_goto:
228 {
229 check_not_toplevel();
230
231 // Get the name of the label
232 m_lx->must_get_next();
233
234 // Find the mark this goto statement points to
235 int m = w->find_byte_mark (TOKEN);
236
237 // If not set, define it
238 if (m == MAX_MARKS)
239 {
240 m = w->add_mark (TOKEN);
241 g_UndefinedLabels[m] = new string (TOKEN);
242 }
243
244 // Add a reference to the mark.
245 w->write (dh_goto);
246 w->add_reference (m);
247 m_lx->must_get_next (tk_semicolon);
248 continue;
249 }
250
251 // ============================================================
252 //
253 case tk_if:
254 {
255 check_not_toplevel();
256 push_scope();
257
258 // Condition
259 m_lx->must_get_next (tk_paren_start);
260
261 // Read the expression and write it.
262 m_lx->must_get_next();
263 data_buffer* c = parse_expression (TYPE_INT);
264 w->write_buffer (c);
265
266 m_lx->must_get_next (tk_paren_end);
267 m_lx->must_get_next (tk_brace_start);
268
269 // Add a mark - to here temporarily - and add a reference to it.
270 // Upon a closing brace, the mark will be adjusted.
271 int marknum = w->add_mark ("");
272
273 // Use dh_if_not_goto - if the expression is not true, we goto the mark
274 // we just defined - and this mark will be at the end of the scope block.
275 w->write (dh_if_not_goto);
276 w->add_reference (marknum);
277
278 // Store it
279 SCOPE (0).mark1 = marknum;
280 SCOPE (0).type = e_if_scope;
281 } break;
282
283 // ============================================================
284 //
285 case tk_else:
286 {
287 check_not_toplevel();
288 m_lx->must_get_next (tk_brace_start);
289
290 // Don't use PushScope as it resets the scope
291 g_ScopeCursor++;
292
293 if (g_ScopeCursor >= MAX_SCOPE)
294 error ("too deep scope");
295
296 if (SCOPE (0).type != e_if_scope)
297 error ("else without preceding if");
298
299 // write down to jump to the end of the else statement
300 // Otherwise we have fall-throughs
301 SCOPE (0).mark2 = w->add_mark ("");
302
303 // Instruction to jump to the end after if block is complete
304 w->write (dh_goto);
305 w->add_reference (SCOPE (0).mark2);
306
307 // Move the ifnot mark here and set type to else
308 w->move_mark (SCOPE (0).mark1);
309 SCOPE (0).type = e_else_scope;
310 }
311 break;
312
313 // ============================================================
314 //
315 case tk_while:
316 {
317 check_not_toplevel();
318 push_scope();
319
320 // While loops need two marks - one at the start of the loop and one at the
321 // end. The condition is checked at the very start of the loop, if it fails,
322 // we use goto to skip to the end of the loop. At the end, we loop back to
323 // the beginning with a go-to statement.
324 int mark1 = w->add_mark (""); // start
325 int mark2 = w->add_mark (""); // end
326
327 // Condition
328 m_lx->must_get_next (tk_paren_start);
329 m_lx->must_get_next();
330 data_buffer* expr = parse_expression (TYPE_INT);
331 m_lx->must_get_next (tk_paren_end);
332 m_lx->must_get_next (tk_brace_start);
333
334 // write condition
335 w->write_buffer (expr);
336
337 // Instruction to go to the end if it fails
338 w->write (dh_if_not_goto);
339 w->add_reference (mark2);
340
341 // Store the needed stuff
342 SCOPE (0).mark1 = mark1;
343 SCOPE (0).mark2 = mark2;
344 SCOPE (0).type = e_while_scope;
345 }
346 break;
347
348 // ============================================================
349 //
350 case tk_for:
351 {
352 check_not_toplevel();
353 push_scope();
354
355 // Initializer
356 m_lx->must_get_next (tk_paren_start);
357 m_lx->must_get_next();
358 data_buffer* init = parse_statement (w);
359
360 if (!init)
361 error ("bad statement for initializer of for");
362
363 m_lx->must_get_next (tk_semicolon);
364
365 // Condition
366 m_lx->must_get_next();
367 data_buffer* cond = parse_expression (TYPE_INT);
368
369 if (!cond)
370 error ("bad statement for condition of for");
371
372 m_lx->must_get_next (tk_semicolon);
373
374 // Incrementor
375 m_lx->must_get_next();
376 data_buffer* incr = parse_statement (w);
377
378 if (!incr)
379 error ("bad statement for incrementor of for");
380
381 m_lx->must_get_next (tk_paren_end);
382 m_lx->must_get_next (tk_brace_start);
383
384 // First, write out the initializer
385 w->write_buffer (init);
386
387 // Init two marks
388 int mark1 = w->add_mark ("");
389 int mark2 = w->add_mark ("");
390
391 // Add the condition
392 w->write_buffer (cond);
393 w->write (dh_if_not_goto);
394 w->add_reference (mark2);
395
396 // Store the marks and incrementor
397 SCOPE (0).mark1 = mark1;
398 SCOPE (0).mark2 = mark2;
399 SCOPE (0).buffer1 = incr;
400 SCOPE (0).type = e_for_scope;
401 }
402 break;
403
404 // ============================================================
405 //
406 case tk_do:
407 {
408 check_not_toplevel();
409 push_scope();
410 m_lx->must_get_next (tk_brace_start);
411 SCOPE (0).mark1 = w->add_mark ("");
412 SCOPE (0).type = e_do_scope;
413 }
414 break;
415
416 // ============================================================
417 //
418 case tk_switch:
419 {
420 // This gets a bit tricky. switch is structured in the
421 // bytecode followingly:
422 //
423 // (expression)
424 // case a: goto casemark1
425 // case b: goto casemark2
426 // case c: goto casemark3
427 // goto mark1 // jump to end if no matches
428 // casemark1: ...
429 // casemark2: ...
430 // casemark3: ...
431 // mark1: // end mark
432
433 check_not_toplevel();
434 push_scope();
435 m_lx->must_get_next (tk_paren_start);
436 m_lx->must_get_next();
437 w->write_buffer (parse_expression (TYPE_INT));
438 m_lx->must_get_next (tk_paren_end);
439 m_lx->must_get_next (tk_brace_start);
440 SCOPE (0).type = e_switch_scope;
441 SCOPE (0).mark1 = w->add_mark (""); // end mark
442 SCOPE (0).buffer1 = null; // default header
443 }
444 break;
445
446 // ============================================================
447 //
448 case tk_case:
449 {
450 // case is only allowed inside switch
451 if (SCOPE (0).type != e_switch_scope)
452 error ("case label outside switch");
453
454 // Get the literal (Zandronum does not support expressions here)
455 m_lx->must_get_next (tk_number);
456 int num = m_lx->get_token()->text.to_long();
457 m_lx->must_get_next (tk_colon);
458
459 for (int i = 0; i < MAX_CASE; i++)
460 if (SCOPE (0).casenumbers[i] == num)
461 error ("multiple case %d labels in one switch", num);
462
463 // write down the expression and case-go-to. This builds
464 // the case tree. The closing event will write the actual
465 // blocks and move the marks appropriately.
466 // AddSwitchCase will add the reference to the mark
467 // for the case block that this heralds, and takes care
468 // of buffering setup and stuff like that.
469 // null the switch buffer for the case-go-to statement,
470 // we want it all under the switch, not into the case-buffers.
471 w->SwitchBuffer = null;
472 w->write (dh_case_goto);
473 w->write (num);
474 add_switch_case (w, null);
475 SCOPE (0).casenumbers[SCOPE (0).casecursor] = num;
476 }
477 break;
478
479 // ============================================================
480 //
481 case tk_default:
482 {
483 if (SCOPE (0).type != e_switch_scope)
484 error ("default label outside switch");
485
486 if (SCOPE (0).buffer1)
487 error ("multiple default labels in one switch");
488
489 m_lx->must_get_next (tk_colon);
490
491 // The default header is buffered into buffer1, since
492 // it has to be the last of the case headers
493 //
494 // Since the expression is pushed into the switch
495 // and is only popped when case succeeds, we have
496 // to pop it with dh_drop manually if we end up in
497 // a default.
498 data_buffer* b = new data_buffer;
499 SCOPE (0).buffer1 = b;
500 b->write (dh_drop);
501 b->write (dh_goto);
502 add_switch_case (w, b);
503 }
504 break;
505
506 // ============================================================
507 //
508 case tk_break:
509 {
510 if (!g_ScopeCursor)
511 error ("unexpected `break`");
512
513 w->write (dh_goto);
514
515 // switch and if use mark1 for the closing point,
516 // for and while use mark2.
517 switch (SCOPE (0).type)
518 {
519 case e_if_scope:
520 case e_switch_scope:
521 {
522 w->add_reference (SCOPE (0).mark1);
523 } break;
524
525 case e_for_scope:
526 case e_while_scope:
527 {
528 w->add_reference (SCOPE (0).mark2);
529 } break;
530
531 default:
532 {
533 error ("unexpected `break`");
534 } break;
535 }
536
537 m_lx->must_get_next (tk_semicolon);
538 }
539 break;
540
541 // ============================================================
542 //
543 case tk_continue:
544 {
545 m_lx->must_get_next (tk_semicolon);
546
547 int curs;
548 bool found = false;
549
550 // Fall through the scope until we find a loop block
551 for (curs = g_ScopeCursor; curs > 0 && !found; curs--)
552 {
553 switch (scopestack[curs].type)
554 {
555 case e_for_scope:
556 case e_while_scope:
557 case e_do_scope:
558 {
559 w->write (dh_goto);
560 w->add_reference (scopestack[curs].mark1);
561 found = true;
562 } break;
563
564 default:
565 break;
566 }
567 }
568
569 // No loop blocks
570 if (!found)
571 error ("`continue`-statement not inside a loop");
572 }
573 break;
574
575 case tk_brace_end:
576 {
577 // Closing brace
578 // If we're in the block stack, we're descending down from it now
579 if (g_ScopeCursor > 0)
580 {
581 switch (SCOPE (0).type)
582 {
583 case e_if_scope:
584 // Adjust the closing mark.
585 w->move_mark (SCOPE (0).mark1);
586
587 // We're returning from if, thus else can be next
588 g_CanElse = true;
589 break;
590
591 case e_else_scope:
592 // else instead uses mark1 for itself (so if expression
593 // fails, jump to else), mark2 means end of else
594 w->move_mark (SCOPE (0).mark2);
595 break;
596
597 case e_for_scope:
598 // write the incrementor at the end of the loop block
599 w->write_buffer (SCOPE (0).buffer1);
600
601 // fall-thru
602 case e_while_scope:
603 // write down the instruction to go back to the start of the loop
604 w->write (dh_goto);
605 w->add_reference (SCOPE (0).mark1);
606
607 // Move the closing mark here since we're at the end of the while loop
608 w->move_mark (SCOPE (0).mark2);
609 break;
610
611 case e_do_scope:
612 {
613 m_lx->must_get_next (tk_while);
614 m_lx->must_get_next (tk_paren_start);
615 m_lx->must_get_next();
616 data_buffer* expr = parse_expression (TYPE_INT);
617 m_lx->must_get_next (tk_paren_end);
618 m_lx->must_get_next (tk_semicolon);
619
620 // If the condition runs true, go back to the start.
621 w->write_buffer (expr);
622 w->write (dh_if_goto);
623 w->add_reference (SCOPE (0).mark1);
624 break;
625 }
626
627 case e_switch_scope:
628 {
629 // Switch closes. Move down to the record buffer of
630 // the lower block.
631 if (SCOPE (1).casecursor != -1)
632 w->SwitchBuffer = SCOPE (1).casebuffers[SCOPE (1).casecursor];
633 else
634 w->SwitchBuffer = null;
635
636 // If there was a default in the switch, write its header down now.
637 // If not, write instruction to jump to the end of switch after
638 // the headers (thus won't fall-through if no case matched)
639 if (SCOPE (0).buffer1)
640 w->write_buffer (SCOPE (0).buffer1);
641 else
642 {
643 w->write (dh_drop);
644 w->write (dh_goto);
645 w->add_reference (SCOPE (0).mark1);
646 }
647
648 // Go through all of the buffers we
649 // recorded down and write them.
650 for (int u = 0; u < MAX_CASE; u++)
651 {
652 if (!SCOPE (0).casebuffers[u])
653 continue;
654
655 w->move_mark (SCOPE (0).casemarks[u]);
656 w->write_buffer (SCOPE (0).casebuffers[u]);
657 }
658
659 // Move the closing mark here
660 w->move_mark (SCOPE (0).mark1);
661 break;
662 }
663
664 case e_unknown_scope:
665 break;
666 }
667
668 // Descend down the stack
669 g_ScopeCursor--;
670 continue;
671 }
672
673 int dataheader = (g_CurMode == MODE_EVENT) ? dh_end_event :
674 (g_CurMode == MODE_MAINLOOP) ? dh_end_main_loop :
675 (g_CurMode == MODE_ONENTER) ? dh_end_on_enter :
676 (g_CurMode == MODE_ONEXIT) ? dh_end_on_exit : -1;
677
678 if (dataheader == -1)
679 error ("unexpected `}`");
680
681 // Data header must be written before mode is changed because
682 // onenter and mainloop go into special buffers, and we want
683 // the closing data headers into said buffers too.
684 w->write (dataheader);
685 g_CurMode = MODE_TOPLEVEL;
686 lexer::token* tok;
687 m_lx->get_next (tk_semicolon);
688 }
689 break;
690
691 // ============================================================
692 case tk_const:
693 {
694 constant_info info;
695
696 // Get the type
697 m_lx->must_get_next();
698 info.type = GetTypeByName (TOKEN);
699
700 if (info.type == TYPE_UNKNOWN || info.type == TYPE_VOID)
701 error ("unknown type `%s` for constant", TOKEN.c_str());
702
703 m_lx->must_get_next();
704 info.name = TOKEN;
705
706 m_lx->must_get_next (tk_assign);
707
708 switch (info.type)
709 {
710 case TYPE_BOOL:
711 case TYPE_INT:
712 {
713 m_lx->must_get_next (tk_number);
714 info.val = m_lx->get_token()->text.to_long();
715 } break;
716
717 case TYPE_STRING:
718 {
719 m_lx->must_get_next (tk_string);
720 info.val = m_lx->get_token()->text;
721 } break;
722
723 case TYPE_UNKNOWN:
724 case TYPE_VOID:
725 break;
726 }
727
728 g_ConstInfo << info;
729
730 m_lx->must_get_next (tk_semicolon);
731 continue;
732 }
733
734 default:
735 {
736 // ============================================================
737 // Label
738 lexer::token* next;
739 if (m_lx->get_token() == tk_symbol &&
740 m_lx->peek_next (next) &&
741 next->type == tk_colon)
742 {
743 check_not_toplevel();
744 string label_name = token_string();
745
746 // want no conflicts..
747 if (FindCommand (label_name))
748 error ("label name `%s` conflicts with command name\n", label_name);
749
750 if (find_global_variable (label_name))
751 error ("label name `%s` conflicts with variable\n", label_name);
752
753 // See if a mark already exists for this label
754 int mark = -1;
755
756 for (int i = 0; i < MAX_MARKS; i++)
757 {
758 if (g_UndefinedLabels[i] && *g_UndefinedLabels[i] == label_name)
759 {
760 mark = i;
761 w->move_mark (i);
762
763 // No longer undefinde
764 delete g_UndefinedLabels[i];
765 g_UndefinedLabels[i] = null;
766 }
767 }
768
769 // Not found in unmarked lists, define it now
770 if (mark == -1)
771 w->add_mark (label_name);
772
773 m_lx->must_get_next (tk_colon);
774 continue;
775 }
776
777 // Check if it's a command
778 CommandDef* comm = FindCommand (TOKEN);
779
780 if (comm)
781 {
782 w->get_current_buffer()->merge (ParseCommand (comm));
783 m_lx->must_get_next (tk_semicolon);
784 continue;
785 }
786
787 // ============================================================
788 // If nothing else, parse it as a statement
789 data_buffer* b = parse_statement (w);
790
791 if (!b)
792 error ("unknown TOKEN `%s`", TOKEN.chars());
793
794 w->write_buffer (b);
795 m_lx->must_get_next (tk_semicolon);
796 }
797 break;
798 }
799 }
800
801 // ===============================================================================
802 // Script file ended. Do some last checks and write the last things to main buffer
803 if (g_CurMode != MODE_TOPLEVEL)
804 error ("script did not end at top level; a `}` is missing somewhere");
805
806 // stateSpawn must be defined!
807 if (!g_stateSpawnDefined)
808 error ("script must have a state named `stateSpawn`!");
809
810 for (int i = 0; i < MAX_MARKS; i++)
811 if (g_UndefinedLabels[i])
812 error ("label `%s` is referenced via `goto` but isn't defined\n", g_UndefinedLabels[i]->chars());
813
814 // Dump the last state's onenter and mainloop
815 w->write_member_buffers();
816
817 // String table
818 w->write_string_table();
819 }
820
821 // ============================================================================
822 // Parses a command call
823 data_buffer* botscript_parser::ParseCommand (CommandDef* comm)
824 {
825 data_buffer* r = new data_buffer (64);
826
827 if (g_CurMode == MODE_TOPLEVEL)
828 error ("command call at top level");
829
830 m_lx->must_get_next (tk_paren_start);
831 m_lx->must_get_next();
832
833 int curarg = 0;
834
835 while (1)
836 {
837 if (m_lx->get_token() == tk_paren_end)
838 {
839 if (curarg < comm->numargs)
840 error ("too few arguments passed to %s\n\tprototype: %s",
841 comm->name.chars(), GetCommandPrototype (comm).chars());
842
843 break;
844 curarg++;
845 }
846
847 if (curarg >= comm->maxargs)
848 error ("too many arguments passed to %s\n\tprototype: %s",
849 comm->name.chars(), GetCommandPrototype (comm).chars());
850
851 r->merge (parse_expression (comm->argtypes[curarg]));
852 m_lx->must_get_next();
853
854 if (curarg < comm->numargs - 1)
855 {
856 m_lx->must_be (tk_comma);
857 m_lx->must_get_next();
858 }
859 else if (curarg < comm->maxargs - 1)
860 {
861 // Can continue, but can terminate as well.
862 if (m_lx->get_token() == tk_paren_end)
863 {
864 curarg++;
865 break;
866 }
867 else
868 {
869 m_lx->must_be (tk_comma);
870 m_lx->must_get_next();
871 }
872 }
873
874 curarg++;
875 }
876
877 // If the script skipped any optional arguments, fill in defaults.
878 while (curarg < comm->maxargs)
879 {
880 r->write (dh_push_number);
881 r->write (comm->defvals[curarg]);
882 curarg++;
883 }
884
885 r->write (dh_command);
886 r->write (comm->number);
887 r->write (comm->maxargs);
888
889 return r;
890 }
891
892 // ============================================================================
893 // Is the given operator an assignment operator?
894 static bool is_assignment_operator (int oper)
895 {
896 switch (oper)
897 {
898 case OPER_ASSIGNADD:
899 case OPER_ASSIGNSUB:
900 case OPER_ASSIGNMUL:
901 case OPER_ASSIGNDIV:
902 case OPER_ASSIGNMOD:
903 case OPER_ASSIGNLEFTSHIFT:
904 case OPER_ASSIGNRIGHTSHIFT:
905 case OPER_ASSIGN:
906 return true;
907 }
908
909 return false;
910 }
911
912 // ============================================================================
913 // Finds an operator's corresponding dataheader
914 static word get_data_header_by_operator (script_variable* var, int oper)
915 {
916 if (is_assignment_operator (oper))
917 {
918 if (!var)
919 error ("operator %d requires left operand to be a variable\n", oper);
920
921 // TODO: At the moment, vars only are global
922 // OPER_ASSIGNLEFTSHIFT and OPER_ASSIGNRIGHTSHIFT do not
923 // have data headers, instead they are expanded out in
924 // the operator parser
925 switch (oper)
926 {
927 case OPER_ASSIGNADD: return dh_add_global_var;
928 case OPER_ASSIGNSUB: return dh_subtract_global_var;
929 case OPER_ASSIGNMUL: return dh_multiply_global_var;
930 case OPER_ASSIGNDIV: return dh_divide_global_var;
931 case OPER_ASSIGNMOD: return dh_mod_global_var;
932 case OPER_ASSIGN: return dh_assign_global_var;
933
934 default: error ("bad assignment operator!!\n");
935 }
936 }
937
938 switch (oper)
939 {
940 case OPER_ADD: return dh_add;
941 case OPER_SUBTRACT: return dh_subtract;
942 case OPER_MULTIPLY: return dh_multiply;
943 case OPER_DIVIDE: return dh_divide;
944 case OPER_MODULUS: return dh_modulus;
945 case OPER_EQUALS: return dh_equals;
946 case OPER_NOTEQUALS: return dh_not_equals;
947 case OPER_LESSTHAN: return dh_less_than;
948 case OPER_GREATERTHAN: return dh_greater_than;
949 case OPER_LESSTHANEQUALS: return dh_at_most;
950 case OPER_GREATERTHANEQUALS: return dh_at_least;
951 case OPER_LEFTSHIFT: return dh_left_shift;
952 case OPER_RIGHTSHIFT: return dh_right_shift;
953 case OPER_OR: return dh_or_logical;
954 case OPER_AND: return dh_and_logical;
955 case OPER_BITWISEOR: return dh_or_bitwise;
956 case OPER_BITWISEEOR: return dh_eor_bitwise;
957 case OPER_BITWISEAND: return dh_and_bitwise;
958 }
959
960 error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper);
961 return 0;
962 }
963
964 // ============================================================================
965 // Parses an expression, potentially recursively
966 data_buffer* botscript_parser::parse_expression (type_e reqtype)
967 {
968 data_buffer* retbuf = new data_buffer (64);
969
970 // Parse first operand
971 retbuf->merge (parse_expr_value (reqtype));
972
973 // Parse any and all operators we get
974 int oper;
975
976 while ( (oper = parse_operator (true)) != -1)
977 {
978 // We peeked the operator, move forward now
979 m_lx->skip();
980
981 // Can't be an assignement operator, those belong in assignments.
982 if (is_assignment_operator (oper))
983 error ("assignment operator inside expression");
984
985 // Parse the right operand.
986 m_lx->must_get_next();
987 data_buffer* rb = parse_expr_value (reqtype);
988
989 if (oper == OPER_TERNARY)
990 {
991 // Ternary operator requires - naturally - a third operand.
992 m_lx->must_get_next (tk_colon);
993 m_lx->must_get_next();
994 data_buffer* tb = parse_expr_value (reqtype);
995
996 // It also is handled differently: there isn't a dataheader for ternary
997 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this.
998 // Behold, big block of writing madness! :P
999 int mark1 = retbuf->add_mark (""); // start of "else" case
1000 int mark2 = retbuf->add_mark (""); // end of expression
1001 retbuf->write (dh_if_not_goto); // if the first operand (condition)
1002 retbuf->add_reference (mark1); // didn't eval true, jump into mark1
1003 retbuf->merge (rb); // otherwise, perform second operand (true case)
1004 retbuf->write (dh_goto); // afterwards, jump to the end, which is
1005 retbuf->add_reference (mark2); // marked by mark2.
1006 retbuf->move_mark (mark1); // move mark1 at the end of the true case
1007 retbuf->merge (tb); // perform third operand (false case)
1008 retbuf->move_mark (mark2); // move the ending mark2 here
1009 }
1010 else
1011 {
1012 // write to buffer
1013 retbuf->merge (rb);
1014 retbuf->write (get_data_header_by_operator (null, oper));
1015 }
1016 }
1017
1018 return retbuf;
1019 }
1020
1021 // ============================================================================
1022 // Parses an operator string. Returns the operator number code.
1023 #define ISNEXT(C) (PeekNext (peek ? 1 : 0) == C)
1024 int botscript_parser::parse_operator (bool peek)
1025 {
1026 string oper;
1027
1028 if (peek)
1029 oper += m_lx->peek_next_string();
1030 else
1031 oper += TOKEN;
1032
1033 if (-oper == "strlen")
1034 return OPER_STRLEN;
1035
1036 // Check one-char operators
1037 bool equalsnext = ISNEXT ("=");
1038
1039 int o = (oper == "=" && !equalsnext) ? OPER_ASSIGN :
1040 (oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN :
1041 (oper == "<" && !equalsnext && !ISNEXT ("<")) ? OPER_LESSTHAN :
1042 (oper == "&" && !ISNEXT ("&")) ? OPER_BITWISEAND :
1043 (oper == "|" && !ISNEXT ("|")) ? OPER_BITWISEOR :
1044 (oper == "+" && !equalsnext) ? OPER_ADD :
1045 (oper == "-" && !equalsnext) ? OPER_SUBTRACT :
1046 (oper == "*" && !equalsnext) ? OPER_MULTIPLY :
1047 (oper == "/" && !equalsnext) ? OPER_DIVIDE :
1048 (oper == "%" && !equalsnext) ? OPER_MODULUS :
1049 (oper == "^") ? OPER_BITWISEEOR :
1050 (oper == "?") ? OPER_TERNARY :
1051 -1;
1052
1053 if (o != -1)
1054 {
1055 return o;
1056 }
1057
1058 // Two-char operators
1059 oper += m_lx->peek_next_string ( (peek ? 1 : 0);
1060 equalsnext = m_lx->peek_next_string (peek ? 2 : 1) == ("=");
1061
1062 o = (oper == "+=") ? OPER_ASSIGNADD :
1063 (oper == "-=") ? OPER_ASSIGNSUB :
1064 (oper == "*=") ? OPER_ASSIGNMUL :
1065 (oper == "/=") ? OPER_ASSIGNDIV :
1066 (oper == "%=") ? OPER_ASSIGNMOD :
1067 (oper == "==") ? OPER_EQUALS :
1068 (oper == "!=") ? OPER_NOTEQUALS :
1069 (oper == ">=") ? OPER_GREATERTHANEQUALS :
1070 (oper == "<=") ? OPER_LESSTHANEQUALS :
1071 (oper == "&&") ? OPER_AND :
1072 (oper == "||") ? OPER_OR :
1073 (oper == "<<" && !equalsnext) ? OPER_LEFTSHIFT :
1074 (oper == ">>" && !equalsnext) ? OPER_RIGHTSHIFT :
1075 -1;
1076
1077 if (o != -1)
1078 {
1079 m_lx->must_get_next();
1080 return o;
1081 }
1082
1083 // Three-char opers
1084 oper += m_lx->peek_next_string (peek ? 2 : 1);
1085 o = oper == "<<=" ? OPER_ASSIGNLEFTSHIFT :
1086 oper == ">>=" ? OPER_ASSIGNRIGHTSHIFT :
1087 -1;
1088
1089 if (o != -1)
1090 {
1091 m_lx->must_get_next();
1092 m_lx->must_get_next();
1093 }
1094
1095 return o;
1096 }
1097
1098 // ============================================================================
1099 string botscript_parser::parse_float()
1100 {
1101 m_lx->must_be (tk_number);
1102 string floatstring = TOKEN;
1103 lexer::token* tok;
1104
1105 // Go after the decimal point
1106 if (m_lx->peek_next (tok) && tok->type == tk_dot)
1107 {
1108 m_lx->skip();
1109 m_lx->must_get_next (tk_number);
1110 floatstring += ".";
1111 floatstring += token_string();
1112 }
1113
1114 return floatstring;
1115 }
1116
1117 // ============================================================================
1118 // Parses a value in the expression and returns the data needed to push
1119 // it, contained in a data buffer. A value can be either a variable, a command,
1120 // a literal or an expression.
1121 data_buffer* botscript_parser::parse_expr_value (type_e reqtype)
1122 {
1123 data_buffer* b = new data_buffer (16);
1124
1125 script_variable* g;
1126
1127 // Prefixing "!" means negation.
1128 bool negate = (m_lx->get_token() == tk_exclamation_mark);
1129
1130 if (negate) // Jump past the "!"
1131 m_lx->skip();
1132
1133 // Handle strlen
1134 if (TOKEN == "strlen")
1135 {
1136 m_lx->must_get_next (tk_paren_start);
1137 m_lx->must_get_next();
1138
1139 // By this TOKEN we should get a string constant.
1140 constant_info* constant = find_constant (TOKEN);
1141
1142 if (!constant || constant->type != TYPE_STRING)
1143 error ("strlen only works with const str");
1144
1145 if (reqtype != TYPE_INT)
1146 error ("strlen returns int but %s is expected\n", GetTypeName (reqtype).c_str());
1147
1148 b->write (dh_push_number);
1149 b->write (constant->val.len());
1150
1151 m_lx->must_get_next (tk_paren_end);
1152 }
1153 else if (TOKEN == "(")
1154 {
1155 // Expression
1156 m_lx->must_get_next();
1157 data_buffer* c = parse_expression (reqtype);
1158 b->merge (c);
1159 m_lx->must_get_next (tk_paren_end);
1160 }
1161 else if (CommandDef* comm = FindCommand (TOKEN))
1162 {
1163 delete b;
1164
1165 // Command
1166 if (reqtype && comm->returnvalue != reqtype)
1167 error ("%s returns an incompatible data type", comm->name.chars());
1168
1169 b = ParseCommand (comm);
1170 }
1171 else if (constant_info* constant = find_constant (TOKEN))
1172 {
1173 // Type check
1174 if (reqtype != constant->type)
1175 error ("constant `%s` is %s, expression requires %s\n",
1176 constant->name.c_str(), GetTypeName (constant->type).c_str(),
1177 GetTypeName (reqtype).c_str());
1178
1179 switch (constant->type)
1180 {
1181 case TYPE_BOOL:
1182 case TYPE_INT:
1183 b->write (dh_push_number);
1184 b->write (atoi (constant->val));
1185 break;
1186
1187 case TYPE_STRING:
1188 b->write_string (constant->val);
1189 break;
1190
1191 case TYPE_VOID:
1192 case TYPE_UNKNOWN:
1193 break;
1194 }
1195 }
1196 else if ((g = find_global_variable (TOKEN)))
1197 {
1198 // Global variable
1199 b->write (dh_push_global_var);
1200 b->write (g->index);
1201 }
1202 else
1203 {
1204 // If nothing else, check for literal
1205 switch (reqtype)
1206 {
1207 case TYPE_VOID:
1208 case TYPE_UNKNOWN:
1209 error ("unknown identifier `%s` (expected keyword, function or variable)", TOKEN.chars());
1210 break;
1211
1212 case TYPE_BOOL:
1213 case TYPE_INT:
1214 {
1215 m_lx->must_be (tk_number);
1216
1217 // All values are written unsigned - thus we need to write the value's
1218 // absolute value, followed by an unary minus for negatives.
1219 b->write (dh_push_number);
1220
1221 long v = atol (TOKEN);
1222 b->write (static_cast<word> (abs (v)));
1223
1224 if (v < 0)
1225 b->write (dh_unary_minus);
1226
1227 break;
1228 }
1229
1230 case TYPE_STRING:
1231 // PushToStringTable either returns the string index of the
1232 // string if it finds it in the table, or writes it to the
1233 // table and returns it index if it doesn't find it there.
1234 m_lx->must_be (tk_string);
1235 b->write_string (TOKEN);
1236 break;
1237 }
1238 }
1239
1240 // Negate it now if desired
1241 if (negate)
1242 b->write (dh_negate_logical);
1243
1244 return b;
1245 }
1246
1247 // ============================================================================
1248 // Parses an assignment. An assignment starts with a variable name, followed
1249 // by an assignment operator, followed by an expression value. Expects current
1250 // TOKEN to be the name of the variable, and expects the variable to be given.
1251 data_buffer* botscript_parser::ParseAssignment (script_variable* var)
1252 {
1253 bool global = !var->statename.len();
1254
1255 // Get an operator
1256 m_lx->must_get_next();
1257 int oper = parse_operator();
1258
1259 if (!is_assignment_operator (oper))
1260 error ("expected assignment operator");
1261
1262 if (g_CurMode == MODE_TOPLEVEL)
1263 error ("can't alter variables at top level");
1264
1265 // Parse the right operand
1266 m_lx->must_get_next();
1267 data_buffer* retbuf = new data_buffer;
1268 data_buffer* expr = parse_expression (var->type);
1269
1270 // <<= and >>= do not have data headers. Solution: expand them.
1271 // a <<= b -> a = a << b
1272 // a >>= b -> a = a >> b
1273 if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT)
1274 {
1275 retbuf->write (global ? dh_push_global_var : dh_push_local_var);
1276 retbuf->write (var->index);
1277 retbuf->merge (expr);
1278 retbuf->write ((oper == OPER_ASSIGNLEFTSHIFT) ? dh_left_shift : dh_right_shift);
1279 retbuf->write (global ? dh_assign_global_var : dh_assign_local_var);
1280 retbuf->write (var->index);
1281 }
1282 else
1283 {
1284 retbuf->merge (expr);
1285 long dh = get_data_header_by_operator (var, oper);
1286 retbuf->write (dh);
1287 retbuf->write (var->index);
1288 }
1289
1290 return retbuf;
1291 }
1292
1293 void botscript_parser::push_scope()
1294 {
1295 g_ScopeCursor++;
1296
1297 if (g_ScopeCursor >= MAX_SCOPE)
1298 error ("too deep scope");
1299
1300 ScopeInfo* info = &SCOPE (0);
1301 info->type = e_unknown_scope;
1302 info->mark1 = 0;
1303 info->mark2 = 0;
1304 info->buffer1 = null;
1305 info->casecursor = -1;
1306
1307 for (int i = 0; i < MAX_CASE; i++)
1308 {
1309 info->casemarks[i] = MAX_MARKS;
1310 info->casebuffers[i] = null;
1311 info->casenumbers[i] = -1;
1312 }
1313 }
1314
1315 data_buffer* botscript_parser::parse_statement (object_writer* w)
1316 {
1317 if (find_constant (TOKEN)) // There should not be constants here.
1318 error ("invalid use for constant\n");
1319
1320 // If it's a variable, expect assignment.
1321 if (script_variable* var = find_global_variable (TOKEN))
1322 return ParseAssignment (var);
1323
1324 return null;
1325 }
1326
1327 void botscript_parser::add_switch_case (object_writer* w, data_buffer* b)
1328 {
1329 ScopeInfo* info = &SCOPE (0);
1330
1331 info->casecursor++;
1332
1333 if (info->casecursor >= MAX_CASE)
1334 error ("too many cases in one switch");
1335
1336 // Init a mark for the case buffer
1337 int m = w->add_mark ("");
1338 info->casemarks[info->casecursor] = m;
1339
1340 // Add a reference to the mark. "case" and "default" both
1341 // add the necessary bytecode before the reference.
1342 if (b)
1343 b->add_reference (m);
1344 else
1345 w->add_reference (m);
1346
1347 // Init a buffer for the case block and tell the object
1348 // writer to record all written data to it.
1349 info->casebuffers[info->casecursor] = w->SwitchBuffer = new data_buffer;
1350 }
1351
1352 constant_info* find_constant (string tok)
1353 {
1354 for (int i = 0; i < g_ConstInfo.size(); i++)
1355 if (g_ConstInfo[i].name == tok)
1356 return &g_ConstInfo[i];
1357
1358 return null;
1359 }
1360
1361 // ============================================================================
1362 //
1363 bool botscript_parser::token_is (e_token a)
1364 {
1365 return (m_lx->get_token() == a);
1366 }
1367
1368 // ============================================================================
1369 //
1370 string botscript_parser::token_string()
1371 {
1372 return m_lx->get_token()->text;
1373 }
1374
1375 // ============================================================================
1376 //
1377 string botscript_parser::describe_position() const
1378 {
1379 lexer::token* tok = m_lx->get_token();
1380 return tok->file + ":" + string (tok->line) + ":" + string (tok->column);
1381 }

mercurial