You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
4.9 KiB
162 lines
4.9 KiB
/** ********************************** */
|
|
/** Part of the QIParser.h declaration */
|
|
/** ********************************** */
|
|
|
|
|
|
#ifndef _qi_polynomial_parser_h_
|
|
#define _qi_polynomial_parser_h_
|
|
|
|
#include <libqi/rpl/bigint.h>
|
|
#include <libqi/io/QIParser.h>
|
|
|
|
unsigned short _current_symbol;
|
|
|
|
/** I. */
|
|
/** *************************** */
|
|
/** Input stream symbol reading */
|
|
/** *************************** */
|
|
#define CURRENT_SYMBOL _current_symbol
|
|
#define NEXT_SYMBOL CURRENT_SYMBOL++
|
|
#define PREV_SYMBOL --CURRENT_SYMBOL
|
|
|
|
#define GET_CURRENT_SYMBOL() ((_current_symbol < _string_length) ? (_quadricDesc.c_str()[CURRENT_SYMBOL]) : '\0')
|
|
#define GET_NEXT_SYMBOL() ((_current_symbol < _string_length) ? (_quadricDesc.c_str()[NEXT_SYMBOL]) : '\0')
|
|
#define GET_PREV_SYMBOL() ((_current_symbol > 0) ? (_quadricDesc.c_str()[PREV_SYMBOL]) : _quadricDesc[0])
|
|
|
|
|
|
/** II. */
|
|
/** ***************************************************** */
|
|
/** Monomial parsing: see the file "monomial_parsing.txt" */
|
|
/** ***************************************************** */
|
|
short m_code[4]; /** Power of X,Y,Z,W */
|
|
short m_sum; /** Value of X+Y+Z+W */
|
|
short current_var; /** Last encountered variable */
|
|
|
|
/** Current monomial's sign */
|
|
short m_sign;
|
|
|
|
|
|
/** Current monomial's coefficient value */
|
|
rpl::bigint m_coefficient;
|
|
|
|
|
|
/** Associate an indice inside m_code for each variable X,Y,Z,W */
|
|
#define VAR_X 3
|
|
#define VAR_Y 2
|
|
#define VAR_Z 1
|
|
#define VAR_W 0
|
|
|
|
/** Resets the code */
|
|
#define reset_code m_sum=m_code[0]=m_code[1]=m_code[2]=m_code[3]=0
|
|
|
|
/** Update each variable's power value as it is encountered */
|
|
#define raise_var ++(m_code[current_var])
|
|
#define raise_x current_var = VAR_X; raise_var
|
|
#define raise_y current_var = VAR_Y; raise_var
|
|
#define raise_z current_var = VAR_Z; raise_var
|
|
#define raise_w current_var = VAR_W; raise_var
|
|
|
|
|
|
/** Sums each digit of the code */
|
|
#define sum_code m_sum = m_code[0] + m_code[1] + m_code[2] + m_code[3]
|
|
|
|
/** Homogenises the code */
|
|
#define hom_code m_code[0] += (2 - m_sum)
|
|
|
|
/** A general purpose macro that checks the code
|
|
and homogenises it if necessary */
|
|
#define check_code \
|
|
sum_code; \
|
|
if (m_sum > 2) { throw "Invalid monomial: " + decode(); }\
|
|
else if (m_sum < 2) { \
|
|
if (m_code[0] != 0) { throw "Invalid monomial: " + decode(); } \
|
|
else hom_code; \
|
|
}
|
|
|
|
/** Does W+2Z+4Y+8X */
|
|
#define hash_code m_code[0] + (m_code[1]<<1) + (m_code[2]<<2) + (m_code[3]<<3)
|
|
|
|
/** Returns the indice inside the vector */
|
|
#define indice_vector m_hash[hash_code]
|
|
|
|
#define init() \
|
|
reset_code; \
|
|
m_coefficient = 1; \
|
|
m_sign = 1;
|
|
|
|
/** When a "+" or a "-" is encountered, we store the
|
|
previously parsed monomial (if exists), then
|
|
we reinit all to prepare for the next monomial, via
|
|
the "init" macro */
|
|
#define next_coeff() \
|
|
try {check_code; } catch(string e) { throw e; }\
|
|
if (indice_vector >= 0 && indice_vector < 10) _vectorialDesc[indice_vector] = m_sign * m_coefficient; \
|
|
init()
|
|
|
|
|
|
/** III. */
|
|
/** ****************************************** */
|
|
/** Templates defining parsing functions for */
|
|
/** each non terminal of the grammar. */
|
|
/** ****************************************** */
|
|
|
|
/** Handy macros to define prototypes and skeletons */
|
|
|
|
/** Header */
|
|
#define PARSE_DECL(name) void parse_##name (void) throw (string)
|
|
|
|
/** Declaration (used in the QIParser's implementation file */
|
|
#define PARSE_IMPL(name) void QIParser::parse_##name (void) throw (string)
|
|
|
|
/** Call to a non terminal checking function */
|
|
#define IS_A(name) parse_##name();
|
|
|
|
/** Booleans used in logical expression */
|
|
#define decl_is_a(name) bool is_a_##name = false
|
|
|
|
/** Automatically declares a prototype for each
|
|
non terminal symbol of the grammar. */
|
|
PARSE_DECL(poly);
|
|
PARSE_DECL(term);
|
|
PARSE_DECL(mono);
|
|
PARSE_DECL(var);
|
|
PARSE_DECL(coef);
|
|
PARSE_DECL(sign);
|
|
PARSE_DECL(eol);
|
|
|
|
|
|
/** IV. */
|
|
/** **************** */
|
|
/** Terminal parsing */
|
|
/** **************** */
|
|
/** Please note that if the read character doesn't match, we *don't*
|
|
* advance to the next character, i.e. "NEXT_SYMBOL" is skipped by
|
|
* the "throw" statement. */
|
|
#define PARSE_TERMINAL(character) \
|
|
do { \
|
|
if ( ! (GET_CURRENT_SYMBOL() == character) ) { \
|
|
stringstream s; \
|
|
s << "Parse error: '" << GET_CURRENT_SYMBOL() << "' at position: " << CURRENT_SYMBOL+1; \
|
|
throw s.str(); \
|
|
} \
|
|
NEXT_SYMBOL; \
|
|
}while(0)
|
|
|
|
|
|
/** V. */
|
|
/** *************************************** */
|
|
/** Debugging function */
|
|
/** Prints the current monomial as a string */
|
|
/** *************************************** */
|
|
inline string decode () {
|
|
stringstream ss;
|
|
|
|
if (m_code[3] > 0) { ss << "x"; if (m_code[3] >= 2) ss << "^" << m_code[3]; ss << " "; }
|
|
if (m_code[2] > 0) { ss << "y"; if (m_code[2] >= 2) ss << "^" << m_code[2]; ss << " "; }
|
|
if (m_code[1] > 0) { ss << "z"; if (m_code[1] >= 2) ss << "^" << m_code[1]; ss << " "; }
|
|
if (m_code[0] > 0) { ss << "w"; if (m_code[0] >= 2) ss << "^" << m_code[0]; }
|
|
return ss.str();
|
|
}
|
|
|
|
#endif
|
|
|
|
|