43 #include "string.h" |
43 #include "string.h" |
44 #include "str.h" |
44 #include "str.h" |
45 #include "common.h" |
45 #include "common.h" |
46 #include "scriptreader.h" |
46 #include "scriptreader.h" |
47 |
47 |
48 static bool IsWhitespace (char c) { |
|
49 // These characters are invisible, thus considered whitespace |
|
50 if (c <= 32 || c == 127 || c == 255) |
|
51 return true; |
|
52 |
|
53 return false; |
|
54 } |
|
55 |
|
56 ScriptReader::ScriptReader (str path) { |
48 ScriptReader::ScriptReader (str path) { |
57 if (!(fp = fopen (path, "r"))) { |
|
58 error ("couldn't open %s for reading!\n", path.chars ()); |
|
59 exit (1); |
|
60 } |
|
61 |
|
62 filepath = path; |
|
63 curline = 1; |
|
64 curchar = 1; |
|
65 pos = 0; |
|
66 token = ""; |
49 token = ""; |
67 atnewline = false; |
50 fc = -1; |
|
51 |
|
52 for (unsigned int u = 0; u < MAX_FILESTACK; u++) |
|
53 fp[u] = NULL; |
|
54 |
|
55 OpenFile (path); |
68 commentmode = 0; |
56 commentmode = 0; |
69 } |
57 } |
70 |
58 |
71 ScriptReader::~ScriptReader () { |
59 ScriptReader::~ScriptReader () { |
72 FinalChecks (); |
60 FinalChecks (); |
73 fclose (fp); |
61 |
|
62 for (unsigned int u = 0; u < MAX_FILESTACK; u++) { |
|
63 if (fp[u]) { |
|
64 ParserWarning ("file idx %u remained open after parsing", u); |
|
65 CloseFile (u); |
|
66 } |
|
67 } |
|
68 } |
|
69 |
|
70 // Opens a file and pushes its pointer to stack |
|
71 void ScriptReader::OpenFile (str path) { |
|
72 if (fc+1 >= MAX_FILESTACK) |
|
73 ParserError ("supposed to open file `%s` but file stack is full! \ |
|
74 do you have recursive `#include` directives?", |
|
75 path.chars()); |
|
76 |
|
77 // Save the position first. |
|
78 if (fc != -1) { |
|
79 savedpos[fc] = ftell (fp[fc]); |
|
80 } |
|
81 |
|
82 fc++; |
|
83 |
|
84 fp[fc] = fopen (path, "r"); |
|
85 if (!fp[fc]) { |
|
86 ParserError ("couldn't open %s for reading!\n", path.chars ()); |
|
87 exit (1); |
|
88 } |
|
89 |
|
90 fseek (fp[fc], 0, SEEK_SET); |
|
91 filepath[fc] = path.chars(); |
|
92 curline[fc] = 1; |
|
93 curchar[fc] = 1; |
|
94 pos[fc] = 0; |
|
95 atnewline = 0; |
|
96 } |
|
97 |
|
98 void ScriptReader::CloseFile (unsigned int u) { |
|
99 if (u >= MAX_FILESTACK) |
|
100 u = fc; |
|
101 |
|
102 if (!fp[u]) |
|
103 return; |
|
104 |
|
105 fclose (fp[u]); |
|
106 fp[u] = NULL; |
|
107 fc--; |
|
108 |
|
109 if (fc != -1) |
|
110 fseek (fp[fc], savedpos[fc], SEEK_SET); |
74 } |
111 } |
75 |
112 |
76 char ScriptReader::ReadChar () { |
113 char ScriptReader::ReadChar () { |
|
114 if (feof (fp[fc])) |
|
115 return 0; |
|
116 |
77 char* c = (char*)malloc (sizeof (char)); |
117 char* c = (char*)malloc (sizeof (char)); |
78 if (!fread (c, sizeof (char), 1, fp)) |
118 if (!fread (c, sizeof (char), 1, fp[fc])) |
79 return 0; |
119 return 0; |
80 |
120 |
81 // We're at a newline, thus next char read will begin the next line |
121 // We're at a newline, thus next char read will begin the next line |
82 if (atnewline) { |
122 if (atnewline) { |
83 atnewline = false; |
123 atnewline = false; |
84 curline++; |
124 curline[fc]++; |
85 curchar = 0; // gets incremented to 1 |
125 curchar[fc] = 0; // gets incremented to 1 |
86 } |
126 } |
87 |
127 |
88 if (c[0] == '\n') |
128 if (c[0] == '\n') { |
89 atnewline = true; |
129 atnewline = true; |
90 |
130 |
91 curchar++; |
131 // Check for pre-processor directives |
|
132 PreprocessDirectives (); |
|
133 } |
|
134 |
|
135 curchar[fc]++; |
92 return c[0]; |
136 return c[0]; |
93 } |
137 } |
94 |
138 |
95 char ScriptReader::PeekChar (int offset) { |
139 char ScriptReader::PeekChar (int offset) { |
96 // Store current position |
140 // Store current position |
97 long curpos = ftell (fp); |
141 long curpos = ftell (fp[fc]); |
98 |
142 |
99 // Forward by offset |
143 // Forward by offset |
100 fseek (fp, offset, SEEK_CUR); |
144 fseek (fp[fc], offset, SEEK_CUR); |
101 |
145 |
102 // Read the character |
146 // Read the character |
103 char* c = (char*)malloc (sizeof (char)); |
147 char* c = (char*)malloc (sizeof (char)); |
104 if (!fread (c, sizeof (char), 1, fp)) |
148 |
|
149 if (!fread (c, sizeof (char), 1, fp[fc])) { |
|
150 fseek (fp[fc], curpos, SEEK_SET); |
105 return 0; |
151 return 0; |
|
152 } |
106 |
153 |
107 // Rewind back |
154 // Rewind back |
108 fseek (fp, curpos, SEEK_SET); |
155 fseek (fp[fc], curpos, SEEK_SET); |
109 |
156 |
110 return c[0]; |
157 return c[0]; |
111 } |
158 } |
112 |
159 |
113 // true if was found, false if not. |
160 // true if was found, false if not. |
114 bool ScriptReader::Next () { |
161 bool ScriptReader::Next (bool peek) { |
115 str tmp = ""; |
162 str tmp = ""; |
116 |
163 // printf ("begin token\n"); |
117 while (!feof (fp)) { |
164 |
|
165 while (1) { |
|
166 // Check end-of-file |
|
167 if (feof (fp[fc])) { |
|
168 // If we're just peeking, we shouldn't |
|
169 // actually close anything.. |
|
170 if (peek) |
|
171 break; |
|
172 |
|
173 CloseFile (); |
|
174 if (fc == -1) |
|
175 break; |
|
176 } |
|
177 |
118 // Check if the next token possibly starts a comment. |
178 // Check if the next token possibly starts a comment. |
119 if (PeekChar () == '/' && !tmp.len()) { |
179 if (PeekChar () == '/' && !tmp.len()) { |
120 char c2 = PeekChar (1); |
180 char c2 = PeekChar (1); |
121 // C++-style comment |
181 // C++-style comment |
122 if (c2 == '/') |
182 if (c2 == '/') |
181 if (!tmp.len()) { |
240 if (!tmp.len()) { |
182 token = ""; |
241 token = ""; |
183 return false; |
242 return false; |
184 } |
243 } |
185 |
244 |
186 pos++; |
245 pos[fc]++; |
187 token = tmp; |
246 token = tmp; |
188 return true; |
247 return true; |
189 } |
248 } |
190 |
249 |
191 // Returns the next token without advancing the cursor. |
250 // Returns the next token without advancing the cursor. |
192 str ScriptReader::PeekNext () { |
251 str ScriptReader::PeekNext () { |
193 // Store current position |
252 // Store current position |
194 int cpos = ftell (fp); |
253 int cpos = ftell (fp[fc]); |
195 |
254 |
196 // Advance on the token. |
255 // Advance on the token. |
197 if (!Next ()) |
256 if (!Next (true)) |
198 return ""; |
257 return ""; |
199 |
258 |
200 str tmp = token; |
259 str tmp = token; |
201 |
260 |
202 // Restore position |
261 // Restore position |
203 fseek (fp, cpos, SEEK_SET); |
262 fseek (fp[fc], cpos, SEEK_SET); |
204 pos--; |
263 pos[fc]--; |
205 |
264 |
206 return tmp; |
265 return tmp; |
207 } |
266 } |
208 |
267 |
209 void ScriptReader::Seek (unsigned int n, int origin) { |
268 void ScriptReader::Seek (unsigned int n, int origin) { |
210 switch (origin) { |
269 switch (origin) { |
211 case SEEK_SET: |
270 case SEEK_SET: |
212 fseek (fp, 0, SEEK_SET); |
271 fseek (fp[fc], 0, SEEK_SET); |
213 pos = 0; |
272 pos[fc] = 0; |
214 break; |
273 break; |
215 case SEEK_CUR: |
274 case SEEK_CUR: |
216 break; |
275 break; |
217 case SEEK_END: |
276 case SEEK_END: |
218 printf ("ScriptReader::Seek: SEEK_END not yet supported.\n"); |
277 printf ("ScriptReader::Seek: SEEK_END not yet supported.\n"); |
236 } |
295 } |
237 } |
296 } |
238 |
297 |
239 void ScriptReader::ParserError (const char* message, ...) { |
298 void ScriptReader::ParserError (const char* message, ...) { |
240 PERFORM_FORMAT (message, outmessage); |
299 PERFORM_FORMAT (message, outmessage); |
241 ParserMessage ("\nParse error\n", outmessage); |
300 ParserMessage ("\nError: ", outmessage); |
242 exit (1); |
301 exit (1); |
243 } |
302 } |
244 |
303 |
245 void ScriptReader::ParserWarning (const char* message, ...) { |
304 void ScriptReader::ParserWarning (const char* message, ...) { |
246 PERFORM_FORMAT (message, outmessage); |
305 PERFORM_FORMAT (message, outmessage); |
247 ParserMessage ("Warning: ", outmessage); |
306 ParserMessage ("Warning: ", outmessage); |
248 } |
307 } |
249 |
308 |
250 void ScriptReader::ParserMessage (const char* header, char* message) { |
309 void ScriptReader::ParserMessage (const char* header, char* message) { |
251 fprintf (stderr, "%sIn file %s, at line %u, col %u: %s\n", |
310 if (fc >= 0 && fc < MAX_FILESTACK) |
252 header, filepath.chars(), curline, curchar, message); |
311 fprintf (stderr, "%sIn file %s, at line %u, col %u: %s\n", |
|
312 header, filepath[fc], curline[fc], curchar[fc], message); |
|
313 else |
|
314 fprintf (stderr, "%s%s\n", header, message); |
253 } |
315 } |
254 |
316 |
255 void ScriptReader::MustString () { |
317 void ScriptReader::MustString () { |
256 MustNext ("\""); |
318 MustNext ("\""); |
257 |
319 |
258 str string; |
320 str string; |
259 // Keep reading characters until we find a terminating quote. |
321 // Keep reading characters until we find a terminating quote. |
260 while (1) { |
322 while (1) { |
261 // can't end here! |
323 // can't end here! |
262 if (feof (fp)) |
324 if (feof (fp[fc])) |
263 ParserError ("unterminated string"); |
325 ParserError ("unterminated string"); |
264 |
326 |
265 char c = ReadChar (); |
327 char c = ReadChar (); |
266 if (c == '"') |
328 if (c == '"') |
267 break; |
329 break; |