src/Lexer.cc

changeset 88
5def6ff8b466
child 89
029a330a9bef
equal deleted inserted replaced
87:8f65914e7046 88:5def6ff8b466
1 /*
2 Copyright 2012-2014 Santeri Piippo
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <cstring>
30 #include "Lexer.h"
31
32 static StringList gFileNameStack;
33 static Lexer* gMainLexer = null;
34
35 // =============================================================================
36 //
37 Lexer::Lexer()
38 {
39 assert (gMainLexer == null);
40 gMainLexer = this;
41 }
42
43 // =============================================================================
44 //
45 Lexer::~Lexer()
46 {
47 gMainLexer = null;
48 }
49
50 // =============================================================================
51 //
52 void Lexer::ProcessFile (String fileName)
53 {
54 gFileNameStack << fileName;
55 FILE* fp = fopen (fileName, "r");
56
57 if (fp == null)
58 Error ("couldn't open %1 for reading: %2", fileName, strerror (errno));
59
60 LexerScanner sc (fp);
61 CheckFileHeader (sc);
62
63 while (sc.GetNextToken())
64 {
65 // Preprocessor commands:
66 if (sc.GetTokenType() == tkHash)
67 {
68 MustGetFromScanner (sc, tkSymbol);
69
70 if (sc.GetTokenText() == "include")
71 {
72 MustGetFromScanner (sc, tkString);
73 String fileName = sc.GetTokenText();
74
75 if (gFileNameStack.Contains (fileName))
76 Error ("attempted to #include %1 recursively", sc.GetTokenText());
77
78 ProcessFile (fileName);
79 }
80 else
81 Error ("unknown preprocessor directive \"#%1\"", sc.GetTokenText());
82 }
83 else
84 {
85 Token tok;
86 tok.file = fileName;
87 tok.line = sc.GetLine();
88 tok.column = sc.GetColumn();
89 tok.type = sc.GetTokenType();
90 tok.text = sc.GetTokenText();
91
92 // devf ("Token #%1: %2:%3:%4: %5 (%6)\n", mTokens.size(),
93 // tok.file, tok.line, tok.column, DescribeToken (&tok), DescribeTokenType (tok.type));
94
95 mTokens << tok;
96 }
97 }
98
99 mTokenPosition = mTokens.begin() - 1;
100 gFileNameStack.Remove (fileName);
101 }
102
103 // ============================================================================
104 //
105 static bool IsValidHeader (String header)
106 {
107 if (header.EndsWith ("\n"))
108 header.RemoveFromEnd (1);
109
110 StringList tokens = header.Split (" ");
111
112 if (tokens.Size() != 2 || tokens[0] != "#!botc" || tokens[1].IsEmpty())
113 return false;
114
115 StringList nums = tokens[1].Split (".");
116
117 if (nums.Size() == 2)
118 nums << "0";
119 elif (nums.Size() != 3)
120 return false;
121
122 bool okA, okB, okC;
123 long major = nums[0].ToLong (&okA);
124 long minor = nums[1].ToLong (&okB);
125 long patch = nums[2].ToLong (&okC);
126
127 if (!okA || !okB || !okC)
128 return false;
129
130 if (VERSION_NUMBER < MAKE_VERSION_NUMBER (major, minor, patch))
131 Error ("The script file requires " APPNAME " v%1, this is v%2",
132 MakeVersionString (major, minor, patch), GetVersionString (EShortForm));
133
134 return true;
135 }
136
137 // ============================================================================
138 //
139 void Lexer::CheckFileHeader (LexerScanner& sc)
140 {
141 if (!IsValidHeader (sc.ReadLine()))
142 Error ("Not a valid botscript file! File must start with '#!botc <version>'");
143 }
144
145 // =============================================================================
146 //
147 bool Lexer::GetNext (EToken req)
148 {
149 Iterator pos = mTokenPosition;
150
151 if (mTokens.IsEmpty())
152 return false;
153
154 mTokenPosition++;
155
156 if (IsAtEnd() || (req != tkAny && GetTokenType() != req))
157 {
158 mTokenPosition = pos;
159 return false;
160 }
161
162 return true;
163 }
164
165 // =============================================================================
166 //
167 void Lexer::MustGetNext (EToken tt)
168 {
169 if (!GetNext())
170 Error ("unexpected EOF");
171
172 if (tt != tkAny)
173 TokenMustBe (tt);
174 }
175
176 // =============================================================================
177 // eugh..
178 //
179 void Lexer::MustGetFromScanner (LexerScanner& sc, EToken tt)
180 {
181 if (!sc.GetNextToken())
182 Error ("unexpected EOF");
183
184 if (tt != tkAny && sc.GetTokenType() != tt)
185 {
186 // TODO
187 Token tok;
188 tok.type = sc.GetTokenType();
189 tok.text = sc.GetTokenText();
190
191 Error ("at %1:%2: expected %3, got %4",
192 gFileNameStack.Last(),
193 sc.GetLine(),
194 DescribeTokenType (tt),
195 DescribeToken (&tok));
196 }
197 }
198
199 // =============================================================================
200 //
201 void Lexer::MustGetAnyOf (const List< EToken >& toks)
202 {
203 if (!GetNext())
204 Error ("unexpected EOF");
205
206 for (EToken tok : toks)
207 if (GetTokenType() == tok)
208 return;
209
210 String toknames;
211
212 for (const EToken& tokType : toks)
213 {
214 if (&tokType == &toks.Last())
215 toknames += " or ";
216 elif (toknames.IsEmpty() == false)
217 toknames += ", ";
218
219 toknames += DescribeTokenType (tokType);
220 }
221
222 Error ("expected %1, got %2", toknames, DescribeToken (GetToken()));
223 }
224
225 // =============================================================================
226 //
227 int Lexer::GetOneSymbol (const StringList& syms)
228 {
229 if (!GetNext())
230 Error ("unexpected EOF");
231
232 if (GetTokenType() == tkSymbol)
233 {
234 for (int i = 0; i < syms.Size(); ++i)
235 {
236 if (syms[i] == GetToken()->text)
237 return i;
238 }
239 }
240
241 Error ("expected one of %1, got %2", syms, DescribeToken (GetToken()));
242 return -1;
243 }
244
245 // =============================================================================
246 //
247 void Lexer::TokenMustBe (EToken tok)
248 {
249 if (GetTokenType() != tok)
250 Error ("expected %1, got %2", DescribeTokenType (tok),
251 DescribeToken (GetToken()));
252 }
253
254 // =============================================================================
255 //
256 String Lexer::DescribeTokenPrivate (EToken tokType, Lexer::Token* tok)
257 {
258 if (tokType < tkLastNamedToken)
259 return "\"" + LexerScanner::GetTokenString (tokType) + "\"";
260
261 switch (tokType)
262 {
263 case tkSymbol: return tok ? tok->text : "a symbol";
264 case tkNumber: return tok ? tok->text : "a number";
265 case tkString: return tok ? ("\"" + tok->text + "\"") : "a string";
266 case tkAny: return tok ? tok->text : "any token";
267 default: break;
268 }
269
270 return "";
271 }
272
273 // =============================================================================
274 //
275 bool Lexer::PeekNext (Lexer::Token* tk)
276 {
277 Iterator pos = mTokenPosition;
278 bool r = GetNext();
279
280 if (r && tk != null)
281 *tk = *mTokenPosition;
282
283 mTokenPosition = pos;
284 return r;
285 }
286
287 // =============================================================================
288 //
289 Lexer* Lexer::GetCurrentLexer()
290 {
291 return gMainLexer;
292 }
293
294 // =============================================================================
295 //
296 String Lexer::PeekNextString (int a)
297 {
298 if (mTokenPosition + a >= mTokens.end())
299 return "";
300
301 Iterator oldpos = mTokenPosition;
302 mTokenPosition += a;
303 String result = GetToken()->text;
304 mTokenPosition = oldpos;
305 return result;
306 }

mercurial