1 /*
2 * This file is part of the Colobot: Gold Edition source code
3 * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4 * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see http://gnu.org/licenses
18 */
19
20 #include "CBot/CBotInstr/CBotCase.h"
21
22 #include "CBot/CBotInstr/CBotTwoOpExpr.h"
23
24 #include "CBot/CBotStack.h"
25 #include "CBot/CBotCStack.h"
26
27 namespace CBot
28 {
29
30 ////////////////////////////////////////////////////////////////////////////////
CBotCase()31 CBotCase::CBotCase()
32 {
33 m_instr = nullptr;
34 }
35
36 ////////////////////////////////////////////////////////////////////////////////
~CBotCase()37 CBotCase::~CBotCase()
38 {
39 delete m_instr;
40 }
41
Compile(CBotToken * & p,CBotCStack * pStack,std::unordered_map<long,CBotInstr * > & labels)42 CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels)
43 {
44 CBotToken* pp = p; // preserves at the ^ token (starting position)
45
46 if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr; // should never happen
47 pStack->SetStartError(pp->GetStart());
48
49 long labelValue = 0;
50
51 if (pp->GetType() == ID_CASE)
52 {
53 CBotInstr* i = nullptr;
54 if (nullptr != (i = CBotTwoOpExpr::Compile(p, pStack, nullptr, true)))
55 {
56 if (pStack->GetType() <= CBotTypLong)
57 {
58 CBotStack* pile = CBotStack::AllocateStack();
59 while ( !i->Execute(pile) );
60 labelValue = pile->GetVar()->GetValLong();
61 pile->Delete();
62
63 if (labels.count(labelValue) > 0)
64 {
65 pStack->SetError(CBotErrRedefCase, p->GetStart());
66 }
67 }
68 else
69 pStack->SetError(CBotErrBadNum, p->GetStart());
70 delete i;
71 }
72 else
73 pStack->SetError(CBotErrBadNum, p->GetStart());
74 }
75
76 if (pStack->IsOk() && IsOfType(p, ID_DOTS))
77 {
78 CBotCase* newCase = new CBotCase();
79 newCase->SetToken(pp);
80 if (pp->GetType() == ID_CASE)
81 labels[labelValue] = newCase;
82 return newCase;
83 }
84
85 pStack->SetError(CBotErrNoDoubleDots, p->GetStart());
86 return nullptr;
87 }
88
89 ////////////////////////////////////////////////////////////////////////////////
Execute(CBotStack * & pj)90 bool CBotCase::Execute(CBotStack* &pj)
91 {
92 if (m_instr == nullptr) return true;
93 CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::BLOCK);
94
95 int state = pile->GetState();
96 CBotInstr* p = m_instr;
97 while (state-- > 0) p = p->GetNext();
98
99 while (p != nullptr)
100 {
101 if (!p->Execute(pile)) return false;
102 pile->IncState();
103 p = p->GetNext();
104 }
105
106 pile->Delete();
107 return pj->IsOk();
108 }
109
110 ////////////////////////////////////////////////////////////////////////////////
RestoreState(CBotStack * & pj,bool bMain)111 void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
112 {
113 if (!bMain) return;
114
115 CBotStack* pile = pj->RestoreStack(this);
116 if (pile == nullptr) return;
117
118 CBotInstr* p = m_instr;
119
120 int state = pile->GetState();
121 while (p != nullptr && state-- > 0)
122 {
123 p->RestoreState(pile, bMain);
124 p = p->GetNext();
125 }
126
127 if (p != nullptr) p->RestoreState(pile, bMain);
128 }
129
GetDebugLinks()130 std::map<std::string, CBotInstr*> CBotCase::GetDebugLinks()
131 {
132 auto links = CBotInstr::GetDebugLinks();
133 links["m_instr"] = m_instr;
134 return links;
135 }
136
137 } // namespace CBot
138