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::BeginParse (ObjWriter* w) { |
74 while (Next()) { |
74 while (Next()) { |
|
75 // ============================================================ |
75 if (!token.icompare ("state")) { |
76 if (!token.icompare ("state")) { |
76 MUST_TOPLEVEL |
77 MUST_TOPLEVEL |
77 |
78 |
78 MustString (); |
79 MustString (); |
79 |
80 |
124 w->Write<word> (e->number); |
126 w->Write<word> (e->number); |
125 g_NumEvents++; |
127 g_NumEvents++; |
126 continue; |
128 continue; |
127 } |
129 } |
128 |
130 |
|
131 // ============================================================ |
129 if (!token.icompare ("mainloop")) { |
132 if (!token.icompare ("mainloop")) { |
130 MUST_TOPLEVEL |
133 MUST_TOPLEVEL |
131 MustNext ("{"); |
134 MustNext ("{"); |
132 |
135 |
133 // Mode must be set before dataheader is written here! |
136 // Mode must be set before dataheader is written here! |
134 g_CurMode = MODE_MAINLOOP; |
137 g_CurMode = MODE_MAINLOOP; |
135 w->Write (DH_MAINLOOP); |
138 w->Write (DH_MAINLOOP); |
136 continue; |
139 continue; |
137 } |
140 } |
138 |
141 |
|
142 // ============================================================ |
139 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
143 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
140 MUST_TOPLEVEL |
144 MUST_TOPLEVEL |
141 bool onenter = !token.compare ("onenter"); |
145 bool onenter = !token.compare ("onenter"); |
142 MustNext ("{"); |
146 MustNext ("{"); |
143 |
147 |
146 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
150 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
147 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
151 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
148 continue; |
152 continue; |
149 } |
153 } |
150 |
154 |
|
155 // ============================================================ |
151 if (!token.compare ("var")) { |
156 if (!token.compare ("var")) { |
152 // For now, only globals are supported |
157 // For now, only globals are supported |
153 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
158 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
154 ParserError ("variables must only be global for now"); |
159 ParserError ("variables must only be global for now"); |
155 |
160 |
268 blockstack[g_BlockStackCursor].mark2 = mark2; |
277 blockstack[g_BlockStackCursor].mark2 = mark2; |
269 blockstack[g_BlockStackCursor].type = BLOCKTYPE_WHILE; |
278 blockstack[g_BlockStackCursor].type = BLOCKTYPE_WHILE; |
270 continue; |
279 continue; |
271 } |
280 } |
272 |
281 |
|
282 // ============================================================ |
|
283 // For loop |
|
284 if (!token.icompare ("for")) { |
|
285 MUST_NOT_TOPLEVEL |
|
286 PushBlockStack (); |
|
287 |
|
288 // Initializer |
|
289 MustNext ("("); |
|
290 MustNext (); |
|
291 DataBuffer* init = ParseStatement (w); |
|
292 MustNext (";"); |
|
293 |
|
294 // Condition |
|
295 MustNext (); |
|
296 DataBuffer* cond = ParseExpression (TYPE_INT); |
|
297 MustNext (";"); |
|
298 |
|
299 // Incrementor |
|
300 MustNext (); |
|
301 DataBuffer* incr = ParseStatement (w); |
|
302 MustNext (")"); |
|
303 MustNext ("{"); |
|
304 |
|
305 // First, write out the initializer |
|
306 w->WriteBuffer (init); |
|
307 |
|
308 // Init two marks |
|
309 int mark1 = w->AddMark (MARKTYPE_INTERNAL, ""); |
|
310 int mark2 = w->AddMark (MARKTYPE_INTERNAL, ""); |
|
311 |
|
312 // Add the condition |
|
313 w->WriteBuffer (cond); |
|
314 w->Write<long> (DH_IFNOTGOTO); |
|
315 w->AddReference (mark2); |
|
316 |
|
317 // Store the marks and incrementor |
|
318 blockstack[g_BlockStackCursor].mark1 = mark1; |
|
319 blockstack[g_BlockStackCursor].mark2 = mark2; |
|
320 blockstack[g_BlockStackCursor].buffer1 = incr; |
|
321 blockstack[g_BlockStackCursor].type = BLOCKTYPE_FOR; |
|
322 continue; |
|
323 } |
|
324 |
|
325 // ============================================================ |
273 if (!token.compare ("}")) { |
326 if (!token.compare ("}")) { |
274 // Closing brace |
327 // Closing brace |
275 |
328 |
276 // If we're in the block stack, we're descending down from it now |
329 // If we're in the block stack, we're descending down from it now |
277 if (g_BlockStackCursor > 0) { |
330 if (g_BlockStackCursor > 0) { |
279 switch (info->type) { |
332 switch (info->type) { |
280 case BLOCKTYPE_IF: |
333 case BLOCKTYPE_IF: |
281 // Adjust the closing mark. |
334 // Adjust the closing mark. |
282 w->MoveMark (info->mark1); |
335 w->MoveMark (info->mark1); |
283 break; |
336 break; |
|
337 case BLOCKTYPE_FOR: |
|
338 // Write the incrementor at the end of the loop block |
|
339 w->WriteBuffer (info->buffer1); |
|
340 // fall-thru |
284 case BLOCKTYPE_WHILE: |
341 case BLOCKTYPE_WHILE: |
285 // Write down the instruction to go back to the start of the loop |
342 // Write down the instruction to go back to the start of the loop |
286 w->Write (DH_GOTO); |
343 w->Write (DH_GOTO); |
287 w->AddReference (info->mark1); |
344 w->AddReference (info->mark1); |
288 |
345 |
312 if (!PeekNext().compare (";")) |
369 if (!PeekNext().compare (";")) |
313 MustNext (";"); |
370 MustNext (";"); |
314 continue; |
371 continue; |
315 } |
372 } |
316 |
373 |
317 // If it's a variable, expect assignment. |
374 // ============================================================ |
318 if (ScriptVar* var = FindGlobalVariable (token)) { |
375 // If nothing else, parse it as a statement (which is either |
319 DataBuffer* b = ParseAssignment (var); |
376 // assignment or expression) |
320 MustNext (";"); |
377 DataBuffer* b = ParseStatement (w); |
321 w->WriteBuffer (b); |
|
322 continue; |
|
323 } |
|
324 |
|
325 // If it's not a keyword, parse it as an expression. |
|
326 DataBuffer* b = ParseExpression (TYPE_VOID); |
|
327 w->WriteBuffer (b); |
378 w->WriteBuffer (b); |
328 MustNext (";"); |
379 MustNext (";"); |
329 } |
380 } |
330 |
381 |
331 if (g_CurMode != MODE_TOPLEVEL) |
382 if (g_CurMode != MODE_TOPLEVEL) |
620 g_BlockStackCursor++; |
671 g_BlockStackCursor++; |
621 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
672 BlockInformation* info = &blockstack[g_BlockStackCursor]; |
622 info->type = 0; |
673 info->type = 0; |
623 info->mark1 = 0; |
674 info->mark1 = 0; |
624 info->mark2 = 0; |
675 info->mark2 = 0; |
625 } |
676 info->buffer1 = NULL; |
|
677 } |
|
678 |
|
679 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { |
|
680 // If it's a variable, expect assignment. |
|
681 if (ScriptVar* var = FindGlobalVariable (token)) { |
|
682 DataBuffer* b = ParseAssignment (var); |
|
683 return b; |
|
684 } |
|
685 |
|
686 // If it's not a keyword, parse it as an expression. |
|
687 DataBuffer* b = ParseExpression (TYPE_VOID); |
|
688 return b; |
|
689 } |