Tue, 11 Feb 2014 03:29:03 +0200
- implemented arrays, don't quite work 100% yet
- restructured Expression::ParseSymbol, local exception no longer needed
src/Expression.cc | file | annotate | diff | comparison | revisions | |
src/LexerScanner.cc | file | annotate | diff | comparison | revisions | |
src/Parser.cc | file | annotate | diff | comparison | revisions | |
src/Parser.h | file | annotate | diff | comparison | revisions | |
src/Tokens.h | file | annotate | diff | comparison | revisions |
--- a/src/Expression.cc Sun Feb 09 22:43:58 2014 +0200 +++ b/src/Expression.cc Tue Feb 11 03:29:03 2014 +0200 @@ -75,114 +75,121 @@ { int pos = mLexer->GetPosition(); ExpressionValue* op = null; - enum ELocalException { failed }; + + if (mLexer->GetNext (tkColon)) + return new ExpressionColon; - try - { - mLexer->MustGetNext (tkAny); + // Check for operator + for (const OperatorInfo& op : gOperators) + if (mLexer->GetNext (op.token)) + return new ExpressionOperator ((EOperator) (&op - &gOperators[0])); - if (mLexer->GetTokenType() == tkColon) - return new ExpressionColon; + // Check sub-expression + if (mLexer->GetNext (tkParenStart)) + { + Expression expr (mParser, mLexer, mType); + mLexer->MustGetNext (tkParenEnd); + return expr.GetResult()->Clone(); + } + + op = new ExpressionValue (mType); - // Check for operator - for (const OperatorInfo& op : gOperators) - if (mLexer->GetTokenType() == op.token) - return new ExpressionOperator ((EOperator) (&op - &gOperators[0])); + // Check function + if (CommandInfo* comm = FindCommandByName (mLexer->PeekNextString())) + { + mLexer->Skip(); + + if (mType != EUnknownType && comm->returnvalue != mType) + Error ("%1 returns an incompatible data type", comm->name); + + op->SetBuffer (mParser->ParseCommand (comm)); + return op; + } - // Check sub-expression - if (mLexer->GetTokenType() == tkParenStart) - { - Expression expr (mParser, mLexer, mType); - mLexer->MustGetNext (tkParenEnd); - return expr.GetResult()->Clone(); - } + // Check for variables + if (mLexer->GetNext (tkDollarSign)) + { + mLexer->MustGetNext (tkSymbol); + Variable* var = mParser->FindVariable (GetTokenString()); + + if (var == null) + Error ("unknown variable %1", GetTokenString()); + + if (var->type != mType) + Error ("expression requires %1, variable $%2 is of type %3", + GetTypeName (mType), var->name, GetTypeName (var->type)); - op = new ExpressionValue (mType); - - // Check function - if (CommandInfo* comm = FindCommandByName (GetTokenString())) + if (var->isarray) { - if (mType != EUnknownType && comm->returnvalue != mType) - Error ("%1 returns an incompatible data type", comm->name); + mLexer->MustGetNext (tkBracketStart); + Expression expr (mParser, mLexer, EIntType); + expr.GetResult()->ConvertToBuffer(); + DataBuffer* buf = expr.GetResult()->GetBuffer()->Clone(); + buf->WriteDWord (dhPushGlobalArray); + buf->WriteDWord (var->index); + op->SetBuffer (buf); + mLexer->MustGetNext (tkBracketEnd); + } + elif (var->writelevel == Variable::WRITE_Constexpr) + op->SetValue (var->value); + else + { + DataBuffer* buf = new DataBuffer (8); - op->SetBuffer (mParser->ParseCommand (comm)); - return op; + if (var->IsGlobal()) + buf->WriteDWord (dhPushGlobalVar); + else + buf->WriteDWord (dhPushLocalVar); + + buf->WriteDWord (var->index); + op->SetBuffer (buf); } - // Check for variables - if (mLexer->GetTokenType() == tkDollarSign) - { - mLexer->MustGetNext (tkSymbol); - Variable* globalvar = mParser->FindVariable (GetTokenString()); - - if (globalvar == null) - Error ("unknown variable %1", GetTokenString()); + return op; + } - if (globalvar->writelevel == Variable::WRITE_Constexpr) - op->SetValue (globalvar->value); - else - { - DataBuffer* buf = new DataBuffer (8); - buf->WriteDWord (dhPushGlobalVar); - buf->WriteDWord (globalvar->index); - op->SetBuffer (buf); - } - - return op; + // Check for literal + switch (mType) + { + case EVoidType: + case EUnknownType: + { + Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString()); + break; } - EToken tt; - - // Check for literal - switch (mType) + case EBoolType: { - case EVoidType: - case EUnknownType: + if (mLexer->GetNext (tkTrue) || mLexer->GetNext (tkFalse)) { - Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString()); - break; + EToken tt = mLexer->GetTokenType(); + op->SetValue (tt == tkTrue ? 1 : 0); + return op; } + } - case EBoolType: + case EIntType: + { + if (mLexer->GetNext (tkNumber)) { - if ((tt = mLexer->GetTokenType()) == tkTrue || tt == tkFalse) - { - op->SetValue (tt == tkTrue ? 1 : 0); - return op; - } - } - case EIntType: - { - if (mLexer->GetTokenType() != tkNumber) - throw failed; - op->SetValue (GetTokenString().ToLong()); return op; } + } - case EStringType: + case EStringType: + { + if (mLexer->GetNext (tkString)) { - if (mLexer->GetTokenType() != tkString) - throw failed; - op->SetValue (GetStringTableIndex (GetTokenString())); return op; } } - - assert (false); - throw failed; - } - catch (ELocalException&) - { - // We use a local enum here since catch(...) would catch Error() calls. - mBadTokenText = mLexer->GetToken()->text; - mLexer->SetPosition (pos); - delete op; - return null; } - assert (false); + mBadTokenText = mLexer->GetToken()->text; + mLexer->SetPosition (pos); + delete op; return null; } @@ -383,6 +390,7 @@ { const OperatorInfo* info = &gOperators[op->GetID()]; bool isconstexpr = true; + assert (values.Size() == info->numoperands); for (ExpressionValue* val : values) { @@ -481,18 +489,22 @@ case opTernary: a = (nums[0] != 0) ? nums[1] : nums[2]; break; case opDivision: + { if (nums[1] == 0) Error ("division by zero in constant expression"); a = nums[0] / nums[1]; break; + } case opModulus: + { if (nums[1] == 0) Error ("modulus by zero in constant expression"); a = nums[0] % nums[1]; break; + } } newval->SetValue (a);
--- a/src/LexerScanner.cc Sun Feb 09 22:43:58 2014 +0200 +++ b/src/LexerScanner.cc Tue Feb 11 03:29:03 2014 +0200 @@ -40,7 +40,6 @@ ">>=", "==", "!=", - "[]", "+=", "-=", "*=",
--- a/src/Parser.cc Sun Feb 09 22:43:58 2014 +0200 +++ b/src/Parser.cc Tue Feb 11 03:29:03 2014 +0200 @@ -178,6 +178,9 @@ ParseFuncdef(); break; + case tkSemicolon: + break; + default: { // Check for labels @@ -206,12 +209,15 @@ DataBuffer* b = ParseStatement(); if (b == false) + { + mLexer->GetNext(); Error ("unknown token `%1`", GetTokenString()); + } buffer()->MergeAndDestroy (b); mLexer->MustGetNext (tkSemicolon); + break; } - break; } } @@ -328,6 +334,7 @@ { Variable* var = new Variable; var->origin = mLexer->DescribeCurrentPosition(); + var->isarray = false; const bool isconst = mLexer->GetNext (tkConst); mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid}); @@ -338,6 +345,15 @@ mLexer->MustGetNext (tkSymbol); String name = GetTokenString(); + if (mLexer->GetNext (tkBracketStart)) + { + mLexer->MustGetNext (tkBracketEnd); + var->isarray = true; + + if (isconst) + Error ("arrays cannot be const"); + } + for (Variable* var : SCOPE(0).globalVariables + SCOPE(0).localVariables) { if (var->name == name) @@ -368,7 +384,7 @@ else { // TODO: might need a VM-wise oninit for this... - Error ("const variables must be constexpr for now"); + Error ("const variables must be constexpr"); } } @@ -989,11 +1005,10 @@ comm->name, comm->GetSignature()); break; - curarg++; } if (curarg >= comm->args.Size()) - Error ("too many arguments passed to %1\n\tusage is: %2", + Error ("too many arguments (%3) passed to %1\n\tusage is: %2", comm->name, comm->GetSignature()); r->MergeAndDestroy (ParseExpression (comm->args[curarg].type, true)); @@ -1096,36 +1111,43 @@ // ============================================================================ // +struct AssignmentDataHeaderInfo +{ + EAssignmentOperator op; + EDataHeader local; + EDataHeader global; + EDataHeader array; +}; + +const AssignmentDataHeaderInfo gAssignmentDataHeaders[] = +{ + { EAssign, dhAssignLocalVar, dhAssignGlobalVar, dhAssignGlobalArray }, + { EAssignAdd, dhAddLocalVar, dhAddGlobalVar, dhAddGlobalArray }, + { EAssignSub, dhSubtractLocalVar, dhSubtractGlobalVar, dhSubtractGlobalArray }, + { EAssignMul, dhMultiplyLocalVar, dhMultiplyGlobalVar, dhMultiplyGlobalArray }, + { EAssignDiv, dhDivideLocalVar, dhDivideGlobalVar, dhDivideGlobalArray }, + { EAssignMod, dhModLocalVar, dhModGlobalVar, dhModGlobalArray }, + { EAssignIncrement, dhIncreaseLocalVar, dhIncreaseGlobalVar, dhIncreaseGlobalArray }, + { EAssignDecrement, dhDecreaseLocalVar, dhDecreaseGlobalVar, dhDecreaseGlobalArray }, +}; + EDataHeader BotscriptParser::GetAssigmentDataHeader (EAssignmentOperator op, Variable* var) { - if (var->IsGlobal()) + for (const auto& a : gAssignmentDataHeaders) { - switch (op) - { - case EAssign: return dhAssignGlobalVar; - case EAssignAdd: return dhAddGlobalVar; - case EAssignSub: return dhSubtractGlobalVar; - case EAssignMul: return dhMultiplyGlobalVar; - case EAssignDiv: return dhDivideGlobalVar; - case EAssignMod: return dhModGlobalVar; - case EAssignIncrement: return dhIncreaseGlobalVar; - case EAssignDecrement: return dhDecreaseGlobalVar; - } + if (a.op != op) + continue; + + if (var->isarray) + return a.array; + + if (var->IsGlobal()) + return a.global; + + return a.local; } - switch (op) - { - case EAssign: return dhAssignLocalVar; - case EAssignAdd: return dhAddLocalVar; - case EAssignSub: return dhSubtractLocalVar; - case EAssignMul: return dhMultiplyLocalVar; - case EAssignDiv: return dhDivideLocalVar; - case EAssignMod: return dhModLocalVar; - case EAssignIncrement: return dhIncreaseLocalVar; - case EAssignDecrement: return dhDecreaseLocalVar; - } - - assert (false); + Error ("WTF: couldn't find data header for operator #%1", op); return (EDataHeader) 0; } @@ -1137,14 +1159,23 @@ // DataBuffer* BotscriptParser::ParseAssignment (Variable* var) { + DataBuffer* retbuf = new DataBuffer; + DataBuffer* arrayindex = null; + if (var->writelevel != Variable::WRITE_Mutable) + Error ("cannot alter read-only variable $%1", var->name); + + if (var->isarray) { - Error ("cannot alter read-only variable $%1", var->name); + mLexer->MustGetNext (tkBracketStart); + Expression expr (this, mLexer, EIntType); + expr.GetResult()->ConvertToBuffer(); + arrayindex = expr.GetResult()->GetBuffer()->Clone(); + mLexer->MustGetNext (tkBracketEnd); } // Get an operator EAssignmentOperator oper = ParseAssignmentOperator(); - DataBuffer* retbuf = new DataBuffer; if (mCurrentMode == ETopLevelMode) Error ("can't alter variables at top level"); @@ -1156,6 +1187,9 @@ retbuf->MergeAndDestroy (expr); } + if (var->isarray) + retbuf->MergeAndDestroy (arrayindex); + #if 0 // <<= and >>= do not have data headers. Solution: expand them. // a <<= b -> a = a << b
--- a/src/Parser.h Sun Feb 09 22:43:58 2014 +0200 +++ b/src/Parser.h Tue Feb 11 03:29:03 2014 +0200 @@ -107,6 +107,7 @@ EWritability writelevel; int value; String origin; + bool isarray; inline bool IsGlobal() const { @@ -134,6 +135,7 @@ EScopeType type; DataBuffer* buffer1; int globalVarIndexBase; + int globalArrayIndexBase; int localVarIndexBase; // switch-related stuff @@ -141,6 +143,7 @@ List<CaseInfo> cases; List<Variable*> localVariables; List<Variable*> globalVariables; + List<Variable*> globalArrays; }; // ============================================================================