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 }