68 |
68 |
69 // ============================================================================ |
69 // ============================================================================ |
70 // Main parser code. Begins read of the script file, checks the syntax of it |
70 // Main parser code. Begins read of the script file, checks the syntax of it |
71 // and writes the data to the object file via ObjWriter - which also takes care |
71 // and writes the data to the object file via ObjWriter - which also takes care |
72 // of necessary buffering so stuff is written in the correct order. |
72 // of necessary buffering so stuff is written in the correct order. |
73 void ScriptReader::BeginParse (ObjWriter* w) { |
73 void ScriptReader::ParseBotScript (ObjWriter* w) { |
74 while (Next()) { |
74 while (Next()) { |
75 // ============================================================ |
75 // ============================================================ |
76 if (!token.icompare ("state")) { |
76 if (!token.compare ("state")) { |
77 MUST_TOPLEVEL |
77 MUST_TOPLEVEL |
78 |
78 |
79 MustString (); |
79 MustString (); |
80 |
80 |
81 // State name must be a word. |
81 // State name must be a word. |
127 g_NumEvents++; |
127 g_NumEvents++; |
128 continue; |
128 continue; |
129 } |
129 } |
130 |
130 |
131 // ============================================================ |
131 // ============================================================ |
132 if (!token.icompare ("mainloop")) { |
132 if (!token.compare ("mainloop")) { |
133 MUST_TOPLEVEL |
133 MUST_TOPLEVEL |
134 MustNext ("{"); |
134 MustNext ("{"); |
135 |
135 |
136 // Mode must be set before dataheader is written here! |
136 // Mode must be set before dataheader is written here! |
137 g_CurMode = MODE_MAINLOOP; |
137 g_CurMode = MODE_MAINLOOP; |
138 w->Write (DH_MAINLOOP); |
138 w->Write (DH_MAINLOOP); |
139 continue; |
139 continue; |
140 } |
140 } |
141 |
141 |
142 // ============================================================ |
142 // ============================================================ |
143 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
143 if (!token.compare ("onenter") || !token.compare ("onexit")) { |
144 MUST_TOPLEVEL |
144 MUST_TOPLEVEL |
145 bool onenter = !token.compare ("onenter"); |
145 bool onenter = !token.compare ("onenter"); |
146 MustNext ("{"); |
146 MustNext ("{"); |
147 |
147 |
148 // Mode must be set before dataheader is written here, |
148 // Mode must be set before dataheader is written here, |
326 continue; |
308 continue; |
327 } |
309 } |
328 |
310 |
329 // ============================================================ |
311 // ============================================================ |
330 // Do/while loop |
312 // Do/while loop |
331 if (!token.icompare ("do")) { |
313 if (!token.compare ("do")) { |
332 MUST_NOT_TOPLEVEL |
314 MUST_NOT_TOPLEVEL |
333 PushBlockStack (); |
315 PushBlockStack (); |
334 MustNext ("{"); |
316 MustNext ("{"); |
335 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); |
317 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); |
336 blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO; |
318 blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO; |
337 continue; |
319 continue; |
338 } |
320 } |
339 |
321 |
340 // ============================================================ |
322 // ============================================================ |
341 // Switch |
323 // Switch |
342 if (!token.icompare ("switch")) { |
324 if (!token.compare ("switch")) { |
343 /* This goes a bit tricky. switch is structured in the |
325 /* This goes a bit tricky. switch is structured in the |
344 * bytecode followingly: |
326 * bytecode followingly: |
345 * (expression) |
327 * (expression) |
346 * case a: goto casemark1 |
328 * case a: goto casemark1 |
347 * case b: goto casemark2 |
329 * case b: goto casemark2 |
360 w->WriteBuffer (ParseExpression (TYPE_INT)); |
342 w->WriteBuffer (ParseExpression (TYPE_INT)); |
361 MustNext (")"); |
343 MustNext (")"); |
362 MustNext ("{"); |
344 MustNext ("{"); |
363 blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH; |
345 blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH; |
364 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark |
346 blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark |
365 continue; |
347 blockstack[g_BlockStackCursor].buffer1 = NULL; // default header |
366 } |
348 continue; |
367 |
349 } |
368 // ============================================================ |
350 |
369 if (!token.icompare ("case")) { |
351 // ============================================================ |
|
352 if (!token.compare ("case")) { |
370 // case is only allowed inside switch |
353 // case is only allowed inside switch |
371 if (g_BlockStackCursor <= 0 || blockstack[g_BlockStackCursor].type != BLOCKTYPE_SWITCH) |
|
372 ParserError ("`case` outside switch"); |
|
373 |
|
374 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
354 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
375 info->casecursor++; |
355 if (info->type != BLOCKTYPE_SWITCH) |
376 if (info->casecursor >= MAX_CASE) |
356 ParserError ("case label outside switch"); |
377 ParserError ("too many `case` statements in one switch"); |
|
378 |
357 |
379 // Get the literal (Zandronum does not support expressions here) |
358 // Get the literal (Zandronum does not support expressions here) |
380 MustNumber (); |
359 MustNumber (); |
381 int num = atoi (token.chars ()); |
360 int num = atoi (token.chars ()); |
382 |
|
383 MustNext (":"); |
361 MustNext (":"); |
384 |
362 |
385 // Init a mark for the case buffer |
363 for (int i = 0; i < MAX_CASE; i++) |
386 int m = w->AddMark (""); |
364 if (info->casenumbers[i] == num) |
387 info->casemarks[info->casecursor] = m; |
365 ParserError ("multiple case %d labels in one switch", num); |
388 |
366 |
389 // Write down the expression and case-go-to. This builds |
367 // Write down the expression and case-go-to. This builds |
390 // the case tree. The closing event will write the actual |
368 // the case tree. The closing event will write the actual |
391 // blocks and move the marks appropriately. |
369 // blocks and move the marks appropriately. |
392 // |
370 // AddSwitchCase will add the reference to the mark |
393 // NULL the switch buffer for the case-go-to statement, |
371 // for the case block that this heralds, and takes care |
|
372 // of buffering setup and stuff like that. |
|
373 // NULL the switch buffer for the case-go-to statement, |
394 // we want it all under the switch, not into the case-buffers. |
374 // we want it all under the switch, not into the case-buffers. |
395 w->SwitchBuffer = NULL; |
375 w->SwitchBuffer = NULL; |
396 w->Write<word> (DH_CASEGOTO); |
376 w->Write<word> (DH_CASEGOTO); |
397 w->Write<word> (num); |
377 w->Write<word> (num); |
398 w->AddReference (m); |
378 AddSwitchCase (w, NULL); |
399 |
379 info->casenumbers[info->casecursor] = num; |
400 // Init a buffer for the case block, tell the object |
380 continue; |
401 // writer to record all written data to it. |
381 } |
402 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer; |
382 |
|
383 if (!token.compare ("default")) { |
|
384 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
|
385 if (info->type != BLOCKTYPE_SWITCH) |
|
386 ParserError ("default label outside switch"); |
|
387 |
|
388 if (info->buffer1) |
|
389 ParserError ("multiple default labels in one switch"); |
|
390 |
|
391 MustNext (":"); |
|
392 |
|
393 // The default header is buffered into buffer1, since |
|
394 // it has to be the last of the case headers |
|
395 // |
|
396 // Since the expression is pushed into the switch |
|
397 // and is only popped when case succeeds, we have |
|
398 // to pop it with DH_DROP manually if we end up in |
|
399 // a default. |
|
400 DataBuffer* b = new DataBuffer; |
|
401 info->buffer1 = b; |
|
402 b->Write<word> (DH_DROP); |
|
403 b->Write<word> (DH_GOTO); |
|
404 AddSwitchCase (w, b); |
403 continue; |
405 continue; |
404 } |
406 } |
405 |
407 |
406 // ============================================================ |
408 // ============================================================ |
407 // Break statement. |
409 // Break statement. |
408 if (!token.icompare ("break")) { |
410 if (!token.compare ("break")) { |
409 if (!g_BlockStackCursor) |
411 if (!g_BlockStackCursor) |
410 ParserError ("unexpected `break`"); |
412 ParserError ("unexpected `break`"); |
411 |
413 |
412 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
414 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
413 |
415 |
469 w->WriteBuffer (expr); |
488 w->WriteBuffer (expr); |
470 w->Write<long> (DH_IFGOTO); |
489 w->Write<long> (DH_IFGOTO); |
471 w->AddReference (info->mark1); |
490 w->AddReference (info->mark1); |
472 break; |
491 break; |
473 } |
492 } |
474 |
|
475 case BLOCKTYPE_SWITCH: { |
493 case BLOCKTYPE_SWITCH: { |
476 // Switch closes. Move down to the record buffer of |
494 // Switch closes. Move down to the record buffer of |
477 // the lower block. |
495 // the lower block. |
478 BlockInformation* previnfo = &blockstack[g_BlockStackCursor - 1]; |
496 BlockInformation* previnfo = &blockstack[g_BlockStackCursor - 1]; |
479 if (previnfo->casecursor != -1) |
497 if (previnfo->casecursor != -1) |
480 w->SwitchBuffer = previnfo->casebuffers[previnfo->casecursor]; |
498 w->SwitchBuffer = previnfo->casebuffers[previnfo->casecursor]; |
481 else |
499 else |
482 w->SwitchBuffer = NULL; |
500 w->SwitchBuffer = NULL; |
|
501 |
|
502 // If there was a default in the switch, write its header down now. |
|
503 // If not, write instruction to jump to the end of switch after |
|
504 // the headers (thus won't fall-through if no case matched) |
|
505 if (info->buffer1) |
|
506 w->WriteBuffer (info->buffer1); |
|
507 else { |
|
508 w->Write<word> (DH_DROP); |
|
509 w->Write<word> (DH_GOTO); |
|
510 w->AddReference (info->mark1); |
|
511 } |
483 |
512 |
484 // Go through all of the buffers we |
513 // Go through all of the buffers we |
485 // recorded down and write them. |
514 // recorded down and write them. |
486 for (unsigned int u = 0; u < MAX_CASE; u++) { |
515 for (unsigned int u = 0; u < MAX_CASE; u++) { |
487 if (!info->casebuffers[u]) |
516 if (!info->casebuffers[u]) |
833 |
863 |
834 // If it's not a keyword, parse it as an expression. |
864 // If it's not a keyword, parse it as an expression. |
835 DataBuffer* b = ParseExpression (TYPE_VOID); |
865 DataBuffer* b = ParseExpression (TYPE_VOID); |
836 return b; |
866 return b; |
837 } |
867 } |
|
868 |
|
869 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) { |
|
870 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
|
871 |
|
872 info->casecursor++; |
|
873 if (info->casecursor >= MAX_CASE) |
|
874 ParserError ("too many cases in one switch"); |
|
875 |
|
876 // Init a mark for the case buffer |
|
877 int m = w->AddMark (""); |
|
878 info->casemarks[info->casecursor] = m; |
|
879 |
|
880 // Add a reference to the mark. "case" and "default" both |
|
881 // add the necessary bytecode before the reference. |
|
882 if (b) |
|
883 b->AddMarkReference (m); |
|
884 else |
|
885 w->AddReference (m); |
|
886 |
|
887 // Init a buffer for the case block and tell the object |
|
888 // writer to record all written data to it. |
|
889 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer; |
|
890 } |