Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * This file is part of the cvc5 project. 3 : : * 4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS 5 : : * in the top-level source directory and their institutional affiliations. 6 : : * All rights reserved. See the file COPYING in the top-level source 7 : : * directory for licensing information. 8 : : * **************************************************************************** 9 : : * 10 : : * The lexer for smt2 11 : : */ 12 : : 13 : : #include "parser/smt2/smt2_lexer.h" 14 : : 15 : : #include <cstdio> 16 : : 17 : : #include "base/output.h" 18 : : #include "parser/lexer.h" 19 : : 20 : : namespace cvc5 { 21 : : namespace parser { 22 : : 23 : 24018 : Smt2Lexer::Smt2Lexer(bool isStrict, bool isSygus) 24 : 24018 : : Lexer(), d_isStrict(isStrict), d_isSygus(isSygus) 25 : : { 26 [ + + ]: 648486 : for (int32_t ch = 'a'; ch <= 'z'; ++ch) 27 : : { 28 : 624468 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL_START); 29 : 624468 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 30 : : } 31 [ + + ]: 168126 : for (int32_t ch = 'a'; ch <= 'f'; ++ch) 32 : : { 33 : 144108 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::HEXADECIMAL_DIGIT); 34 : : } 35 [ + + ]: 648486 : for (int32_t ch = 'A'; ch <= 'Z'; ++ch) 36 : : { 37 : 624468 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL_START); 38 : 624468 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 39 : : } 40 [ + + ]: 168126 : for (int32_t ch = 'A'; ch <= 'F'; ++ch) 41 : : { 42 : 144108 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::HEXADECIMAL_DIGIT); 43 : : } 44 [ + + ]: 264198 : for (int32_t ch = '0'; ch <= '9'; ++ch) 45 : : { 46 : 240180 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::HEXADECIMAL_DIGIT); 47 : 240180 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::DECIMAL_DIGIT); 48 : 240180 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 49 : : } 50 : 24018 : d_charClass['0'] |= static_cast<uint32_t>(CharacterClass::BIT); 51 : 24018 : d_charClass['1'] |= static_cast<uint32_t>(CharacterClass::BIT); 52 : : // ~!@$%^&*_-+|=<>.?/ 53 [ + + ]: 432324 : for (int32_t ch : s_extraSymbolChars) 54 : : { 55 : 408306 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL_START); 56 : 408306 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::SYMBOL); 57 : : } 58 [ + + ]: 2377782 : for (int32_t ch : s_printableAsciiChars) 59 : : { 60 : 2353764 : d_charClass[ch] |= static_cast<uint32_t>(CharacterClass::PRINTABLE); 61 : : } 62 : : // whitespace 63 : 24018 : d_charClass[' '] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 64 : 24018 : d_charClass['\t'] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 65 : 24018 : d_charClass['\r'] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 66 : 24018 : d_charClass['\n'] |= static_cast<uint32_t>(CharacterClass::WHITESPACE); 67 : 24018 : } 68 : : 69 : 14942848 : const char* Smt2Lexer::tokenStr() const 70 : : { 71 [ + - ][ + - ]: 14942848 : Assert(!d_token.empty() && d_token.back() == 0); [ - + ][ - + ] [ - - ] 72 : 14942848 : return d_token.data(); 73 : : } 74 : 748821 : bool Smt2Lexer::isStrict() const { return d_isStrict; } 75 : 24018 : bool Smt2Lexer::isSygus() const { return d_isSygus; } 76 : : 77 : 32784329 : Token Smt2Lexer::nextTokenInternal() 78 : : { 79 [ + - ]: 32784329 : Trace("lexer-debug") << "Call nextToken" << std::endl; 80 : 32784329 : d_token.clear(); 81 : 32784329 : Token ret = computeNextToken(); 82 : : // null terminate? 83 : 32784323 : d_token.push_back(0); 84 [ + - ]: 65568646 : Trace("lexer-debug") << "Return nextToken " << ret << " / " << tokenStr() 85 : 32784323 : << std::endl; 86 : 32784323 : return ret; 87 : : } 88 : : 89 : 32784329 : Token Smt2Lexer::computeNextToken() 90 : : { 91 : 32784329 : bumpSpan(); 92 : : int32_t ch; 93 : : // skip whitespace and comments 94 : 50239 : for (;;) 95 : : { 96 : : do 97 : : { 98 [ + + ]: 50829326 : if ((ch = nextChar()) == EOF) 99 : : { 100 : 20967 : return Token::EOF_TOK; 101 : : } 102 [ + + ]: 50808359 : } while (isCharacterClass(ch, CharacterClass::WHITESPACE)); 103 : : 104 [ + + ]: 32813601 : if (ch != ';') 105 : : { 106 : 32763358 : break; 107 : : } 108 [ + + ]: 1379060 : while ((ch = nextChar()) != '\n') 109 : : { 110 [ + + ]: 1328821 : if (ch == EOF) 111 : : { 112 : 4 : return Token::EOF_TOK; 113 : : } 114 : : } 115 : : } 116 : 32763358 : bumpSpan(); 117 : 32763358 : pushToToken(ch); 118 [ + + ][ + + ]: 32763358 : switch (ch) [ + + ][ + ] 119 : : { 120 : 8457028 : case '(': return Token::LPAREN_TOK; 121 : 8456860 : case ')': return Token::RPAREN_TOK; 122 : 249401 : case '|': 123 : : do 124 : : { 125 : 261415 : ch = nextChar(); 126 [ - + ]: 261415 : if (ch == EOF) 127 : : { 128 : 0 : return Token::UNTERMINATED_QUOTED_SYMBOL; 129 : : } 130 : 261415 : pushToToken(ch); 131 [ + + ]: 261415 : } while (ch != '|'); 132 : 12014 : return Token::QUOTED_SYMBOL; 133 : 23159 : case '#': 134 [ + + ][ + - ]: 23159 : ch = nextChar(); 135 : : switch (ch) 136 : : { 137 : 17934 : case 'b': 138 : 17934 : pushToToken(ch); 139 : : // parse [01]+ 140 [ + + ]: 17934 : if (!parseNonEmptyCharList(CharacterClass::BIT)) 141 : : { 142 : 6 : parseError("Error expected bit string"); 143 : : } 144 : 17932 : return Token::BINARY_LITERAL; 145 : 3362 : case 'x': 146 : 3362 : pushToToken(ch); 147 : : // parse [0-9a-fA-F]+ 148 [ + + ]: 3362 : if (!parseNonEmptyCharList(CharacterClass::HEXADECIMAL_DIGIT)) 149 : : { 150 : 6 : parseError("Error expected hexadecimal string"); 151 : : } 152 : 3360 : return Token::HEX_LITERAL; 153 : 1863 : case 'f': 154 : 1863 : pushToToken(ch); 155 : : // parse [0-9]+m[0-9]+ 156 [ - + ]: 1863 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 157 : : { 158 : 0 : parseError("Error expected decimal for finite field value"); 159 : : } 160 [ - + ]: 1863 : if (!parseLiteralChar('m')) 161 : : { 162 : 0 : parseError("Error bad syntax for finite field value"); 163 : : } 164 [ - + ]: 1863 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 165 : : { 166 : 0 : parseError("Error expected decimal for finite field size"); 167 : : } 168 : 1863 : return Token::FIELD_LITERAL; 169 : 0 : default: 170 : : // otherwise error 171 : 0 : parseError("Error finding token following #"); 172 : 0 : break; 173 : : } 174 : 0 : break; 175 : 194308 : case '"': 176 : : for (;;) 177 : : { 178 : 194308 : ch = nextChar(); 179 [ - + ]: 194308 : if (ch == EOF) 180 : : { 181 : 0 : return Token::UNTERMINATED_STRING_LITERAL; 182 : : } 183 [ + + ]: 194308 : else if (!isCharacterClass(ch, CharacterClass::PRINTABLE)) 184 : : { 185 : 3 : parseError("Non-printable character in string literal"); 186 : : } 187 [ + + ]: 194307 : else if (ch == '"') 188 : : { 189 : 30203 : pushToToken(ch); 190 : 30203 : ch = nextChar(); 191 : : // "" denotes the escape sequence for " 192 [ + + ]: 30203 : if (ch != '"') 193 : : { 194 : 30149 : saveChar(ch); 195 : 30149 : return Token::STRING_LITERAL; 196 : : } 197 : : } 198 : 164158 : pushToToken(ch); 199 : : } 200 : : break; 201 : 44804 : case ':': 202 : : // parse a simple symbol 203 [ - + ]: 44804 : if (!parseChar(CharacterClass::SYMBOL_START)) 204 : : { 205 : 0 : parseError("Error expected symbol following :"); 206 : : } 207 : 44804 : parseNonEmptyCharList(CharacterClass::SYMBOL); 208 : 44804 : return Token::KEYWORD; 209 : 15739343 : default: 210 [ + + ]: 15739343 : if (isCharacterClass(ch, CharacterClass::DECIMAL_DIGIT)) 211 : : { 212 : 1573956 : Token res = Token::INTEGER_LITERAL; 213 : : // parse [0-9]* 214 : 1573956 : parseCharList(CharacterClass::DECIMAL_DIGIT); 215 : : // maybe .[0-9]+ 216 : 1573956 : ch = nextChar(); 217 [ + + ]: 1573956 : if (ch == '.') 218 : : { 219 : 64414 : pushToToken(ch); 220 : 64414 : res = Token::DECIMAL_LITERAL; 221 : : // parse [0-9]+ 222 [ + + ]: 64414 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 223 : : { 224 : 3 : parseError("Error expected decimal string following ."); 225 : : } 226 : : } 227 [ + + ]: 1509542 : else if (ch == '/') 228 : : { 229 : 9 : pushToToken(ch); 230 : 9 : res = Token::RATIONAL_LITERAL; 231 : : // parse [0-9]+ 232 [ - + ]: 9 : if (!parseNonEmptyCharList(CharacterClass::DECIMAL_DIGIT)) 233 : : { 234 : 0 : parseError("Error expected decimal string following ."); 235 : : } 236 : : } 237 : : else 238 : : { 239 : : // otherwise, undo 240 : 1509533 : saveChar(ch); 241 : : } 242 : 1573955 : return res; 243 : : } 244 [ + - ]: 14165387 : else if (isCharacterClass(ch, CharacterClass::SYMBOL_START)) 245 : : { 246 : : // otherwise, we are a simple symbol or standard alphanumeric token 247 : : // note that we group the case when `:` is here. 248 : 14165387 : parseCharList(CharacterClass::SYMBOL); 249 : : // tokenize the current symbol, which may be a special case 250 : 14165387 : return tokenizeCurrentSymbol(); 251 : : } 252 : : // otherwise error 253 : 0 : break; 254 : : } 255 : 0 : parseError("Error finding token"); 256 : 0 : return Token::NONE; 257 : : } 258 : : 259 : 1863 : bool Smt2Lexer::parseLiteralChar(int32_t chc) 260 : : { 261 : 1863 : int32_t ch = nextChar(); 262 [ - + ]: 1863 : if (ch != chc) 263 : : { 264 : : // will be an error 265 : 0 : return false; 266 : : } 267 : 1863 : pushToToken(ch); 268 : 1863 : return true; 269 : : } 270 : : 271 : 44804 : bool Smt2Lexer::parseChar(CharacterClass cc) 272 : : { 273 : 44804 : int32_t ch = nextChar(); 274 [ - + ]: 44804 : if (!isCharacterClass(ch, cc)) 275 : : { 276 : : // will be an error 277 : 0 : return false; 278 : : } 279 : 44804 : pushToToken(ch); 280 : 44804 : return true; 281 : : } 282 : : 283 : 134249 : bool Smt2Lexer::parseNonEmptyCharList(CharacterClass cc) 284 : : { 285 : : // must contain at least one character 286 : 134249 : int32_t ch = nextChar(); 287 [ + + ]: 134249 : if (!isCharacterClass(ch, cc)) 288 : : { 289 : : // will be an error 290 : 5 : return false; 291 : : } 292 : 134244 : pushToToken(ch); 293 : 134244 : parseCharList(cc); 294 : 134244 : return true; 295 : : } 296 : : 297 : 67283683 : void Smt2Lexer::parseCharList(CharacterClass cc) 298 : : { 299 : : int32_t ch; 300 : : for (;;) 301 : : { 302 : 67283683 : ch = nextChar(); 303 [ + + ]: 67283683 : if (!isCharacterClass(ch, cc)) 304 : : { 305 : : // failed, we are done, put the character back 306 : 15873587 : saveChar(ch); 307 : 15873587 : return; 308 : : } 309 : 51410096 : pushToToken(ch); 310 : : } 311 : : } 312 : : 313 : 14165387 : Token Smt2Lexer::tokenizeCurrentSymbol() const 314 : : { 315 [ - + ][ - + ]: 14165387 : Assert(!d_token.empty()); [ - - ] 316 [ + + ][ + + ]: 14165387 : switch (d_token[0]) [ + + ][ + + ] 317 : : { 318 : 18335 : case '!': 319 [ + + ]: 18335 : if (d_token.size() == 1) 320 : : { 321 : 18235 : return Token::ATTRIBUTE_TOK; 322 : : } 323 : 100 : break; 324 : 739718 : case 'a': 325 [ + + ][ + + ]: 739718 : if (d_token.size() == 2 && d_token[1] == 's') [ + + ] 326 : : { 327 : 2012 : return Token::AS_TOK; 328 : : } 329 : 737706 : break; 330 : 207223 : case 'p': 331 [ + + ][ + + ]: 207223 : if (d_token.size() == 3 && d_token[1] == 'a' && d_token[2] == 'r') [ + - ][ + + ] 332 : : { 333 : 207 : return Token::PAR_TOK; 334 : : } 335 : 207016 : break; 336 : 234479 : case 'l': 337 [ + + ][ + + ]: 234479 : if (d_token.size() == 3 && d_token[1] == 'e' && d_token[2] == 't') [ + + ][ + + ] 338 : : { 339 : 189782 : return Token::LET_TOK; 340 : : } 341 : 44697 : break; 342 : 19297 : case 'm': 343 [ + + ][ + + ]: 21033 : if (d_token.size() == 5 && d_token[1] == 'a' && d_token[2] == 't' 344 [ + + ][ + - ]: 21033 : && d_token[3] == 'c' && d_token[4] == 'h') [ + - ][ + + ] 345 : : { 346 : 152 : return Token::MATCH_TOK; 347 : : } 348 : 19145 : break; 349 : 2560870 : case '_': 350 [ + + ]: 2560870 : if (d_token.size() == 1) 351 : : { 352 : 700958 : return Token::INDEX_TOK; 353 : : } 354 : 1859912 : break; 355 : 329012 : case '-': 356 : : { 357 : : // note that `-4`, `-4.0`, `-4/5` are SMT-LIB symbols, hence we only 358 : : // convert these to literals if we are not strict parsing. 359 [ + + ][ + + ]: 329012 : if (!d_isStrict && d_token.size() >= 2) [ + + ] 360 : : { 361 : : // reparse as a negative numeral, rational or decimal 362 : 18397 : Token ret = Token::INTEGER_LITERAL; 363 [ + + ]: 18483 : for (size_t i = 1, tsize = d_token.size(); i < tsize; i++) 364 : : { 365 [ + + ]: 18423 : if (isCharacterClass(d_token[i], CharacterClass::DECIMAL_DIGIT)) 366 : : { 367 : 80 : continue; 368 : : } 369 [ + + ][ + - ]: 18343 : else if (i + 1 < tsize && ret == Token::INTEGER_LITERAL) 370 : : { 371 [ + + ]: 120 : if (d_token[i] == '.') 372 : : { 373 : 3 : ret = Token::DECIMAL_LITERAL; 374 : 3 : continue; 375 : : } 376 [ + + ]: 117 : else if (d_token[i] == '/') 377 : : { 378 : 3 : ret = Token::RATIONAL_LITERAL; 379 : 3 : continue; 380 : : } 381 : : } 382 : 18337 : return Token::SYMBOL; 383 : : } 384 : 60 : return ret; 385 : : } 386 : : } 387 : 310615 : break; 388 : 10056453 : default: break; 389 : : } 390 : : // otherwise not a special symbol 391 : 13235644 : return Token::SYMBOL; 392 : : } 393 : : 394 : : } // namespace parser 395 : : } // namespace cvc5