File indexing completed on 2024-05-12 05:55:09

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