66 bool g_stateSpawnDefined = false; |
66 bool g_stateSpawnDefined = false; |
67 bool g_GotMainLoop = false; |
67 bool g_GotMainLoop = false; |
68 unsigned int g_ScopeCursor = 0; |
68 unsigned int g_ScopeCursor = 0; |
69 DataBuffer* g_IfExpression = NULL; |
69 DataBuffer* g_IfExpression = NULL; |
70 bool g_CanElse = false; |
70 bool g_CanElse = false; |
|
71 str* g_UnmarkedLabels[MAX_MARKS]; |
71 |
72 |
72 // ============================================================================ |
73 // ============================================================================ |
73 // Main parser code. Begins read of the script file, checks the syntax of it |
74 // Main parser code. Begins read of the script file, checks the syntax of it |
74 // and writes the data to the object file via ObjWriter - which also takes care |
75 // and writes the data to the object file via ObjWriter - which also takes care |
75 // of necessary buffering so stuff is written in the correct order. |
76 // of necessary buffering so stuff is written in the correct order. |
76 void ScriptReader::ParseBotScript (ObjWriter* w) { |
77 void ScriptReader::ParseBotScript (ObjWriter* w) { |
77 // Zero the entire block stack first |
78 // Zero the entire block stack first |
78 for (int i = 0; i < MAX_SCOPE; i++) |
79 for (int i = 0; i < MAX_SCOPE; i++) |
79 ZERO(scopestack[i]); |
80 ZERO(scopestack[i]); |
80 |
81 |
|
82 for (int i = 0; i < MAX_MARKS; i++) |
|
83 g_UnmarkedLabels[i] = NULL; |
|
84 |
81 while (Next()) { |
85 while (Next()) { |
82 // Check if else is potentically valid |
86 // Check if else is potentically valid |
83 if (!token.compare ("else") && !g_CanElse) |
87 if (!token.compare ("else") && !g_CanElse) |
84 ParserError ("else without preceding if"); |
88 ParserError ("else without preceding if"); |
85 if (token.compare ("else") != 0) |
89 if (token.compare ("else") != 0) |
195 |
199 |
196 // Get the name of the label |
200 // Get the name of the label |
197 MustNext (); |
201 MustNext (); |
198 |
202 |
199 // Find the mark this goto statement points to |
203 // Find the mark this goto statement points to |
200 // TODO: This should define the mark instead of bombing |
|
201 // out if the mark isn't found! |
|
202 unsigned int m = w->FindMark (token); |
204 unsigned int m = w->FindMark (token); |
203 if (m == MAX_MARKS) |
205 |
204 ParserError ("unknown label `%s`!", token.chars()); |
206 // If not set, define it |
|
207 if (m == MAX_MARKS) { |
|
208 m = w->AddMark (token); |
|
209 g_UnmarkedLabels[m] = new str (token); |
|
210 } |
205 |
211 |
206 // Add a reference to the mark. |
212 // Add a reference to the mark. |
207 w->Write<word> (DH_GOTO); |
213 w->Write<word> (DH_GOTO); |
208 w->AddReference (m); |
214 w->AddReference (m); |
209 MustNext (";"); |
215 MustNext (";"); |
499 // ============================================================ |
505 // ============================================================ |
500 // Label |
506 // Label |
501 if (!PeekNext().compare (":")) { |
507 if (!PeekNext().compare (":")) { |
502 MUST_NOT_TOPLEVEL |
508 MUST_NOT_TOPLEVEL |
503 |
509 |
|
510 // want no conflicts.. |
504 if (IsKeyword (token)) |
511 if (IsKeyword (token)) |
505 ParserError ("label name `%s` conflicts with keyword\n", token.chars()); |
512 ParserError ("label name `%s` conflicts with keyword\n", token.chars()); |
506 if (FindCommand (token)) |
513 if (FindCommand (token)) |
507 ParserError ("label name `%s` conflicts with command name\n", token.chars()); |
514 ParserError ("label name `%s` conflicts with command name\n", token.chars()); |
508 if (FindGlobalVariable (token)) |
515 if (FindGlobalVariable (token)) |
509 ParserError ("label name `%s` conflicts with variable\n", token.chars()); |
516 ParserError ("label name `%s` conflicts with variable\n", token.chars()); |
510 |
517 |
511 w->AddMark (token); |
518 // See if the label is already defined but unmarked |
|
519 int mark = -1; |
|
520 for (int i = 0; i < MAX_MARKS; i++) { |
|
521 if (g_UnmarkedLabels[i] && !g_UnmarkedLabels[i]->compare (token)) { |
|
522 mark = i; |
|
523 w->MoveMark (i); |
|
524 |
|
525 // No longer unmarked |
|
526 delete g_UnmarkedLabels[i]; |
|
527 g_UnmarkedLabels[i] = NULL; |
|
528 } |
|
529 } |
|
530 |
|
531 // Not found in unmarked lists, define it now |
|
532 if (mark == -1) |
|
533 w->AddMark (token); |
|
534 |
512 MustNext (":"); |
535 MustNext (":"); |
513 continue; |
536 continue; |
514 } |
537 } |
515 |
538 |
516 // ============================================================ |
539 // ============================================================ |
629 |
652 |
630 // stateSpawn must be defined! |
653 // stateSpawn must be defined! |
631 if (!g_stateSpawnDefined) |
654 if (!g_stateSpawnDefined) |
632 ParserError ("script must have a state named `stateSpawn`!"); |
655 ParserError ("script must have a state named `stateSpawn`!"); |
633 |
656 |
|
657 for (int i = 0; i < MAX_MARKS; i++) |
|
658 if (g_UnmarkedLabels[i]) |
|
659 ParserError ("label `%s` is referenced via `goto` but isn't defined\n", g_UnmarkedLabels[i]->chars()); |
|
660 |
634 // Dump the last state's onenter and mainloop |
661 // Dump the last state's onenter and mainloop |
635 w->WriteBuffers (); |
662 w->WriteBuffers (); |
636 |
663 |
637 // String table |
664 // String table |
638 w->WriteStringTable (); |
665 w->WriteStringTable (); |