40 #define SCOPE(n) scopestack[g_ScopeCursor - n] |
40 #define SCOPE(n) scopestack[g_ScopeCursor - n] |
41 |
41 |
42 // TODO: make these static |
42 // TODO: make these static |
43 int g_NumStates = 0; |
43 int g_NumStates = 0; |
44 int g_NumEvents = 0; |
44 int g_NumEvents = 0; |
45 parsermode_e g_CurMode = MODE_TOPLEVEL; |
45 parsermode_e g_current_mode = MODE_TOPLEVEL; |
46 string g_CurState = ""; |
46 string g_CurState = ""; |
47 bool g_stateSpawnDefined = false; |
47 bool g_stateSpawnDefined = false; |
48 bool g_GotMainLoop = false; |
48 bool g_GotMainLoop = false; |
49 int g_ScopeCursor = 0; |
49 int g_ScopeCursor = 0; |
50 data_buffer* g_IfExpression = null; |
50 data_buffer* g_IfExpression = null; |
51 bool g_CanElse = false; |
51 bool g_CanElse = false; |
52 static string* g_undefined_labels[MAX_MARKS]; // TODO: make a list |
52 static string* g_undefined_labels[MAX_MARKS]; // TODO: make a list |
53 list<constant_info> g_ConstInfo; |
53 list<constant_info> g_ConstInfo; |
54 |
54 |
55 static botscript_parser* g_current_parser = null; |
|
56 |
|
57 // ============================================================================ |
55 // ============================================================================ |
58 // |
56 // |
59 botscript_parser::botscript_parser() : |
57 botscript_parser::botscript_parser() : |
60 m_lx (new lexer) {} |
58 m_lx (new lexer) {} |
61 |
59 |
68 |
66 |
69 // ============================================================================ |
67 // ============================================================================ |
70 // |
68 // |
71 void botscript_parser::check_toplevel() |
69 void botscript_parser::check_toplevel() |
72 { |
70 { |
73 if (g_CurMode != MODE_TOPLEVEL) |
71 if (g_current_mode != MODE_TOPLEVEL) |
74 error ("%1-statements may only be defined at top level!", token_string().chars()); |
72 error ("%1-statements may only be defined at top level!", token_string()); |
75 } |
73 } |
76 |
74 |
77 // ============================================================================ |
75 // ============================================================================ |
78 // |
76 // |
79 void botscript_parser::check_not_toplevel() |
77 void botscript_parser::check_not_toplevel() |
80 { |
78 { |
81 if (g_CurMode == MODE_TOPLEVEL) |
79 if (g_current_mode == MODE_TOPLEVEL) |
82 error ("%1-statements must not be defined at top level!", token_string().chars()); |
80 error ("%1-statements must not be defined at top level!", token_string()); |
83 } |
81 } |
84 |
82 |
85 // ============================================================================ |
83 // ============================================================================ |
86 // Main parser code. Begins read of the script file, checks the syntax of it |
84 // Main parser code. Begins read of the script file, checks the syntax of it |
87 // and writes the data to the object file via Objwriter - which also takes care |
85 // and writes the data to the object file via Objwriter - which also takes care |
209 m_lx->must_get_next (tk_semicolon); |
207 m_lx->must_get_next (tk_semicolon); |
210 continue; |
208 continue; |
211 } |
209 } |
212 |
210 |
213 // If nothing else, parse it as a statement |
211 // If nothing else, parse it as a statement |
214 data_buffer* b = parse_statement (w); |
212 data_buffer* b = parse_statement(); |
215 |
213 |
216 if (!b) |
214 if (!b) |
217 error ("unknown token `%1`", token_string()); |
215 error ("unknown token `%1`", token_string()); |
218 |
216 |
219 m_writer->write_buffer (b); |
217 m_writer->write_buffer (b); |
223 } |
221 } |
224 } |
222 } |
225 |
223 |
226 // =============================================================================== |
224 // =============================================================================== |
227 // Script file ended. Do some last checks and write the last things to main buffer |
225 // Script file ended. Do some last checks and write the last things to main buffer |
228 if (g_CurMode != MODE_TOPLEVEL) |
226 if (g_current_mode != MODE_TOPLEVEL) |
229 error ("script did not end at top level; a `}` is missing somewhere"); |
227 error ("script did not end at top level; a `}` is missing somewhere"); |
230 |
228 |
231 // stateSpawn must be defined! |
229 // stateSpawn must be defined! |
232 if (!g_stateSpawnDefined) |
230 if (!g_stateSpawnDefined) |
233 error ("script must have a state named `stateSpawn`!"); |
231 error ("script must have a state named `stateSpawn`!"); |
234 |
232 |
235 for (int i = 0; i < MAX_MARKS; i++) |
233 for (int i = 0; i < MAX_MARKS; i++) |
236 if (g_undefined_labels[i]) |
234 if (g_undefined_labels[i]) |
237 error ("label `%s` is referenced via `goto` but isn't defined\n", g_undefined_labels[i]->chars()); |
235 error ("label `%1` is referenced via `goto` but isn't defined\n", g_undefined_labels[i]); |
238 |
236 |
239 // Dump the last state's onenter and mainloop |
237 // Dump the last state's onenter and mainloop |
240 m_writer->write_member_buffers(); |
238 m_writer->write_member_buffers(); |
241 |
239 |
242 // String table |
240 // String table |
289 |
287 |
290 if (!e) |
288 if (!e) |
291 error ("bad event, got `%1`\n", token_string()); |
289 error ("bad event, got `%1`\n", token_string()); |
292 |
290 |
293 m_lx->must_get_next (tk_brace_start); |
291 m_lx->must_get_next (tk_brace_start); |
294 g_CurMode = MODE_EVENT; |
292 g_current_mode = MODE_EVENT; |
295 m_writer->write (dh_event); |
293 m_writer->write (dh_event); |
296 m_writer->write (e->number); |
294 m_writer->write (e->number); |
297 g_NumEvents++; |
295 g_NumEvents++; |
298 } |
296 } |
299 |
297 |
303 { |
301 { |
304 check_toplevel(); |
302 check_toplevel(); |
305 m_lx->must_get_next (tk_brace_start); |
303 m_lx->must_get_next (tk_brace_start); |
306 |
304 |
307 // Mode must be set before dataheader is written here! |
305 // Mode must be set before dataheader is written here! |
308 g_CurMode = MODE_MAINLOOP; |
306 g_current_mode = MODE_MAINLOOP; |
309 m_writer->write (dh_main_loop); |
307 m_writer->write (dh_main_loop); |
310 } |
308 } |
311 |
309 |
312 // ============================================================================ |
310 // ============================================================================ |
313 // |
311 // |
317 bool onenter = (token_is (tk_onenter)); |
315 bool onenter = (token_is (tk_onenter)); |
318 m_lx->must_get_next (tk_brace_start); |
316 m_lx->must_get_next (tk_brace_start); |
319 |
317 |
320 // Mode must be set before dataheader is written here, |
318 // Mode must be set before dataheader is written here, |
321 // because onenter goes to a separate buffer. |
319 // because onenter goes to a separate buffer. |
322 g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
320 g_current_mode = onenter ? MODE_ONENTER : MODE_ONEXIT; |
323 m_writer->write (onenter ? dh_on_enter : dh_on_exit); |
321 m_writer->write (onenter ? dh_on_enter : dh_on_exit); |
324 } |
322 } |
325 |
323 |
326 // ============================================================================ |
324 // ============================================================================ |
327 // |
325 // |
328 void botscript_parser::parse_variable_declaration() |
326 void botscript_parser::parse_variable_declaration() |
329 { |
327 { |
330 // For now, only globals are supported |
328 // For now, only globals are supported |
331 if (g_CurMode != MODE_TOPLEVEL || g_CurState.is_empty() == false) |
329 if (g_current_mode != MODE_TOPLEVEL || g_CurState.is_empty() == false) |
332 error ("variables must only be global for now"); |
330 error ("variables must only be global for now"); |
333 |
331 |
334 type_e type = (token_is (tk_int)) ? TYPE_INT : |
332 type_e type = (token_is (tk_int)) ? TYPE_INT : |
335 (token_is (tk_str)) ? TYPE_STRING : |
333 (token_is (tk_str)) ? TYPE_STRING : |
336 TYPE_BOOL; |
334 TYPE_BOOL; |
369 |
367 |
370 // Add a reference to the mark. |
368 // Add a reference to the mark. |
371 m_writer->write (dh_goto); |
369 m_writer->write (dh_goto); |
372 m_writer->add_reference (m); |
370 m_writer->add_reference (m); |
373 m_lx->must_get_next (tk_semicolon); |
371 m_lx->must_get_next (tk_semicolon); |
374 continue; |
|
375 } |
372 } |
376 |
373 |
377 // ============================================================================ |
374 // ============================================================================ |
378 // |
375 // |
379 void botscript_parser::parse_if() |
376 void botscript_parser::parse_if() |
590 // null the switch buffer for the case-go-to statement, |
587 // null the switch buffer for the case-go-to statement, |
591 // we want it all under the switch, not into the case-buffers. |
588 // we want it all under the switch, not into the case-buffers. |
592 m_writer->SwitchBuffer = null; |
589 m_writer->SwitchBuffer = null; |
593 m_writer->write (dh_case_goto); |
590 m_writer->write (dh_case_goto); |
594 m_writer->write (num); |
591 m_writer->write (num); |
595 add_switch_case (m_writer, null); |
592 add_switch_case (null); |
596 SCOPE (0).casenumbers[SCOPE (0).casecursor] = num; |
593 SCOPE (0).casenumbers[SCOPE (0).casecursor] = num; |
597 } |
594 } |
598 |
595 |
599 // ============================================================================ |
596 // ============================================================================ |
600 // |
597 // |
784 break; |
781 break; |
785 } |
782 } |
786 |
783 |
787 // Descend down the stack |
784 // Descend down the stack |
788 g_ScopeCursor--; |
785 g_ScopeCursor--; |
789 continue; |
786 return; |
790 } |
787 } |
791 |
788 |
792 int dataheader = (g_CurMode == MODE_EVENT) ? dh_end_event : |
789 int dataheader = (g_current_mode == MODE_EVENT) ? dh_end_event : |
793 (g_CurMode == MODE_MAINLOOP) ? dh_end_main_loop : |
790 (g_current_mode == MODE_MAINLOOP) ? dh_end_main_loop : |
794 (g_CurMode == MODE_ONENTER) ? dh_end_on_enter : |
791 (g_current_mode == MODE_ONENTER) ? dh_end_on_enter : |
795 (g_CurMode == MODE_ONEXIT) ? dh_end_on_exit : -1; |
792 (g_current_mode == MODE_ONEXIT) ? dh_end_on_exit : -1; |
796 |
793 |
797 if (dataheader == -1) |
794 if (dataheader == -1) |
798 error ("unexpected `}`"); |
795 error ("unexpected `}`"); |
799 |
796 |
800 // Data header must be written before mode is changed because |
797 // Data header must be written before mode is changed because |
801 // onenter and mainloop go into special buffers, and we want |
798 // onenter and mainloop go into special buffers, and we want |
802 // the closing data headers into said buffers too. |
799 // the closing data headers into said buffers too. |
803 m_writer->write (dataheader); |
800 m_writer->write (dataheader); |
804 g_CurMode = MODE_TOPLEVEL; |
801 g_current_mode = MODE_TOPLEVEL; |
805 m_lx->get_next (tk_semicolon); |
802 m_lx->get_next (tk_semicolon); |
806 } |
803 } |
807 |
804 |
808 // ============================================================================ |
805 // ============================================================================ |
809 // |
806 // |
855 check_not_toplevel(); |
852 check_not_toplevel(); |
856 string label_name = token_string(); |
853 string label_name = token_string(); |
857 |
854 |
858 // want no conflicts.. |
855 // want no conflicts.. |
859 if (find_command_by_name (label_name)) |
856 if (find_command_by_name (label_name)) |
860 error ("label name `%s` conflicts with command name\n", label_name); |
857 error ("label name `%1` conflicts with command name\n", label_name); |
861 |
858 |
862 if (find_global_variable (label_name)) |
859 if (find_global_variable (label_name)) |
863 error ("label name `%s` conflicts with variable\n", label_name); |
860 error ("label name `%1` conflicts with variable\n", label_name); |
864 |
861 |
865 // See if a mark already exists for this label |
862 // See if a mark already exists for this label |
866 int mark = -1; |
863 int mark = -1; |
867 |
864 |
868 for (int i = 0; i < MAX_MARKS; i++) |
865 for (int i = 0; i < MAX_MARKS; i++) |
889 // Parses a command call |
886 // Parses a command call |
890 data_buffer* botscript_parser::ParseCommand (command_info* comm) |
887 data_buffer* botscript_parser::ParseCommand (command_info* comm) |
891 { |
888 { |
892 data_buffer* r = new data_buffer (64); |
889 data_buffer* r = new data_buffer (64); |
893 |
890 |
894 if (g_CurMode == MODE_TOPLEVEL) |
891 if (g_current_mode == MODE_TOPLEVEL) |
895 error ("command call at top level"); |
892 error ("command call at top level"); |
896 |
893 |
897 m_lx->must_get_next (tk_paren_start); |
894 m_lx->must_get_next (tk_paren_start); |
898 m_lx->must_get_next(); |
895 m_lx->must_get_next(); |
899 |
896 |
902 while (1) |
899 while (1) |
903 { |
900 { |
904 if (token_is (tk_paren_end)) |
901 if (token_is (tk_paren_end)) |
905 { |
902 { |
906 if (curarg < comm->numargs) |
903 if (curarg < comm->numargs) |
907 error ("too few arguments passed to %s\n\tprototype: %s", |
904 error ("too few arguments passed to %1\n\tprototype: %2", |
908 comm->name.chars(), get_command_signature (comm).chars()); |
905 comm->name, get_command_signature (comm)); |
909 |
906 |
910 break; |
907 break; |
911 curarg++; |
908 curarg++; |
912 } |
909 } |
913 |
910 |
914 if (curarg >= comm->maxargs) |
911 if (curarg >= comm->maxargs) |
915 error ("too many arguments passed to %s\n\tprototype: %s", |
912 error ("too many arguments passed to %1\n\tprototype: %2", |
916 comm->name.chars(), get_command_signature (comm).chars()); |
913 comm->name, get_command_signature (comm)); |
917 |
914 |
918 r->merge (parse_expression (comm->args[curarg].type)); |
915 r->merge (parse_expression (comm->args[curarg].type)); |
919 m_lx->must_get_next(); |
916 m_lx->must_get_next(); |
920 |
917 |
921 if (curarg < comm->numargs - 1) |
918 if (curarg < comm->numargs - 1) |
1002 } |
1001 } |
1003 } |
1002 } |
1004 |
1003 |
1005 switch (oper) |
1004 switch (oper) |
1006 { |
1005 { |
1007 case OPER_ADD: return dh_add; |
1006 case OPER_ADD: return dh_add; |
1008 case OPER_SUBTRACT: return dh_subtract; |
1007 case OPER_SUBTRACT: return dh_subtract; |
1009 case OPER_MULTIPLY: return dh_multiply; |
1008 case OPER_MULTIPLY: return dh_multiply; |
1010 case OPER_DIVIDE: return dh_divide; |
1009 case OPER_DIVIDE: return dh_divide; |
1011 case OPER_MODULUS: return dh_modulus; |
1010 case OPER_MODULUS: return dh_modulus; |
1012 case OPER_EQUALS: return dh_equals; |
1011 case OPER_EQUALS: return dh_equals; |
1013 case OPER_NOTEQUALS: return dh_not_equals; |
1012 case OPER_NOTEQUALS: return dh_not_equals; |
1014 case OPER_LESSTHAN: return dh_less_than; |
1013 case OPER_LESSTHAN: return dh_less_than; |
1015 case OPER_GREATERTHAN: return dh_greater_than; |
1014 case OPER_GREATERTHAN: return dh_greater_than; |
1016 case OPER_LESSTHANEQUALS: return dh_at_most; |
1015 case OPER_LESSTHANEQUALS: return dh_at_most; |
1017 case OPER_GREATERTHANEQUALS: return dh_at_least; |
1016 case OPER_GREATERTHANEQUALS: return dh_at_least; |
1018 case OPER_LEFTSHIFT: return dh_left_shift; |
1017 case OPER_LEFTSHIFT: return dh_left_shift; |
1019 case OPER_RIGHTSHIFT: return dh_right_shift; |
1018 case OPER_RIGHTSHIFT: return dh_right_shift; |
1020 case OPER_OR: return dh_or_logical; |
1019 case OPER_OR: return dh_or_logical; |
1021 case OPER_AND: return dh_and_logical; |
1020 case OPER_AND: return dh_and_logical; |
1022 case OPER_BITWISEOR: return dh_or_bitwise; |
1021 case OPER_BITWISEOR: return dh_or_bitwise; |
1023 case OPER_BITWISEEOR: return dh_eor_bitwise; |
1022 case OPER_BITWISEEOR: return dh_eor_bitwise; |
1024 case OPER_BITWISEAND: return dh_and_bitwise; |
1023 case OPER_BITWISEAND: return dh_and_bitwise; |
1025 } |
1024 } |
1026 |
1025 |
1027 error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); |
1026 error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); |
1028 return 0; |
1027 return 0; |
1029 } |
1028 } |
1030 |
1029 |
1031 // ============================================================================ |
1030 // ============================================================================ |
1032 // Parses an expression, potentially recursively |
1031 // Parses an expression, potentially recursively |
|
1032 // |
1033 data_buffer* botscript_parser::parse_expression (type_e reqtype) |
1033 data_buffer* botscript_parser::parse_expression (type_e reqtype) |
1034 { |
1034 { |
1035 data_buffer* retbuf = new data_buffer (64); |
1035 data_buffer* retbuf = new data_buffer (64); |
1036 |
1036 |
1037 // Parse first operand |
1037 // Parse first operand |
1183 |
1186 |
1184 // ============================================================================ |
1187 // ============================================================================ |
1185 // Parses a value in the expression and returns the data needed to push |
1188 // Parses a value in the expression and returns the data needed to push |
1186 // it, contained in a data buffer. A value can be either a variable, a command, |
1189 // it, contained in a data buffer. A value can be either a variable, a command, |
1187 // a literal or an expression. |
1190 // a literal or an expression. |
|
1191 // |
1188 data_buffer* botscript_parser::parse_expr_value (type_e reqtype) |
1192 data_buffer* botscript_parser::parse_expr_value (type_e reqtype) |
1189 { |
1193 { |
1190 data_buffer* b = new data_buffer (16); |
1194 data_buffer* b = new data_buffer (16); |
1191 script_variable* g; |
1195 script_variable* g; |
1192 |
1196 |
1207 |
1211 |
1208 if (!constant || constant->type != TYPE_STRING) |
1212 if (!constant || constant->type != TYPE_STRING) |
1209 error ("strlen only works with const str"); |
1213 error ("strlen only works with const str"); |
1210 |
1214 |
1211 if (reqtype != TYPE_INT) |
1215 if (reqtype != TYPE_INT) |
1212 error ("strlen returns int but %s is expected\n", GetTypeName (reqtype).c_str()); |
1216 error ("strlen returns int but %1 is expected\n", GetTypeName (reqtype)); |
1213 |
1217 |
1214 b->write (dh_push_number); |
1218 b->write (dh_push_number); |
1215 b->write (constant->val.len()); |
1219 b->write (constant->val.len()); |
1216 |
1220 |
1217 m_lx->must_get_next (tk_paren_end); |
1221 m_lx->must_get_next (tk_paren_end); |
1229 { |
1233 { |
1230 delete b; |
1234 delete b; |
1231 |
1235 |
1232 // Command |
1236 // Command |
1233 if (reqtype && comm->returnvalue != reqtype) |
1237 if (reqtype && comm->returnvalue != reqtype) |
1234 error ("%s returns an incompatible data type", comm->name.chars()); |
1238 error ("%1 returns an incompatible data type", comm->name); |
1235 |
1239 |
1236 b = ParseCommand (comm); |
1240 b = ParseCommand (comm); |
1237 } |
1241 } |
1238 else if (constant_info* constant = find_constant (token_string())) |
1242 else if (constant_info* constant = find_constant (token_string())) |
1239 { |
1243 { |
1240 // Type check |
1244 // Type check |
1241 if (reqtype != constant->type) |
1245 if (reqtype != constant->type) |
1242 error ("constant `%s` is %s, expression requires %s\n", |
1246 error ("constant `%1` is %2, expression requires %3\n", |
1243 constant->name.c_str(), GetTypeName (constant->type).c_str(), |
1247 constant->name, GetTypeName (constant->type), |
1244 GetTypeName (reqtype).c_str()); |
1248 GetTypeName (reqtype)); |
1245 |
1249 |
1246 switch (constant->type) |
1250 switch (constant->type) |
1247 { |
1251 { |
1248 case TYPE_BOOL: |
1252 case TYPE_BOOL: |
1249 case TYPE_INT: |
1253 case TYPE_INT: |
1313 |
1317 |
1314 // ============================================================================ |
1318 // ============================================================================ |
1315 // Parses an assignment. An assignment starts with a variable name, followed |
1319 // Parses an assignment. An assignment starts with a variable name, followed |
1316 // by an assignment operator, followed by an expression value. Expects current |
1320 // by an assignment operator, followed by an expression value. Expects current |
1317 // token to be the name of the variable, and expects the variable to be given. |
1321 // token to be the name of the variable, and expects the variable to be given. |
1318 data_buffer* botscript_parser::ParseAssignment (script_variable* var) |
1322 // |
|
1323 data_buffer* botscript_parser::parse_assignment (script_variable* var) |
1319 { |
1324 { |
1320 bool global = !var->statename.len(); |
1325 bool global = !var->statename.len(); |
1321 |
1326 |
1322 // Get an operator |
1327 // Get an operator |
1323 m_lx->must_get_next(); |
1328 m_lx->must_get_next(); |
1324 int oper = parse_operator(); |
1329 int oper = parse_operator(); |
1325 |
1330 |
1326 if (!is_assignment_operator (oper)) |
1331 if (!is_assignment_operator (oper)) |
1327 error ("expected assignment operator"); |
1332 error ("expected assignment operator"); |
1328 |
1333 |
1329 if (g_CurMode == MODE_TOPLEVEL) |
1334 if (g_current_mode == MODE_TOPLEVEL) |
1330 error ("can't alter variables at top level"); |
1335 error ("can't alter variables at top level"); |
1331 |
1336 |
1332 // Parse the right operand |
1337 // Parse the right operand |
1333 m_lx->must_get_next(); |
1338 m_lx->must_get_next(); |
1334 data_buffer* retbuf = new data_buffer; |
1339 data_buffer* retbuf = new data_buffer; |
1377 info->casebuffers[i] = null; |
1384 info->casebuffers[i] = null; |
1378 info->casenumbers[i] = -1; |
1385 info->casenumbers[i] = -1; |
1379 } |
1386 } |
1380 } |
1387 } |
1381 |
1388 |
1382 data_buffer* botscript_parser::parse_statement (object_writer* w) |
1389 // ============================================================================ |
|
1390 // |
|
1391 data_buffer* botscript_parser::parse_statement() |
1383 { |
1392 { |
1384 if (find_constant (token_string())) // There should not be constants here. |
1393 if (find_constant (token_string())) // There should not be constants here. |
1385 error ("invalid use for constant\n"); |
1394 error ("invalid use for constant\n"); |
1386 |
1395 |
1387 // If it's a variable, expect assignment. |
1396 // If it's a variable, expect assignment. |
1388 if (script_variable* var = find_global_variable (token_string())) |
1397 if (script_variable* var = find_global_variable (token_string())) |
1389 return ParseAssignment (var); |
1398 return parse_assignment (var); |
1390 |
1399 |
1391 return null; |
1400 return null; |
1392 } |
1401 } |
1393 |
1402 |
1394 void botscript_parser::add_switch_case (object_writer* w, data_buffer* b) |
1403 // ============================================================================ |
|
1404 // |
|
1405 void botscript_parser::add_switch_case (data_buffer* b) |
1395 { |
1406 { |
1396 ScopeInfo* info = &SCOPE (0); |
1407 ScopeInfo* info = &SCOPE (0); |
1397 |
1408 |
1398 info->casecursor++; |
1409 info->casecursor++; |
1399 |
1410 |