2024-01-05 12:04
BullseyeCoverage 9.6.4
expr/ Lexer.cpp
1 // Expression evaluator lexer implementation
2
3 #include <cassert>
4 #include <cctype>
5 #include <cstdlib>
6 #include <cstring>
7 #include "Lexer.h"
8
9 void Lexer::unitTest()
10 {
11 Token token;
12 assert(unitTest(" ") == Token::Kind::endOfInput);
13 assert(unitTest("!") == Token::Kind::logicalNot);
14 assert(unitTest("!=") == Token::Kind::notEqual);
15 assert(unitTest("&") == Token::Kind::bitwiseAnd);
16 assert(unitTest("&&") == Token::Kind::logicalAnd);
17 assert(unitTest("0") == Token::Kind::number);
18 assert(unitTest("12") == Token::Kind::number);
19 assert(unitTest("<") == Token::Kind::lessThan);
20 assert(unitTest("<=") == Token::Kind::lessThanEq);
21 assert(unitTest("<<") == Token::Kind::shiftLeft);
22 assert(unitTest("==") == Token::Kind::equal);
23 assert(unitTest(">") == Token::Kind::greaterThan);
24 assert(unitTest(">=") == Token::Kind::greaterThanEq);
25 assert(unitTest(">>") == Token::Kind::shiftRight);
26 assert(unitTest("^") == Token::Kind::bitwiseXor);
27 assert(unitTest("|") == Token::Kind::bitwiseOr);
28 assert(unitTest("||") == Token::Kind::logicalOr);
29 assert(unitTest("~") == Token::Kind::bitwiseNot);
30 try {
31 unitTest("@");
32 assert(false);
33 }
34 catch (const char*) {
35 }
36 }
37
38 Token::Kind Lexer::unitTest(const char* string)
39 {
40 Token token;
41 Lexer(string).read(token);
42 return token.kind;
43 }
44
45 bool Lexer::read(Token& token)
46 {
47 while (isspace(*m_next)) {
48 m_next++;
49 }
50 char* end;
51 switch (*m_next) {
52 case '\0':
53 token.kind = Token::Kind::endOfInput;
54 break;
55 case '!':
56 m_next++;
57 token.kind = Token::Kind::logicalNot;
58 if (*m_next == '=') { token.kind = Token::Kind::notEqual; m_next++; }
59 break;
60 case '%':
61 m_next++;
62 token.kind = Token::Kind::modulus;
63 break;
64 case '&':
65 m_next++;
66 token.kind = Token::Kind::bitwiseAnd;
67 if (*m_next == '&') { token.kind = Token::Kind::logicalAnd; m_next++; }
68 break;
69 case '(':
70 m_next++;
71 token.kind = Token::Kind::parenLeft;
72 break;
73 case ')':
74 m_next++;
75 token.kind = Token::Kind::parenRight;
76 break;
77 case '*':
78 m_next++;
79 token.kind = Token::Kind::multiply;
80 break;
81 case '+':
82 m_next++;
83 token.kind = Token::Kind::plus;
84 break;
85 case '-':
86 m_next++;
87 token.kind = Token::Kind::minus;
88 break;
89 case '/':
90 m_next++;
91 token.kind = Token::Kind::divide;
92 break;
93a case '0':
93b case '1':
93c case '2':
93d case '3':
93e case '4':
93f case '5':
93g case '6':
93h case '7':
93i case '8':
93j case '9':
94 token.kind = Token::Kind::number;
95 token.value = strtol(m_next, &end, 0);
96 m_next = end;
97 break;
98 case '<':
99 m_next++;
100 token.kind = Token::Kind::lessThan;
101 if (*m_next == '=') { token.kind = Token::Kind::lessThanEq; m_next++; } else
102 if (*m_next == '<') { token.kind = Token::Kind::shiftLeft; m_next++; }
103 break;
104 case '=':
105 if (*m_next == '=') { token.kind = Token::Kind::equal; m_next += 2; }
106 break;
107 case '>':
108 m_next++;
109 token.kind = Token::Kind::greaterThan;
110 if (*m_next == '=') { token.kind = Token::Kind::greaterThanEq; m_next++; } else
111 if (*m_next == '>') { token.kind = Token::Kind::shiftRight; m_next++; }
112 break;
113 case '^':
114 m_next++;
115 token.kind = Token::Kind::bitwiseXor;
116 break;
117 case '|':
118 m_next++;
119 token.kind = Token::Kind::bitwiseOr;
120 if (*m_next == '|') { token.kind = Token::Kind::logicalOr; m_next++; }
121 break;
122 case '~':
123 m_next++;
124 token.kind = Token::Kind::bitwiseNot;
125 break;
126 default:
127 throw "syntax error";
128 }
129 return token.kind != Token::Kind::endOfInput;
130 }