File indexing completed on 2024-04-21 03:41:37
0001 /* 0002 SPDX-FileCopyrightText: 2005 Inge Wallin <inge@lysator.liu.se> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "parser.h" 0007 0008 #include <cctype> 0009 0010 #include "kalzium_libscience_debug.h" 0011 0012 Parser::Parser() 0013 { 0014 start(QString()); 0015 } 0016 0017 Parser::Parser(const QString &_str) 0018 { 0019 start(_str); 0020 } 0021 0022 Parser::~Parser() = default; 0023 0024 void Parser::start(const QString &_str) 0025 { 0026 m_str = _str; 0027 0028 if (_str.isNull()) { 0029 m_index = -1; 0030 m_nextChar = -1; 0031 m_nextToken = -1; 0032 } else { 0033 m_index = 0; 0034 m_nextChar = m_str.at(0).toLatin1(); 0035 getNextToken(); 0036 } 0037 } 0038 0039 // ---------------------------------------------------------------- 0040 0041 // Skip whitespace, and try to parse the following characters as an int. 0042 // 0043 // Return true if successful. 0044 0045 bool Parser::parseInt(int *_result) 0046 { 0047 int sign = 1; 0048 0049 skipWhitespace(); 0050 0051 if (m_nextChar == '-') { 0052 sign = -1; 0053 getNextChar(); 0054 } 0055 0056 if (!isdigit(m_nextChar)) { 0057 return false; 0058 } 0059 0060 int result = 0; 0061 while (isdigit(m_nextChar)) { 0062 result = result * 10 + (m_nextChar - '0'); 0063 getNextChar(); 0064 } 0065 0066 *_result = sign * result; 0067 return true; 0068 } 0069 0070 // Skip whitespace, and try to parse the following characters as a 0071 // simple float of the type -?[0-9]+'.'?[0-9]* 0072 // 0073 // Return true if successful. 0074 0075 bool Parser::parseSimpleFloat(double *_result) 0076 { 0077 double sign = 1.0; 0078 0079 skipWhitespace(); 0080 if (m_nextChar == '-') { 0081 sign = -1.0; 0082 getNextChar(); 0083 } 0084 0085 if (!isdigit(m_nextChar)) { 0086 return false; 0087 } 0088 0089 double result = 0.0; 0090 0091 // The integer. 0092 while (isdigit(m_nextChar)) { 0093 result = result * 10.0 + (double)(m_nextChar - '0'); 0094 getNextChar(); 0095 } 0096 *_result = result; 0097 0098 if (m_nextChar != '.' || !isdigit(getNextChar())) { 0099 *_result = sign * result; 0100 return true; 0101 } 0102 0103 double decimal = 0.1; 0104 while (isdigit(m_nextChar)) { 0105 result += decimal * (double)(m_nextChar - '0'); 0106 decimal /= 10.0; 0107 getNextChar(); 0108 } 0109 0110 *_result = sign * result; 0111 return true; 0112 } 0113 0114 // ---------------------------------------------------------------- 0115 // protected methods 0116 0117 int Parser::getNextChar() 0118 { 0119 // qCDebug(KALZIUM_LIBSCIENCE_LOG) << "Parser::getNextChar(): char = " << m_nextChar; 0120 // qCDebug(KALZIUM_LIBSCIENCE_LOG) << "m_str.size() " << m_str.size() << " with m_str: " << m_str << " and m_index: " << m_index; 0121 0122 ++m_index; 0123 0124 if (m_index == -1) { 0125 return -1; 0126 } 0127 0128 // If end of string, then reset the parser. 0129 if (m_index == m_str.size()) { 0130 m_index = -1; 0131 m_nextChar = -1; 0132 } else { 0133 m_nextChar = m_str.at(m_index).toLatin1(); 0134 } 0135 0136 // Take care of null-terminated strings. 0137 if (m_nextChar == 0) { 0138 m_index = -1; 0139 m_nextChar = -1; 0140 } 0141 0142 return m_nextChar; 0143 } 0144 0145 int Parser::skipWhitespace() 0146 { 0147 while (QChar(m_nextChar).isSpace()) { 0148 getNextChar(); 0149 } 0150 0151 return m_nextChar; 0152 } 0153 0154 // Get the next token. This corresponds to the lexical analyzer of a 0155 // standard parser, e.g as generated by lex. 0156 // 0157 // This basic parser supports integers and simple 0158 // floats. Reimplement this method to extend it. 0159 0160 int Parser::getNextToken() 0161 { 0162 int saveIndex = m_index; 0163 0164 skipWhitespace(); 0165 if (isdigit(nextChar())) { 0166 // At this point we know that there is a valid number in the 0167 // string. The only question now, is whether it is an int or a 0168 // float. 0169 0170 parseInt(&m_intVal); 0171 0172 skipWhitespace(); 0173 if (nextChar() == '.') { 0174 m_index = saveIndex; 0175 0176 // No need to check since we already know it is correct. 0177 (void)parseSimpleFloat(&m_floatVal); 0178 m_nextToken = FLOAT_TOKEN; 0179 } else { 0180 m_nextToken = INT_TOKEN; 0181 } 0182 } else if (nextChar() != -1) { 0183 // Any character. 0184 m_nextToken = nextChar(); 0185 getNextChar(); 0186 } else { 0187 // End of string. 0188 m_nextToken = -1; 0189 } 0190 0191 return m_nextToken; 0192 }