72 if (!newfile) |
72 if (!newfile) |
73 ParserError ("couldn't open included file `%s`!", token.chars()); |
73 ParserError ("couldn't open included file `%s`!", token.chars()); |
74 fclose (newfile); |
74 fclose (newfile); |
75 ScriptReader* newreader = new ScriptReader (token.chars()); |
75 ScriptReader* newreader = new ScriptReader (token.chars()); |
76 newreader->BeginParse (w); |
76 newreader->BeginParse (w); |
77 } else if (!token.icompare ("state")) { |
77 continue; |
|
78 } |
|
79 |
|
80 if (!token.icompare ("state")) { |
78 MUST_TOPLEVEL |
81 MUST_TOPLEVEL |
79 |
82 |
80 MustString (); |
83 MustString (); |
81 |
84 |
82 // State name must be a word. |
85 // State name must be a word. |
122 g_CurMode = MODE_EVENT; |
128 g_CurMode = MODE_EVENT; |
123 |
129 |
124 w->Write (DH_EVENT); |
130 w->Write (DH_EVENT); |
125 w->Write<long> (e->number); |
131 w->Write<long> (e->number); |
126 g_NumEvents++; |
132 g_NumEvents++; |
127 } else if (!token.icompare ("mainloop")) { |
133 continue; |
|
134 } |
|
135 |
|
136 if (!token.icompare ("mainloop")) { |
128 MUST_TOPLEVEL |
137 MUST_TOPLEVEL |
129 MustNext ("{"); |
138 MustNext ("{"); |
130 g_CurMode = MODE_MAINLOOP; |
139 g_CurMode = MODE_MAINLOOP; |
131 w->Write (DH_MAINLOOP); |
140 w->Write (DH_MAINLOOP); |
132 gotMainLoop = true; |
141 gotMainLoop = true; |
133 } else if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
142 continue; |
|
143 } |
|
144 |
|
145 if (!token.icompare ("onenter") || !token.icompare ("onexit")) { |
134 MUST_TOPLEVEL |
146 MUST_TOPLEVEL |
135 bool onenter = !token.compare ("onenter"); |
147 bool onenter = !token.compare ("onenter"); |
136 |
148 |
137 MustNext ("{"); |
149 MustNext ("{"); |
138 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
150 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
139 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
151 w->Write (onenter ? DH_ONENTER : DH_ONEXIT); |
140 } else if (!token.compare ("int") || !token.compare ("bool")) { |
152 continue; |
|
153 } |
|
154 |
|
155 if (!token.compare ("var")) { |
141 // For now, only globals are supported |
156 // For now, only globals are supported |
142 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
157 if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) |
143 ParserError ("variables must only be global for now"); |
158 ParserError ("variables must only be global for now"); |
144 |
159 |
145 // Variable definition |
|
146 int type = !token.compare ("int") ? RETURNVAL_INT: RETURNVAL_BOOLEAN; |
|
147 |
|
148 MustNext (); |
160 MustNext (); |
|
161 |
|
162 // Var name must not be a number |
|
163 if (token.isnumber()) |
|
164 ParserError ("variable name must not be a number"); |
|
165 |
149 str varname = token; |
166 str varname = token; |
150 ScriptVar* var = DeclareGlobalVariable (this, varname, type); |
167 ScriptVar* var = DeclareGlobalVariable (this, varname); |
151 |
168 |
152 if (!var) |
169 if (!var) |
153 ParserError ("declaring %s variable %s failed", |
170 ParserError ("declaring %s variable %s failed", |
154 g_CurState.len() ? "state" : "global", varname.chars()); |
171 g_CurState.len() ? "state" : "global", varname.chars()); |
155 |
172 |
156 // Assign it, if desired |
|
157 if (!PeekNext().compare ("=")) { |
|
158 MustNext ("="); |
|
159 MustValue (type); |
|
160 |
|
161 var->value = token; |
|
162 } |
|
163 |
|
164 MustNext (";"); |
173 MustNext (";"); |
165 } else if (!token.compare ("}")) { |
174 continue; |
|
175 } |
|
176 |
|
177 if (!token.compare ("}")) { |
166 // Closing brace |
178 // Closing brace |
167 int dataheader = (g_CurMode == MODE_EVENT) ? DH_ENDEVENT : |
179 int dataheader = (g_CurMode == MODE_EVENT) ? DH_ENDEVENT : |
168 (g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP : |
180 (g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP : |
169 (g_CurMode == MODE_ONENTER) ? DH_ENDONENTER : |
181 (g_CurMode == MODE_ONENTER) ? DH_ENDONENTER : |
170 (g_CurMode == MODE_ONEXIT) ? DH_ENDONEXIT : -1; |
182 (g_CurMode == MODE_ONEXIT) ? DH_ENDONEXIT : -1; |
175 // Closing brace.. |
187 // Closing brace.. |
176 w->Write (dataheader); |
188 w->Write (dataheader); |
177 g_CurMode = MODE_TOPLEVEL; |
189 g_CurMode = MODE_TOPLEVEL; |
178 |
190 |
179 MustNext (";"); |
191 MustNext (";"); |
180 } else { |
192 continue; |
181 // Check if it's a command. |
193 } |
182 CommandDef* comm = GetCommandByName (token); |
194 // Check global variables |
183 if (comm) |
195 ScriptVar* g = FindGlobalVariable (token); |
184 ParseCommand (comm, w); |
196 if (g) { |
185 else |
197 // Not in top level, unfortunately.. |
186 ParserError ("unknown keyword `%s`", token.chars()); |
198 if (g_CurMode == MODE_TOPLEVEL) |
187 } |
199 ParserError ("can't alter variables at top level"); |
|
200 |
|
201 // Only addition for now.. |
|
202 MustNext (); |
|
203 |
|
204 // Build operator string. Only '=' is one |
|
205 // character, others are two. |
|
206 str oper = token; |
|
207 if (token.compare ("=") != 0) { |
|
208 MustNext (); |
|
209 oper += token; |
|
210 } |
|
211 |
|
212 // Unary operators |
|
213 if (!oper.compare ("++")) { |
|
214 w->Write<long> (DH_INCGLOBALVAR); |
|
215 w->Write<long> (g->index); |
|
216 } else if (!oper.compare ("--")) { |
|
217 w->Write<long> (DH_DECGLOBALVAR); |
|
218 w->Write<long> (g->index); |
|
219 } |
|
220 |
|
221 // And only with numbers for now too. |
|
222 // TODO: make a proper expression parser! |
|
223 MustNumber(); |
|
224 |
|
225 int val = atoi (token.chars()); |
|
226 w->Write<long> (DH_PUSHNUMBER); |
|
227 w->Write<long> (val); |
|
228 |
|
229 int dataheader = !oper.compare("=") ? DH_ASSIGNGLOBALVAR : |
|
230 !oper.compare("+=") ? DH_ADDGLOBALVAR : |
|
231 !oper.compare("-=") ? DH_SUBGLOBALVAR : |
|
232 !oper.compare("*=") ? DH_MULGLOBALVAR : |
|
233 !oper.compare("/=") ? DH_DIVGLOBALVAR : |
|
234 !oper.compare("%=") ? DH_MODGLOBALVAR : -1; |
|
235 |
|
236 if (dataheader == -1) |
|
237 ParserError ("bad operator `%s`!", oper.chars()); |
|
238 |
|
239 w->Write<long> (dataheader); |
|
240 w->Write<long> (g->index); |
|
241 |
|
242 MustNext (";"); |
|
243 continue; |
|
244 } |
|
245 |
|
246 // Check if it's a command. |
|
247 CommandDef* comm = GetCommandByName (token); |
|
248 if (comm) { |
|
249 ParseCommand (comm, w); |
|
250 continue; |
|
251 } |
|
252 |
|
253 ParserError ("unknown keyword `%s`", token.chars()); |
188 } |
254 } |
189 |
255 |
190 if (g_CurMode != MODE_TOPLEVEL) |
256 if (g_CurMode != MODE_TOPLEVEL) |
191 ParserError ("script did not end at top level; did you forget a `}`?"); |
257 ParserError ("script did not end at top level; did you forget a `}`?"); |
192 |
258 |
227 MustNext (")"); |
293 MustNext (")"); |
228 curarg++; |
294 curarg++; |
229 break; |
295 break; |
230 } |
296 } |
231 |
297 |
232 /* |
298 if (!PeekNext().len()) |
233 if (!Next ()) |
|
234 ParserError ("unexpected end-of-file, unterminated command"); |
299 ParserError ("unexpected end-of-file, unterminated command"); |
235 |
300 |
236 // If we get a ")" now, the user probably gave too few parameters |
301 // If we get a ")" now, the user probably gave too few parameters |
237 if (!token.compare (")")) |
302 if (!PeekNext().compare (")")) |
238 ParserError ("unexpected `)`, did you pass too few parameters? (need %d)", comm->numargs); |
303 ParserError ("unexpected `)`, did you pass too few parameters? (need %d)", comm->numargs); |
239 */ |
304 |
240 |
305 // Argument may be using a variable |
241 switch (comm->argtypes[curarg]) { |
306 ScriptVar* g = FindGlobalVariable (PeekNext ()); |
242 case RETURNVAL_INT: |
307 if (g && comm->argtypes[curarg] != RETURNVAL_STRING) { |
243 MustNumber(); |
308 // Advance cursor past the var name |
244 w->Write<long> (DH_PUSHNUMBER); |
309 Next(); |
245 w->Write<long> (atoi (token.chars ())); |
310 |
246 break; |
311 w->Write<long> (DH_PUSHGLOBALVAR); |
247 case RETURNVAL_BOOLEAN: |
312 w->Write<long> (g->index); |
248 MustBool(); |
313 } else { |
249 w->Write<long> (DH_PUSHNUMBER); |
314 // Check for raw value |
250 w->Write<long> (BoolValue ()); |
315 switch (comm->argtypes[curarg]) { |
251 break; |
316 case RETURNVAL_INT: |
252 case RETURNVAL_STRING: |
317 MustNumber(); |
253 MustString(); |
318 w->Write<long> (DH_PUSHNUMBER); |
254 w->Write<long> (DH_PUSHSTRINGINDEX); |
319 w->Write<long> (atoi (token.chars ())); |
255 w->Write<long> (PushToStringTable (token.chars())); |
320 break; |
256 break; |
321 case RETURNVAL_BOOLEAN: |
|
322 MustBool(); |
|
323 w->Write<long> (DH_PUSHNUMBER); |
|
324 w->Write<long> (BoolValue ()); |
|
325 break; |
|
326 case RETURNVAL_STRING: |
|
327 MustString(); |
|
328 w->Write<long> (DH_PUSHSTRINGINDEX); |
|
329 w->Write<long> (PushToStringTable (token.chars())); |
|
330 break; |
|
331 } |
257 } |
332 } |
258 |
333 |
259 if (curarg < comm->numargs - 1) { |
334 if (curarg < comm->numargs - 1) { |
260 MustNext (","); |
335 MustNext (","); |
261 } else if (curarg < comm->maxargs - 1) { |
336 } else if (curarg < comm->maxargs - 1) { |