parser.cxx

changeset 68
588cc27e84bb
parent 67
0a202714eea4
child 69
29a3e669d648
equal deleted inserted replaced
67:0a202714eea4 68:588cc27e84bb
48 #include "scriptreader.h" 48 #include "scriptreader.h"
49 #include "events.h" 49 #include "events.h"
50 #include "commands.h" 50 #include "commands.h"
51 #include "stringtable.h" 51 #include "stringtable.h"
52 #include "variables.h" 52 #include "variables.h"
53 #include "array.h"
53 54
54 #define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \ 55 #define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \
55 ParserError ("%s-statements may only be defined at top level!", token.chars()); 56 ParserError ("%s-statements may only be defined at top level!", token.chars());
56 57
57 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \ 58 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \
68 unsigned int g_ScopeCursor = 0; 69 unsigned int g_ScopeCursor = 0;
69 DataBuffer* g_IfExpression = NULL; 70 DataBuffer* g_IfExpression = NULL;
70 bool g_CanElse = false; 71 bool g_CanElse = false;
71 str* g_UndefinedLabels[MAX_MARKS]; 72 str* g_UndefinedLabels[MAX_MARKS];
72 bool g_Neurosphere = false; // neurosphere-compat 73 bool g_Neurosphere = false; // neurosphere-compat
74 array<constinfo_t> g_ConstInfo;
73 75
74 // ============================================================================ 76 // ============================================================================
75 // Main parser code. Begins read of the script file, checks the syntax of it 77 // Main parser code. Begins read of the script file, checks the syntax of it
76 // and writes the data to the object file via ObjWriter - which also takes care 78 // and writes the data to the object file via ObjWriter - which also takes care
77 // of necessary buffering so stuff is written in the correct order. 79 // of necessary buffering so stuff is written in the correct order.
256 258
257 if (token == "else") { 259 if (token == "else") {
258 MUST_NOT_TOPLEVEL 260 MUST_NOT_TOPLEVEL
259 MustNext ("{"); 261 MustNext ("{");
260 262
261 // Don't use PushScope that will reset the scope. 263 // Don't use PushScope as it resets the scope
262 g_ScopeCursor++; 264 g_ScopeCursor++;
263 if (g_ScopeCursor >= MAX_SCOPE) 265 if (g_ScopeCursor >= MAX_SCOPE)
264 ParserError ("too deep scope"); 266 ParserError ("too deep scope");
265 267
266 if (SCOPE(0).type != SCOPETYPE_IF) 268 if (SCOPE(0).type != SCOPETYPE_IF)
548 // Not found in unmarked lists, define it now 550 // Not found in unmarked lists, define it now
549 if (mark == -1) 551 if (mark == -1)
550 w->AddMark (token); 552 w->AddMark (token);
551 553
552 MustNext (":"); 554 MustNext (":");
555 continue;
556 }
557
558 // ============================================================
559 if (token == "const") {
560 constinfo_t info;
561
562 // Get the type
563 MustNext ();
564 info.type = GetTypeByName (token);
565
566 if (info.type == TYPE_UNKNOWN || info.type == TYPE_VOID)
567 ParserError ("unknown type `%s` for constant", (char*)token);
568
569 MustNext ();
570 info.name = token;
571
572 MustNext ("=");
573
574 switch (info.type) {
575 case TYPE_BOOL:
576 case TYPE_INT:
577 MustNumber (false);
578 info.val = token;
579 break;
580 case TYPE_STRING:
581 MustString ();
582 info.val = token;
583 break;
584 case TYPE_FLOAT:
585 MustNext ();
586 info.val = ParseFloat ();
587 break;
588 case TYPE_UNKNOWN:
589 case TYPE_VOID:
590 break;
591 }
592
593 g_ConstInfo << info;
594
595 MustNext (";");
553 continue; 596 continue;
554 } 597 }
555 598
556 // ============================================================ 599 // ============================================================
557 if (token == "}") { 600 if (token == "}") {
819 return 0; 862 return 0;
820 } 863 }
821 864
822 // ============================================================================ 865 // ============================================================================
823 // Parses an expression, potentially recursively 866 // Parses an expression, potentially recursively
824 DataBuffer* ScriptReader::ParseExpression (int reqtype) { 867 DataBuffer* ScriptReader::ParseExpression (type_e reqtype) {
825 DataBuffer* retbuf = new DataBuffer (64); 868 DataBuffer* retbuf = new DataBuffer (64);
826 869
827 // Parse first operand 870 // Parse first operand
828 retbuf->Merge (ParseExprValue (reqtype)); 871 retbuf->Merge (ParseExprValue (reqtype));
829 872
878 if (peek) 921 if (peek)
879 oper += PeekNext (); 922 oper += PeekNext ();
880 else 923 else
881 oper += token; 924 oper += token;
882 925
926 if (-oper == "strlen")
927 return OPER_STRLEN;
928
883 // Check one-char operators 929 // Check one-char operators
884 bool equalsnext = ISNEXT ("="); 930 bool equalsnext = ISNEXT ("=");
885 931
886 int o = (oper == "=" && !equalsnext) ? OPER_ASSIGN : 932 int o = (oper == "=" && !equalsnext) ? OPER_ASSIGN :
887 (oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN : 933 (oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN :
938 984
939 return o; 985 return o;
940 } 986 }
941 987
942 // ============================================================================ 988 // ============================================================================
989 str ScriptReader::ParseFloat () {
990 MustNumber (true);
991 str floatstring = token;
992
993 // Go after the decimal point
994 if (PeekNext () == ".") {
995 Next (".");
996 MustNumber (false);
997 floatstring += ".";
998 floatstring += token;
999 }
1000
1001 return floatstring;
1002 }
1003
1004 // ============================================================================
943 // Parses a value in the expression and returns the data needed to push 1005 // Parses a value in the expression and returns the data needed to push
944 // it, contained in a data buffer. A value can be either a variable, a command, 1006 // it, contained in a data buffer. A value can be either a variable, a command,
945 // a literal or an expression. 1007 // a literal or an expression.
946 DataBuffer* ScriptReader::ParseExprValue (int reqtype) { 1008 DataBuffer* ScriptReader::ParseExprValue (type_e reqtype) {
947 DataBuffer* b = new DataBuffer(16); 1009 DataBuffer* b = new DataBuffer(16);
948 1010
949 ScriptVar* g; 1011 ScriptVar* g;
950 1012
951 // Prefixing "!" means negation. 1013 // Prefixing "!" means negation.
952 bool negate = (token == "!"); 1014 bool negate = (token == "!");
953 if (negate) // Jump past the "!" 1015 if (negate) // Jump past the "!"
954 Next (); 1016 Next ();
955 1017
956 if (token == "(") { 1018 // Handle strlen
1019 if (token == "strlen") {
1020 MustNext ("(");
1021 MustNext ();
1022
1023 // By this token we should get a string constant.
1024 constinfo_t* constant = FindConstant (token);
1025 if (!constant || constant->type != TYPE_STRING)
1026 ParserError ("strlen only works with const str");
1027
1028 if (reqtype != TYPE_INT)
1029 ParserError ("strlen returns int but %s is expected\n", (char*)GetTypeName (reqtype));
1030
1031 b->Write<word> (DH_PUSHNUMBER);
1032 b->Write<word> (constant->val.len ());
1033
1034 MustNext (")");
1035 } else if (token == "(") {
957 // Expression 1036 // Expression
958 MustNext (); 1037 MustNext ();
959 DataBuffer* c = ParseExpression (reqtype); 1038 DataBuffer* c = ParseExpression (reqtype);
960 b->Merge (c); 1039 b->Merge (c);
961 MustNext (")"); 1040 MustNext (")");
964 1043
965 // Command 1044 // Command
966 if (reqtype && comm->returnvalue != reqtype) 1045 if (reqtype && comm->returnvalue != reqtype)
967 ParserError ("%s returns an incompatible data type", comm->name.chars()); 1046 ParserError ("%s returns an incompatible data type", comm->name.chars());
968 b = ParseCommand (comm); 1047 b = ParseCommand (comm);
1048 } else if (constinfo_t* constant = FindConstant (token)) {
1049 // Type check
1050 if (reqtype != constant->type)
1051 ParserError ("constant `%s` is %s, expression requires %s\n",
1052 (char*)constant->name, (char*)GetTypeName (constant->type),
1053 (char*)GetTypeName (reqtype));
1054
1055 switch (constant->type) {
1056 case TYPE_BOOL:
1057 case TYPE_INT:
1058 b->Write<word> (DH_PUSHNUMBER);
1059 b->Write<word> (atoi (constant->val));
1060 break;
1061 case TYPE_FLOAT:
1062 b->WriteFloat (constant->val);
1063 break;
1064 case TYPE_STRING:
1065 b->WriteString (constant->val);
1066 break;
1067 case TYPE_VOID:
1068 case TYPE_UNKNOWN:
1069 break;
1070 }
969 } else if ((g = FindGlobalVariable (token))) { 1071 } else if ((g = FindGlobalVariable (token))) {
970 // Global variable 1072 // Global variable
971 b->Write<word> (DH_PUSHGLOBALVAR); 1073 b->Write<word> (DH_PUSHGLOBALVAR);
972 b->Write<word> (g->index); 1074 b->Write<word> (g->index);
973 } else { 1075 } else {
974 // If nothing else, check for literal 1076 // If nothing else, check for literal
975 printf ("reqtype: %d\n", reqtype);
976 switch (reqtype) { 1077 switch (reqtype) {
977 case TYPE_VOID: 1078 case TYPE_VOID:
1079 case TYPE_UNKNOWN:
978 ParserError ("unknown identifier `%s` (expected keyword, function or variable)", token.chars()); 1080 ParserError ("unknown identifier `%s` (expected keyword, function or variable)", token.chars());
979 break; 1081 break;
980 case TYPE_BOOL: 1082 case TYPE_BOOL:
981 case TYPE_INT: { 1083 case TYPE_INT: {
982 MustNumber (true); 1084 MustNumber (true);
994 case TYPE_STRING: 1096 case TYPE_STRING:
995 // PushToStringTable either returns the string index of the 1097 // PushToStringTable either returns the string index of the
996 // string if it finds it in the table, or writes it to the 1098 // string if it finds it in the table, or writes it to the
997 // table and returns it index if it doesn't find it there. 1099 // table and returns it index if it doesn't find it there.
998 MustString (true); 1100 MustString (true);
999 b->Write<word> (DH_PUSHSTRINGINDEX); 1101 b->WriteString (token);
1000 b->Write<word> (PushToStringTable (token.chars()));
1001 break; 1102 break;
1002 case TYPE_FLOAT: { 1103 case TYPE_FLOAT: {
1003 str floatstring; 1104 str floatstring = ParseFloat ();
1004
1005 MustNumber (true);
1006 floatstring += token;
1007
1008 // Go after the decimal point
1009 if (PeekNext () == ".") {
1010 MustNext (".");
1011 MustNumber (false);
1012 floatstring += ".";
1013 floatstring += token;
1014 }
1015
1016 // TODO: Casting float to word causes the decimal to be lost.
1017 // Find a way to store the number without such loss.
1018 float val = atof (floatstring);
1019 b->Write<word> (DH_PUSHNUMBER);
1020 b->Write<word> (static_cast<word> ((val > 0) ? val : -val));
1021 if (val < 0)
1022 b->Write<word> (DH_UNARYMINUS);
1023 1105
1024 // TODO: Keep this check after decimal loss is fixed, but make 1106 // TODO: Keep this check after decimal loss is fixed, but make
1025 // it a real precision loss check. 55.5123 -> 55.512299, this 1107 // it a real precision loss check. 55.5123 -> 55.512299, this
1026 // should probably be warned of. 1108 // should probably be warned of.
1027 float check = static_cast<float> (static_cast<word> (val)); 1109 float check = static_cast<float> (static_cast<word> (atof (floatstring)));
1028 if (val != check) 1110 if (atof (floatstring) != check)
1029 ParserWarning ("floating point number %f loses precision (-> %f)", val, check); 1111 ParserWarning ("floating point number %f loses precision (-> %f)",
1112 atof (floatstring), check);
1113
1114 b->WriteFloat (floatstring);
1115 break;
1030 } 1116 }
1031 } 1117 }
1032 } 1118 }
1033 1119
1034 // Negate it now if desired 1120 // Negate it now if desired
1046 bool global = !var->statename.len (); 1132 bool global = !var->statename.len ();
1047 1133
1048 // Get an operator 1134 // Get an operator
1049 MustNext (); 1135 MustNext ();
1050 int oper = ParseOperator (); 1136 int oper = ParseOperator ();
1051 printf ("got operator %d\n", oper);
1052 if (!IsAssignmentOperator (oper)) 1137 if (!IsAssignmentOperator (oper))
1053 ParserError ("expected assignment operator"); 1138 ParserError ("expected assignment operator");
1054 1139
1055 if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction 1140 if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction
1056 ParserError ("can't alter variables at top level"); 1141 ParserError ("can't alter variables at top level");
1097 info->casenumbers[i] = -1; 1182 info->casenumbers[i] = -1;
1098 } 1183 }
1099 } 1184 }
1100 1185
1101 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) { 1186 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) {
1187 if (FindConstant (token)) // There should not be constants here.
1188 ParserError ("invalid use for constant\n");
1189
1102 // If it's a variable, expect assignment. 1190 // If it's a variable, expect assignment.
1103 if (ScriptVar* var = FindGlobalVariable (token)) { 1191 if (ScriptVar* var = FindGlobalVariable (token))
1104 DataBuffer* b = ParseAssignment (var); 1192 return ParseAssignment (var);
1105 return b;
1106 }
1107 1193
1108 return NULL; 1194 return NULL;
1109 } 1195 }
1110 1196
1111 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) { 1197 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) {
1128 1214
1129 // Init a buffer for the case block and tell the object 1215 // Init a buffer for the case block and tell the object
1130 // writer to record all written data to it. 1216 // writer to record all written data to it.
1131 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer; 1217 info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer;
1132 } 1218 }
1219
1220 constinfo_t* FindConstant (str token) {
1221 for (uint i = 0; i < g_ConstInfo.size(); i++)
1222 if (g_ConstInfo[i].name == token)
1223 return &g_ConstInfo[i];
1224 return NULL;
1225 }

mercurial