File indexing completed on 2024-05-12 17:22:29
0001 // cnumberparser.cpp 0002 // Complex number support : complex number parser using a recursive 0003 // descent approach. 0004 // 0005 // This file is part of the SpeedCrunch project 0006 // Copyright (C) 2013, 2015-2016 Hadrien Theveneau <theveneau@gmail.com>. 0007 // 0008 // This program is free software; you can redistribute it and/or 0009 // modify it under the terms of the GNU General Public License 0010 // as published by the Free Software Foundation; either version 2 0011 // of the License, or (at your option) any later version. 0012 // 0013 // This program is distributed in the hope that it will be useful, 0014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0016 // GNU General Public License for more details. 0017 // 0018 // You should have received a copy of the GNU General Public License 0019 // along with this program; see the file COPYING. If not, write to 0020 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 // Boston, MA 02110-1301, USA. 0022 0023 0024 // This complex number parser currently recognizes the following forms : 0025 // 0026 // a 0027 // a+ib 0028 // a+jb 0029 // a+bi 0030 // a+bj 0031 // ib 0032 // jb 0033 // bi 0034 // bj 0035 // 0036 // The grammar describing one complex number is: 0037 // 0038 // complex_number -> part suite 0039 // suite -> [] 0040 // suite -> + part suite 0041 // 0042 // part -> prefixed_part 0043 // part -> postfixed_part 0044 // 0045 // part_prefixed -> i base_number 0046 // part_prefixed -> j base_number 0047 // 0048 // part_postfixed -> base_number postfix 0049 // 0050 // postfix -> i 0051 // postfix -> j 0052 // postfix -> [] 0053 0054 0055 #include "cnumberparser.h" 0056 0057 using namespace CNumberParserExceptions; 0058 0059 CNumberParser::CNumberParser(const char * _str) : 0060 str(_str) 0061 { 0062 } 0063 0064 /* Parses a complex number using a recursive-desent approach. * 0065 * If successfull, stores the result into *Number. * 0066 * See header file for details. */ 0067 void CNumberParser::parse (CNumber * Number) { 0068 /* Parsing */ 0069 CNumber a = part(); 0070 CNumber b = suite(); 0071 /* Processing */ 0072 *Number = a + b; 0073 } 0074 0075 /* Null string or empty string. strlen(NULL) is undefined. */ 0076 static char _isempty(const char* p){ return p == NULL || *p == '\0'; } 0077 0078 /* Parsing functions. * 0079 * Each of the following function parses one producion of the grammar */ 0080 CNumber CNumberParser::part () { 0081 if (_isempty(str)) { 0082 return CMath::nan(); 0083 } 0084 else if (strncmp(str, "NaN", 3) == 0) { 0085 return CMath::nan(); 0086 } 0087 else if (*str == 'i' || *str == 'j') { 0088 return part_prefixed(); 0089 } 0090 else if (isdigit (*str) || *str == '-' || *str == '+' || *str == '.') { 0091 /* Example cases : 1.0 -1.0 +1.0 .5 */ 0092 return part_postfixed(); 0093 } 0094 else { 0095 return CMath::nan(); 0096 } 0097 } 0098 0099 CNumber CNumberParser::suite () { 0100 if (_isempty(str)) { 0101 return CNumber(0); 0102 } 0103 else if (*str == '+') { 0104 accept(); 0105 CNumber a = part(); 0106 CNumber b = suite(); 0107 return a + b; 0108 } 0109 else if (*str == '-') { 0110 accept(); 0111 CNumber a = part(); 0112 CNumber b = suite(); 0113 return (-a) + b; 0114 } 0115 else { 0116 return CNumber(0); 0117 } 0118 } 0119 0120 CNumber CNumberParser::part_prefixed () { 0121 if (*str == 'i' || *str == 'j') { 0122 /* Parsing */ 0123 accept(); 0124 HNumber y = base_number(); 0125 /* Processing */ 0126 HNumber x = HNumber(0); 0127 CNumber res = CNumber(x, y); 0128 return res; 0129 } 0130 else { 0131 throw UnexpectedSymbol(*str); 0132 } 0133 } 0134 0135 HNumber CNumberParser::base_number () { 0136 /* FIXME ! Error checking ! */ 0137 HNumber x = HMath::parse_str(str, &str); 0138 return x; 0139 } 0140 0141 CNumber CNumberParser::part_postfixed () { 0142 /* Parsing */ 0143 HNumber x = base_number(); 0144 postfix_t p = postfix(); 0145 0146 /* Processing */ 0147 if (p == REAL) /* If real part of a complex number */ 0148 return CNumber(x, 0); 0149 else if (p == IMAG) /* If imaginary part */ 0150 return CNumber(0, x); 0151 else { /* Should never happen */ 0152 throw LogicError(); 0153 } 0154 } 0155 0156 CNumberParser::postfix_t CNumberParser::postfix () { 0157 if (*str == 'i' || *str == 'j') { 0158 accept(); 0159 return IMAG; 0160 } 0161 else { 0162 return REAL; 0163 } 0164 } 0165