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 }