Lexer.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Lexer.h"
  7. #include <AK/CharacterTypes.h>
  8. #include <AK/Function.h>
  9. #include <AK/HashTable.h>
  10. #include <AK/StdLibExtras.h>
  11. #include <AK/String.h>
  12. namespace Cpp {
  13. Lexer::Lexer(StringView input, size_t start_line)
  14. : m_input(input)
  15. , m_previous_position { start_line, 0 }
  16. , m_position { start_line, 0 }
  17. {
  18. }
  19. char Lexer::peek(size_t offset) const
  20. {
  21. if ((m_index + offset) >= m_input.length())
  22. return 0;
  23. return m_input[m_index + offset];
  24. }
  25. char Lexer::consume()
  26. {
  27. VERIFY(m_index < m_input.length());
  28. char ch = m_input[m_index++];
  29. m_previous_position = m_position;
  30. if (ch == '\n') {
  31. m_position.line++;
  32. m_position.column = 0;
  33. } else {
  34. m_position.column++;
  35. }
  36. return ch;
  37. }
  38. constexpr bool is_valid_first_character_of_identifier(char ch)
  39. {
  40. return is_ascii_alpha(ch) || ch == '_' || ch == '$';
  41. }
  42. constexpr bool is_valid_nonfirst_character_of_identifier(char ch)
  43. {
  44. return is_valid_first_character_of_identifier(ch) || is_ascii_digit(ch);
  45. }
  46. constexpr StringView s_known_keywords[] = {
  47. "alignas",
  48. "alignof",
  49. "and",
  50. "and_eq",
  51. "asm",
  52. "bitand",
  53. "bitor",
  54. "break",
  55. "case",
  56. "catch",
  57. "class",
  58. "compl",
  59. "const",
  60. "const_cast",
  61. "constexpr",
  62. "continue",
  63. "decltype",
  64. "default",
  65. "delete",
  66. "do",
  67. "dynamic_cast",
  68. "else",
  69. "enum",
  70. "explicit",
  71. "export",
  72. "extern",
  73. "false",
  74. "final",
  75. "for",
  76. "friend",
  77. "goto",
  78. "if",
  79. "inline",
  80. "mutable",
  81. "namespace",
  82. "new",
  83. "noexcept",
  84. "not",
  85. "not_eq",
  86. "nullptr",
  87. "operator",
  88. "or",
  89. "or_eq",
  90. "override",
  91. "private",
  92. "protected",
  93. "public",
  94. "register",
  95. "reinterpret_cast",
  96. "return",
  97. "signed",
  98. "sizeof",
  99. "static",
  100. "static_assert",
  101. "static_cast",
  102. "struct",
  103. "switch",
  104. "template",
  105. "this",
  106. "thread_local",
  107. "throw",
  108. "true",
  109. "try",
  110. "typedef",
  111. "typeid",
  112. "typename",
  113. "union",
  114. "using",
  115. "virtual",
  116. "volatile",
  117. "while",
  118. "xor",
  119. "xor_eq"
  120. };
  121. constexpr StringView s_known_types[] = {
  122. "ByteBuffer",
  123. "CircularDeque",
  124. "CircularQueue",
  125. "Deque",
  126. "DoublyLinkedList",
  127. "FileSystemPath",
  128. "Array",
  129. "Function",
  130. "HashMap",
  131. "HashTable",
  132. "IPv4Address",
  133. "IntrusiveList",
  134. "JsonArray",
  135. "JsonObject",
  136. "JsonValue",
  137. "MappedFile",
  138. "NetworkOrdered",
  139. "NonnullOwnPtr",
  140. "NonnullOwnPtrVector",
  141. "NonnullRefPtr",
  142. "NonnullRefPtrVector",
  143. "Optional",
  144. "OwnPtr",
  145. "RefPtr",
  146. "Result",
  147. "ScopeGuard",
  148. "SinglyLinkedList",
  149. "String",
  150. "StringBuilder",
  151. "StringImpl",
  152. "StringView",
  153. "Utf8View",
  154. "Vector",
  155. "WeakPtr",
  156. "auto",
  157. "bool",
  158. "char",
  159. "char16_t",
  160. "char32_t",
  161. "char8_t",
  162. "double",
  163. "float",
  164. "i16",
  165. "i32",
  166. "i64",
  167. "i8",
  168. "int",
  169. "int",
  170. "long",
  171. "short",
  172. "signed",
  173. "u16",
  174. "u32",
  175. "u64",
  176. "u8",
  177. "unsigned",
  178. "void",
  179. "wchar_t"
  180. };
  181. static bool is_keyword(StringView string)
  182. {
  183. static HashTable<String> keywords(array_size(s_known_keywords));
  184. if (keywords.is_empty()) {
  185. keywords.set_from(s_known_keywords);
  186. }
  187. return keywords.contains(string);
  188. }
  189. static bool is_known_type(StringView string)
  190. {
  191. static HashTable<String> types(array_size(s_known_types));
  192. if (types.is_empty()) {
  193. types.set_from(s_known_types);
  194. }
  195. return types.contains(string);
  196. }
  197. void Lexer::lex_impl(Function<void(Token)> callback)
  198. {
  199. size_t token_start_index = 0;
  200. Position token_start_position;
  201. auto emit_single_char_token = [&](auto type) {
  202. callback(Token(type, m_position, m_position, m_input.substring_view(m_index, 1)));
  203. consume();
  204. };
  205. auto begin_token = [&] {
  206. token_start_index = m_index;
  207. token_start_position = m_position;
  208. };
  209. auto commit_token = [&](auto type) {
  210. if (m_options.ignore_whitespace && type == Token::Type::Whitespace)
  211. return;
  212. callback(Token(type, token_start_position, m_previous_position, m_input.substring_view(token_start_index, m_index - token_start_index)));
  213. };
  214. auto emit_token_equals = [&](auto type, auto equals_type) {
  215. if (peek(1) == '=') {
  216. begin_token();
  217. consume();
  218. consume();
  219. commit_token(equals_type);
  220. return;
  221. }
  222. emit_single_char_token(type);
  223. };
  224. auto match_escape_sequence = [&]() -> size_t {
  225. switch (peek(1)) {
  226. case '\'':
  227. case '"':
  228. case '?':
  229. case '\\':
  230. case 'a':
  231. case 'b':
  232. case 'f':
  233. case 'n':
  234. case 'r':
  235. case 't':
  236. case 'v':
  237. return 2;
  238. case '0':
  239. case '1':
  240. case '2':
  241. case '3':
  242. case '4':
  243. case '5':
  244. case '6':
  245. case '7': {
  246. size_t octal_digits = 1;
  247. for (size_t i = 0; i < 2; ++i) {
  248. char next = peek(2 + i);
  249. if (next < '0' || next > '7')
  250. break;
  251. ++octal_digits;
  252. }
  253. return 1 + octal_digits;
  254. }
  255. case 'x': {
  256. size_t hex_digits = 0;
  257. while (is_ascii_hex_digit(peek(2 + hex_digits)))
  258. ++hex_digits;
  259. return 2 + hex_digits;
  260. }
  261. case 'u':
  262. case 'U': {
  263. bool is_unicode = true;
  264. size_t number_of_digits = peek(1) == 'u' ? 4 : 8;
  265. for (size_t i = 0; i < number_of_digits; ++i) {
  266. if (!is_ascii_hex_digit(peek(2 + i))) {
  267. is_unicode = false;
  268. break;
  269. }
  270. }
  271. return is_unicode ? 2 + number_of_digits : 0;
  272. }
  273. default:
  274. return 0;
  275. }
  276. };
  277. auto match_string_prefix = [&](char quote) -> size_t {
  278. if (peek() == quote)
  279. return 1;
  280. if (peek() == 'L' && peek(1) == quote)
  281. return 2;
  282. if (peek() == 'u') {
  283. if (peek(1) == quote)
  284. return 2;
  285. if (peek(1) == '8' && peek(2) == quote)
  286. return 3;
  287. }
  288. if (peek() == 'U' && peek(1) == quote)
  289. return 2;
  290. return 0;
  291. };
  292. while (m_index < m_input.length()) {
  293. auto ch = peek();
  294. if (is_ascii_space(ch)) {
  295. begin_token();
  296. while (is_ascii_space(peek()))
  297. consume();
  298. commit_token(Token::Type::Whitespace);
  299. continue;
  300. }
  301. if (ch == '(') {
  302. emit_single_char_token(Token::Type::LeftParen);
  303. continue;
  304. }
  305. if (ch == ')') {
  306. emit_single_char_token(Token::Type::RightParen);
  307. continue;
  308. }
  309. if (ch == '{') {
  310. emit_single_char_token(Token::Type::LeftCurly);
  311. continue;
  312. }
  313. if (ch == '}') {
  314. emit_single_char_token(Token::Type::RightCurly);
  315. continue;
  316. }
  317. if (ch == '[') {
  318. emit_single_char_token(Token::Type::LeftBracket);
  319. continue;
  320. }
  321. if (ch == ']') {
  322. emit_single_char_token(Token::Type::RightBracket);
  323. continue;
  324. }
  325. if (ch == '<') {
  326. begin_token();
  327. consume();
  328. if (peek() == '<') {
  329. consume();
  330. if (peek() == '=') {
  331. consume();
  332. commit_token(Token::Type::LessLessEquals);
  333. continue;
  334. }
  335. commit_token(Token::Type::LessLess);
  336. continue;
  337. }
  338. if (peek() == '=') {
  339. consume();
  340. commit_token(Token::Type::LessEquals);
  341. continue;
  342. }
  343. if (peek() == '>') {
  344. consume();
  345. commit_token(Token::Type::LessGreater);
  346. continue;
  347. }
  348. commit_token(Token::Type::Less);
  349. continue;
  350. }
  351. if (ch == '>') {
  352. begin_token();
  353. consume();
  354. if (peek() == '>') {
  355. consume();
  356. if (peek() == '=') {
  357. consume();
  358. commit_token(Token::Type::GreaterGreaterEquals);
  359. continue;
  360. }
  361. commit_token(Token::Type::GreaterGreater);
  362. continue;
  363. }
  364. if (peek() == '=') {
  365. consume();
  366. commit_token(Token::Type::GreaterEquals);
  367. continue;
  368. }
  369. commit_token(Token::Type::Greater);
  370. continue;
  371. }
  372. if (ch == ',') {
  373. emit_single_char_token(Token::Type::Comma);
  374. continue;
  375. }
  376. if (ch == '+') {
  377. begin_token();
  378. consume();
  379. if (peek() == '+') {
  380. consume();
  381. commit_token(Token::Type::PlusPlus);
  382. continue;
  383. }
  384. if (peek() == '=') {
  385. consume();
  386. commit_token(Token::Type::PlusEquals);
  387. continue;
  388. }
  389. commit_token(Token::Type::Plus);
  390. continue;
  391. }
  392. if (ch == '-') {
  393. begin_token();
  394. consume();
  395. if (peek() == '-') {
  396. consume();
  397. commit_token(Token::Type::MinusMinus);
  398. continue;
  399. }
  400. if (peek() == '=') {
  401. consume();
  402. commit_token(Token::Type::MinusEquals);
  403. continue;
  404. }
  405. if (peek() == '>') {
  406. consume();
  407. if (peek() == '*') {
  408. consume();
  409. commit_token(Token::Type::ArrowAsterisk);
  410. continue;
  411. }
  412. commit_token(Token::Type::Arrow);
  413. continue;
  414. }
  415. commit_token(Token::Type::Minus);
  416. continue;
  417. }
  418. if (ch == '*') {
  419. emit_token_equals(Token::Type::Asterisk, Token::Type::AsteriskEquals);
  420. continue;
  421. }
  422. if (ch == '%') {
  423. emit_token_equals(Token::Type::Percent, Token::Type::PercentEquals);
  424. continue;
  425. }
  426. if (ch == '^') {
  427. emit_token_equals(Token::Type::Caret, Token::Type::CaretEquals);
  428. continue;
  429. }
  430. if (ch == '!') {
  431. emit_token_equals(Token::Type::ExclamationMark, Token::Type::ExclamationMarkEquals);
  432. continue;
  433. }
  434. if (ch == '=') {
  435. emit_token_equals(Token::Type::Equals, Token::Type::EqualsEquals);
  436. continue;
  437. }
  438. if (ch == '&') {
  439. begin_token();
  440. consume();
  441. if (peek() == '&') {
  442. consume();
  443. commit_token(Token::Type::AndAnd);
  444. continue;
  445. }
  446. if (peek() == '=') {
  447. consume();
  448. commit_token(Token::Type::AndEquals);
  449. continue;
  450. }
  451. commit_token(Token::Type::And);
  452. continue;
  453. }
  454. if (ch == '|') {
  455. begin_token();
  456. consume();
  457. if (peek() == '|') {
  458. consume();
  459. commit_token(Token::Type::PipePipe);
  460. continue;
  461. }
  462. if (peek() == '=') {
  463. consume();
  464. commit_token(Token::Type::PipeEquals);
  465. continue;
  466. }
  467. commit_token(Token::Type::Pipe);
  468. continue;
  469. }
  470. if (ch == '~') {
  471. emit_single_char_token(Token::Type::Tilde);
  472. continue;
  473. }
  474. if (ch == '?') {
  475. emit_single_char_token(Token::Type::QuestionMark);
  476. continue;
  477. }
  478. if (ch == ':') {
  479. begin_token();
  480. consume();
  481. if (peek() == ':') {
  482. consume();
  483. if (peek() == '*') {
  484. consume();
  485. commit_token(Token::Type::ColonColonAsterisk);
  486. continue;
  487. }
  488. commit_token(Token::Type::ColonColon);
  489. continue;
  490. }
  491. commit_token(Token::Type::Colon);
  492. continue;
  493. }
  494. if (ch == ';') {
  495. emit_single_char_token(Token::Type::Semicolon);
  496. continue;
  497. }
  498. if (ch == '.') {
  499. begin_token();
  500. consume();
  501. if (peek() == '*') {
  502. consume();
  503. commit_token(Token::Type::DotAsterisk);
  504. continue;
  505. }
  506. commit_token(Token::Type::Dot);
  507. continue;
  508. }
  509. if (ch == '#') {
  510. begin_token();
  511. consume();
  512. while (AK::is_ascii_space(peek()))
  513. consume();
  514. size_t directive_start = m_index;
  515. if (is_valid_first_character_of_identifier(peek()))
  516. while (peek() && is_valid_nonfirst_character_of_identifier(peek()))
  517. consume();
  518. auto directive = StringView(m_input.characters_without_null_termination() + directive_start, m_index - directive_start);
  519. if (directive == "include"sv) {
  520. commit_token(Token::Type::IncludeStatement);
  521. if (is_ascii_space(peek())) {
  522. begin_token();
  523. do {
  524. consume();
  525. } while (is_ascii_space(peek()));
  526. commit_token(Token::Type::Whitespace);
  527. }
  528. begin_token();
  529. if (peek() == '<' || peek() == '"') {
  530. char closing = consume() == '<' ? '>' : '"';
  531. while (peek() && peek() != closing && peek() != '\n')
  532. consume();
  533. if (peek() && consume() == '\n') {
  534. commit_token(Token::Type::IncludePath);
  535. continue;
  536. }
  537. commit_token(Token::Type::IncludePath);
  538. begin_token();
  539. }
  540. } else {
  541. while (peek()) {
  542. if (peek() == '\\' && peek(1) == '\n') {
  543. consume();
  544. consume();
  545. } else if (peek() == '\n') {
  546. break;
  547. } else {
  548. consume();
  549. }
  550. }
  551. commit_token(Token::Type::PreprocessorStatement);
  552. }
  553. continue;
  554. }
  555. if (ch == '/' && peek(1) == '/') {
  556. begin_token();
  557. while (peek() && peek() != '\n')
  558. consume();
  559. commit_token(Token::Type::Comment);
  560. continue;
  561. }
  562. if (ch == '/' && peek(1) == '*') {
  563. begin_token();
  564. consume();
  565. consume();
  566. bool comment_block_ends = false;
  567. while (peek()) {
  568. if (peek() == '*' && peek(1) == '/') {
  569. comment_block_ends = true;
  570. break;
  571. }
  572. consume();
  573. }
  574. if (comment_block_ends) {
  575. consume();
  576. consume();
  577. }
  578. commit_token(Token::Type::Comment);
  579. continue;
  580. }
  581. if (ch == '/') {
  582. emit_token_equals(Token::Type::Slash, Token::Type::SlashEquals);
  583. continue;
  584. }
  585. if (size_t prefix = match_string_prefix('"'); prefix > 0) {
  586. begin_token();
  587. for (size_t i = 0; i < prefix; ++i)
  588. consume();
  589. while (peek()) {
  590. if (peek() == '\\') {
  591. if (size_t escape = match_escape_sequence(); escape > 0) {
  592. commit_token(Token::Type::DoubleQuotedString);
  593. begin_token();
  594. for (size_t i = 0; i < escape; ++i)
  595. consume();
  596. commit_token(Token::Type::EscapeSequence);
  597. begin_token();
  598. continue;
  599. }
  600. }
  601. // If string is not terminated - stop before EOF
  602. if (!peek(1))
  603. break;
  604. if (consume() == '"')
  605. break;
  606. }
  607. commit_token(Token::Type::DoubleQuotedString);
  608. continue;
  609. }
  610. if (size_t prefix = match_string_prefix('R'); prefix > 0 && peek(prefix) == '"') {
  611. begin_token();
  612. for (size_t i = 0; i < prefix + 1; ++i)
  613. consume();
  614. size_t prefix_start = m_index;
  615. while (peek() && peek() != '(')
  616. consume();
  617. StringView prefix_string = m_input.substring_view(prefix_start, m_index - prefix_start);
  618. while (peek()) {
  619. if (consume() == '"') {
  620. VERIFY(m_index >= prefix_string.length() + 2);
  621. VERIFY(m_input[m_index - 1] == '"');
  622. if (m_input[m_index - 1 - prefix_string.length() - 1] == ')') {
  623. StringView suffix_string = m_input.substring_view(m_index - 1 - prefix_string.length(), prefix_string.length());
  624. if (prefix_string == suffix_string)
  625. break;
  626. }
  627. }
  628. }
  629. commit_token(Token::Type::RawString);
  630. continue;
  631. }
  632. if (size_t prefix = match_string_prefix('\''); prefix > 0) {
  633. begin_token();
  634. for (size_t i = 0; i < prefix; ++i)
  635. consume();
  636. while (peek()) {
  637. if (peek() == '\\') {
  638. if (size_t escape = match_escape_sequence(); escape > 0) {
  639. commit_token(Token::Type::SingleQuotedString);
  640. begin_token();
  641. for (size_t i = 0; i < escape; ++i)
  642. consume();
  643. commit_token(Token::Type::EscapeSequence);
  644. begin_token();
  645. continue;
  646. }
  647. }
  648. if (consume() == '\'')
  649. break;
  650. }
  651. commit_token(Token::Type::SingleQuotedString);
  652. continue;
  653. }
  654. if (is_ascii_digit(ch) || (ch == '.' && is_ascii_digit(peek(1)))) {
  655. begin_token();
  656. consume();
  657. auto type = ch == '.' ? Token::Type::Float : Token::Type::Integer;
  658. bool is_hex = false;
  659. bool is_binary = false;
  660. auto match_exponent = [&]() -> size_t {
  661. char ch = peek();
  662. if (ch != 'e' && ch != 'E' && ch != 'p' && ch != 'P')
  663. return 0;
  664. type = Token::Type::Float;
  665. size_t length = 1;
  666. ch = peek(length);
  667. if (ch == '+' || ch == '-') {
  668. ++length;
  669. }
  670. for (ch = peek(length); is_ascii_digit(ch); ch = peek(length)) {
  671. ++length;
  672. }
  673. return length;
  674. };
  675. auto match_type_literal = [&]() -> size_t {
  676. size_t length = 0;
  677. for (;;) {
  678. char ch = peek(length);
  679. if ((ch == 'u' || ch == 'U') && type == Token::Type::Integer) {
  680. ++length;
  681. } else if ((ch == 'f' || ch == 'F') && !is_binary) {
  682. type = Token::Type::Float;
  683. ++length;
  684. } else if (ch == 'l' || ch == 'L') {
  685. ++length;
  686. } else
  687. return length;
  688. }
  689. };
  690. if (peek() == 'b' || peek() == 'B') {
  691. consume();
  692. is_binary = true;
  693. for (char ch = peek(); ch == '0' || ch == '1' || (ch == '\'' && peek(1) != '\''); ch = peek()) {
  694. consume();
  695. }
  696. } else {
  697. if (peek() == 'x' || peek() == 'X') {
  698. consume();
  699. is_hex = true;
  700. }
  701. for (char ch = peek(); (is_hex ? is_ascii_hex_digit(ch) : is_ascii_digit(ch)) || (ch == '\'' && peek(1) != '\'') || ch == '.'; ch = peek()) {
  702. if (ch == '.') {
  703. if (type == Token::Type::Integer) {
  704. type = Token::Type::Float;
  705. } else
  706. break;
  707. };
  708. consume();
  709. }
  710. }
  711. if (!is_binary) {
  712. size_t length = match_exponent();
  713. for (size_t i = 0; i < length; ++i)
  714. consume();
  715. }
  716. size_t length = match_type_literal();
  717. for (size_t i = 0; i < length; ++i)
  718. consume();
  719. commit_token(type);
  720. continue;
  721. }
  722. if (is_valid_first_character_of_identifier(ch)) {
  723. begin_token();
  724. while (peek() && is_valid_nonfirst_character_of_identifier(peek()))
  725. consume();
  726. auto token_view = StringView(m_input.characters_without_null_termination() + token_start_index, m_index - token_start_index);
  727. if (is_keyword(token_view))
  728. commit_token(Token::Type::Keyword);
  729. else if (is_known_type(token_view))
  730. commit_token(Token::Type::KnownType);
  731. else
  732. commit_token(Token::Type::Identifier);
  733. continue;
  734. }
  735. if (ch == '\\' && peek(1) == '\n') {
  736. consume();
  737. consume();
  738. continue;
  739. }
  740. dbgln("Unimplemented token character: {}", ch);
  741. emit_single_char_token(Token::Type::Unknown);
  742. }
  743. }
  744. Vector<Token> Lexer::lex()
  745. {
  746. Vector<Token> tokens;
  747. lex_impl([&](auto token) {
  748. tokens.append(move(token));
  749. });
  750. return tokens;
  751. }
  752. }