47 gMainLexer = null; |
47 gMainLexer = null; |
48 } |
48 } |
49 |
49 |
50 // ============================================================================= |
50 // ============================================================================= |
51 // |
51 // |
52 void Lexer::ProcessFile (String fileName) |
52 void Lexer::processFile (String fileName) |
53 { |
53 { |
54 gFileNameStack << fileName; |
54 gFileNameStack << fileName; |
55 FILE* fp = fopen (fileName, "r"); |
55 FILE* fp = fopen (fileName, "r"); |
56 |
56 |
57 if (fp == null) |
57 if (fp == null) |
58 Error ("couldn't open %1 for reading: %2", fileName, strerror (errno)); |
58 error ("couldn't open %1 for reading: %2", fileName, strerror (errno)); |
59 |
59 |
60 LexerScanner sc (fp); |
60 LexerScanner sc (fp); |
61 CheckFileHeader (sc); |
61 checkFileHeader (sc); |
62 |
62 |
63 while (sc.GetNextToken()) |
63 while (sc.getNextToken()) |
64 { |
64 { |
65 // Preprocessor commands: |
65 // Preprocessor commands: |
66 if (sc.GetTokenType() ==TK_Hash) |
66 if (sc.getTokenType() ==TK_Hash) |
67 { |
67 { |
68 MustGetFromScanner (sc,TK_Symbol); |
68 mustGetFromScanner (sc,TK_Symbol); |
69 |
69 |
70 if (sc.GetTokenText() == "include") |
70 if (sc.getTokenText() == "include") |
71 { |
71 { |
72 MustGetFromScanner (sc,TK_String); |
72 mustGetFromScanner (sc,TK_String); |
73 String fileName = sc.GetTokenText(); |
73 String fileName = sc.getTokenText(); |
74 |
74 |
75 if (gFileNameStack.Contains (fileName)) |
75 if (gFileNameStack.contains (fileName)) |
76 Error ("attempted to #include %1 recursively", sc.GetTokenText()); |
76 error ("attempted to #include %1 recursively", sc.getTokenText()); |
77 |
77 |
78 ProcessFile (fileName); |
78 processFile (fileName); |
79 } |
79 } |
80 else |
80 else |
81 Error ("unknown preprocessor directive \"#%1\"", sc.GetTokenText()); |
81 error ("unknown preprocessor directive \"#%1\"", sc.getTokenText()); |
82 } |
82 } |
83 else |
83 else |
84 { |
84 { |
85 TokenInfo tok; |
85 TokenInfo tok; |
86 tok.file = fileName; |
86 tok.file = fileName; |
87 tok.line = sc.GetLine(); |
87 tok.line = sc.getLine(); |
88 tok.column = sc.GetColumn(); |
88 tok.column = sc.getColumn(); |
89 tok.type = sc.GetTokenType(); |
89 tok.type = sc.getTokenType(); |
90 tok.text = sc.GetTokenText(); |
90 tok.text = sc.getTokenText(); |
91 |
91 |
92 // devf ("Token #%1: %2:%3:%4: %5 (%6)\n", mTokens.Size(), |
92 // devf ("Token #%1: %2:%3:%4: %5 (%6)\n", mTokens.size(), |
93 // tok.file, tok.line, tok.column, DescribeToken (&tok), |
93 // tok.file, tok.line, tok.column, DescribeToken (&tok), |
94 // GetTokenTypeString (tok.type)); |
94 // GetTokenTypeString (tok.type)); |
95 |
95 |
96 mTokens << tok; |
96 m_tokens << tok; |
97 } |
97 } |
98 } |
98 } |
99 |
99 |
100 mTokenPosition = mTokens.begin() - 1; |
100 m_tokenPosition = m_tokens.begin() - 1; |
101 gFileNameStack.Remove (fileName); |
101 gFileNameStack.removeOne (fileName); |
102 } |
102 } |
103 |
103 |
104 // ============================================================================ |
104 // ============================================================================ |
105 // |
105 // |
106 static bool IsValidHeader (String header) |
106 static bool IsValidHeader (String header) |
107 { |
107 { |
108 if (header.EndsWith ("\n")) |
108 if (header.endsWith ("\n")) |
109 header.RemoveFromEnd (1); |
109 header.removeFromEnd (1); |
110 |
110 |
111 StringList tokens = header.Split (" "); |
111 StringList tokens = header.split (" "); |
112 |
112 |
113 if (tokens.Size() != 2 || tokens[0] != "#!botc" || tokens[1].IsEmpty()) |
113 if (tokens.size() != 2 || tokens[0] != "#!botc" || tokens[1].isEmpty()) |
114 return false; |
114 return false; |
115 |
115 |
116 StringList nums = tokens[1].Split ("."); |
116 StringList nums = tokens[1].split ("."); |
117 |
117 |
118 if (nums.Size() == 2) |
118 if (nums.size() == 2) |
119 nums << "0"; |
119 nums << "0"; |
120 elif (nums.Size() != 3) |
120 elif (nums.size() != 3) |
121 return false; |
121 return false; |
122 |
122 |
123 bool okA, okB, okC; |
123 bool okA, okB, okC; |
124 long major = nums[0].ToLong (&okA); |
124 long major = nums[0].toLong (&okA); |
125 long minor = nums[1].ToLong (&okB); |
125 long minor = nums[1].toLong (&okB); |
126 long patch = nums[2].ToLong (&okC); |
126 long patch = nums[2].toLong (&okC); |
127 |
127 |
128 if (!okA || !okB || !okC) |
128 if (!okA || !okB || !okC) |
129 return false; |
129 return false; |
130 |
130 |
131 if (VERSION_NUMBER < MAKE_VERSION_NUMBER (major, minor, patch)) |
131 if (VERSION_NUMBER < MAKE_VERSION_NUMBER (major, minor, patch)) |
132 Error ("The script file requires " APPNAME " v%1, this is v%2", |
132 error ("The script file requires " APPNAME " v%1, this is v%2", |
133 MakeVersionString (major, minor, patch), GetVersionString (false)); |
133 makeVersionString (major, minor, patch), versionString (false)); |
134 |
134 |
135 return true; |
135 return true; |
136 } |
136 } |
137 |
137 |
138 // ============================================================================ |
138 // ============================================================================ |
139 // |
139 // |
140 void Lexer::CheckFileHeader (LexerScanner& sc) |
140 void Lexer::checkFileHeader (LexerScanner& sc) |
141 { |
141 { |
142 if (!IsValidHeader (sc.ReadLine())) |
142 if (!IsValidHeader (sc.readLine())) |
143 Error ("Not a valid botscript file! File must start with '#!botc <version>'"); |
143 error ("Not a valid botscript file! File must start with '#!botc <version>'"); |
144 } |
144 } |
145 |
145 |
146 // ============================================================================= |
146 // ============================================================================= |
147 // |
147 // |
148 bool Lexer::Next (ETokenType req) |
148 bool Lexer::next (ETokenType req) |
149 { |
149 { |
150 Iterator pos = mTokenPosition; |
150 Iterator pos = m_tokenPosition; |
151 |
151 |
152 if (mTokens.IsEmpty()) |
152 if (m_tokens.isEmpty()) |
153 return false; |
153 return false; |
154 |
154 |
155 mTokenPosition++; |
155 m_tokenPosition++; |
156 |
156 |
157 if (IsAtEnd() || (req !=TK_Any && TokenType() != req)) |
157 if (isAtEnd() || (req !=TK_Any && tokenType() != req)) |
158 { |
158 { |
159 mTokenPosition = pos; |
159 m_tokenPosition = pos; |
160 return false; |
160 return false; |
161 } |
161 } |
162 |
162 |
163 return true; |
163 return true; |
164 } |
164 } |
165 |
165 |
166 // ============================================================================= |
166 // ============================================================================= |
167 // |
167 // |
168 void Lexer::MustGetNext (ETokenType tok) |
168 void Lexer::mustGetNext (ETokenType tok) |
169 { |
169 { |
170 if (!Next()) |
170 if (!next()) |
171 Error ("unexpected EOF"); |
171 error ("unexpected EOF"); |
172 |
172 |
173 if (tok !=TK_Any) |
173 if (tok !=TK_Any) |
174 TokenMustBe (tok); |
174 tokenMustBe (tok); |
175 } |
175 } |
176 |
176 |
177 // ============================================================================= |
177 // ============================================================================= |
178 // eugh.. |
178 // eugh.. |
179 // |
179 // |
180 void Lexer::MustGetFromScanner (LexerScanner& sc, ETokenType tt) |
180 void Lexer::mustGetFromScanner (LexerScanner& sc, ETokenType tt) |
181 { |
181 { |
182 if (!sc.GetNextToken()) |
182 if (sc.getNextToken() == false) |
183 Error ("unexpected EOF"); |
183 error ("unexpected EOF"); |
184 |
184 |
185 if (tt !=TK_Any && sc.GetTokenType() != tt) |
185 if (tt != TK_Any && sc.getTokenType() != tt) |
186 { |
186 { |
187 // TODO |
187 // TODO |
188 TokenInfo tok; |
188 TokenInfo tok; |
189 tok.type = sc.GetTokenType(); |
189 tok.type = sc.getTokenType(); |
190 tok.text = sc.GetTokenText(); |
190 tok.text = sc.getTokenText(); |
191 |
191 |
192 Error ("at %1:%2: expected %3, got %4", |
192 error ("at %1:%2: expected %3, got %4", |
193 gFileNameStack.Last(), |
193 gFileNameStack.last(), |
194 sc.GetLine(), |
194 sc.getLine(), |
195 DescribeTokenType (tt), |
195 describeTokenType (tt), |
196 DescribeToken (&tok)); |
196 describeToken (&tok)); |
197 } |
197 } |
198 } |
198 } |
199 |
199 |
200 // ============================================================================= |
200 // ============================================================================= |
201 // |
201 // |
202 void Lexer::MustGetAnyOf (const List<ETokenType>& toks) |
202 void Lexer::mustGetAnyOf (const List<ETokenType>& toks) |
203 { |
203 { |
204 if (!Next()) |
204 if (!next()) |
205 Error ("unexpected EOF"); |
205 error ("unexpected EOF"); |
206 |
206 |
207 for (ETokenType tok : toks) |
207 for (ETokenType tok : toks) |
208 if (TokenType() == tok) |
208 if (tokenType() == tok) |
209 return; |
209 return; |
210 |
210 |
211 String toknames; |
211 String toknames; |
212 |
212 |
213 for (const ETokenType& tokType : toks) |
213 for (const ETokenType& tokType : toks) |
214 { |
214 { |
215 if (&tokType == &toks.Last()) |
215 if (&tokType == &toks.last()) |
216 toknames += " or "; |
216 toknames += " or "; |
217 elif (toknames.IsEmpty() == false) |
217 elif (toknames.isEmpty() == false) |
218 toknames += ", "; |
218 toknames += ", "; |
219 |
219 |
220 toknames += DescribeTokenType (tokType); |
220 toknames += describeTokenType (tokType); |
221 } |
221 } |
222 |
222 |
223 Error ("expected %1, got %2", toknames, DescribeToken (Token())); |
223 error ("expected %1, got %2", toknames, describeToken (token())); |
224 } |
224 } |
225 |
225 |
226 // ============================================================================= |
226 // ============================================================================= |
227 // |
227 // |
228 int Lexer::GetOneSymbol (const StringList& syms) |
228 int Lexer::getOneSymbol (const StringList& syms) |
229 { |
229 { |
230 if (!Next()) |
230 if (!next()) |
231 Error ("unexpected EOF"); |
231 error ("unexpected EOF"); |
232 |
232 |
233 if (TokenType() ==TK_Symbol) |
233 if (tokenType() ==TK_Symbol) |
234 { |
234 { |
235 for (int i = 0; i < syms.Size(); ++i) |
235 for (int i = 0; i < syms.size(); ++i) |
236 { |
236 { |
237 if (syms[i] == Token()->text) |
237 if (syms[i] == token()->text) |
238 return i; |
238 return i; |
239 } |
239 } |
240 } |
240 } |
241 |
241 |
242 Error ("expected one of %1, got %2", syms, DescribeToken (Token())); |
242 error ("expected one of %1, got %2", syms, describeToken (token())); |
243 return -1; |
243 return -1; |
244 } |
244 } |
245 |
245 |
246 // ============================================================================= |
246 // ============================================================================= |
247 // |
247 // |
248 void Lexer::TokenMustBe (ETokenType tok) |
248 void Lexer::tokenMustBe (ETokenType tok) |
249 { |
249 { |
250 if (TokenType() != tok) |
250 if (tokenType() != tok) |
251 Error ("expected %1, got %2", DescribeTokenType (tok), |
251 error ("expected %1, got %2", describeTokenType (tok), |
252 DescribeToken (Token())); |
252 describeToken (token())); |
253 } |
253 } |
254 |
254 |
255 // ============================================================================= |
255 // ============================================================================= |
256 // |
256 // |
257 String Lexer::DescribeTokenPrivate (ETokenType tokType, Lexer::TokenInfo* tok) |
257 String Lexer::describeTokenPrivate (ETokenType tokType, Lexer::TokenInfo* tok) |
258 { |
258 { |
259 if (tokType <gLastNamedToken) |
259 if (tokType <gLastNamedToken) |
260 return "\"" + LexerScanner::GetTokenString (tokType) + "\""; |
260 return "\"" + LexerScanner::getTokenString (tokType) + "\""; |
261 |
261 |
262 switch (tokType) |
262 switch (tokType) |
263 { |
263 { |
264 case TK_Symbol: return tok ? tok->text : "a symbol"; |
264 case TK_Symbol: return tok ? tok->text : "a symbol"; |
265 case TK_Number: return tok ? tok->text : "a number"; |
265 case TK_Number: return tok ? tok->text : "a number"; |
271 return ""; |
271 return ""; |
272 } |
272 } |
273 |
273 |
274 // ============================================================================= |
274 // ============================================================================= |
275 // |
275 // |
276 bool Lexer::PeekNext (Lexer::TokenInfo* tk) |
276 bool Lexer::peekNext (Lexer::TokenInfo* tk) |
277 { |
277 { |
278 Iterator pos = mTokenPosition; |
278 Iterator pos = m_tokenPosition; |
279 bool r = Next(); |
279 bool r = next(); |
280 |
280 |
281 if (r && tk != null) |
281 if (r && tk != null) |
282 *tk = *mTokenPosition; |
282 *tk = *m_tokenPosition; |
283 |
283 |
284 mTokenPosition = pos; |
284 m_tokenPosition = pos; |
285 return r; |
285 return r; |
286 } |
286 } |
287 |
287 |
288 // ============================================================================= |
288 // ============================================================================= |
289 // |
289 // |
290 bool Lexer::PeekNextType (ETokenType req) |
290 bool Lexer::peekNextType (ETokenType req) |
291 { |
291 { |
292 Iterator pos = mTokenPosition; |
292 Iterator pos = m_tokenPosition; |
293 bool result = false; |
293 bool result = false; |
294 |
294 |
295 if (Next() && TokenType() == req) |
295 if (next() && tokenType() == req) |
296 result = true; |
296 result = true; |
297 |
297 |
298 mTokenPosition = pos; |
298 m_tokenPosition = pos; |
299 return result; |
299 return result; |
300 } |
300 } |
301 |
301 |
302 // ============================================================================= |
302 // ============================================================================= |
303 // |
303 // |
304 Lexer* Lexer::GetCurrentLexer() |
304 Lexer* Lexer::getCurrentLexer() |
305 { |
305 { |
306 return gMainLexer; |
306 return gMainLexer; |
307 } |
307 } |
308 |
308 |
309 // ============================================================================= |
309 // ============================================================================= |
310 // |
310 // |
311 String Lexer::PeekNextString (int a) |
311 String Lexer::peekNextString (int a) |
312 { |
312 { |
313 if (mTokenPosition + a >= mTokens.end()) |
313 if (m_tokenPosition + a >= m_tokens.end()) |
314 return ""; |
314 return ""; |
315 |
315 |
316 Iterator oldpos = mTokenPosition; |
316 Iterator oldpos = m_tokenPosition; |
317 mTokenPosition += a; |
317 m_tokenPosition += a; |
318 String result = Token()->text; |
318 String result = token()->text; |
319 mTokenPosition = oldpos; |
319 m_tokenPosition = oldpos; |
320 return result; |
320 return result; |
321 } |
321 } |
322 |
322 |
323 // ============================================================================= |
323 // ============================================================================= |
324 // |
324 // |
325 String Lexer::DescribeCurrentPosition() |
325 String Lexer::describeCurrentPosition() |
326 { |
326 { |
327 return Token()->file + ":" + Token()->line; |
327 return token()->file + ":" + token()->line; |
328 } |
328 } |
329 |
329 |
330 // ============================================================================= |
330 // ============================================================================= |
331 // |
331 // |
332 String Lexer::DescribeTokenPosition() |
332 String Lexer::describeTokenPosition() |
333 { |
333 { |
334 return Format ("%1 / %2", mTokenPosition - mTokens.begin(), mTokens.Size()); |
334 return format ("%1 / %2", m_tokenPosition - m_tokens.begin(), m_tokens.size()); |
335 } |
335 } |