src/parser.cxx

changeset 72
03e4d9db3fd9
parent 71
11f23fabf8a6
child 73
1ee9b312dc18
equal deleted inserted replaced
71:11f23fabf8a6 72:03e4d9db3fd9
1 /*
2 * botc source code
3 * Copyright (C) 2012 Santeri `Dusk` Piippo
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of the developer nor the names of its contributors may
15 * be used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 * 4. Redistributions in any form must be accompanied by information on how to
18 * obtain complete source code for the software and any accompanying
19 * software that uses the software. The source code must either be included
20 * in the distribution or be available for no more than the cost of
21 * distribution plus a nominal fee, and must be freely redistributable
22 * under reasonable conditions. For an executable file, complete source
23 * code means the source code for all modules it contains. It does not
24 * include source code for modules or files that typically accompany the
25 * major components of the operating system on which the executable file
26 * runs.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #define __PARSER_CXX__
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include "common.h"
46 #include "str.h"
47 #include "objwriter.h" 1 #include "objwriter.h"
48 #include "scriptreader.h" 2 #include "scriptreader.h"
49 #include "events.h" 3 #include "events.h"
50 #include "commands.h" 4 #include "commands.h"
51 #include "stringtable.h" 5 #include "stringtable.h"
52 #include "variables.h" 6 #include "variables.h"
53 #include "array.h" 7 #include "containers.h"
54 8
55 #define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \ 9 #define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \
56 ParserError ("%s-statements may only be defined at top level!", token.chars()); 10 ParserError ("%s-statements may only be defined at top level!", token.chars());
57 11
58 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \ 12 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \
61 #define SCOPE(n) scopestack[g_ScopeCursor - n] 15 #define SCOPE(n) scopestack[g_ScopeCursor - n]
62 16
63 int g_NumStates = 0; 17 int g_NumStates = 0;
64 int g_NumEvents = 0; 18 int g_NumEvents = 0;
65 parsermode_e g_CurMode = MODE_TOPLEVEL; 19 parsermode_e g_CurMode = MODE_TOPLEVEL;
66 str g_CurState = ""; 20 string g_CurState = "";
67 bool g_stateSpawnDefined = false; 21 bool g_stateSpawnDefined = false;
68 bool g_GotMainLoop = false; 22 bool g_GotMainLoop = false;
69 unsigned int g_ScopeCursor = 0; 23 unsigned int g_ScopeCursor = 0;
70 DataBuffer* g_IfExpression = NULL; 24 DataBuffer* g_IfExpression = null;
71 bool g_CanElse = false; 25 bool g_CanElse = false;
72 str* g_UndefinedLabels[MAX_MARKS]; 26 string* g_UndefinedLabels[MAX_MARKS];
73 bool g_Neurosphere = false; // neurosphere-compat 27 bool g_Neurosphere = false; // neurosphere-compat
74 array<constinfo_t> g_ConstInfo; 28 list<constinfo_t> g_ConstInfo;
75 29
76 // ============================================================================ 30 // ============================================================================
77 // Main parser code. Begins read of the script file, checks the syntax of it 31 // Main parser code. Begins read of the script file, checks the syntax of it
78 // and writes the data to the object file via ObjWriter - which also takes care 32 // and writes the data to the object file via ObjWriter - which also takes care
79 // of necessary buffering so stuff is written in the correct order. 33 // of necessary buffering so stuff is written in the correct order.
81 // Zero the entire block stack first 35 // Zero the entire block stack first
82 for (int i = 0; i < MAX_SCOPE; i++) 36 for (int i = 0; i < MAX_SCOPE; i++)
83 ZERO(scopestack[i]); 37 ZERO(scopestack[i]);
84 38
85 for (int i = 0; i < MAX_MARKS; i++) 39 for (int i = 0; i < MAX_MARKS; i++)
86 g_UndefinedLabels[i] = NULL; 40 g_UndefinedLabels[i] = null;
87 41
88 while (Next()) { 42 while (Next()) {
89 // Check if else is potentically valid 43 // Check if else is potentically valid
90 if (token == "else" && !g_CanElse) 44 if (token == "else" && !g_CanElse)
91 ParserError ("else without preceding if"); 45 ParserError ("else without preceding if");
99 MustString (); 53 MustString ();
100 54
101 // State name must be a word. 55 // State name must be a word.
102 if (token.first (" ") != token.len()) 56 if (token.first (" ") != token.len())
103 ParserError ("state name must be a single word, got `%s`", token.chars()); 57 ParserError ("state name must be a single word, got `%s`", token.chars());
104 str statename = token; 58 string statename = token;
105 59
106 // stateSpawn is special - it *must* be defined. If we 60 // stateSpawn is special - it *must* be defined. If we
107 // encountered it, then mark down that we have it. 61 // encountered it, then mark down that we have it.
108 if (-token == "statespawn") 62 if (-token == "statespawn")
109 g_stateSpawnDefined = true; 63 g_stateSpawnDefined = true;
183 TYPE_BOOL; 137 TYPE_BOOL;
184 138
185 MustNext (); 139 MustNext ();
186 140
187 // Var name must not be a number 141 // Var name must not be a number
188 if (token.isnumber()) 142 if (token.is_numeric())
189 ParserError ("variable name must not be a number"); 143 ParserError ("variable name must not be a number");
190 144
191 str varname = token; 145 string varname = token;
192 ScriptVar* var = DeclareGlobalVariable (this, type, varname); 146 ScriptVar* var = DeclareGlobalVariable (this, type, varname);
193 147
194 if (!var) 148 if (!var)
195 ParserError ("declaring %s variable %s failed", 149 ParserError ("declaring %s variable %s failed",
196 g_CurState.len() ? "state" : "global", varname.chars()); 150 g_CurState.len() ? "state" : "global", varname.chars());
211 unsigned int m = w->FindMark (token); 165 unsigned int m = w->FindMark (token);
212 166
213 // If not set, define it 167 // If not set, define it
214 if (m == MAX_MARKS) { 168 if (m == MAX_MARKS) {
215 m = w->AddMark (token); 169 m = w->AddMark (token);
216 g_UndefinedLabels[m] = new str (token); 170 g_UndefinedLabels[m] = new string (token);
217 } 171 }
218 172
219 // Add a reference to the mark. 173 // Add a reference to the mark.
220 w->Write (DH_GOTO); 174 w->Write (DH_GOTO);
221 w->AddReference (m); 175 w->AddReference (m);
401 w->WriteBuffer (ParseExpression (TYPE_INT)); 355 w->WriteBuffer (ParseExpression (TYPE_INT));
402 MustNext (")"); 356 MustNext (")");
403 MustNext ("{"); 357 MustNext ("{");
404 SCOPE(0).type = SCOPETYPE_SWITCH; 358 SCOPE(0).type = SCOPETYPE_SWITCH;
405 SCOPE(0).mark1 = w->AddMark (""); // end mark 359 SCOPE(0).mark1 = w->AddMark (""); // end mark
406 SCOPE(0).buffer1 = NULL; // default header 360 SCOPE(0).buffer1 = null; // default header
407 continue; 361 continue;
408 } 362 }
409 363
410 // ============================================================ 364 // ============================================================
411 if (token == "case") { 365 if (token == "case") {
426 // the case tree. The closing event will write the actual 380 // the case tree. The closing event will write the actual
427 // blocks and move the marks appropriately. 381 // blocks and move the marks appropriately.
428 // AddSwitchCase will add the reference to the mark 382 // AddSwitchCase will add the reference to the mark
429 // for the case block that this heralds, and takes care 383 // for the case block that this heralds, and takes care
430 // of buffering setup and stuff like that. 384 // of buffering setup and stuff like that.
431 // NULL the switch buffer for the case-go-to statement, 385 // null the switch buffer for the case-go-to statement,
432 // we want it all under the switch, not into the case-buffers. 386 // we want it all under the switch, not into the case-buffers.
433 w->SwitchBuffer = NULL; 387 w->SwitchBuffer = null;
434 w->Write (DH_CASEGOTO); 388 w->Write (DH_CASEGOTO);
435 w->Write (num); 389 w->Write (num);
436 AddSwitchCase (w, NULL); 390 AddSwitchCase (w, null);
437 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num; 391 SCOPE(0).casenumbers[SCOPE(0).casecursor] = num;
438 continue; 392 continue;
439 } 393 }
440 394
441 if (token == "default") { 395 if (token == "default") {
540 mark = i; 494 mark = i;
541 w->MoveMark (i); 495 w->MoveMark (i);
542 496
543 // No longer undefinde 497 // No longer undefinde
544 delete g_UndefinedLabels[i]; 498 delete g_UndefinedLabels[i];
545 g_UndefinedLabels[i] = NULL; 499 g_UndefinedLabels[i] = null;
546 } 500 }
547 } 501 }
548 502
549 // Not found in unmarked lists, define it now 503 // Not found in unmarked lists, define it now
550 if (mark == -1) 504 if (mark == -1)
561 // Get the type 515 // Get the type
562 MustNext (); 516 MustNext ();
563 info.type = GetTypeByName (token); 517 info.type = GetTypeByName (token);
564 518
565 if (info.type == TYPE_UNKNOWN || info.type == TYPE_VOID) 519 if (info.type == TYPE_UNKNOWN || info.type == TYPE_VOID)
566 ParserError ("unknown type `%s` for constant", (char*)token); 520 ParserError ("unknown type `%s` for constant", token.c_str());
567 521
568 MustNext (); 522 MustNext ();
569 info.name = token; 523 info.name = token;
570 524
571 MustNext ("="); 525 MustNext ("=");
640 // Switch closes. Move down to the record buffer of 594 // Switch closes. Move down to the record buffer of
641 // the lower block. 595 // the lower block.
642 if (SCOPE(1).casecursor != -1) 596 if (SCOPE(1).casecursor != -1)
643 w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor]; 597 w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor];
644 else 598 else
645 w->SwitchBuffer = NULL; 599 w->SwitchBuffer = null;
646 600
647 // If there was a default in the switch, write its header down now. 601 // If there was a default in the switch, write its header down now.
648 // If not, write instruction to jump to the end of switch after 602 // If not, write instruction to jump to the end of switch after
649 // the headers (thus won't fall-through if no case matched) 603 // the headers (thus won't fall-through if no case matched)
650 if (SCOPE(0).buffer1) 604 if (SCOPE(0).buffer1)
899 retbuf->Merge (tb); // perform third operand (false case) 853 retbuf->Merge (tb); // perform third operand (false case)
900 retbuf->MoveMark (mark2); // move the ending mark2 here 854 retbuf->MoveMark (mark2); // move the ending mark2 here
901 } else { 855 } else {
902 // Write to buffer 856 // Write to buffer
903 retbuf->Merge (rb); 857 retbuf->Merge (rb);
904 retbuf->Write (DataHeaderByOperator (NULL, oper)); 858 retbuf->Write (DataHeaderByOperator (null, oper));
905 } 859 }
906 } 860 }
907 861
908 return retbuf; 862 return retbuf;
909 } 863 }
910 864
911 // ============================================================================ 865 // ============================================================================
912 // Parses an operator string. Returns the operator number code. 866 // Parses an operator string. Returns the operator number code.
913 #define ISNEXT(char) (!PeekNext (peek ? 1 : 0) == char) 867 #define ISNEXT(C) (PeekNext (peek ? 1 : 0) == C)
914 int ScriptReader::ParseOperator (bool peek) { 868 int ScriptReader::ParseOperator (bool peek) {
915 str oper; 869 string oper;
916 if (peek) 870 if (peek)
917 oper += PeekNext (); 871 oper += PeekNext ();
918 else 872 else
919 oper += token; 873 oper += token;
920 874
979 933
980 return o; 934 return o;
981 } 935 }
982 936
983 // ============================================================================ 937 // ============================================================================
984 str ScriptReader::ParseFloat () { 938 string ScriptReader::ParseFloat () {
985 MustNumber (true); 939 MustNumber (true);
986 str floatstring = token; 940 string floatstring = token;
987 941
988 // Go after the decimal point 942 // Go after the decimal point
989 if (PeekNext () == ".") { 943 if (PeekNext () == ".") {
990 Next ("."); 944 Next (".");
991 MustNumber (false); 945 MustNumber (false);
1019 constinfo_t* constant = FindConstant (token); 973 constinfo_t* constant = FindConstant (token);
1020 if (!constant || constant->type != TYPE_STRING) 974 if (!constant || constant->type != TYPE_STRING)
1021 ParserError ("strlen only works with const str"); 975 ParserError ("strlen only works with const str");
1022 976
1023 if (reqtype != TYPE_INT) 977 if (reqtype != TYPE_INT)
1024 ParserError ("strlen returns int but %s is expected\n", (char*)GetTypeName (reqtype)); 978 ParserError ("strlen returns int but %s is expected\n", GetTypeName (reqtype).c_str());
1025 979
1026 b->Write (DH_PUSHNUMBER); 980 b->Write (DH_PUSHNUMBER);
1027 b->Write (constant->val.len ()); 981 b->Write (constant->val.len ());
1028 982
1029 MustNext (")"); 983 MustNext (")");
1042 b = ParseCommand (comm); 996 b = ParseCommand (comm);
1043 } else if (constinfo_t* constant = FindConstant (token)) { 997 } else if (constinfo_t* constant = FindConstant (token)) {
1044 // Type check 998 // Type check
1045 if (reqtype != constant->type) 999 if (reqtype != constant->type)
1046 ParserError ("constant `%s` is %s, expression requires %s\n", 1000 ParserError ("constant `%s` is %s, expression requires %s\n",
1047 (char*)constant->name, (char*)GetTypeName (constant->type), 1001 constant->name.c_str(), GetTypeName (constant->type).c_str(),
1048 (char*)GetTypeName (reqtype)); 1002 GetTypeName (reqtype).c_str());
1049 1003
1050 switch (constant->type) { 1004 switch (constant->type) {
1051 case TYPE_BOOL: 1005 case TYPE_BOOL:
1052 case TYPE_INT: 1006 case TYPE_INT:
1053 b->Write (DH_PUSHNUMBER); 1007 b->Write (DH_PUSHNUMBER);
1150 1104
1151 ScopeInfo* info = &SCOPE(0); 1105 ScopeInfo* info = &SCOPE(0);
1152 info->type = SCOPETYPE_UNKNOWN; 1106 info->type = SCOPETYPE_UNKNOWN;
1153 info->mark1 = 0; 1107 info->mark1 = 0;
1154 info->mark2 = 0; 1108 info->mark2 = 0;
1155 info->buffer1 = NULL; 1109 info->buffer1 = null;
1156 info->casecursor = -1; 1110 info->casecursor = -1;
1157 for (int i = 0; i < MAX_CASE; i++) { 1111 for (int i = 0; i < MAX_CASE; i++) {
1158 info->casemarks[i] = MAX_MARKS; 1112 info->casemarks[i] = MAX_MARKS;
1159 info->casebuffers[i] = NULL; 1113 info->casebuffers[i] = null;
1160 info->casenumbers[i] = -1; 1114 info->casenumbers[i] = -1;
1161 } 1115 }
1162 } 1116 }
1163 1117
1164 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { 1118 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) {
1167 1121
1168 // If it's a variable, expect assignment. 1122 // If it's a variable, expect assignment.
1169 if (ScriptVar* var = FindGlobalVariable (token)) 1123 if (ScriptVar* var = FindGlobalVariable (token))
1170 return ParseAssignment (var); 1124 return ParseAssignment (var);
1171 1125
1172 return NULL; 1126 return null;
1173 } 1127 }
1174 1128
1175 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) { 1129 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) {
1176 ScopeInfo* info = &SCOPE(0); 1130 ScopeInfo* info = &SCOPE(0);
1177 1131
1193 // Init a buffer for the case block and tell the object 1147 // Init a buffer for the case block and tell the object
1194 // writer to record all written data to it. 1148 // writer to record all written data to it.
1195 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer; 1149 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer;
1196 } 1150 }
1197 1151
1198 constinfo_t* FindConstant (str token) { 1152 constinfo_t* FindConstant (string token) {
1199 for (uint i = 0; i < g_ConstInfo.size(); i++) 1153 for (uint i = 0; i < g_ConstInfo.size(); i++)
1200 if (g_ConstInfo[i].name == token) 1154 if (g_ConstInfo[i].name == token)
1201 return &g_ConstInfo[i]; 1155 return &g_ConstInfo[i];
1202 return NULL; 1156 return null;
1203 } 1157 }

mercurial