Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * Top contributors (to current version): 3 : : * Andrew Reynolds, Scott Talbert 4 : : * 5 : : * This file is part of the cvc5 project. 6 : : * 7 : : * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS 8 : : * in the top-level source directory and their institutional affiliations. 9 : : * All rights reserved. See the file COPYING in the top-level source 10 : : * directory for licensing information. 11 : : * **************************************************************************** 12 : : * 13 : : * The lexer for smt2 14 : : */ 15 : : 16 : : #include "parser/smt2/smt2_lexer.h" 17 : : 18 : : #include <cstdio> 19 : : 20 : : #include "base/output.h" 21 : : #include "parser/lexer.h" 22 : : 23 : : namespace cvc5 { 24 : : namespace parser { 25 : : 26 : 24101 : Smt2Lexer::Smt2Lexer(bool isStrict, bool isSygus) 27 : : : Lexer(), 28 : : d_isStrict(isStrict), 29 : 24101 : d_isSygus(isSygus) 30 : : { 31 [ + + ]: 650727 : for (int32_t ch = 'a'; ch <= 'z'; ++ch) 32 : : { 33 : 626626 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL_START); 34 : 626626 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 35 : : } 36 [ + + ]: 168707 : for (int32_t ch = 'a'; ch <= 'f'; ++ch) 37 : : { 38 : 144606 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::HEXADECIMAL_DIGIT); 39 : : } 40 [ + + ]: 650727 : for (int32_t ch = 'A'; ch <= 'Z'; ++ch) 41 : : { 42 : 626626 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL_START); 43 : 626626 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 44 : : } 45 [ + + ]: 168707 : for (int32_t ch = 'A'; ch <= 'F'; ++ch) 46 : : { 47 : 144606 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::HEXADECIMAL_DIGIT); 48 : : } 49 [ + + ]: 265111 : for (int32_t ch = '0'; ch <= '9'; ++ch) 50 : : { 51 : 241010 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::HEXADECIMAL_DIGIT); 52 : 241010 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::DECIMAL_DIGIT); 53 : 241010 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 54 : : } 55 : 24101 : d_charClass['0'] |= static_cast<uint32_t>(CharacterClass::BIT); 56 : 24101 : d_charClass['1'] |= static_cast<uint32_t>(CharacterClass::BIT); 57 : : // ~!@$%^&*_-+|=<>.?/ 58 [ + + ]: 433818 : for (int32_t ch : s_extraSymbolChars) 59 : : { 60 : 409717 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL_START); 61 : 409717 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 62 : : } 63 [ + + ]: 2386000 : for (int32_t ch : s_printableAsciiChars) 64 : : { 65 : 2361900 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::PRINTABLE); 66 : : } 67 : : // whitespace 68 : 24101 : d_charClass[' '] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 69 : 24101 : d_charClass['\t'] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 70 : 24101 : d_charClass['\r'] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 71 : 24101 : d_charClass['\n'] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 72 : 24101 : } 73 : : 74 : 15486600 : const char* Smt2Lexer::tokenStr() const 75 : : { 76 [ + - ][ + - ]: 30973300 : Assert(!d_token.empty() && d_token.back() == 0); [ - + ][ - - ] 77 : 15486600 : return d_token.data(); 78 : : } 79 : 425451 : bool Smt2Lexer::isStrict() const { return d_isStrict; } 80 : 24101 : bool Smt2Lexer::isSygus() const { return d_isSygus; } 81 : : 82 : 33387100 : Token Smt2Lexer::nextTokenInternal() 83 : : { 84 [ + - ]: 33387100 : Trace("lexer-debug") << "Call nextToken" << std::endl; 85 : 33387100 : d_token.clear(); 86 : 33387100 : Token ret = computeNextToken(); 87 : : // null terminate? 88 : 33387100 : d_token.push_back(0); 89 [ + - ]: 66774200 : Trace("lexer-debug") << "Return nextToken " << ret << " / " << tokenStr() 90 : 33387100 : << std::endl; 91 : 33387100 : return ret; 92 : : } 93 : : 94 : 33387100 : Token Smt2Lexer::computeNextToken() 95 : : { 96 : 33387100 : bumpSpan(); 97 : : int32_t ch; 98 : : // skip whitespace and comments 99 : : for (;;) 100 : : { 101 : 17544900 : do 102 : : { 103 [ + + ]: 50932000 : if ((ch = nextChar()) == EOF) 104 : : { 105 : 20746 : return Token::EOF_TOK; 106 : : } 107 [ + + ]: 50911300 : } while (isCharacterClass(ch, CharacterClass::WHITESPACE)); 108 : : 109 [ + + ]: 33408000 : if (ch != ';') 110 : : { 111 : 33366400 : break; 112 : : } 113 [ + + ]: 1070710 : while ((ch = nextChar()) != '\n') 114 : : { 115 [ + + ]: 1029080 : if (ch == EOF) 116 : : { 117 : 4 : return Token::EOF_TOK; 118 : : } 119 : : } 120 : : } 121 : 33366400 : bumpSpan(); 122 : 33366400 : pushToToken(ch); 123 [ + + ][ + + ]: 33366400 : switch (ch) [ + + ][ + ] 124 : : { 125 : 8622190 : case '(': return Token::LPAREN_TOK; 126 : 8622040 : case ')': return Token::RPAREN_TOK; 127 : 251306 : case '|': 128 : 238676 : do 129 : : { 130 : 251306 : ch = nextChar(); 131 [ - + ]: 251306 : if (ch == EOF) 132 : : { 133 : 0 : return Token::UNTERMINATED_QUOTED_SYMBOL; 134 : : } 135 : 251306 : pushToToken(ch); 136 [ + + ]: 251306 : } while (ch != '|'); 137 : 12630 : return Token::QUOTED_SYMBOL; 138 : 19318 : case '#': 139 [ + + ][ + - ]: 19318 : ch = nextChar(); 140 : : switch (ch) 141 : : { 142 : 13937 : case 'b': 143 : 13937 : pushToToken(ch); 144 : : // parse [01]+ 145 [ + + ]: 13937 : if (!parseNonEmptyCharList(CharacterClass::BIT)) 146 : : { 147 : 6 : parseError("Error expected bit string"); 148 : : } 149 : 13935 : return Token::BINARY_LITERAL; 150 : 3354 : case 'x': 151 : 3354 : pushToToken(ch); 152 : : // parse [0-9a-fA-F]+ 153 [ + + ]: 3354 : if (!parseNonEmptyCharList(CharacterClass::HEXADECIMAL_DIGIT)) 154 : : { 155 : 6 : parseError("Error expected hexadecimal string"); 156 : : } 157 : 3352 : return Token::HEX_LITERAL; 158 : 2027 : case 'f': 159 : 2027 : pushToToken(ch); 160 : : // parse [0-9]+m[0-9]+ 161 [ - + ]: 2027 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 162 : : { 163 : 0 : parseError("Error expected decimal for finite field value"); 164 : : } 165 [ - + ]: 2027 : if (!parseLiteralChar('m')) 166 : : { 167 : 0 : parseError("Error bad syntax for finite field value"); 168 : : } 169 [ - + ]: 2027 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 170 : : { 171 : 0 : parseError("Error expected decimal for finite field size"); 172 : : } 173 : 2027 : return Token::FIELD_LITERAL; 174 : 0 : default: 175 : : // otherwise error 176 : 0 : parseError("Error finding token following #"); 177 : 0 : break; 178 : : } 179 : 0 : break; 180 : 207293 : case '"': 181 : : for (;;) 182 : : { 183 : 207293 : ch = nextChar(); 184 [ - + ]: 207293 : if (ch == EOF) 185 : : { 186 : 0 : return Token::UNTERMINATED_STRING_LITERAL; 187 : : } 188 [ + + ]: 207293 : else if (!isCharacterClass(ch, CharacterClass::PRINTABLE)) 189 : : { 190 : 3 : parseError("Non-printable character in string literal"); 191 : : } 192 [ + + ]: 207292 : else if (ch == '"') 193 : : { 194 : 30919 : pushToToken(ch); 195 : 30919 : ch = nextChar(); 196 : : // "" denotes the escape sequence for " 197 [ + + ]: 30919 : if (ch != '"') 198 : : { 199 : 30865 : saveChar(ch); 200 : 30865 : return Token::STRING_LITERAL; 201 : : } 202 : : } 203 : 176427 : pushToToken(ch); 204 : : } 205 : : break; 206 : 48763 : case ':': 207 : : // parse a simple symbol 208 [ - + ]: 48763 : if (!parseChar(CharacterClass::SYMBOL_START)) 209 : : { 210 : 0 : parseError("Error expected symbol following :"); 211 : : } 212 : 48763 : parseNonEmptyCharList(CharacterClass::SYMBOL); 213 : 48763 : return Token::KEYWORD; 214 : 16010500 : default: 215 [ + + ]: 16010500 : if (isCharacterClass(ch, CharacterClass::DECIMAL_DIGIT)) 216 : : { 217 : 1344620 : Token res = Token::INTEGER_LITERAL; 218 : : // parse [0-9]* 219 : 1344620 : parseCharList(CharacterClass::DECIMAL_DIGIT); 220 : : // maybe .[0-9]+ 221 : 1344620 : ch = nextChar(); 222 [ + + ]: 1344620 : if (ch == '.') 223 : : { 224 : 68645 : pushToToken(ch); 225 : 68645 : res = Token::DECIMAL_LITERAL; 226 : : // parse [0-9]+ 227 [ + + ]: 68645 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 228 : : { 229 : 3 : parseError("Error expected decimal string following ."); 230 : : } 231 : : } 232 [ + + ]: 1275980 : else if (ch == '/') 233 : : { 234 : 9 : pushToToken(ch); 235 : 9 : res = Token::RATIONAL_LITERAL; 236 : : // parse [0-9]+ 237 [ - + ]: 9 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 238 : : { 239 : 0 : parseError("Error expected decimal string following ."); 240 : : } 241 : : } 242 : : else 243 : : { 244 : : // otherwise, undo 245 : 1275970 : saveChar(ch); 246 : : } 247 : 1344620 : return res; 248 : : } 249 [ + - ]: 14665900 : else if (isCharacterClass(ch, CharacterClass::SYMBOL_START)) 250 : : { 251 : : // otherwise, we are a simple symbol or standard alphanumeric token 252 : : // note that we group the case when `:` is here. 253 : 14665900 : parseCharList(CharacterClass::SYMBOL); 254 : : // tokenize the current symbol, which may be a special case 255 : 14665900 : return tokenizeCurrentSymbol(); 256 : : } 257 : : // otherwise error 258 : 0 : break; 259 : : } 260 : 0 : parseError("Error finding token"); 261 : 0 : return Token::NONE; 262 : : } 263 : : 264 : 2027 : bool Smt2Lexer::parseLiteralChar(int32_t chc) 265 : : { 266 : 2027 : int32_t ch = nextChar(); 267 [ - + ]: 2027 : if (ch != chc) 268 : : { 269 : : // will be an error 270 : 0 : return false; 271 : : } 272 : 2027 : pushToToken(ch); 273 : 2027 : return true; 274 : : } 275 : : 276 : 48763 : bool Smt2Lexer::parseChar(CharacterClass cc) 277 : : { 278 : 48763 : int32_t ch = nextChar(); 279 [ - + ]: 48763 : if (!isCharacterClass(ch, cc)) 280 : : { 281 : : // will be an error 282 : 0 : return false; 283 : : } 284 : 48763 : pushToToken(ch); 285 : 48763 : return true; 286 : : } 287 : : 288 : 138762 : bool Smt2Lexer::parseNonEmptyCharList(CharacterClass cc) 289 : : { 290 : : // must contain at least one character 291 : 138762 : int32_t ch = nextChar(); 292 [ + + ]: 138762 : if (!isCharacterClass(ch, cc)) 293 : : { 294 : : // will be an error 295 : 5 : return false; 296 : : } 297 : 138757 : pushToToken(ch); 298 : 138757 : parseCharList(cc); 299 : 138757 : return true; 300 : : } 301 : : 302 : 69436300 : void Smt2Lexer::parseCharList(CharacterClass cc) 303 : : { 304 : : int32_t ch; 305 : : for (;;) 306 : : { 307 : 69436300 : ch = nextChar(); 308 [ + + ]: 69436300 : if (!isCharacterClass(ch, cc)) 309 : : { 310 : : // failed, we are done, put the character back 311 : 16149300 : saveChar(ch); 312 : 16149300 : return; 313 : : } 314 : 53287000 : pushToToken(ch); 315 : : } 316 : : } 317 : : 318 : 14665900 : Token Smt2Lexer::tokenizeCurrentSymbol() const 319 : : { 320 [ - + ][ - + ]: 14665900 : Assert(!d_token.empty()); [ - - ] 321 [ + + ][ + + ]: 14665900 : switch (d_token[0]) [ + + ][ + + ] 322 : : { 323 : 20785 : case '!': 324 [ + + ]: 20785 : if (d_token.size() == 1) 325 : : { 326 : 20721 : return Token::ATTRIBUTE_TOK; 327 : : } 328 : 64 : break; 329 : 782489 : case 'a': 330 [ + + ][ + + ]: 782489 : if (d_token.size() == 2 && d_token[1] == 's') [ + + ] 331 : : { 332 : 2051 : return Token::AS_TOK; 333 : : } 334 : 780438 : break; 335 : 236433 : case 'p': 336 [ + + ][ + + ]: 236433 : if (d_token.size() == 3 && d_token[1] == 'a' && d_token[2] == 'r') [ + - ][ + + ] 337 : : { 338 : 200 : return Token::PAR_TOK; 339 : : } 340 : 236233 : break; 341 : 270624 : case 'l': 342 [ + + ][ + + ]: 270624 : if (d_token.size() == 3 && d_token[1] == 'e' && d_token[2] == 't') [ + + ][ + + ] 343 : : { 344 : 222232 : return Token::LET_TOK; 345 : : } 346 : 48392 : break; 347 : 17505 : case 'm': 348 [ + + ][ + + ]: 19375 : if (d_token.size() == 5 && d_token[1] == 'a' && d_token[2] == 't' 349 [ + + ][ + - ]: 19375 : && d_token[3] == 'c' && d_token[4] == 'h') [ + - ][ + + ] 350 : : { 351 : 163 : return Token::MATCH_TOK; 352 : : } 353 : 17342 : break; 354 : 2583020 : case '_': 355 [ + + ]: 2583020 : if (d_token.size() == 1) 356 : : { 357 : 394579 : return Token::INDEX_TOK; 358 : : } 359 : 2188440 : break; 360 : 366322 : case '-': 361 : : { 362 : : // note that `-4`, `-4.0`, `-4/5` are SMT-LIB symbols, hence we only 363 : : // convert these to literals if we are not strict parsing. 364 [ + + ][ + + ]: 366322 : if (!d_isStrict && d_token.size() >= 2) [ + + ] 365 : : { 366 : : // reparse as a negative numeral, rational or decimal 367 : 19946 : Token ret = Token::INTEGER_LITERAL; 368 [ + + ]: 19989 : for (size_t i = 1, tsize = d_token.size(); i < tsize; i++) 369 : : { 370 [ + + ]: 19964 : if (isCharacterClass(d_token[i], CharacterClass::DECIMAL_DIGIT)) 371 : : { 372 : 37 : continue; 373 : : } 374 [ + + ][ + - ]: 19927 : else if (i + 1 < tsize && ret == Token::INTEGER_LITERAL) 375 : : { 376 [ + + ]: 73 : if (d_token[i] == '.') 377 : : { 378 : 3 : ret = Token::DECIMAL_LITERAL; 379 : 3 : continue; 380 : : } 381 [ + + ]: 70 : else if (d_token[i] == '/') 382 : : { 383 : 3 : ret = Token::RATIONAL_LITERAL; 384 : 3 : continue; 385 : : } 386 : : } 387 : 19921 : return Token::SYMBOL; 388 : : } 389 : 25 : return ret; 390 : : } 391 : : } 392 : 346376 : break; 393 : 10388700 : default: break; 394 : : } 395 : : // otherwise not a special symbol 396 : 14006000 : return Token::SYMBOL; 397 : : } 398 : : 399 : : } // namespace parser 400 : : } // namespace cvc5