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_UndefinedLabels[MAX_MARKS]; |
71 str* g_UndefinedLabels[MAX_MARKS]; |
|
72 bool g_Neurosphere = false; // neurosphere-compat |
72 |
73 |
73 // ============================================================================ |
74 // ============================================================================ |
74 // Main parser code. Begins read of the script file, checks the syntax of it |
75 // Main parser code. Begins read of the script file, checks the syntax of it |
75 // and writes the data to the object file via ObjWriter - which also takes care |
76 // and writes the data to the object file via ObjWriter - which also takes care |
76 // of necessary buffering so stuff is written in the correct order. |
77 // of necessary buffering so stuff is written in the correct order. |
82 for (int i = 0; i < MAX_MARKS; i++) |
83 for (int i = 0; i < MAX_MARKS; i++) |
83 g_UndefinedLabels[i] = NULL; |
84 g_UndefinedLabels[i] = NULL; |
84 |
85 |
85 while (Next()) { |
86 while (Next()) { |
86 // Check if else is potentically valid |
87 // Check if else is potentically valid |
87 if (!token.compare ("else") && !g_CanElse) |
88 if (token == "else" && !g_CanElse) |
88 ParserError ("else without preceding if"); |
89 ParserError ("else without preceding if"); |
89 if (token.compare ("else") != 0) |
90 if (token != "else") |
90 g_CanElse = false; |
91 g_CanElse = false; |
91 |
92 |
92 // ============================================================ |
93 // ============================================================ |
93 if (!token.compare ("state")) { |
94 if (token == "state") { |
94 MUST_TOPLEVEL |
95 MUST_TOPLEVEL |
95 |
96 |
96 MustString (); |
97 MustString (); |
97 |
98 |
98 // State name must be a word. |
99 // State name must be a word. |
144 g_NumEvents++; |
145 g_NumEvents++; |
145 continue; |
146 continue; |
146 } |
147 } |
147 |
148 |
148 // ============================================================ |
149 // ============================================================ |
149 if (!token.compare ("mainloop")) { |
150 if (token == "mainloop") { |
150 MUST_TOPLEVEL |
151 MUST_TOPLEVEL |
151 MustNext ("{"); |
152 MustNext ("{"); |
152 |
153 |
153 // Mode must be set before dataheader is written here! |
154 // Mode must be set before dataheader is written here! |
154 g_CurMode = MODE_MAINLOOP; |
155 g_CurMode = MODE_MAINLOOP; |
155 w->Write (DH_MAINLOOP); |
156 w->Write (DH_MAINLOOP); |
156 continue; |
157 continue; |
157 } |
158 } |
158 |
159 |
159 // ============================================================ |
160 // ============================================================ |
160 if (!token.compare ("onenter") || !token.compare ("onexit")) { |
161 if (token == "onenter" || token == "onexit") { |
161 MUST_TOPLEVEL |
162 MUST_TOPLEVEL |
162 bool onenter = !token.compare ("onenter"); |
163 bool onenter = token == "onenter"; |
163 MustNext ("{"); |
164 MustNext ("{"); |
164 |
165 |
165 // Mode must be set before dataheader is written here, |
166 // Mode must be set before dataheader is written here, |
166 // because onenter goes to a separate buffer. |
167 // because onenter goes to a separate buffer. |
167 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
168 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
168 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
169 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
169 continue; |
170 continue; |
170 } |
171 } |
171 |
172 |
172 // ============================================================ |
173 // ============================================================ |
173 if (!token.compare ("var")) { |
174 if (token == "var") { |
174 // For now, only globals are supported |
175 // For now, only globals are supported |
175 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
176 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
176 ParserError ("variables must only be global for now"); |
177 ParserError ("variables must only be global for now"); |
177 |
178 |
178 MustNext (); |
179 MustNext (); |
274 continue; |
275 continue; |
275 } |
276 } |
276 |
277 |
277 // ============================================================ |
278 // ============================================================ |
278 // While |
279 // While |
279 if (!token.compare ("while")) { |
280 if (token == "while") { |
280 MUST_NOT_TOPLEVEL |
281 MUST_NOT_TOPLEVEL |
281 PushScope (); |
282 PushScope (); |
282 |
283 |
283 // While loops need two marks - one at the start of the loop and one at the |
284 // While loops need two marks - one at the start of the loop and one at the |
284 // end. The condition is checked at the very start of the loop, if it fails, |
285 // end. The condition is checked at the very start of the loop, if it fails, |
351 continue; |
352 continue; |
352 } |
353 } |
353 |
354 |
354 // ============================================================ |
355 // ============================================================ |
355 // Do/while loop |
356 // Do/while loop |
356 if (!token.compare ("do")) { |
357 if (token == "do") { |
357 MUST_NOT_TOPLEVEL |
358 MUST_NOT_TOPLEVEL |
358 PushScope (); |
359 PushScope (); |
359 MustNext ("{"); |
360 MustNext ("{"); |
360 SCOPE(0).mark1 = w->AddMark (""); |
361 SCOPE(0).mark1 = w->AddMark (""); |
361 SCOPE(0).type = SCOPETYPE_DO; |
362 SCOPE(0).type = SCOPETYPE_DO; |
362 continue; |
363 continue; |
363 } |
364 } |
364 |
365 |
365 // ============================================================ |
366 // ============================================================ |
366 // Switch |
367 // Switch |
367 if (!token.compare ("switch")) { |
368 if (token == "switch") { |
368 /* This goes a bit tricky. switch is structured in the |
369 /* This goes a bit tricky. switch is structured in the |
369 * bytecode followingly: |
370 * bytecode followingly: |
370 * (expression) |
371 * (expression) |
371 * case a: goto casemark1 |
372 * case a: goto casemark1 |
372 * case b: goto casemark2 |
373 * case b: goto casemark2 |
390 SCOPE(0).buffer1 = NULL; // default header |
391 SCOPE(0).buffer1 = NULL; // default header |
391 continue; |
392 continue; |
392 } |
393 } |
393 |
394 |
394 // ============================================================ |
395 // ============================================================ |
395 if (!token.compare ("case")) { |
396 if (token == "case") { |
396 // case is only allowed inside switch |
397 // case is only allowed inside switch |
397 if (SCOPE(0).type != SCOPETYPE_SWITCH) |
398 if (SCOPE(0).type != SCOPETYPE_SWITCH) |
398 ParserError ("case label outside switch"); |
399 ParserError ("case label outside switch"); |
399 |
400 |
400 // Get the literal (Zandronum does not support expressions here) |
401 // Get the literal (Zandronum does not support expressions here) |
420 AddSwitchCase (w, NULL); |
421 AddSwitchCase (w, NULL); |
421 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; |
422 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; |
422 continue; |
423 continue; |
423 } |
424 } |
424 |
425 |
425 if (!token.compare ("default")) { |
426 if (token == "default") { |
426 if (SCOPE(0).type != SCOPETYPE_SWITCH) |
427 if (SCOPE(0).type != SCOPETYPE_SWITCH) |
427 ParserError ("default label outside switch"); |
428 ParserError ("default label outside switch"); |
428 |
429 |
429 if (SCOPE(0).buffer1) |
430 if (SCOPE(0).buffer1) |
430 ParserError ("multiple default labels in one switch"); |
431 ParserError ("multiple default labels in one switch"); |
637 if (!PeekNext().compare (";")) |
643 if (!PeekNext().compare (";")) |
638 MustNext (";"); |
644 MustNext (";"); |
639 continue; |
645 continue; |
640 } |
646 } |
641 |
647 |
642 // ============================================================ |
648 // Check if it's a command |
643 // If nothing else, parse it as a statement (which is either |
649 CommandDef* comm = FindCommand (token); |
644 // assignment or expression) |
650 if (comm) { |
|
651 w->GetCurrentBuffer()->Merge (ParseCommand (comm)); |
|
652 MustNext (";"); |
|
653 continue; |
|
654 } |
|
655 |
|
656 // ============================================================ |
|
657 // If nothing else, parse it as a statement |
645 DataBuffer* b = ParseStatement (w); |
658 DataBuffer* b = ParseStatement (w); |
646 w->WriteBuffer (b); |
659 w->WriteBuffer (b); |
647 MustNext (";"); |
660 MustNext (";"); |
648 } |
661 } |
649 |
662 |
|
663 // =============================================================================== |
|
664 // Script file ended. Do some last checks and write the last things to main buffer |
650 if (g_CurMode != MODE_TOPLEVEL) |
665 if (g_CurMode != MODE_TOPLEVEL) |
651 ParserError ("script did not end at top level; did you forget a `}`?"); |
666 ParserError ("script did not end at top level; did you forget a `}`?"); |
652 |
667 |
653 // stateSpawn must be defined! |
668 // stateSpawn must be defined! |
654 if (!g_stateSpawnDefined) |
669 if (!g_stateSpawnDefined) |
815 MustNext (); |
830 MustNext (); |
816 DataBuffer* tb = ParseExprValue (reqtype); |
831 DataBuffer* tb = ParseExprValue (reqtype); |
817 |
832 |
818 // It also is handled differently: there isn't a dataheader for ternary |
833 // It also is handled differently: there isn't a dataheader for ternary |
819 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
834 // operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this. |
|
835 // Behold, big block of writing madness! :P |
820 int mark1 = retbuf->AddMark (""); // start of "else" case |
836 int mark1 = retbuf->AddMark (""); // start of "else" case |
821 int mark2 = retbuf->AddMark (""); // end of expression |
837 int mark2 = retbuf->AddMark (""); // end of expression |
822 retbuf->Write<word> (DH_IFNOTGOTO); |
838 retbuf->Write<word> (DH_IFNOTGOTO); // if the first operand (condition) |
823 retbuf->AddMarkReference (mark1); |
839 retbuf->AddMarkReference (mark1); // didn't eval true, jump into mark1 |
824 retbuf->Merge (rb); |
840 retbuf->Merge (rb); // otherwise, perform second operand (true case) |
825 retbuf->Write<word> (DH_GOTO); |
841 retbuf->Write<word> (DH_GOTO); // afterwards, jump to the end, which is |
826 retbuf->AddMarkReference (mark2); |
842 retbuf->AddMarkReference (mark2); // marked by mark2. |
827 retbuf->MoveMark (mark1); // start of "else" case |
843 retbuf->MoveMark (mark1); // move mark1 at the end of the true case |
828 retbuf->Merge (tb); |
844 retbuf->Merge (tb); // perform third operand (false case) |
829 retbuf->Write<word> (DH_GOTO); |
845 retbuf->MoveMark (mark2); // move the ending mark2 here |
830 retbuf->AddMarkReference (mark2); |
|
831 retbuf->MoveMark (mark2); // move endmark to end |
|
832 } else { |
846 } else { |
833 // Write to buffer |
847 // Write to buffer |
834 retbuf->Merge (rb); |
848 retbuf->Merge (rb); |
835 retbuf->Write<word> (DataHeaderByOperator (NULL, oper)); |
849 retbuf->Write<word> (DataHeaderByOperator (NULL, oper)); |
836 } |
850 } |
1051 g_ScopeCursor++; |
1065 g_ScopeCursor++; |
1052 if (g_ScopeCursor >= MAX_SCOPE) |
1066 if (g_ScopeCursor >= MAX_SCOPE) |
1053 ParserError ("too deep scope"); |
1067 ParserError ("too deep scope"); |
1054 |
1068 |
1055 ScopeInfo* info = &SCOPE(0); |
1069 ScopeInfo* info = &SCOPE(0); |
1056 info->type = 0; |
1070 info->type = SCOPETYPE_UNKNOWN; |
1057 info->mark1 = 0; |
1071 info->mark1 = 0; |
1058 info->mark2 = 0; |
1072 info->mark2 = 0; |
1059 info->buffer1 = NULL; |
1073 info->buffer1 = NULL; |
1060 info->casecursor = -1; |
1074 info->casecursor = -1; |
1061 for (int i = 0; i < MAX_CASE; i++) { |
1075 for (int i = 0; i < MAX_CASE; i++) { |