| 84 "mainloop", |
84 "mainloop", |
| 85 "onenter", |
85 "onenter", |
| 86 "onexit", |
86 "onexit", |
| 87 "state", |
87 "state", |
| 88 "switch", |
88 "switch", |
| 89 "str" |
89 "str", |
| 90 "void", |
90 "void", |
| 91 "while", |
91 "while", |
| 92 "enum", |
92 "enum", |
| 93 "func", |
93 "func", |
| 94 "return", |
94 "return", |
| 95 }; |
95 }; |
| 96 |
96 |
| 97 static_assert (countof (g_token_strings) == (int) last_named_token, |
97 static_assert (countof (g_token_strings) == (int) tk_last_named_token + 1, |
| 98 "Count of g_token_strings is not the same as the amount of named token identifiers."); |
98 "Count of g_token_strings is not the same as the amount of named token identifiers."); |
| 99 |
99 |
| 100 // ============================================================================= |
100 // ============================================================================= |
| 101 // |
101 // |
| 102 lexer_scanner::lexer_scanner (FILE* fp) : |
102 lexer_scanner::lexer_scanner (FILE* fp) : |
| 124 // |
124 // |
| 125 bool lexer_scanner::check_string (const char* c, int flags) |
125 bool lexer_scanner::check_string (const char* c, int flags) |
| 126 { |
126 { |
| 127 bool r = strncmp (m_ptr, c, strlen (c)) == 0; |
127 bool r = strncmp (m_ptr, c, strlen (c)) == 0; |
| 128 |
128 |
| 129 // There is to be whitespace after words |
129 // There is to be a non-symbol character after words |
| 130 if (r && (flags & f_check_word) && !isspace (m_ptr[strlen (c)])) |
130 if (r && (flags & f_check_word) && is_symbol_char (m_ptr[strlen (c)], true)) |
| 131 r = false; |
131 r = false; |
| 132 |
132 |
| 133 // Advance the cursor unless we want to just peek |
133 // Advance the cursor unless we want to just peek |
| 134 if (r && !(flags & f_check_peek)) |
134 if (r && !(flags & f_check_peek)) |
| 135 m_ptr += strlen (c); |
135 m_ptr += strlen (c); |
| 141 // |
141 // |
| 142 bool lexer_scanner::get_next_token() |
142 bool lexer_scanner::get_next_token() |
| 143 { |
143 { |
| 144 m_token_text = ""; |
144 m_token_text = ""; |
| 145 |
145 |
| 146 while (isspace (*m_ptr) == true) |
146 while (isspace (*m_ptr)) |
| 147 { |
147 skip(); |
| 148 if (*m_ptr == '\n') |
|
| 149 { |
|
| 150 m_line++; |
|
| 151 m_line_break_pos = m_ptr; |
|
| 152 } |
|
| 153 |
|
| 154 m_ptr++; |
|
| 155 } |
|
| 156 |
148 |
| 157 // Check for comments |
149 // Check for comments |
| 158 if (strncmp (m_ptr, "//", 2) == 0) |
150 if (strncmp (m_ptr, "//", 2) == 0) |
| 159 { |
151 { |
| 160 m_ptr += 2; |
152 m_ptr += 2; |
| 161 |
153 |
| 162 while (*(++m_ptr) != '\n') |
154 while (*m_ptr != '\n') |
| 163 ; |
155 skip(); |
| 164 |
156 |
| 165 return get_next_token(); |
157 return get_next_token(); |
| 166 } |
158 } |
| 167 elif (strncmp (m_ptr, "/*", 2) == 0) |
159 elif (strncmp (m_ptr, "/*", 2) == 0) |
| 168 { |
160 { |
| 169 m_ptr += 2; |
161 skip (2); // skip the start symbols |
| 170 |
162 |
| 171 while (strncmp (++m_ptr, "*/", 2) != 0) |
163 while (strncmp (m_ptr, "*/", 2) != 0) |
| 172 { |
164 skip(); |
| 173 if (*m_ptr == '\n') |
165 |
| 174 { |
166 skip (2); // skip the end symbols |
| 175 m_line++; |
|
| 176 m_line_break_pos = m_ptr; |
|
| 177 } |
|
| 178 } |
|
| 179 |
|
| 180 m_ptr += 2; // skip the */ |
|
| 181 return get_next_token(); |
167 return get_next_token(); |
| 182 } |
168 } |
| 183 |
169 |
| 184 if (*m_ptr == '\0') |
170 if (*m_ptr == '\0') |
| 185 return false; |
171 return false; |
| 186 |
172 |
| 187 // Check tokens |
173 // Check tokens |
| 188 for (int i = 0; i < (int) (sizeof g_token_strings / sizeof * g_token_strings); ++i) |
174 for (int i = 0; i < countof (g_token_strings); ++i) |
| 189 { |
175 { |
| 190 if (check_string (g_token_strings[i], f_check_word)) |
176 int flags = 0; |
| |
177 |
| |
178 if (i >= tk_first_named_token) |
| |
179 flags |= f_check_word; |
| |
180 |
| |
181 if (check_string (g_token_strings[i], flags)) |
| 191 { |
182 { |
| 192 m_token_text = g_token_strings[i]; |
183 m_token_text = g_token_strings[i]; |
| 193 m_token_type = (e_token) i; |
184 m_token_type = (e_token) i; |
| 194 return true; |
185 return true; |
| 195 } |
186 } |
| 227 m_token_type = tk_string; |
218 m_token_type = tk_string; |
| 228 m_ptr++; // skip the final quote |
219 m_ptr++; // skip the final quote |
| 229 return true; |
220 return true; |
| 230 } |
221 } |
| 231 |
222 |
| 232 m_token_type = tk_symbol; |
|
| 233 |
|
| 234 if (isdigit (*m_ptr)) |
223 if (isdigit (*m_ptr)) |
| 235 { |
224 { |
| 236 while (isdigit (*m_ptr)) |
225 while (isdigit (*m_ptr)) |
| 237 m_token_text += *m_ptr++; |
226 m_token_text += *m_ptr++; |
| 238 |
227 |
| 239 m_token_type = tk_number; |
228 m_token_type = tk_number; |
| 240 return true; |
229 return true; |
| 241 } |
230 } |
| 242 |
231 |
| 243 if (is_symbol_char (*m_ptr)) |
232 if (is_symbol_char (*m_ptr, false)) |
| 244 { |
233 { |
| |
234 m_token_type = tk_symbol; |
| |
235 |
| 245 while (m_ptr != '\0') |
236 while (m_ptr != '\0') |
| 246 { |
237 { |
| 247 if (!is_symbol_char (*m_ptr)) |
238 if (!is_symbol_char (*m_ptr, true)) |
| 248 break; |
|
| 249 |
|
| 250 bool stop_here = false; |
|
| 251 |
|
| 252 for (string i : g_token_strings) |
|
| 253 { |
|
| 254 if (check_string (i, f_check_peek | f_check_word)) |
|
| 255 { |
|
| 256 stop_here = true; |
|
| 257 break; |
|
| 258 } |
|
| 259 } |
|
| 260 |
|
| 261 if (stop_here) |
|
| 262 break; |
239 break; |
| 263 |
240 |
| 264 m_token_text += *m_ptr++; |
241 m_token_text += *m_ptr++; |
| 265 } |
242 } |
| 266 |
243 |
| 271 return false; |
248 return false; |
| 272 } |
249 } |
| 273 |
250 |
| 274 // ============================================================================= |
251 // ============================================================================= |
| 275 // |
252 // |
| |
253 void lexer_scanner::skip() |
| |
254 { |
| |
255 if (*m_ptr == '\n') |
| |
256 { |
| |
257 m_line++; |
| |
258 m_line_break_pos = m_ptr; |
| |
259 } |
| |
260 |
| |
261 m_ptr++; |
| |
262 } |
| |
263 |
| |
264 // ============================================================================= |
| |
265 // |
| |
266 void lexer_scanner::skip (int chars) |
| |
267 { |
| |
268 for (int i = 0; i < chars; ++i) |
| |
269 skip(); |
| |
270 } |
| |
271 |
| |
272 // ============================================================================= |
| |
273 // |
| 276 string lexer_scanner::get_token_string (e_token a) |
274 string lexer_scanner::get_token_string (e_token a) |
| 277 { |
275 { |
| 278 assert ((int) a <= last_named_token); |
276 assert ((int) a <= tk_last_named_token); |
| 279 return g_token_strings[a]; |
277 return g_token_strings[a]; |
| 280 } |
278 } |