hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
lexer.cpp
Go to the documentation of this file.
1//
2// Created by XIaokang00010 on 2023/1/24.
3//
4
5#include "lexer.hpp"
6
7namespace yoi {
8 lexer::lexer(std::wstringstream ss) : stream(std::move(ss)), line(0), col(0), curCh() {
9 getCh();
10 }
11
12 void lexer::getCh() {
13 start:
14 if (!stream) {
15 panic(line, col, "hoshi::lexer::getCh() - eof");
16 }
17 if (!stream.get(curCh) || stream.fail()) {
18 curCh = '\0';
19 }
20 if (curCh == L'\n') {
21 line++, col = 0;
22 } else if (curCh == L'\r') {
23 goto start;
24 } else {
25 col++;
26 }
27 }
28
30 if (curCh == '\0') {
32 }
33 while (curCh == ' ' or curCh == '\n' or curCh == '\t') getCh();
34 if (std::isalpha(curCh) or curCh == '_') {
35 return curToken = alphaStart();
36 } else if (std::isdigit(curCh)) {
37 return curToken = digitStart();
38 } else if (curCh == L'+') {
39 return curToken = plusStart();
40 } else if (curCh == L'-') {
41 return curToken = minusStart();
42 } else if (curCh == L'*') {
43 return curToken = asteriskStart();
44 } else if (curCh == L'/') {
45 return curToken = slashStart();
46 } else if (curCh == L'%') {
47 return curToken = percentSignStart();
48 } else if (curCh == L'!') {
49 return curToken = notStart();
50 } else if (curCh == L'=') {
51 return curToken = equalStart();
52 } else if (curCh == L'>') {
53 return curToken = greaterStart();
54 } else if (curCh == L'<') {
55 return curToken = lessStart();
56 } else if (curCh == L'"' or curCh == L'\'') {
57 return curToken = strStart();
58 } else if (curCh == L';') {
59 return curToken = semicolonStart();
60 } else if (curCh == L':') {
61 return curToken = colonStart();
62 } else if (curCh == L',') {
63 return curToken = commaStart();
64 } else if (curCh == L'.') {
65 return curToken = dotStart();
66 } else if (curCh == L'(') {
68 } else if (curCh == L')') {
70 } else if (curCh == L'[') {
71 return curToken = leftBracketStart();
72 } else if (curCh == L']') {
73 return curToken = rightBracketStart();
74 } else if (curCh == L'{') {
75 return curToken = leftBracesStart();
76 } else if (curCh == L'}') {
77 return curToken = rightBracesStart();
78 } else if (curCh == L'&') {
79 return curToken = andStart();
80 } else if (curCh == L'|') {
81 return curToken = orStart();
82 } else if (curCh == L'^') {
83 return curToken = xorStart();
84 } else if (curCh == L'#') {
85 return curToken = sharpStart();
86 } else if (curCh == L'!') {
87 return curToken = notStart();
88 } else if (curCh == L'\0') {
90 } else {
91 panic(line, col, "hoshi::lexer::scan() - undefined token");
92 return {};
93 }
94 }
95
98 wstr tempStr;
99 tempStr += curCh;
100 getCh();
101 while (isalpha(curCh) or isdigit(curCh) or curCh == L'_') {
102 tempStr += curCh;
103 getCh();
104 }
105
106 // 关键词处理
107 if (tempStr == L"return") {
108 tok.kind = token::tokenKind::kReturn;
109 } else if (tempStr == L"continue") {
111 } else if (tempStr == L"break") {
112 tok.kind = token::tokenKind::kBreak;
113 } else if (tempStr == L"for") {
114 tok.kind = token::tokenKind::kFor;
115 } else if (tempStr == L"forEach") {
117 } else if (tempStr == L"while") {
118 tok.kind = token::tokenKind::kWhile;
119 } else if (tempStr == L"func") {
120 tok.kind = token::tokenKind::kFunc;
121 } else if (tempStr == L"use") {
122 tok.kind = token::tokenKind::kUse;
123 } else if (tempStr == L"let") {
124 tok.kind = token::tokenKind::kLet;
125 } else if (tempStr == L"cast") {
126 tok.kind = token::tokenKind::kCast;
127 } else if (tempStr == L"in") {
128 tok.kind = token::tokenKind::kIn;
129 } else if (tempStr == L"if") {
130 tok.kind = token::tokenKind::kIf;
131 } else if (tempStr == L"else") {
132 tok.kind = token::tokenKind::kElse;
133 } else if (tempStr == L"elif") {
134 tok.kind = token::tokenKind::kElif;
135 } else if (tempStr == L"interface") {
137 } else if (tempStr == L"constructor") {
139 } else if (tempStr == L"finalizer") {
141 } else if (tempStr == L"struct") {
142 tok.kind = token::tokenKind::kStruct;
143 } else if (tempStr == L"impl") {
144 tok.kind = token::tokenKind::kImpl;
145 } else if (tempStr == L"null") {
146 tok.kind = token::tokenKind::kNull;
147 } else if (tempStr == L"import") {
148 tok.kind = token::tokenKind::kImport;
149 } else if (tempStr == L"export") {
150 tok.kind = token::tokenKind::kExport;
151 } else if (tempStr == L"as") {
152 tok.kind = token::tokenKind::kAs;
153 } else if (tempStr == L"from") {
154 tok.kind = token::tokenKind::kFrom;
155 } else if (tempStr == L"type_id") {
156 tok.kind = token::tokenKind::kTypeId;
157 } else if (tempStr == L"dyn_cast") {
159 } else if (tempStr == L"try") {
160 tok.kind = token::tokenKind::kTry;
161 } else if (tempStr == L"catch") {
162 tok.kind = token::tokenKind::kCatch;
163 } else if (tempStr == L"finally") {
165 } else if (tempStr == L"throw") {
166 tok.kind = token::tokenKind::kThrow;
167 } else if (tempStr == L"noffi") {
168 tok.kind = token::tokenKind::kNoFFI;
169 } else if (tempStr == L"always_inline") {
171 } else if (tempStr == L"new") {
172 tok.kind = token::tokenKind::kNew;
173 } else if (tempStr == L"interfaceof") {
175 } else if (tempStr == L"static") {
176 tok.kind = token::tokenKind::kStatic;
177 } else if (tempStr == L"intrinsic") {
179 } else if (tempStr == L"callable") {
181 } else if (tempStr == L"alias") {
182 tok.kind = token::tokenKind::kAlias;
183 } else if (tempStr == L"enum") {
184 tok.kind = token::tokenKind::kEnum;
185 } else if (tempStr == L"datastruct") {
187 } else if (tempStr == L"datafield") {
189 } else if (tempStr == L"weak") {
190 tok.kind = token::tokenKind::kWeak;
191 } else if (tempStr == L"generator") {
193 } else if (tempStr == L"yield") {
194 tok.kind = token::tokenKind::kYield;
195 } else if (tempStr == L"decltype") {
197 } else if (tempStr == L"concept") {
199 } else if (tempStr == L"satisfy") {
201 } else if (tempStr == L"operator") {
202 scan();
203 return operatorStart();
204 } else if (tempStr == L"true" or tempStr == L"false") {
205 tok.kind = token::tokenKind::boolean;
206 tok.basicVal.vBool = tempStr == L"true";
207 } else {
208 tok.strVal = tempStr;
209 }
210
211 return tok;
212 }
213
215 wchar strV = curCh;
217 getCh();
218 while (curCh != strV) {
219 if (curCh == '\\') {
220 getCh();
221 tok.strVal += '\\';
222 }
223 tok.strVal += curCh;
224 getCh();
225 }
226 getCh(); // skip "
227 std::wistringstream ss{tok.strVal};
228 tok.strVal = {};
229 parseString(ss, tok.strVal);
230 if (strV == L'\'' && tok.strVal.size() > 1)
231 panic(line, col, "lexer::strStart() - character literal length > 1");
232 return tok;
233 }
234
236 enum class MatchPattern {
237 hex,
238 oct,
239 dec,
240 bin
241 } matchPattern = MatchPattern::dec;
243 wstr tempStr;
244 if (curCh == '0') {
245 tempStr += curCh;
246 getCh();
247 switch (curCh) {
248 case 'x':
249 case 'X':
250 matchPattern = MatchPattern::hex;
251 getCh();
252 tempStr += curCh;
253 getCh();
254 break;
255 case 'b':
256 case 'B':
257 matchPattern = MatchPattern::bin;
258 getCh();
259 tempStr += curCh;
260 getCh();
261 break;
262 case '0':
263 case '1':
264 case '2':
265 case '3':
266 case '4':
267 case '5':
268 case '6':
269 case '7':
270 matchPattern = MatchPattern::oct;
271 tempStr += curCh;
272 getCh();
273 break;
274 case 'o':
275 case 'O':
276 matchPattern = MatchPattern::oct;
277 getCh();
278 tempStr += curCh;
279 getCh();
280 break;
281 default:
282 break;
283 }
284 }
285 while (isdigit(curCh) || (matchPattern == MatchPattern::hex && isxdigit(curCh))) {
286 tempStr += curCh;
287 getCh();
288 }
289 if (curCh == '.') {
290 yoi_assert(line, col, matchPattern == MatchPattern::dec, "lexer::digitStart() - invalid match pattern");
291 tok.kind = token::tokenKind::decimal;
292 tempStr += curCh;
293 getCh();
294 while (isdigit(curCh)) {
295 tempStr += curCh;
296 getCh();
297 }
298 }
299 if (tok.kind == token::tokenKind::integer) {
300 switch (curCh) {
301 case 'u':
302 case 'U':
303 getCh();
305 break;
306 case 's':
307 case 'S':
308 getCh();
310 break;
311 }
312 int base = 10;
313 switch (matchPattern) {
314 case MatchPattern::dec: {
315 base = 10;
316 break;
317 }
318 case MatchPattern::hex: {
319 base = 16;
320 break;
321 }
322 case MatchPattern::oct: {
323 base = 8;
324 break;
325 }
326 case MatchPattern::bin: {
327 base = 2;
328 break;
329 }
330 }
331 if (tok.kind == token::tokenKind::integer)
332 tok.basicVal.vInt = std::stoll(tempStr, nullptr, base);
333 else if (tok.kind == token::tokenKind::unsignedInt)
334 tok.basicVal.vUint = std::stoull(tempStr, nullptr, base);
335 else if (tok.kind == token::tokenKind::shortInt)
336 tok.basicVal.vShort = static_cast<int16_t>(std::stoi(tempStr, nullptr, base));
337 } else {
338 tok.basicVal.vDeci = std::stod(tempStr);
339 }
340 return tok;
341 }
342
345 getCh();
346 if (curCh == '=') {
348 getCh();
349 } else if (curCh == '-') {
351 getCh();
352 } else if (curCh == '>') {
353 tok.kind = token::tokenKind::toSign;
354 getCh();
355 }
356 return tok;
357 }
358
361 getCh();
362 if (curCh == '=') {
364 getCh();
365 } else if (curCh == '+') {
367 getCh();
368 }
369 return tok;
370 }
371
374 getCh();
375 if (curCh == '=') {
377 getCh();
378 }
379 return tok;
380 }
381
384 uint64_t startLine = line, startCol = col;
385 getCh();
386 if (curCh == '=') {
388 getCh();
389 } else if (curCh == '/') {
390 wstr commentText = L"//";
391 getCh();
392 while (curCh and curCh != '\n') {
393 commentText += curCh;
394 getCh();
395 }
396 comments.push_back({startLine, startCol, commentText, false});
397 return scan(); // 单行注释解析
398 } else if (curCh == '*') {
399 wstr commentText = L"/*";
400 getCh();
401 while (curCh) {
402 commentText += curCh;
403 if (curCh == '*') {
404 getCh();
405 if (curCh == '/') {
406 commentText += curCh;
407 getCh();
408 break;
409 }
410 } else {
411 getCh();
412 }
413 }
414 comments.push_back({startLine, startCol, commentText, true});
415 return scan(); // 多行注释解析
416 }
417 return tok;
418 }
419
422 getCh();
423 if (curCh == '=') {
425 getCh();
426 }
427 return tok;
428 }
429
432 getCh();
433 if (curCh == '=') {
434 tok.kind = token::tokenKind::equal;
435 getCh();
436 }
437 return tok;
438 }
439
442 getCh();
443 if (curCh == '=') {
445 getCh();
446 }
447 return tok;
448 }
449
452 getCh();
453 if (curCh == '=') {
455 getCh();
456 } else if (curCh == '<') {
458 getCh();
459 }
460 return tok;
461 }
462
465 getCh();
466 if (curCh == '=') {
468 getCh();
469 } else if (curCh == '>') {
471 getCh();
472 }
473 return tok;
474 }
475
481
484 getCh();
485 if (curCh == '=') {
487 getCh();
488 }
489 return tok;
490 }
491
497
499 getCh();
500 if (curCh == '.' && stream.peek() == '.') {
501 getCh(); getCh(); // skip ".."
503 }
504
506 return tok;
507 }
508
514
520
526
532
538
544
546 states.emplace_back(line, col, (int64_t) stream.tellg(), curCh, curToken);
547 }
548
550 stream.clear();
551 lexerState &state = states.back();
552 line = state.line, col = state.col, curCh = state.curCh, curToken = state.curToken;
553 stream.seekg(state.pos);
554 dropState();
555 }
556
558 if (!states.empty())
559 states.pop_back();
560 }
561
564 getCh();
565 if (curCh == '&') {
567 getCh();
568 }
569 return tok;
570 }
571
574 getCh();
575 if (curCh == '|') {
576 tok.kind = token::tokenKind::logicOr;
577 getCh();
578 }
579 return tok;
580 }
581
587
593
599
601
602 }
603
605
606 }
607
609
610 }
611
615
616
618
619 }
620
622 line(line), col(col), kind(kind), basicVal(), strVal() {
623
624 }
625
627 line(line), col(col), kind(kind), basicVal(basicVal), strVal() {
628
629 }
630
631 lexer::token::token(int64_t line, int64_t col, lexer::token::tokenKind kind, wstr strVal) :
632 line(line), col(col), kind(kind), basicVal(), strVal(std::move(strVal)) {
633
634 }
635
636
638
639 }
640
641 lexer::lexerState::lexerState(int64_t line, int64_t col, std::istream::pos_type pos, wchar curCh,
643 :
644 line(line), col(col), pos(pos), curCh(curCh), curToken(std::move(curToken)) {
645
646 }
647
649 yoi::wstr operatorId{L"operator"};
650 switch (curToken.kind) {
651 case token::tokenKind::plus: operatorId += L"+"; break;
652 case token::tokenKind::minus: operatorId += L"-"; break;
653 case token::tokenKind::asterisk: operatorId += L"*"; break;
654 case token::tokenKind::slash: operatorId += L"/"; break;
655 case token::tokenKind::percentSign: operatorId += L"%"; break;
656 case token::tokenKind::lessThan: operatorId += L"<"; break;
657 case token::tokenKind::greaterThan: operatorId += L">"; break;
658 case token::tokenKind::equal: operatorId += L"=="; break;
659 case token::tokenKind::notEqual: operatorId += L"!="; break;
660 case token::tokenKind::binaryAnd: operatorId += L"&"; break;
661 case token::tokenKind::binaryNot: operatorId += L"~"; break;
662 case token::tokenKind::binaryOr: operatorId += L"|"; break;
663 case token::tokenKind::binaryXor: operatorId += L"^"; break;
664 case token::tokenKind::binaryShiftLeft: operatorId += L"<<"; break;
665 case token::tokenKind::binaryShiftRight: operatorId += L">>"; break;
666 case token::tokenKind::incrementSign: operatorId += L"++"; break;
667 case token::tokenKind::decrementSign: operatorId += L"--"; break;
668 case token::tokenKind::directAssignSign: operatorId += L":="; break;
669 case token::tokenKind::additionAssignment: operatorId += L"+="; break;
670 case token::tokenKind::subtractionAssignment: operatorId += L"-="; break;
671 case token::tokenKind::multiplicationAssignment: operatorId += L"*="; break;
672 case token::tokenKind::divisionAssignment: operatorId += L"/="; break;
673 case token::tokenKind::reminderAssignment: operatorId += L"%="; break;
674 case token::tokenKind::assignSign: operatorId += L"="; break;
676 scan();
677 yoi_assert(curToken.kind == token::tokenKind::rightParentheses, line, col, "lexer::operatorStart() - invalid operator");
678 operatorId += L"()";
679 break;
680 }
682 scan();
683 yoi_assert(curToken.kind == token::tokenKind::rightBracket, line, col, "lexer::operatorStart() - invalid operator");
684 operatorId += L"[]";
685 break;
686 }
687 default: panic(line, col, "lexer::operatorStart() - unknown operator");
688 }
689 return curToken = lexer::token{line, col, token::tokenKind::identifier, std::move(operatorId)};
690 }
693} // namespace yoi
vec< lexerState > states
Definition lexer.hpp:171
token percentSignStart()
Definition lexer.cpp:420
token equalStart()
Definition lexer.cpp:430
token rightBracesStart()
Definition lexer.cpp:539
token scan()
Definition lexer.cpp:29
token semicolonStart()
Definition lexer.cpp:476
token andStart()
Definition lexer.cpp:562
token curToken
Definition lexer.hpp:173
lexer(std::wstringstream ss)
Definition lexer.cpp:8
token strStart()
Definition lexer.cpp:214
token greaterStart()
Definition lexer.cpp:463
token alphaStart()
Definition lexer.cpp:96
token xorStart()
Definition lexer.cpp:582
token leftParenthesesStart()
Definition lexer.cpp:509
std::wstringstream stream
Definition lexer.hpp:15
token asteriskStart()
Definition lexer.cpp:372
vec< Comment > comments
Definition lexer.hpp:23
token digitStart()
Definition lexer.cpp:235
token binaryNotStart()
Definition lexer.cpp:594
void getCh()
Definition lexer.cpp:12
token plusStart()
Definition lexer.cpp:359
token orStart()
Definition lexer.cpp:572
token slashStart()
Definition lexer.cpp:382
int64_t col
Definition lexer.hpp:176
token rightBracketStart()
Definition lexer.cpp:527
int64_t line
Definition lexer.hpp:176
token sharpStart()
Definition lexer.cpp:588
void saveState()
Definition lexer.cpp:545
token minusStart()
Definition lexer.cpp:343
token dotStart()
Definition lexer.cpp:498
void returnState()
Definition lexer.cpp:549
token leftBracesStart()
Definition lexer.cpp:533
token colonStart()
Definition lexer.cpp:482
wchar curCh
Definition lexer.hpp:174
token leftBracketStart()
Definition lexer.cpp:521
token notStart()
Definition lexer.cpp:440
token operatorStart()
Definition lexer.cpp:648
token commaStart()
Definition lexer.cpp:492
token lessStart()
Definition lexer.cpp:450
token rightParenthesesStart()
Definition lexer.cpp:515
void dropState()
Definition lexer.cpp:557
Definition json.hpp:5639
wstr::value_type wchar
Definition def.hpp:52
void parseString(std::wistream &input, wstr &value)
Definition def.cpp:35
void yoi_assert(bool condition, yoi::indexT line, yoi::indexT col, const std::string &msg)
Asserts a condition that would be true and throws a runtime_error if it is false.
Definition def.cpp:217
std::wstring wstr
Definition def.hpp:51
void panic(yoi::indexT line, yoi::indexT col, const std::string &msg)
Definition def.cpp:141
std::istream::pos_type pos
Definition lexer.hpp:162
uint64_t col
Definition lexer.hpp:26
enum yoi::lexer::token::tokenKind kind
uint64_t line
Definition lexer.hpp:26
union yoi::lexer::token::vBasicValue basicVal